| 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 "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 |