OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "mojo/public/python/src/python_system_helper.h" | 5 #include "mojo/public/python/src/python_system_helper.h" |
6 | 6 |
7 #include "Python.h" | 7 #include "Python.h" |
8 | 8 |
9 #include "mojo/public/cpp/environment/environment.h" | |
10 #include "mojo/public/cpp/environment/logging.h" | |
11 #include "mojo/public/cpp/system/macros.h" | |
12 #include "mojo/public/cpp/utility/run_loop.h" | 9 #include "mojo/public/cpp/utility/run_loop.h" |
| 10 #include "mojo/public/python/src/common.h" |
13 | 11 |
14 namespace { | 12 namespace { |
15 | 13 class QuitCurrentRunLoop : public mojo::Closure::Runnable { |
16 class ScopedGIL { | |
17 public: | 14 public: |
18 ScopedGIL() { state_ = PyGILState_Ensure(); } | 15 void Run() const override { |
19 | 16 mojo::RunLoop::current()->Quit(); |
20 ~ScopedGIL() { PyGILState_Release(state_); } | |
21 | |
22 private: | |
23 PyGILState_STATE state_; | |
24 | |
25 MOJO_DISALLOW_COPY_AND_ASSIGN(ScopedGIL); | |
26 }; | |
27 | |
28 enum ScopedPyRefAcquire { | |
29 kAcquire, | |
30 }; | |
31 | |
32 class ScopedPyRef { | |
33 public: | |
34 ScopedPyRef(PyObject* object) : object_(object) {} | |
35 ScopedPyRef(PyObject* object, ScopedPyRefAcquire) : object_(object) { | |
36 Py_XINCREF(object_); | |
37 } | 17 } |
38 | 18 |
39 ~ScopedPyRef() { | 19 static mojo::Closure NewQuitClosure() { |
40 if (object_) { | 20 return mojo::Closure( |
41 ScopedGIL acquire_gil; | 21 static_cast<mojo::Closure::Runnable*>(new QuitCurrentRunLoop())); |
42 Py_DECREF(object_); | |
43 } | |
44 } | 22 } |
45 | |
46 operator PyObject*() const { return object_; } | |
47 | |
48 private: | |
49 PyObject* object_; | |
50 | |
51 MOJO_DISALLOW_COPY_AND_ASSIGN(ScopedPyRef); | |
52 }; | 23 }; |
53 | 24 |
54 class PythonClosure : public mojo::Closure::Runnable { | |
55 public: | |
56 PythonClosure(PyObject* callable) : callable_(callable, kAcquire) { | |
57 MOJO_DCHECK(callable); | |
58 } | |
59 | |
60 void Run() const override { | |
61 ScopedGIL acquire_gil; | |
62 ScopedPyRef empty_tuple(PyTuple_New(0)); | |
63 if (!empty_tuple) { | |
64 mojo::RunLoop::current()->Quit(); | |
65 return; | |
66 } | |
67 | |
68 ScopedPyRef result(PyObject_CallObject(callable_, empty_tuple)); | |
69 if (!result) { | |
70 mojo::RunLoop::current()->Quit(); | |
71 return; | |
72 } | |
73 } | |
74 | |
75 private: | |
76 ScopedPyRef callable_; | |
77 | |
78 MOJO_DISALLOW_COPY_AND_ASSIGN(PythonClosure); | |
79 }; | |
80 | |
81 void AsyncCallbackForwarder(void* closure, MojoResult result) { | |
82 mojo::Callback<void(MojoResult)>* callback = | |
83 static_cast<mojo::Callback<void(MojoResult)>*>(closure); | |
84 // callback will be deleted when it is run. | |
85 callback->Run(result); | |
86 } | |
87 | |
88 } // namespace | 25 } // namespace |
89 | 26 |
90 namespace mojo { | 27 namespace mojo { |
91 namespace python { | 28 namespace python { |
92 | 29 |
93 class PythonAsyncWaiter::AsyncWaiterRunnable | |
94 : public mojo::Callback<void(MojoResult)>::Runnable { | |
95 public: | |
96 AsyncWaiterRunnable(PyObject* callable, CallbackMap* callbacks) | |
97 : wait_id_(0), callable_(callable, kAcquire), callbacks_(callbacks) { | |
98 MOJO_DCHECK(callable); | |
99 MOJO_DCHECK(callbacks_); | |
100 } | |
101 | |
102 void set_wait_id(int wait_id) { wait_id_ = wait_id; } | |
103 | |
104 void Run(MojoResult mojo_result) const override { | |
105 MOJO_DCHECK(wait_id_); | |
106 | |
107 // Remove to reference to this object from PythonAsyncWaiter and ensure this | |
108 // object will be destroyed when this method exits. | |
109 MOJO_DCHECK(callbacks_->find(wait_id_) != callbacks_->end()); | |
110 internal::SharedPtr<mojo::Callback<void(MojoResult)>> self = | |
111 (*callbacks_)[wait_id_]; | |
112 callbacks_->erase(wait_id_); | |
113 | |
114 ScopedGIL acquire_gil; | |
115 ScopedPyRef args_tuple(Py_BuildValue("(i)", mojo_result)); | |
116 if (!args_tuple) { | |
117 mojo::RunLoop::current()->Quit(); | |
118 return; | |
119 } | |
120 | |
121 ScopedPyRef result(PyObject_CallObject(callable_, args_tuple)); | |
122 if (!result) { | |
123 mojo::RunLoop::current()->Quit(); | |
124 return; | |
125 } | |
126 } | |
127 | |
128 private: | |
129 MojoAsyncWaitID wait_id_; | |
130 ScopedPyRef callable_; | |
131 CallbackMap* callbacks_; | |
132 | |
133 MOJO_DISALLOW_COPY_AND_ASSIGN(AsyncWaiterRunnable); | |
134 }; | |
135 | |
136 Closure BuildClosure(PyObject* callable) { | 30 Closure BuildClosure(PyObject* callable) { |
137 if (!PyCallable_Check(callable)) | 31 if (!PyCallable_Check(callable)) |
138 return Closure(); | 32 return Closure(); |
139 | 33 |
140 return Closure( | 34 return mojo::Closure( |
141 static_cast<mojo::Closure::Runnable*>(new PythonClosure(callable))); | 35 NewRunnableFromCallable(callable, QuitCurrentRunLoop::NewQuitClosure())); |
142 } | 36 } |
143 | 37 |
144 PythonAsyncWaiter::PythonAsyncWaiter() { | 38 PythonAsyncWaiter* NewAsyncWaiter() { |
145 async_waiter_ = Environment::GetDefaultAsyncWaiter(); | 39 return new PythonAsyncWaiter(QuitCurrentRunLoop::NewQuitClosure()); |
146 } | |
147 | |
148 PythonAsyncWaiter::~PythonAsyncWaiter() { | |
149 for (CallbackMap::const_iterator it = callbacks_.begin(); | |
150 it != callbacks_.end(); | |
151 ++it) { | |
152 async_waiter_->CancelWait(it->first); | |
153 } | |
154 } | |
155 | |
156 MojoAsyncWaitID PythonAsyncWaiter::AsyncWait(MojoHandle handle, | |
157 MojoHandleSignals signals, | |
158 MojoDeadline deadline, | |
159 PyObject* callable) { | |
160 AsyncWaiterRunnable* runner = new AsyncWaiterRunnable(callable, &callbacks_); | |
161 internal::SharedPtr<mojo::Callback<void(MojoResult)>> callback( | |
162 new mojo::Callback<void(MojoResult)>( | |
163 static_cast<mojo::Callback<void(MojoResult)>::Runnable*>(runner))); | |
164 MojoAsyncWaitID wait_id = async_waiter_->AsyncWait( | |
165 handle, signals, deadline, &AsyncCallbackForwarder, callback.get()); | |
166 callbacks_[wait_id] = callback; | |
167 runner->set_wait_id(wait_id); | |
168 return wait_id; | |
169 } | |
170 | |
171 void PythonAsyncWaiter::CancelWait(MojoAsyncWaitID wait_id) { | |
172 if (callbacks_.find(wait_id) != callbacks_.end()) { | |
173 async_waiter_->CancelWait(wait_id); | |
174 callbacks_.erase(wait_id); | |
175 } | |
176 } | 40 } |
177 | 41 |
178 } // namespace python | 42 } // namespace python |
179 } // namespace mojo | 43 } // namespace mojo |
OLD | NEW |