|
5 | 5 |
|
6 | 6 | namespace NppPythonScript |
7 | 7 | { |
8 | | - /* |
| 8 | + /* |
9 | 9 |
|
10 | | - This whole schenanigans is necessary, as you can't call PyGILState_Ensure() from a thread that already has the GIL. |
| 10 | + This whole schenanigans is necessary, as you can't call PyGILState_Ensure() from a thread that already has the GIL. |
11 | 11 |
|
12 | | - For the ScintillaWrapper (specifically, but not exclusively), it's tricky to impossible to tell if we need to release the GIL. If we're running on the |
13 | | - Python worker thread, and we make a call to Scintilla, that triggers a callback, we need to give it up (in order that the callback can run). The callback |
14 | | - identification must be performed with the GIL, so it would block if we didn't give it up. (There's an optimisation that if no callbacks are registered, then it |
15 | | - doesn't check, and doesn't acquire the GIL) |
| 12 | + For the ScintillaWrapper (specifically, but not exclusively), it's tricky to impossible to tell if we need to release the GIL. If we're running on the |
| 13 | + Python worker thread, and we make a call to Scintilla, that triggers a callback, we need to give it up (in order that the callback can run). The callback |
| 14 | + identification must be performed with the GIL, so it would block if we didn't give it up. (There's an optimisation that if no callbacks are registered, then it |
| 15 | + doesn't check, and doesn't acquire the GIL) |
16 | 16 | |
17 | 17 | However, if we're being called from the replace function, and therefore the main thread, we probably don't even have the GIL to give up. |
18 | 18 | |
19 | 19 | With the different threads running the different callbacks, and python code running on a thread (*generally* - see the editor.replace() suite) |
20 | | - it has become impossible to manage manually (read: the Wrong Way To Do It(tm)). These objects manage the GIL, and provide a easy, safe way to ensure |
| 20 | + it has become impossible to manage manually (read: the Wrong Way To Do It(tm)). These objects manage the GIL, and provide a easy, safe way to ensure |
21 | 21 | you have the GIL when you need it, and give it up correctly whatever happens in the mean time. |
22 | 22 |
|
23 | | - The doIHaveTheGIL() function is taken from Python 3.4.0, Issue #17522. An extra workaround is included to make it work when Py_DEBUG is defined. |
24 | | - - see note below where PyThreadState_GET is redefined. |
25 | | - */ |
| 23 | + The doIHaveTheGIL() function is taken from Python 3.4.0, Issue #17522. An extra workaround is included to make it work when Py_DEBUG is defined. |
| 24 | + - see note below where PyThreadState_GET is redefined. |
| 25 | + */ |
26 | 26 |
|
27 | 27 |
|
28 | 28 | #ifdef Py_DEBUG |
29 | | - /* For Py_DEBUG, PyThreadState_GET() is redefined to PyThreadState_Get(), which checks that the current ThreadState is not null |
30 | | - * We "undo" that define here, as we need to get the current threadstate without checking if it's not set |
31 | | - */ |
| 29 | + /* For Py_DEBUG, PyThreadState_GET() is redefined to PyThreadState_Get(), which checks that the current ThreadState is not null |
| 30 | + * We "undo" that define here, as we need to get the current threadstate without checking if it's not set |
| 31 | + */ |
32 | 32 | #undef PyThreadState_GET |
33 | 33 | #define PyThreadState_GET() (_PyThreadState_Current) |
34 | 34 | #endif |
35 | 35 |
|
36 | | - class GILHandler |
| 36 | + class GILHandler |
37 | 37 | { |
38 | 38 | protected: |
39 | 39 | static bool doIHaveTheGIL() |
40 | 40 | { |
41 | 41 | //TODO check if PyThreadState_GET should be used or something else |
42 | | - PyThreadState* thisThreadState = PyGILState_GetThisThreadState(); |
43 | | - return (thisThreadState && thisThreadState == _PyThreadState_UncheckedGet()); |
| 42 | + PyThreadState* thisThreadState = PyGILState_GetThisThreadState(); |
| 43 | + return (thisThreadState && thisThreadState == PyThreadState_GetUnchecked()); |
44 | 44 | } |
45 | 45 |
|
46 | 46 | }; |
47 | 47 |
|
48 | 48 |
|
49 | | - /* GILLock holds the GIL whilst it exists. If you already have the GIL, it will do nothing. |
50 | | - * If however, you didn't already have the lock, it will obtain the lock on construction, |
51 | | - * and release it back upon destruction. |
52 | | - */ |
53 | | - class GILLock : public GILHandler |
| 49 | + /* GILLock holds the GIL whilst it exists. If you already have the GIL, it will do nothing. |
| 50 | + * If however, you didn't already have the lock, it will obtain the lock on construction, |
| 51 | + * and release it back upon destruction. |
| 52 | + */ |
| 53 | + class GILLock : public GILHandler |
54 | 54 | { |
55 | 55 | public: |
56 | 56 | GILLock(); |
57 | 57 | virtual ~GILLock(); |
58 | 58 |
|
59 | 59 | private: |
60 | | - GILLock(const GILLock&); /* disable copying */ |
61 | | - GILLock& operator = (const GILLock&); /* disable assignment */ |
| 60 | + GILLock(const GILLock&) = delete; /* disable copying */ |
| 61 | + GILLock& operator = (const GILLock&) = delete; /* disable assignment */ |
62 | 62 | PyGILState_STATE m_state; |
63 | 63 | bool m_hasLock; |
64 | 64 | }; |
65 | 65 |
|
66 | 66 |
|
67 | | - /* GILRelease will release the GIL if you have it for as long as the object exists. |
68 | | - * On destruction it will reacquire the lock. You can reacquire the GIL sooner than |
69 | | - * destruction by calling reacquire(). This makes the destructor a no-op. |
70 | | - */ |
71 | | - class GILRelease : public GILHandler |
| 67 | + /* GILRelease will release the GIL if you have it for as long as the object exists. |
| 68 | + * On destruction it will reacquire the lock. You can reacquire the GIL sooner than |
| 69 | + * destruction by calling reacquire(). This makes the destructor a no-op. |
| 70 | + */ |
| 71 | + class GILRelease : public GILHandler |
72 | 72 | { |
73 | 73 | public: |
74 | | - GILRelease(); |
75 | | - virtual ~GILRelease(); |
| 74 | + GILRelease(); |
| 75 | + virtual ~GILRelease(); |
76 | 76 |
|
77 | | - /** Reacquire the GIL after releasing it |
78 | | - * This is performed automatically on destruction of this object, but if |
79 | | - * you need to reacquire the lock before the object is disposed, then use this method |
80 | | - * After usage of this method, the destructor becomes a no-op |
81 | | - */ |
82 | | - void reacquire(); |
| 77 | + /** Reacquire the GIL after releasing it |
| 78 | + * This is performed automatically on destruction of this object, but if |
| 79 | + * you need to reacquire the lock before the object is disposed, then use this method |
| 80 | + * After usage of this method, the destructor becomes a no-op |
| 81 | + */ |
| 82 | + void reacquire(); |
83 | 83 |
|
84 | 84 | private: |
85 | | - GILRelease(const GILRelease&); |
86 | | - GILRelease& operator = (const GILRelease&); /* disable assignment */ |
87 | | - PyThreadState *m_threadState; |
| 85 | + GILRelease(const GILRelease&); |
| 86 | + GILRelease& operator = (const GILRelease&); /* disable assignment */ |
| 87 | + PyThreadState *m_threadState; |
88 | 88 | bool m_lockReleased; |
89 | 89 | }; |
90 | 90 |
|
|
0 commit comments