Skip to main content

Modules/fcntlmodule.c (part 2)

Source:

cpython 3.14 @ ab2d84fe1023/Modules/fcntlmodule.c

This annotation covers file locking (flock, lockf) and ioctl with buffer arguments. See modules_fcntl_detail for fcntl.fcntl, constants, and basic ioctl.

Map

LinesSymbolRole
1-80fcntl_flock_implfcntl.flock(fd, operation) — BSD-style file locking
81-180fcntl_lockf_implfcntl.lockf(fd, cmd, length, start, whence) — POSIX record locking
181-280fcntl_ioctl_implioctl with mutable buffer (bytearray in/out)
281-350Locking constantsLOCK_SH, LOCK_EX, LOCK_NB, LOCK_UN

Reading

fcntl.flock

// CPython: Modules/fcntlmodule.c:82 fcntl_flock_impl
static PyObject *
fcntl_flock_impl(PyObject *module, int fd, int code)
{
/* BSD advisory lock; operates on the whole file.
LOCK_SH: shared (read) lock
LOCK_EX: exclusive (write) lock
LOCK_NB: non-blocking (raises BlockingIOError if contended)
LOCK_UN: unlock */
int ret;
Py_BEGIN_ALLOW_THREADS
ret = flock(fd, code);
Py_END_ALLOW_THREADS
if (ret < 0)
return PyErr_SetFromErrno(PyExc_OSError);
Py_RETURN_NONE;
}

flock locks are per open file description, not per process. Child processes inherit flock locks across fork.

fcntl.lockf

// CPython: Modules/fcntlmodule.c:140 fcntl_lockf_impl
static PyObject *
fcntl_lockf_impl(PyObject *module, int fd, int code,
PyObject *lenobj, PyObject *startobj, int whence)
{
/* POSIX record locking via F_SETLKW / F_SETLK.
Locks a byte range [start, start+length) within the file.
whence: SEEK_SET (0), SEEK_CUR (1), SEEK_END (2) */
struct flock l;
l.l_type = (code & LOCK_UN) ? F_UNLCK :
(code & LOCK_SH) ? F_RDLCK : F_WRLCK;
l.l_start = (off_t)start;
l.l_len = (off_t)len;
l.l_whence = (short)whence;
int cmd = (code & LOCK_NB) ? F_SETLK : F_SETLKW;
Py_BEGIN_ALLOW_THREADS
int ret = fcntl(fd, cmd, &l);
Py_END_ALLOW_THREADS
...
}

lockf uses the POSIX fcntl(F_SETLKW) mechanism, which supports byte-range locking and is per-process (not inherited across fork).

ioctl with buffer

// CPython: Modules/fcntlmodule.c:230 fcntl_ioctl_impl
/* ioctl(fd, request, arg=0, mutate_flag=True)
If arg is a bytearray and mutate_flag is True:
- Pass arg's buffer to ioctl
- The kernel may modify it in-place (e.g. TIOCGWINSZ fills struct winsize)
Returns bytes containing the (possibly modified) buffer. */

gopy notes

fcntl.flock is in module/fcntl/module.go using syscall.Flock. fcntl.lockf uses syscall.FcntlFlock with syscall.F_SETLK/F_SETLKW. ioctl with buffer uses unix.IoctlGetWinsize and related helpers from golang.org/x/sys/unix.