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