112 lines
2.6 KiB
C
112 lines
2.6 KiB
C
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <errno.h>
|
|
|
|
#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();
|
|
}
|
|
}
|
|
}
|