Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / mojo / public / python / src / python_system_helper.cc
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
3 // found in the LICENSE file.
4
5 #include "mojo/public/python/src/python_system_helper.h"
6
7 #include "Python.h"
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"
13
14 namespace {
15
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 class PythonClosure : public mojo::Closure::Runnable {
29  public:
30   PythonClosure(PyObject* callable) : callable_(callable) {
31     MOJO_DCHECK(callable);
32     Py_XINCREF(callable);
33   }
34
35   virtual ~PythonClosure() {
36     ScopedGIL acquire_gil;
37     Py_DECREF(callable_);
38   }
39
40   virtual void Run() const MOJO_OVERRIDE {
41     ScopedGIL acquire_gil;
42     PyObject* empty_tuple = PyTuple_New(0);
43     if (!empty_tuple) {
44       mojo::RunLoop::current()->Quit();
45       return;
46     }
47
48     PyObject* result = PyObject_CallObject(callable_, empty_tuple);
49     Py_DECREF(empty_tuple);
50     if (result) {
51       Py_DECREF(result);
52     } else {
53       mojo::RunLoop::current()->Quit();
54       return;
55     }
56   }
57
58  private:
59   PyObject* callable_;
60
61   MOJO_DISALLOW_COPY_AND_ASSIGN(PythonClosure);
62 };
63
64 void AsyncCallbackForwarder(void* closure, MojoResult result) {
65   mojo::Callback<void(MojoResult)>* callback =
66       static_cast<mojo::Callback<void(MojoResult)>*>(closure);
67   // callback will be deleted when it is run.
68   callback->Run(result);
69 }
70
71 }  // namespace
72
73 namespace mojo {
74 namespace python {
75
76 class PythonAsyncWaiter::AsyncWaiterRunnable
77     : public mojo::Callback<void(MojoResult)>::Runnable {
78  public:
79   AsyncWaiterRunnable(PyObject* callable, CallbackMap* callbacks)
80       : wait_id_(0), callable_(callable), callbacks_(callbacks) {
81     MOJO_DCHECK(callable);
82     MOJO_DCHECK(callbacks_);
83     Py_XINCREF(callable);
84   }
85
86   virtual ~AsyncWaiterRunnable() {
87     ScopedGIL acquire_gil;
88     Py_DECREF(callable_);
89   }
90
91   void set_wait_id(int wait_id) { wait_id_ = wait_id; }
92
93   virtual void Run(MojoResult mojo_result) const MOJO_OVERRIDE {
94     MOJO_DCHECK(wait_id_);
95
96     // Remove to reference to this object from PythonAsyncWaiter and ensure this
97     // object will be destroyed when this method exits.
98     MOJO_DCHECK(callbacks_->find(wait_id_) != callbacks_->end());
99     internal::SharedPtr<mojo::Callback<void(MojoResult)> > self =
100         (*callbacks_)[wait_id_];
101     callbacks_->erase(wait_id_);
102
103     ScopedGIL acquire_gil;
104     PyObject* args_tuple = Py_BuildValue("(i)", mojo_result);
105     if (!args_tuple) {
106       mojo::RunLoop::current()->Quit();
107       return;
108     }
109
110     PyObject* result = PyObject_CallObject(callable_, args_tuple);
111     Py_DECREF(args_tuple);
112     if (result) {
113       Py_DECREF(result);
114     } else {
115       mojo::RunLoop::current()->Quit();
116       return;
117     }
118   }
119
120  private:
121   MojoAsyncWaitID wait_id_;
122   PyObject* callable_;
123   CallbackMap* callbacks_;
124
125   MOJO_DISALLOW_COPY_AND_ASSIGN(AsyncWaiterRunnable);
126 };
127
128 Closure BuildClosure(PyObject* callable) {
129   if (!PyCallable_Check(callable))
130     return Closure();
131
132   return Closure(
133       static_cast<mojo::Closure::Runnable*>(new PythonClosure(callable)));
134 }
135
136 PythonAsyncWaiter::PythonAsyncWaiter() {
137   async_waiter_ = Environment::GetDefaultAsyncWaiter();
138 }
139
140 PythonAsyncWaiter::~PythonAsyncWaiter() {
141   for (CallbackMap::const_iterator it = callbacks_.begin();
142        it != callbacks_.end();
143        ++it) {
144     async_waiter_->CancelWait(it->first);
145   }
146 }
147
148 MojoAsyncWaitID PythonAsyncWaiter::AsyncWait(MojoHandle handle,
149                                              MojoHandleSignals signals,
150                                              MojoDeadline deadline,
151                                              PyObject* callable) {
152   AsyncWaiterRunnable* runner = new AsyncWaiterRunnable(callable, &callbacks_);
153   internal::SharedPtr<mojo::Callback<void(MojoResult)> > callback(
154       new mojo::Callback<void(MojoResult)>(
155           static_cast<mojo::Callback<void(MojoResult)>::Runnable*>(runner)));
156   MojoAsyncWaitID wait_id = async_waiter_->AsyncWait(
157       handle, signals, deadline, &AsyncCallbackForwarder, callback.get());
158   callbacks_[wait_id] = callback;
159   runner->set_wait_id(wait_id);
160   return wait_id;
161 }
162
163 void PythonAsyncWaiter::CancelWait(MojoAsyncWaitID wait_id) {
164   if (callbacks_.find(wait_id) != callbacks_.end()) {
165     async_waiter_->CancelWait(wait_id);
166     callbacks_.erase(wait_id);
167   }
168 }
169
170 }  // namespace python
171 }  // namespace mojo