4f814f0f3ca2e4616de28bb25bdad77ac35c64e2
[folly.git] / folly / python / futures.h
1 /*
2  * Copyright 2017-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 /*
17  *  This file serves as a helper for bridging folly::future and python
18  *  asyncio.future.
19  */
20
21 #pragma once
22
23 #include <Python.h>
24 #include <folly/Executor.h>
25 #include <folly/ScopeGuard.h>
26 #include <folly/futures/Future.h>
27 #include <folly/python/executor_api.h>
28
29 namespace folly {
30 namespace python {
31
32 class PyGILStateGuard {
33  public:
34   ~PyGILStateGuard() {
35     PyGILState_Release(gstate);
36   }
37
38  private:
39   PyGILState_STATE gstate{PyGILState_Ensure()};
40 };
41
42 inline folly::Executor* getExecutor() {
43   PyGILStateGuard gstate;
44   import_folly__executor();
45   return get_executor();
46 }
47
48 template <typename T>
49 void bridgeFuture(
50     folly::Executor* executor,
51     folly::Future<T>&& futureFrom,
52     folly::Function<void(folly::Try<T>&&, PyObject*)> callback,
53     PyObject* userData) {
54   // We are handing over a pointer to a python object to c++ and need
55   // to make sure it isn't removed by python in that time.
56   Py_INCREF(userData);
57   auto guard = folly::makeGuard([=] { Py_DECREF(userData); });
58   // Handle the lambdas for cython
59   // run callback from our Q
60   futureFrom.via(executor).then(
61       [ callback = std::move(callback), userData, guard = std::move(guard) ](
62           folly::Try<T> && res) mutable {
63         // This will run from inside the gil, called by the asyncio add_reader
64         callback(std::move(res), userData);
65         // guard goes out of scope here, and its stored function is called
66       });
67 }
68
69 template <typename T>
70 void bridgeFuture(
71     folly::Future<T>&& futureFrom,
72     folly::Function<void(folly::Try<T>&&, PyObject*)> callback,
73     PyObject* userData) {
74   bridgeFuture(
75       getExecutor(), std::move(futureFrom), std::move(callback), userData);
76 }
77
78 } // python
79 } // folly