Skip to main content

Python/thread.c (part 2)

Source:

cpython 3.14 @ ab2d84fe1023/Python/thread.c

This annotation covers thread-local storage (TLS/TSS). See python_thread_detail for thread creation, locking (PyThread_allocate_lock), and the GIL.

Map

LinesSymbolRole
1-100PyThread_tss_createCreate a thread-specific storage key
101-200PyThread_tss_set, PyThread_tss_getSet/get per-thread value for a key
201-300PyThread_tss_deleteDelete the key (free system resources)
301-400PyThread_get_thread_identReturn the platform thread ID
401-500PyThread_get_thread_native_idOS-native thread ID (Linux TID, macOS thread_id)
501-700TSS for PyThreadStateautoTSSkey — maps thread ID to PyThreadState *

Reading

Thread-specific storage (POSIX)

// CPython: Python/thread_pthread.h:240 PyThread_tss_create
int
PyThread_tss_create(Py_tss_t *key)
{
assert(key && !key->_is_initialized);
int r = pthread_key_create(&(key->_key), NULL);
if (r) {
if (r == ENOMEM) errno = ENOMEM;
return -1;
}
key->_is_initialized = 1;
return 0;
}

void *
PyThread_tss_get(Py_tss_t *key)
{
assert(key && key->_is_initialized);
return pthread_getspecific(key->_key);
}

int
PyThread_tss_set(Py_tss_t *key, void *value)
{
assert(key && key->_is_initialized);
return pthread_setspecific(key->_key, value);
}

autoTSSkey — linking thread to PyThreadState

// CPython: Python/thread.c:420 autoTSSkey
/* autoTSSkey maps each OS thread to its PyThreadState */
/* Created at interpreter startup */
static Py_tss_t autoTSSkey = Py_tss_NEEDS_INIT;

PyThreadState *
PyGILState_GetThisThreadState(void)
{
if (!autoTSSkey._is_initialized) return NULL;
return (PyThreadState *)PyThread_tss_get(&autoTSSkey);
}

PyGILState_Ensure() uses this to find (or create) the PyThreadState for the calling thread.

Thread ID

// CPython: Python/thread.c:310 PyThread_get_thread_ident
unsigned long
PyThread_get_thread_ident(void)
{
#ifdef __APPLE__
uint64_t tid;
pthread_threadid_np(NULL, &tid);
return (unsigned long)tid;
#else
return (unsigned long)pthread_self();
#endif
}

threading.get_ident() returns this value. It is unique per live thread but may be reused after a thread exits.

PyThread_get_thread_native_id (3.8+)

// CPython: Python/thread.c:380 PyThread_get_thread_native_id
unsigned long
PyThread_get_thread_native_id(void)
{
#ifdef __linux__
return (unsigned long)syscall(SYS_gettid); /* Linux kernel TID */
#elif defined(__APPLE__)
uint64_t tid;
pthread_threadid_np(NULL, &tid);
return (unsigned long)tid;
#endif
}

threading.get_native_id() returns the OS-level thread ID, visible in top and perf.

gopy notes

TLS in gopy uses Go's goroutine-local storage via a sync.Map keyed by goroutine_id() (from runtime internals). PyThread_tss_* maps to vm.TSSKey / vm.TSSGet / vm.TSSSet. PyGILState_GetThisThreadState looks up the current goroutine's vm.ThreadState in the global map.