#ifdef HAVE_CONFIG_H #include #endif #include #include "atfork_impl.h" #include "../internal/malloc.h" /* * The atfork hook table (todo 20). * * The list is a doubly linked chain in registration order (head = oldest * registration). fork() runs the phases through __vlibc_atfork_prepare/ * parent/child around the syscall; pthread_atfork (todo 45) appends * entries via __vlibc_atfork_register. Nodes live on the malloc heap: * registration happens long after the allocator is up, and fork() itself * never allocates — the phases only walk the existing chain. * * Phase order (POSIX 1003.1-2008 pthread_atfork): * - prepare: reverse registration order (tail to head); * - parent and child: registration order (head to tail). */ struct vlibc_atfork_entry *volatile __vlibc_atfork_list = 0; // NOLINTBEGIN(bugprone-easily-swappable-parameters) int __vlibc_atfork_register(void (*prepare)(void), void (*parent)(void), void (*child)(void)) { struct vlibc_atfork_entry *node; struct vlibc_atfork_entry *tail; node = (struct vlibc_atfork_entry *)__libc_malloc(sizeof(*node)); if (node == 0) { errno = ENOMEM; return -1; } node->prepare = prepare; node->parent = parent; node->child = child; node->prev = 0; node->next = 0; /* Append at the tail so the chain stays in registration order. */ if (__vlibc_atfork_list == 0) { __vlibc_atfork_list = node; return 0; } tail = __vlibc_atfork_list; while (tail->next != 0) { tail = tail->next; } tail->next = node; node->prev = tail; return 0; } // NOLINTEND(bugprone-easily-swappable-parameters) void __vlibc_atfork_prepare(void) { struct vlibc_atfork_entry *node = __vlibc_atfork_list; /* Reverse registration order: walk to the tail, then back. */ while (node != 0 && node->next != 0) { node = node->next; } for (; node != 0; node = node->prev) { if (node->prepare != 0) { node->prepare(); } } } void __vlibc_atfork_parent(void) { struct vlibc_atfork_entry *node; /* Registration order. */ for (node = __vlibc_atfork_list; node != 0; node = node->next) { if (node->parent != 0) { node->parent(); } } } void __vlibc_atfork_child(void) { struct vlibc_atfork_entry *node; /* Registration order. */ for (node = __vlibc_atfork_list; node != 0; node = node->next) { if (node->child != 0) { node->child(); } } }