aboutsummaryrefslogtreecommitdiff
path: root/nptl/sysdeps/unix/sysv/linux/i386/createthread.c
diff options
context:
space:
mode:
Diffstat (limited to 'nptl/sysdeps/unix/sysv/linux/i386/createthread.c')
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/createthread.c170
1 files changed, 31 insertions, 139 deletions
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/createthread.c b/nptl/sysdeps/unix/sysv/linux/i386/createthread.c
index def163350f..37e3d94996 100644
--- a/nptl/sysdeps/unix/sysv/linux/i386/createthread.c
+++ b/nptl/sysdeps/unix/sysv/linux/i386/createthread.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002 Free Software Foundation, Inc.
+/* 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.
@@ -17,141 +17,33 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#include <sched.h>
-#include <setjmp.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <atomic.h>
-#include <ldsodefs.h>
-#include <tls.h>
-
-
-#define CLONE_SIGNAL (CLONE_SIGHAND | CLONE_THREAD)
-
-
-static int
-create_thread (struct pthread *pd, STACK_VARIABLES_PARMS)
-{
- union user_desc_init desc;
-
- /* Describe the thread-local storage segment. */
-
- /* The 'entry_number' field. The first three bits of the segment
- register value select the GDT, ignore them. We get the index
- from the value of the %gs register in the current thread. */
- desc.vals[0] = TLS_GET_GS () >> 3;
- /* The 'base_addr' field. Pointer to the TCB. */
- desc.vals[1] = (unsigned long int) pd;
- /* The 'limit' field. We use 4GB which is 0xfffff pages. */
- desc.vals[2] = 0xfffff;
- /* Collapsed value of the bitfield:
- .seg_32bit = 1
- .contents = 0
- .read_exec_only = 0
- .limit_in_pages = 1
- .seg_not_present = 0
- .useable = 1 */
- desc.vals[3] = 0x51;
-
-
- assert (pd->header.data.tcb != NULL);
-
-
- if (__builtin_expect (THREAD_GETMEM (THREAD_SELF, report_events), 0))
- {
- /* The parent thread is supposed to report events. Check whether
- the TD_CREATE event is needed, too. */
- const int _idx = __td_eventword (TD_CREATE);
- const uint32_t _mask = __td_eventmask (TD_CREATE);
-
- if ((_mask & (__nptl_threads_events.event_bits[_idx]
- | pd->eventbuf.eventmask.event_bits[_idx])) != 0)
- {
- /* We have to report the new thread. Make sure the thread
- does not run far by forcing it to get a lock. We lock it
- here too so that the new thread cannot continue until we
- tell it to. */
- lll_lock (pd->lock);
-
- /* Create the thread. */
- if (__clone (start_thread_debug, STACK_VARIABLES_ARGS,
- CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL |
- CLONE_SETTLS | CLONE_PARENT_SETTID |
- CLONE_CHILD_CLEARTID | CLONE_DETACHED | 0,
- pd, &pd->tid, &desc.desc, &pd->tid) == -1)
- /* Failed. */
- return errno;
-
- /* We now have for sure more than one thread. */
- pd->header.data.multiple_threads = 1;
-
- /* Now fill in the information about the new thread in
- the newly created thread's data structure. We cannot let
- the new thread do this since we don't know whether it was
- already scheduled when we send the event. */
- pd->eventbuf.eventnum = TD_CREATE;
- pd->eventbuf.eventdata = pd;
-
- /* Enqueue the descriptor. */
- do
- pd->nextevent = __nptl_last_event;
- while (atomic_compare_and_exchange_acq (&__nptl_last_event, pd,
- pd->nextevent) != 0);
-
- /* Now call the function which signals the event. */
- __nptl_create_event ();
-
- /* And finally restart the new thread. */
- lll_unlock (pd->lock);
-
- return 0;
- }
- }
-
-#ifdef NEED_DL_SYSINFO
- assert (THREAD_GETMEM (THREAD_SELF, header.data.sysinfo)
- == pd->header.data.sysinfo);
-#endif
-
- /* We rely heavily on various flags the CLONE function understands:
-
- CLONE_VM, CLONE_FS, CLONE_FILES
- These flags select semantics with shared address space and
- file descriptors according to what POSIX requires.
-
- CLONE_SIGNAL
- This flag selects the POSIX signal semantics.
-
- CLONE_SETTLS
- The sixth parameter to CLONE determines the TLS area for the
- new thread.
-
- CLONE_PARENT_SETTID
- The kernels writes the thread ID of the newly created thread
- into the location pointed to by the fifth parameters to CLONE.
-
- Note that it would be semantically equivalent to use
- CLONE_CHILD_SETTID but it is be more expensive in the kernel.
-
- CLONE_CHILD_CLEARTID
- The kernels clears the thread ID of a thread that has called
- sys_exit() - using the same parameter as CLONE_SETTID.
-
- CLONE_DETACHED
- No signal is generated if the thread exists and it is
- automatically reaped.
-
- The termination signal is chosen to be zero which means no signal
- is sent. */
- if (__clone (start_thread, STACK_VARIABLES_ARGS,
- CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL |
- CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID |
- CLONE_DETACHED | 0, pd, &pd->tid, &desc.desc, &pd->tid) == -1)
- /* Failed. */
- return errno;
-
- /* We now have for sure more than one thread. */
- THREAD_SETMEM (THREAD_SELF, header.data.multiple_threads, 1);
-
- return 0;
-}
+/* The "thread register" gets initialized from a segment descriptor.
+ Initialize such a descriptor first. */
+#define PREPARE_CREATE \
+ union user_desc_init desc; \
+ \
+ /* Describe the thread-local storage segment. */ \
+ \
+ /* The 'entry_number' field. The first three bits of the segment \
+ register value select the GDT, ignore them. We get the index \
+ from the value of the %gs register in the current thread. */ \
+ desc.vals[0] = TLS_GET_GS () >> 3; \
+ /* The 'base_addr' field. Pointer to the TCB. */ \
+ desc.vals[1] = (unsigned long int) pd; \
+ /* The 'limit' field. We use 4GB which is 0xfffff pages. */ \
+ desc.vals[2] = 0xfffff; \
+ /* Collapsed value of the bitfield: \
+ .seg_32bit = 1 \
+ .contents = 0 \
+ .read_exec_only = 0 \
+ .limit_in_pages = 1 \
+ .seg_not_present = 0 \
+ .useable = 1 */ \
+ desc.vals[3] = 0x51
+
+/* Value passed to 'clone' for initialization of the thread register. */
+#define TLS_VALUE &desc.desc
+
+
+/* Get the real implementation. */
+#include <nptl/sysdeps/pthread/createthread.c>