Update syscall lists for Linux 5.12.
[glibc.git] / posix / register-atfork.c
blob6fd9e4c56aafd7cca710474cd60d5dc0a6b4e78a
1 /* Copyright (C) 2002-2021 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 #include <libc-lock.h>
20 #include <stdbool.h>
21 #include <register-atfork.h>
23 #define DYNARRAY_ELEMENT struct fork_handler
24 #define DYNARRAY_STRUCT fork_handler_list
25 #define DYNARRAY_PREFIX fork_handler_list_
26 #define DYNARRAY_INITIAL_SIZE 48
27 #include <malloc/dynarray-skeleton.c>
29 static struct fork_handler_list fork_handlers;
30 static bool fork_handler_init = false;
32 static int atfork_lock = LLL_LOCK_INITIALIZER;
34 int
35 __register_atfork (void (*prepare) (void), void (*parent) (void),
36 void (*child) (void), void *dso_handle)
38 lll_lock (atfork_lock, LLL_PRIVATE);
40 if (!fork_handler_init)
42 fork_handler_list_init (&fork_handlers);
43 fork_handler_init = true;
46 struct fork_handler *newp = fork_handler_list_emplace (&fork_handlers);
47 if (newp != NULL)
49 newp->prepare_handler = prepare;
50 newp->parent_handler = parent;
51 newp->child_handler = child;
52 newp->dso_handle = dso_handle;
55 /* Release the lock. */
56 lll_unlock (atfork_lock, LLL_PRIVATE);
58 return newp == NULL ? ENOMEM : 0;
60 libc_hidden_def (__register_atfork)
62 static struct fork_handler *
63 fork_handler_list_find (struct fork_handler_list *fork_handlers,
64 void *dso_handle)
66 for (size_t i = 0; i < fork_handler_list_size (fork_handlers); i++)
68 struct fork_handler *elem = fork_handler_list_at (fork_handlers, i);
69 if (elem->dso_handle == dso_handle)
70 return elem;
72 return NULL;
75 void
76 __unregister_atfork (void *dso_handle)
78 lll_lock (atfork_lock, LLL_PRIVATE);
80 struct fork_handler *first = fork_handler_list_find (&fork_handlers,
81 dso_handle);
82 /* Removing is done by shifting the elements in the way the elements
83 that are not to be removed appear in the beginning in dynarray.
84 This avoid the quadradic run-time if a naive strategy to remove and
85 shift one element at time. */
86 if (first != NULL)
88 struct fork_handler *new_end = first;
89 first++;
90 for (; first != fork_handler_list_end (&fork_handlers); ++first)
92 if (first->dso_handle != dso_handle)
94 *new_end = *first;
95 ++new_end;
99 ptrdiff_t removed = first - new_end;
100 for (size_t i = 0; i < removed; i++)
101 fork_handler_list_remove_last (&fork_handlers);
104 lll_unlock (atfork_lock, LLL_PRIVATE);
107 void
108 __run_fork_handlers (enum __run_fork_handler_type who, _Bool do_locking)
110 struct fork_handler *runp;
112 if (who == atfork_run_prepare)
114 if (do_locking)
115 lll_lock (atfork_lock, LLL_PRIVATE);
116 size_t sl = fork_handler_list_size (&fork_handlers);
117 for (size_t i = sl; i > 0; i--)
119 runp = fork_handler_list_at (&fork_handlers, i - 1);
120 if (runp->prepare_handler != NULL)
121 runp->prepare_handler ();
124 else
126 size_t sl = fork_handler_list_size (&fork_handlers);
127 for (size_t i = 0; i < sl; i++)
129 runp = fork_handler_list_at (&fork_handlers, i);
130 if (who == atfork_run_child && runp->child_handler)
131 runp->child_handler ();
132 else if (who == atfork_run_parent && runp->parent_handler)
133 runp->parent_handler ();
135 if (do_locking)
136 lll_unlock (atfork_lock, LLL_PRIVATE);
141 libc_freeres_fn (free_mem)
143 lll_lock (atfork_lock, LLL_PRIVATE);
145 fork_handler_list_free (&fork_handlers);
147 lll_unlock (atfork_lock, LLL_PRIVATE);