• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2   Logic for a better replacement of PyGILState_Ensure().
3 
4   This version is ready to handle the case of a non-Python-started
5   thread in which we do a large number of calls to CFFI callbacks.  If
6   we were to rely on PyGILState_Ensure() for that, we would constantly
7   be creating and destroying PyThreadStates---it is slow, and
8   PyThreadState_Delete() will actually walk the list of all thread
9   states, making it O(n). :-(
10 
11   This version only creates one PyThreadState object the first time we
12   see a given thread, and keep it alive until the thread is really
13   shut down, using a destructor on the tls key.
14 */
15 
16 #include <pthread.h>
17 #include "misc_thread_common.h"
18 
19 
20 static pthread_key_t cffi_tls_key;
21 
init_cffi_tls(void)22 static void init_cffi_tls(void)
23 {
24     if (pthread_key_create(&cffi_tls_key, &cffi_thread_shutdown) != 0)
25         PyErr_SetString(PyExc_OSError, "pthread_key_create() failed");
26 }
27 
_make_cffi_tls(void)28 static struct cffi_tls_s *_make_cffi_tls(void)
29 {
30     void *p = calloc(1, sizeof(struct cffi_tls_s));
31     if (p == NULL)
32         return NULL;
33     if (pthread_setspecific(cffi_tls_key, p) != 0) {
34         free(p);
35         return NULL;
36     }
37     return p;
38 }
39 
get_cffi_tls(void)40 static struct cffi_tls_s *get_cffi_tls(void)
41 {
42     void *p = pthread_getspecific(cffi_tls_key);
43     if (p == NULL)
44         p = _make_cffi_tls();
45     return (struct cffi_tls_s *)p;
46 }
47 
48 #define save_errno      save_errno_only
49 #define restore_errno   restore_errno_only
50