Skip to main content

Modules/_multiprocessing/semaphore.c (part 5)

Source:

cpython 3.14 @ ab2d84fe1023/Modules/_multiprocessing/semaphore.c

This annotation covers multiprocessing synchronization primitives. See module_multiprocessing4_detail for Process, Queue, Pipe, and Manager.

Map

LinesSymbolRole
1-80SemLock.__init__Create a named or unnamed POSIX semaphore
81-180SemLock.acquireDecrement with optional timeout
181-260SemLock.releaseIncrement and wake waiting processes
261-360SemLock._rebuildReconstruct from FD for pickling
361-500Shared memory/dev/shm-based memory segments

Reading

SemLock.acquire

// CPython: Modules/_multiprocessing/semaphore.c:280 semlock_acquire
static PyObject *
semlock_acquire(SemLockObject *self, PyObject *args, PyObject *kwds)
{
double timeout = -1.0; /* -1 = block forever */
int blocking = 1;
...
if (!blocking) {
int res = sem_trywait(self->handle);
return PyBool_FromLong(res == 0);
}
if (timeout > 0) {
struct timespec deadline;
...
int res = sem_timedwait(self->handle, &deadline);
return PyBool_FromLong(res == 0);
}
Py_BEGIN_ALLOW_THREADS
sem_wait(self->handle);
Py_END_ALLOW_THREADS
Py_RETURN_TRUE;
}

SemLock wraps POSIX semaphores (sem_open/sem_init). It is the foundation for multiprocessing.Lock, Semaphore, BoundedSemaphore, and Condition. The GIL is released during blocking sem_wait so other Python threads can run.

SemLock._rebuild

// CPython: Modules/_multiprocessing/semaphore.c:480 semlock_rebuild
static PyObject *
semlock_rebuild(PyTypeObject *type, PyObject *args)
{
/* Used by multiprocessing to pass a lock between processes via pickling.
The semaphore name (for named) or fd (for unnamed) is transferred. */
SEM_HANDLE handle;
char *name = NULL;
if (name) {
handle = sem_open(name, 0); /* Reopen by name */
} else {
handle = (SEM_HANDLE)fd; /* Inherit fd across fork */
}
return newsemlockobject(type, handle, kind, maxvalue, name);
}

Named semaphores persist in /dev/shm (or the kernel's semaphore namespace). They survive process death if not explicitly sem_unlink-ed. Unnamed semaphores are passed via file descriptor inheritance across fork.

gopy notes

SemLock is module/multiprocessing.SemLock in module/multiprocessing/module.go. It wraps sync.Mutex for inter-goroutine use. For inter-process use (cross-fork), it falls back to named POSIX semaphores via syscall.Open on /dev/shm/. _rebuild reconstructs from the inherited file descriptor.