]> git.proxmox.com Git - ceph.git/blob - ceph/src/mgr/Gil.h
update sources to v12.1.0
[ceph.git] / ceph / src / mgr / Gil.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2017 SUSE LLC
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15 #ifndef GIL_H_
16 #define GIL_H_
17
18 #include "Python.h"
19
20 #include "common/debug.h"
21
22 #define dout_context g_ceph_context
23 #define dout_subsys ceph_subsys_mgr
24 #undef dout_prefix
25 #define dout_prefix *_dout << "mgr " << __func__ << " "
26
27 //
28 // Use one of these in any scope in which you need to hold Python's
29 // Global Interpreter Lock.
30 //
31 // Do *not* nest these, as a second GIL acquire will deadlock (see
32 // https://docs.python.org/2/c-api/init.html#c.PyEval_RestoreThread)
33 //
34 // If in doubt, explicitly put a scope around the block of code you
35 // know you need the GIL in.
36 //
37 // See the comment below for when to set new_thread == true
38 //
39 class Gil {
40 public:
41 Gil(const Gil&) = delete;
42 Gil& operator=(const Gil&) = delete;
43
44 Gil(PyThreadState *ts, bool new_thread = false) : pThreadState(ts)
45 {
46 assert(pThreadState != nullptr);
47
48 // Acquire the GIL, set the current thread state
49 PyEval_RestoreThread(pThreadState);
50 dout(20) << "GIL acquired for thread state " << pThreadState << dendl;
51
52 //
53 // If called from a separate OS thread (i.e. a thread not created
54 // by Python, that does't already have a python thread state that
55 // was created when that thread was active), we need to manually
56 // create and switch to a python thread state specifically for this
57 // OS thread.
58 //
59 // Note that instead of requring the caller to set new_thread == true
60 // when calling this from a separate OS thread, we could figure out
61 // if this was necessary automatically, as follows:
62 //
63 // if (pThreadState->thread_id != PyThread_get_thread_ident()) {
64 //
65 // However, this means we're accessing pThreadState->thread_id, but
66 // the Python C API docs say that "The only public data member is
67 // PyInterpreterState *interp", i.e. doing this would violate
68 // something that's meant to be a black box.
69 //
70 if (new_thread) {
71 pNewThreadState = PyThreadState_New(pThreadState->interp);
72 PyThreadState_Swap(pNewThreadState);
73 dout(20) << "Switched to new thread state " << pNewThreadState << dendl;
74 }
75 }
76
77 ~Gil()
78 {
79 if (pNewThreadState != nullptr) {
80 dout(20) << "Destroying new thread state " << pNewThreadState << dendl;
81 PyThreadState_Swap(pThreadState);
82 PyThreadState_Clear(pNewThreadState);
83 PyThreadState_Delete(pNewThreadState);
84 }
85 // Release the GIL, reset the thread state to NULL
86 PyEval_SaveThread();
87 dout(20) << "GIL released for thread state " << pThreadState << dendl;
88 }
89
90 private:
91 PyThreadState *pThreadState;
92 PyThreadState *pNewThreadState = nullptr;
93 };
94
95 #endif
96