]> git.ipfire.org Git - thirdparty/glibc.git/blob - nptl/sysdeps/pthread/createthread.c
Update.
[thirdparty/glibc.git] / nptl / sysdeps / pthread / createthread.c
1 /* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
4
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.
9
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.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
19
20 #include <sched.h>
21 #include <setjmp.h>
22 #include <signal.h>
23 #include <stdlib.h>
24 #include <atomic.h>
25 #include <ldsodefs.h>
26 #include <tls.h>
27
28
29 #define CLONE_SIGNAL (CLONE_SIGHAND | CLONE_THREAD)
30
31 /* Unless otherwise specified, the thread "register" is going to be
32 initialized with a pointer to the TCB. */
33 #ifndef TLS_VALUE
34 # define TLS_VALUE pd
35 #endif
36
37 #ifndef ARCH_CLONE
38 # define ARCH_CLONE __clone
39 #endif
40
41
42 #ifndef TLS_MULTIPLE_THREADS_IN_TCB
43 /* Variable set to a nonzero value if more than one thread runs or ran. */
44 int __pthread_multiple_threads attribute_hidden;
45 /* Pointer to the corresponding variable in libc. */
46 int *__libc_multiple_threads_ptr attribute_hidden;
47 #endif
48
49
50 static int
51 create_thread (struct pthread *pd, STACK_VARIABLES_PARMS)
52 {
53 #ifdef PREPARE_CREATE
54 PREPARE_CREATE;
55 #endif
56
57 #ifdef TLS_TCB_AT_TP
58 assert (pd->header.tcb != NULL);
59 #endif
60
61 if (__builtin_expect (THREAD_GETMEM (THREAD_SELF, report_events), 0))
62 {
63 /* The parent thread is supposed to report events. Check whether
64 the TD_CREATE event is needed, too. */
65 const int _idx = __td_eventword (TD_CREATE);
66 const uint32_t _mask = __td_eventmask (TD_CREATE);
67
68 if ((_mask & (__nptl_threads_events.event_bits[_idx]
69 | pd->eventbuf.eventmask.event_bits[_idx])) != 0)
70 {
71 /* We have to report the new thread. Make sure the thread
72 does not run far by forcing it to get a lock. We lock it
73 here too so that the new thread cannot continue until we
74 tell it to. */
75 lll_lock (pd->lock);
76
77 /* Create the thread. */
78 if (ARCH_CLONE (start_thread_debug, STACK_VARIABLES_ARGS,
79 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL |
80 CLONE_SETTLS | CLONE_PARENT_SETTID |
81 CLONE_CHILD_CLEARTID | CLONE_DETACHED | 0,
82 pd, &pd->tid, TLS_VALUE, &pd->tid) == -1)
83 /* Failed. */
84 return errno;
85
86 /* We now have for sure more than one thread. The main
87 thread might not yet have the flag set. No need to set
88 the global variable again if this is what we use. */
89 #ifdef TLS_MULTIPLE_THREADS_IN_TCB
90 # if TLS_DTV_AT_TP
91 p_multiple_threads (THREAD_SELF) = 1;
92 # else
93 THREAD_SETMEM (THREAD_SELF, header.multiple_threads, 1);
94 # endif
95 #endif
96
97 /* Now fill in the information about the new thread in
98 the newly created thread's data structure. We cannot let
99 the new thread do this since we don't know whether it was
100 already scheduled when we send the event. */
101 pd->eventbuf.eventnum = TD_CREATE;
102 pd->eventbuf.eventdata = pd;
103
104 /* Enqueue the descriptor. */
105 do
106 pd->nextevent = __nptl_last_event;
107 while (atomic_compare_and_exchange_bool_acq (&__nptl_last_event, pd,
108 pd->nextevent) != 0);
109
110 /* Now call the function which signals the event. */
111 __nptl_create_event ();
112
113 /* And finally restart the new thread. */
114 lll_unlock (pd->lock);
115
116 return 0;
117 }
118 }
119
120 #ifdef NEED_DL_SYSINFO
121 assert (THREAD_GETMEM (THREAD_SELF, header.sysinfo) == pd->header.sysinfo);
122 #endif
123
124 /* We rely heavily on various flags the CLONE function understands:
125
126 CLONE_VM, CLONE_FS, CLONE_FILES
127 These flags select semantics with shared address space and
128 file descriptors according to what POSIX requires.
129
130 CLONE_SIGNAL
131 This flag selects the POSIX signal semantics.
132
133 CLONE_SETTLS
134 The sixth parameter to CLONE determines the TLS area for the
135 new thread.
136
137 CLONE_PARENT_SETTID
138 The kernels writes the thread ID of the newly created thread
139 into the location pointed to by the fifth parameters to CLONE.
140
141 Note that it would be semantically equivalent to use
142 CLONE_CHILD_SETTID but it is be more expensive in the kernel.
143
144 CLONE_CHILD_CLEARTID
145 The kernels clears the thread ID of a thread that has called
146 sys_exit() in the location pointed to by the seventh parameter
147 to CLONE.
148
149 CLONE_DETACHED
150 No signal is generated if the thread exists and it is
151 automatically reaped.
152
153 The termination signal is chosen to be zero which means no signal
154 is sent. */
155 if (ARCH_CLONE (start_thread, STACK_VARIABLES_ARGS,
156 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL |
157 CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID |
158 CLONE_DETACHED | 0, pd, &pd->tid, TLS_VALUE, &pd->tid) == -1)
159 /* Failed. */
160 return errno;
161
162 /* We now have for sure more than one thread. The main thread might
163 not yet have the flag set. No need to set the global variable
164 again if this is what we use. */
165 #ifdef TLS_MULTIPLE_THREADS_IN_TCB
166 # if TLS_DTV_AT_TP
167 p_multiple_threads (THREAD_SELF) = 1;
168 # else
169 THREAD_SETMEM (THREAD_SELF, header.multiple_threads, 1);
170 # endif
171 #endif
172
173 return 0;
174 }