1f6a51e4468baea84c11fa0f96b39977120fd219
[kopensolaris-gnu/glibc.git] / nptl / sysdeps / unix / sysv / solaris2 / kopensolaris-gnu / createthread.c
1 /* Copyright (C) 2002, 2003, 2004, 2006, 2007, 2008
2     Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
5    OpenSolaris bits contributed by David Bartley
6     <dtbartle@csclub.uwaterloo.ca>, 2008.
7
8    The GNU C Library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Lesser General Public
10    License as published by the Free Software Foundation; either
11    version 2.1 of the License, or (at your option) any later version.
12
13    The GNU C Library is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Lesser General Public License for more details.
17
18    You should have received a copy of the GNU Lesser General Public
19    License along with the GNU C Library; if not, write to the Free
20    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21    02111-1307 USA.  */
22
23 #include <tls.h>
24 #include <ucontext.h>
25 #include <sys/stack.h>
26 #include <sys/stack.h>
27 #include <sys/regset.h>
28 #include <inline-syscall.h>
29 #include <sched_priv.h>
30 #include <createthread_arch.c>
31
32 DECLARE_INLINE_SYSCALL (int, lwp_create, ucontext_t *ucp, int flags,
33     pthread_t *new_lwp);
34 DECLARE_INLINE_SYSCALL (int, lwp_continue, pthread_t lwpid);
35 DECLARE_INLINE_SYSCALL (int, lwp_kill, pthread_t lwpid, int sig);
36
37 #ifndef TLS_MULTIPLE_THREADS_IN_TCB
38 /* Pointer to the corresponding variable in libc.  */
39 int *__libc_multiple_threads_ptr attribute_hidden;
40 #endif
41
42 static int
43 create_thread (struct pthread *pd, const struct pthread_attr *attr,
44                STACK_VARIABLES_PARMS)
45 {
46 #ifdef TLS_TCB_AT_TP
47   assert (pd->header.tcb != NULL);
48 #endif
49
50   /* Do arch-specific creation.  */
51   ucontext_t ctx = {0};
52   int errval = create_thread_arch (&ctx, pd, attr, STACK_VARIABLES_ARGS);
53   if (errval != 0)
54     return errval;
55
56   /* Threads inherit the parent's sigmask.  */
57   pthread_sigmask (SIG_SETMASK, NULL, &ctx.uc_sigmask);
58
59   /* One more thread.  We cannot have the thread do this itself, since it
60      might exist but not have been scheduled yet by the time we've returned
61      and need to check the value to behave correctly.  We must do it before
62      creating the thread, in case it does get scheduled first and then
63      might mistakenly think it was the only thread.  In the failure case,
64      we momentarily store a false value; this doesn't matter because there
65      is no kosher thing a signal handler interrupting us right here can do
66      that cares whether the thread count is correct.  */
67   atomic_increment (&__nptl_nthreads);
68
69   /* We set the thread to be initially suspended so that we can set
70      scheduling magic.  */
71   int lwp_flags =
72       ((attr->flags & ATTR_FLAG_DAEMON) ? THR_DAEMON : 0) |
73       ((attr->flags & ATTR_FLAG_DETACHSTATE) ? THR_DETACHED : 0);
74   if ((attr->flags & ATTR_FLAG_THR_CREATE) == 0)
75     lwp_flags |= THR_SUSPENDED;
76   errval = INLINE_SYSCALL (lwp_create, 3, &ctx, lwp_flags, &pd->tid);
77   if (errval == 0 && (attr->flags & ATTR_FLAG_THR_CREATE) == 0)
78     {
79       /* Set scheduling.  */
80       if (attr->flags & (ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET))
81         {
82           int policy, priority;
83           errval = __sched_getscheduler_id (P_LWPID, pd->tid,
84             &policy, &priority);
85           if (errval == 0)
86             {
87               if (attr->flags & ATTR_FLAG_SCHED_SET)
88                 priority = attr->schedparam.__sched_priority;
89               if (attr->flags & ATTR_FLAG_POLICY_SET)
90                 policy = attr->schedpolicy;
91
92               errval = __sched_setscheduler_id (P_LWPID, pd->tid,
93                 policy, priority);
94             }
95
96           if (errval != 0)
97             errval = EPERM;
98         }
99
100       /* Resume thread if requested.  */
101       if (errval == 0)
102         {
103           if (!(attr->flags & ATTR_FLAG_SUSPENDED))
104             errval = INLINE_SYSCALL (lwp_continue, 1, pd->tid);
105         }
106
107       /* Kill the thread if we didn't succeed above.  */
108       if (errval != 0)
109         INLINE_SYSCALL (lwp_kill, 2, pd->tid, SIGKILL);
110     }
111
112   if (errval == 0)
113     {
114       /* We now have for sure more than one thread.  The main thread might
115          not yet have the flag set.  No need to set the global variable
116          again if this is what we use.  */
117       THREAD_SETMEM (THREAD_SELF, header.multiple_threads, 1);
118     }
119   else
120     {
121       atomic_decrement (&__nptl_nthreads); /* Oops, we lied for a second.  */
122
123       /* Failed.  If the thread is detached, remove the TCB here since
124          the caller cannot do this.  The caller remembered the thread
125          as detached and cannot reverify that it is not since it must
126          not access the thread descriptor again.  */
127       if (IS_DETACHED (pd))
128         __deallocate_stack (pd);
129     }
130
131   return errval;
132 }