1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "fork.h"
/* Lock to protect allocation and deallocation of fork handlers. */
lll_lock_t __fork_lock = LLL_LOCK_INITIALIZER;
/* Number of pre-allocated handler entries. */
#define NHANDLER 48
/* Memory pool for fork handler structures. */
static struct fork_handler_pool
{
struct fork_handler_pool *next;
struct fork_handler mem[NHANDLER];
} fork_handler_pool;
static struct fork_handler *
fork_handler_alloc (void)
{
struct fork_handler_pool *runp = &fork_handler_pool;
struct fork_handler *result = NULL;
unsigned int i;
do
{
/* Search for an empty entry. */
for (i = 0; i < NHANDLER; ++i)
if (runp->mem[i].refcntr == 0)
goto found;
}
while ((runp = runp->next) != NULL);
/* We have to allocate a new entry. */
runp = (struct fork_handler_pool *) calloc (1, sizeof (*runp));
if (runp != NULL)
{
/* Enqueue the new memory pool into the list. */
runp->next = fork_handler_pool.next;
fork_handler_pool.next = runp;
/* We use the last entry on the page. This means when we start
searching from the front the next time we will find the first
entry unused. */
i = NHANDLER - 1;
found:
result = &runp->mem[i];
result->refcntr = 1;
result->need_signal = 0;
}
return result;
}
int
__register_atfork (
void (*prepare) (void),
void (*parent) (void),
void (*child) (void),
void *dso_handle)
{
/* Get the lock to not conflict with other allocations. */
lll_lock (__fork_lock);
struct fork_handler *newp = fork_handler_alloc ();
if (newp != NULL)
{
/* Initialize the new record. */
newp->prepare_handler = prepare;
newp->parent_handler = parent;
newp->child_handler = child;
newp->dso_handle = dso_handle;
newp->next = __fork_handlers;
__fork_handlers = newp;
}
/* Release the lock. */
lll_unlock (__fork_lock);
return newp == NULL ? ENOMEM : 0;
}
|