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