Use ENTER_KERNEL instead of int $0x80.
[kopensolaris-gnu/glibc.git] / nptl / sysdeps / unix / sysv / linux / i386 / createthread.c
1 /* Copyright (C) 2002 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
32 static int
33 create_thread (struct pthread *pd, STACK_VARIABLES_PARMS)
34 {
35   union user_desc_init desc;
36
37   /* Describe the thread-local storage segment.  */
38
39   /* The 'entry_number' field.  The first three bits of the segment
40      register value select the GDT, ignore them.  We get the index
41      from the value of the %gs register in the current thread.  */
42   desc.vals[0] = TLS_GET_GS () >> 3;
43   /* The 'base_addr' field.  Pointer to the TCB.  */
44   desc.vals[1] = (unsigned long int) pd;
45   /* The 'limit' field.  We use 4GB which is 0xfffff pages.  */
46   desc.vals[2] = 0xfffff;
47   /* Collapsed value of the bitfield:
48        .seg_32bit = 1
49        .contents = 0
50        .read_exec_only = 0
51        .limit_in_pages = 1
52        .seg_not_present = 0
53        .useable = 1 */
54   desc.vals[3] = 0x51;
55
56
57   assert (pd->header.data.tcb != NULL);
58
59
60   if (__builtin_expect (THREAD_GETMEM (THREAD_SELF, report_events), 0))
61     {
62       /* The parent thread is supposed to report events.  Check whether
63          the TD_CREATE event is needed, too.  */
64       const int _idx = __td_eventword (TD_CREATE);
65       const uint32_t _mask = __td_eventmask (TD_CREATE);
66
67       if ((_mask & (__nptl_threads_events.event_bits[_idx]
68                     | pd->eventbuf.eventmask.event_bits[_idx])) != 0)
69         {
70           /* We have to report the new thread.  Make sure the thread
71              does not run far by forcing it to get a lock.  We lock it
72              here too so that the new thread cannot continue until we
73              tell it to.  */
74           lll_lock (pd->lock);
75
76           /* Create the thread.  */
77           if (__clone (start_thread_debug, STACK_VARIABLES_ARGS,
78                        CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL |
79                        CLONE_SETTLS | CLONE_PARENT_SETTID |
80                        CLONE_CHILD_CLEARTID | CLONE_DETACHED | 0,
81                        pd, &pd->tid, &desc.desc, &pd->tid) == -1)
82             /* Failed.  */
83             return errno;
84
85           /* We now have for sure more than one thread.  */
86           pd->header.data.multiple_threads = 1;
87
88           /* Now fill in the information about the new thread in
89              the newly created thread's data structure.  We cannot let
90              the new thread do this since we don't know whether it was
91              already scheduled when we send the event.  */
92           pd->eventbuf.eventnum = TD_CREATE;
93           pd->eventbuf.eventdata = pd;
94
95           /* Enqueue the descriptor.  */
96           do
97             pd->nextevent = __nptl_last_event;
98           while (atomic_compare_and_exchange_acq (&__nptl_last_event, pd,
99                                                   pd->nextevent) != 0);
100
101           /* Now call the function which signals the event.  */
102           __nptl_create_event ();
103
104           /* And finally restart the new thread.  */
105           lll_unlock (pd->lock);
106
107           return 0;
108         }
109     }
110
111 #ifdef NEED_DL_SYSINFO
112   assert (THREAD_GETMEM (THREAD_SELF, header.data.sysinfo)
113           == pd->header.data.sysinfo);
114 #endif
115
116   /* We rely heavily on various flags the CLONE function understands:
117
118      CLONE_VM, CLONE_FS, CLONE_FILES
119         These flags select semantics with shared address space and
120         file descriptors according to what POSIX requires.
121
122      CLONE_SIGNAL
123         This flag selects the POSIX signal semantics.
124
125      CLONE_SETTLS
126         The sixth parameter to CLONE determines the TLS area for the
127         new thread.
128
129      CLONE_PARENT_SETTID
130         The kernels writes the thread ID of the newly created thread
131         into the location pointed to by the fifth parameters to CLONE.
132
133         Note that it would be semantically equivalent to use
134         CLONE_CHILD_SETTID but it is be more expensive in the kernel.
135
136      CLONE_CHILD_CLEARTID
137         The kernels clears the thread ID of a thread that has called
138         sys_exit() - using the same parameter as CLONE_SETTID.
139
140      CLONE_DETACHED
141         No signal is generated if the thread exists and it is
142         automatically reaped.
143
144      The termination signal is chosen to be zero which means no signal
145      is sent.  */
146   if (__clone (start_thread, STACK_VARIABLES_ARGS,
147                CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL |
148                CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID |
149                CLONE_DETACHED | 0, pd, &pd->tid, &desc.desc, &pd->tid) == -1)
150     /* Failed.  */
151     return errno;
152
153   /* We now have for sure more than one thread.  */
154   THREAD_SETMEM (THREAD_SELF, header.data.multiple_threads, 1);
155
156   return 0;
157 }