1 /*
2 * This file is subject to the terms and conditions of the LGPL V2.1
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 2019 Kalray Inc.
7 */
8
9 #include "pthreadP.h"
10 #include <lowlevellock.h>
11
12 unsigned long int __fork_generation attribute_hidden;
13
14 static void
clear_once_control(void * arg)15 clear_once_control (void *arg)
16 {
17 pthread_once_t *once_control = (pthread_once_t *) arg;
18
19 *once_control = 0;
20 lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
21 }
22
23
24 int
__pthread_once(once_control,init_routine)25 __pthread_once (once_control, init_routine)
26 pthread_once_t *once_control;
27 void (*init_routine) (void);
28 {
29 while (1)
30 {
31 int oldval, val, newval;
32
33 val = *once_control;
34 do
35 {
36 /* Check if the initialized has already been done. */
37 if ((val & 2) != 0)
38 return 0;
39
40 oldval = val;
41 newval = (oldval & 3) | __fork_generation | 1;
42 val = atomic_compare_and_exchange_val_acq (once_control, newval, oldval);
43 } while (__builtin_expect (val != oldval, 0));
44
45 /* Check if another thread already runs the initializer. */
46 if ((oldval & 1) != 0)
47 {
48 /* Check whether the initializer execution was interrupted
49 * by a fork. */
50 if (((oldval ^ newval) & -4) == 0)
51 {
52 /* Same generation, some other thread was faster. Wait. */
53 lll_futex_wait (once_control, newval, LLL_PRIVATE);
54 continue;
55 }
56 }
57 /* This thread is the first here. Do the initialization.
58 * Register a cleanup handler so that in case the thread gets
59 * interrupted the initialization can be restarted. */
60 pthread_cleanup_push (clear_once_control, once_control);
61
62 init_routine ();
63
64 pthread_cleanup_pop (0);
65
66 /* Add one to *once_control. */
67 atomic_increment (once_control);
68
69 /* Wake up all other threads. */
70 lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
71 break;
72 }
73
74 return 0;
75 }
76 weak_alias (__pthread_once, pthread_once)
77 strong_alias (__pthread_once, __pthread_once_internal)
78