11320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Copyright 2014 The Chromium Authors. All rights reserved.
21320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Use of this source code is governed by a BSD-style license that can be
31320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// found in the LICENSE file.
41320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "mojo/public/python/src/python_system_helper.h"
61320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "Python.h"
81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "mojo/public/cpp/environment/environment.h"
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "mojo/public/cpp/environment/logging.h"
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "mojo/public/cpp/system/macros.h"
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "mojo/public/cpp/utility/run_loop.h"
131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace {
151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciclass ScopedGIL {
171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public:
181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ScopedGIL() { state_ = PyGILState_Ensure(); }
191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ~ScopedGIL() { PyGILState_Release(state_); }
211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private:
231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  PyGILState_STATE state_;
241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  MOJO_DISALLOW_COPY_AND_ASSIGN(ScopedGIL);
261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci};
271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciclass PythonClosure : public mojo::Closure::Runnable {
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public:
301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  PythonClosure(PyObject* callable) : callable_(callable) {
311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    MOJO_DCHECK(callable);
321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    Py_XINCREF(callable);
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  virtual ~PythonClosure() {
361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ScopedGIL acquire_gil;
371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    Py_DECREF(callable_);
381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  virtual void Run() const MOJO_OVERRIDE {
411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ScopedGIL acquire_gil;
421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    PyObject* empty_tuple = PyTuple_New(0);
431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (!empty_tuple) {
441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      mojo::RunLoop::current()->Quit();
451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return;
461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    PyObject* result = PyObject_CallObject(callable_, empty_tuple);
491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    Py_DECREF(empty_tuple);
501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (result) {
511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      Py_DECREF(result);
521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    } else {
531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      mojo::RunLoop::current()->Quit();
541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return;
551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private:
591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  PyObject* callable_;
601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  MOJO_DISALLOW_COPY_AND_ASSIGN(PythonClosure);
621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci};
631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid AsyncCallbackForwarder(void* closure, MojoResult result) {
651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  mojo::Callback<void(MojoResult)>* callback =
661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      static_cast<mojo::Callback<void(MojoResult)>*>(closure);
671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // callback will be deleted when it is run.
681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  callback->Run(result);
691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}  // namespace
721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace mojo {
741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace python {
751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciclass PythonAsyncWaiter::AsyncWaiterRunnable
771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    : public mojo::Callback<void(MojoResult)>::Runnable {
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public:
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  AsyncWaiterRunnable(PyObject* callable, CallbackMap* callbacks)
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      : wait_id_(0), callable_(callable), callbacks_(callbacks) {
811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    MOJO_DCHECK(callable);
821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    MOJO_DCHECK(callbacks_);
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    Py_XINCREF(callable);
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  virtual ~AsyncWaiterRunnable() {
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ScopedGIL acquire_gil;
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    Py_DECREF(callable_);
891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  void set_wait_id(int wait_id) { wait_id_ = wait_id; }
921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  virtual void Run(MojoResult mojo_result) const MOJO_OVERRIDE {
941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    MOJO_DCHECK(wait_id_);
951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Remove to reference to this object from PythonAsyncWaiter and ensure this
971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // object will be destroyed when this method exits.
981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    MOJO_DCHECK(callbacks_->find(wait_id_) != callbacks_->end());
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    internal::SharedPtr<mojo::Callback<void(MojoResult)> > self =
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        (*callbacks_)[wait_id_];
1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    callbacks_->erase(wait_id_);
1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ScopedGIL acquire_gil;
1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    PyObject* args_tuple = Py_BuildValue("(i)", mojo_result);
1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (!args_tuple) {
1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      mojo::RunLoop::current()->Quit();
1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return;
1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    PyObject* result = PyObject_CallObject(callable_, args_tuple);
1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    Py_DECREF(args_tuple);
1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (result) {
1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      Py_DECREF(result);
1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    } else {
1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      mojo::RunLoop::current()->Quit();
1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return;
1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private:
1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  MojoAsyncWaitID wait_id_;
1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  PyObject* callable_;
1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CallbackMap* callbacks_;
1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  MOJO_DISALLOW_COPY_AND_ASSIGN(AsyncWaiterRunnable);
1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci};
1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciClosure BuildClosure(PyObject* callable) {
1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!PyCallable_Check(callable))
1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return Closure();
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return Closure(
1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      static_cast<mojo::Closure::Runnable*>(new PythonClosure(callable)));
1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciPythonAsyncWaiter::PythonAsyncWaiter() {
1371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  async_waiter_ = Environment::GetDefaultAsyncWaiter();
1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciPythonAsyncWaiter::~PythonAsyncWaiter() {
1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for (CallbackMap::const_iterator it = callbacks_.begin();
1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci       it != callbacks_.end();
1431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci       ++it) {
1441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    async_waiter_->CancelWait(it->first);
1451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciMojoAsyncWaitID PythonAsyncWaiter::AsyncWait(MojoHandle handle,
1491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                             MojoHandleSignals signals,
1501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                             MojoDeadline deadline,
1511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                             PyObject* callable) {
1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  AsyncWaiterRunnable* runner = new AsyncWaiterRunnable(callable, &callbacks_);
1531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  internal::SharedPtr<mojo::Callback<void(MojoResult)> > callback(
1541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      new mojo::Callback<void(MojoResult)>(
1551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          static_cast<mojo::Callback<void(MojoResult)>::Runnable*>(runner)));
1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  MojoAsyncWaitID wait_id = async_waiter_->AsyncWait(
1571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      handle, signals, deadline, &AsyncCallbackForwarder, callback.get());
1581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  callbacks_[wait_id] = callback;
1591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  runner->set_wait_id(wait_id);
1601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return wait_id;
1611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid PythonAsyncWaiter::CancelWait(MojoAsyncWaitID wait_id) {
1641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (callbacks_.find(wait_id) != callbacks_.end()) {
1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    async_waiter_->CancelWait(wait_id);
1661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    callbacks_.erase(wait_id);
1671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}  // namespace python
1711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}  // namespace mojo
172