@@ -192,17 +192,118 @@ class _curses.window "PyCursesWindowObject *" "clinic_state()->window_type"
192
192
[clinic start generated code]*/
193
193
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=ae6cb623018f2cbc]*/
194
194
195
- /* Tells whether setupterm() has been called to initialise terminfo. */
195
+ /*
196
+ * Tells whether setupterm() has been called to initialise terminfo.
197
+ *
198
+ * Use curses_setupterm_{was,set}_called() for atomic reads and writes.
199
+ */
196
200
static int curses_setupterm_called = FALSE;
197
201
198
- /* Tells whether initscr() has been called to initialise curses. */
202
+ static inline int
203
+ curses_setupterm_was_called (void )
204
+ {
205
+ #ifdef Py_GIL_DISABLED
206
+ return _Py_atomic_load_int (& curses_setupterm_called );
207
+ #else
208
+ return curses_setupterm_called ;
209
+ #endif
210
+ }
211
+
212
+ static inline void
213
+ curses_setupterm_set_called (void )
214
+ {
215
+ #ifdef Py_GIL_DISABLED
216
+ _Py_atomic_store_int (& curses_setupterm_called , TRUE);
217
+ #else
218
+ curses_setupterm_called = called ? TRUE : FALSE;
219
+ #endif
220
+ }
221
+
222
+ /*
223
+ * Tells whether initscr() has been called to initialise curses.
224
+ *
225
+ * Use curses_initscr_{was,set}_called() for atomic reads and writes.
226
+ */
199
227
static int curses_initscr_called = FALSE;
200
228
201
- /* Tells whether start_color() has been called to initialise color usage. */
229
+ static inline int
230
+ curses_initscr_was_called (void )
231
+ {
232
+ #ifdef Py_GIL_DISABLED
233
+ return _Py_atomic_load_int (& curses_initscr_called );
234
+ #else
235
+ return curses_initscr_called ;
236
+ #endif
237
+ }
238
+
239
+ static inline void
240
+ curses_initscr_set_called (void )
241
+ {
242
+ #ifdef Py_GIL_DISABLED
243
+ _Py_atomic_store_int (& curses_initscr_called , TRUE);
244
+ #else
245
+ curses_initscr_called = TRUE;
246
+ #endif
247
+ }
248
+
249
+ /*
250
+ * Tells whether start_color() has been called to initialise color usage.
251
+ *
252
+ * Use curses_start_color_{was,set}_called() for atomic reads and writes.
253
+ */
202
254
static int curses_start_color_called = FALSE;
203
255
256
+ static inline int
257
+ curses_start_color_was_called (void )
258
+ {
259
+ #ifdef Py_GIL_DISABLED
260
+ return _Py_atomic_load_int (& curses_start_color_called );
261
+ #else
262
+ return curses_start_color_called ;
263
+ #endif
264
+ }
265
+
266
+ static inline void
267
+ curses_start_color_set_called (void )
268
+ {
269
+ #ifdef Py_GIL_DISABLED
270
+ _Py_atomic_store_int (& curses_start_color_called , TRUE);
271
+ #else
272
+ curses_start_color_called = TRUE;
273
+ #endif
274
+ }
275
+
276
+ /*
277
+ * The curses screen encoding.
278
+ *
279
+ * Use curses_{get,set}_screen_encoding() to
280
+ * safely (atomically) access this variable.
281
+ */
204
282
static const char * curses_screen_encoding = NULL ;
205
283
284
+ /* Atomically retrieve the current screen encoding. */
285
+ static inline const char *
286
+ curses_get_screen_encoding (void )
287
+ {
288
+ #ifdef Py_GIL_DISABLED
289
+ return (const char * )_Py_atomic_load_ptr (& curses_screen_encoding );
290
+ #else
291
+ return curses_screen_encoding ;
292
+ #endif
293
+ }
294
+
295
+ /* Atomically set the current screen encoding. */
296
+ static inline void
297
+ curses_set_screen_encoding (const char * encoding )
298
+ {
299
+ assert (encoding != NULL );
300
+ #ifdef Py_GIL_DISABLED
301
+ _Py_atomic_store_ptr (& curses_screen_encoding , (char * )encoding );
302
+ #else
303
+ curses_screen_encoding = encoding ;
304
+ #endif
305
+ }
306
+
206
307
/* Utility Checking Procedures */
207
308
208
309
/*
@@ -215,7 +316,7 @@ static const char *curses_screen_encoding = NULL;
215
316
* type is directly taken from the global state for now.
216
317
*/
217
318
static inline int
218
- _PyCursesCheckFunction (int called , const char * funcname )
319
+ _PyCursesStatelessCheckWasCalled (int called , const char * funcname )
219
320
{
220
321
if (called == TRUE) {
221
322
return 1 ;
@@ -232,7 +333,7 @@ _PyCursesCheckFunction(int called, const char *funcname)
232
333
* The exception type is obtained from the 'module' state.
233
334
*/
234
335
static inline int
235
- _PyCursesStatefulCheckFunction (PyObject * module , int called , const char * funcname )
336
+ _PyCursesCheckWasCalled (PyObject * module , int called , const char * funcname )
236
337
{
237
338
if (called == TRUE) {
238
339
return 1 ;
@@ -244,30 +345,24 @@ _PyCursesStatefulCheckFunction(PyObject *module, int called, const char *funcnam
244
345
245
346
#define PyCursesStatefulSetupTermCalled (MODULE ) \
246
347
do { \
247
- if (!_PyCursesStatefulCheckFunction(MODULE, \
248
- curses_setupterm_called, \
249
- "setupterm")) \
250
- { \
348
+ int called = curses_setupterm_was_called(); \
349
+ if (!_PyCursesCheckWasCalled(MODULE, called, "setupterm")) { \
251
350
return 0; \
252
351
} \
253
352
} while (0)
254
353
255
354
#define PyCursesStatefulInitialised (MODULE ) \
256
355
do { \
257
- if (!_PyCursesStatefulCheckFunction(MODULE, \
258
- curses_initscr_called, \
259
- "initscr")) \
260
- { \
356
+ int called = curses_initscr_was_called(); \
357
+ if (!_PyCursesCheckWasCalled(MODULE, called, "initscr")) { \
261
358
return 0; \
262
359
} \
263
360
} while (0)
264
361
265
362
#define PyCursesStatefulInitialisedColor (MODULE ) \
266
363
do { \
267
- if (!_PyCursesStatefulCheckFunction(MODULE, \
268
- curses_start_color_called, \
269
- "start_color")) \
270
- { \
364
+ int called = curses_start_color_was_called(); \
365
+ if (!_PyCursesCheckWasCalled(MODULE, called, "start_color")) { \
271
366
return 0; \
272
367
} \
273
368
} while (0)
@@ -350,7 +445,7 @@ PyCurses_ConvertToChtype(PyCursesWindowObject *win, PyObject *obj, chtype *ch)
350
445
if (win )
351
446
encoding = win -> encoding ;
352
447
else
353
- encoding = curses_screen_encoding ;
448
+ encoding = curses_get_screen_encoding () ;
354
449
bytes = PyUnicode_AsEncodedString (obj , encoding , NULL );
355
450
if (bytes == NULL )
356
451
return 0 ;
@@ -3356,7 +3451,7 @@ _curses_initscr_impl(PyObject *module)
3356
3451
{
3357
3452
WINDOW * win ;
3358
3453
3359
- if (curses_initscr_called ) {
3454
+ if (curses_initscr_was_called () ) {
3360
3455
wrefresh (stdscr );
3361
3456
_cursesmodule_state * state = get_cursesmodule_state (module );
3362
3457
return PyCursesWindow_New (state , stdscr , NULL );
@@ -3370,7 +3465,8 @@ _curses_initscr_impl(PyObject *module)
3370
3465
return NULL ;
3371
3466
}
3372
3467
3373
- curses_initscr_called = curses_setupterm_called = TRUE;
3468
+ curses_initscr_set_called ();
3469
+ curses_setupterm_set_called ();
3374
3470
3375
3471
PyObject * module_dict = PyModule_GetDict (module ); // borrowed
3376
3472
if (module_dict == NULL ) {
@@ -3467,7 +3563,7 @@ _curses_initscr_impl(PyObject *module)
3467
3563
if (winobj == NULL ) {
3468
3564
return NULL ;
3469
3565
}
3470
- curses_screen_encoding = (( PyCursesWindowObject * )winobj )-> encoding ;
3566
+ curses_set_screen_encoding ((( PyCursesWindowObject * )winobj )-> encoding ) ;
3471
3567
return winobj ;
3472
3568
}
3473
3569
@@ -3522,8 +3618,7 @@ _curses_setupterm_impl(PyObject *module, const char *term, int fd)
3522
3618
return NULL ;
3523
3619
}
3524
3620
3525
- curses_setupterm_called = TRUE;
3526
-
3621
+ curses_setupterm_set_called ();
3527
3622
Py_RETURN_NONE ;
3528
3623
}
3529
3624
@@ -4332,7 +4427,7 @@ _curses_start_color_impl(PyObject *module)
4332
4427
return NULL ;
4333
4428
}
4334
4429
4335
- curses_start_color_called = TRUE ;
4430
+ curses_start_color_set_called () ;
4336
4431
4337
4432
PyObject * module_dict = PyModule_GetDict (module ); // borrowed
4338
4433
if (module_dict == NULL ) {
@@ -4854,21 +4949,24 @@ static PyMethodDef PyCurses_methods[] = {
4854
4949
initialised or not. */
4855
4950
4856
4951
static inline int
4857
- curses_capi_setupterm_called (void )
4952
+ curses_capi_setupterm_was_called (void )
4858
4953
{
4859
- return _PyCursesCheckFunction (curses_setupterm_called , "setupterm" );
4954
+ int called = curses_setupterm_was_called ();
4955
+ return _PyCursesStatelessCheckWasCalled (called , "setupterm" );
4860
4956
}
4861
4957
4862
4958
static inline int
4863
- curses_capi_initscr_called (void )
4959
+ curses_capi_initscr_was_called (void )
4864
4960
{
4865
- return _PyCursesCheckFunction (curses_initscr_called , "initscr" );
4961
+ int called = curses_initscr_was_called ();
4962
+ return _PyCursesStatelessCheckWasCalled (called , "initscr" );
4866
4963
}
4867
4964
4868
4965
static inline int
4869
- curses_capi_start_color_called (void )
4966
+ curses_capi_start_color_was_called (void )
4870
4967
{
4871
- return _PyCursesCheckFunction (curses_start_color_called , "start_color" );
4968
+ int called = curses_start_color_was_called ();
4969
+ return _PyCursesStatelessCheckWasCalled (called , "start_color" );
4872
4970
}
4873
4971
4874
4972
static void *
@@ -4881,9 +4979,9 @@ curses_capi_new(_cursesmodule_state *state)
4881
4979
return NULL ;
4882
4980
}
4883
4981
capi [0 ] = (void * )Py_NewRef (state -> window_type );
4884
- capi [1 ] = curses_capi_setupterm_called ;
4885
- capi [2 ] = curses_capi_initscr_called ;
4886
- capi [3 ] = curses_capi_start_color_called ;
4982
+ capi [1 ] = curses_capi_setupterm_was_called ;
4983
+ capi [2 ] = curses_capi_initscr_was_called ;
4984
+ capi [3 ] = curses_capi_start_color_was_called ;
4887
4985
return (void * )capi ;
4888
4986
}
4889
4987
@@ -4944,9 +5042,24 @@ curses_capi_capsule_new(void *capi)
4944
5042
4945
5043
/* Module initialization */
4946
5044
5045
+ /* Indicate whether the module has been loaded or not. */
5046
+ static int curses_module_loaded = 0 ;
5047
+
4947
5048
static int
4948
5049
cursesmodule_exec (PyObject * module )
4949
5050
{
5051
+ if (_Py_atomic_load_int (& curses_module_loaded )) {
5052
+ PyErr_SetString (PyExc_ImportError ,
5053
+ "module 'curses' can only be loaded once per process" );
5054
+ return -1 ;
5055
+ }
5056
+
5057
+ #ifdef Py_GIL_DISABLED
5058
+ _Py_atomic_store_int (& curses_module_loaded , 1 );
5059
+ #else
5060
+ curses_module_loaded = 1 ;
5061
+ #endif
5062
+
4950
5063
_cursesmodule_state * state = get_cursesmodule_state (module );
4951
5064
/* Initialize object type */
4952
5065
state -> window_type = (PyTypeObject * )PyType_FromModuleAndSpec (
0 commit comments