]> git.proxmox.com Git - ceph.git/blame - ceph/src/mgr/Gil.h
update sources to v12.1.0
[ceph.git] / ceph / src / mgr / Gil.h
CommitLineData
31f18b77
FG
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//
39class Gil {
40public:
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
90private:
91 PyThreadState *pThreadState;
92 PyThreadState *pNewThreadState = nullptr;
93};
94
95#endif
96