summaryrefslogtreecommitdiff
path: root/nptl/sysdeps/unix/sysv/solaris2/kopensolaris-gnu/createthread.c
diff options
context:
space:
mode:
Diffstat (limited to 'nptl/sysdeps/unix/sysv/solaris2/kopensolaris-gnu/createthread.c')
-rw-r--r--nptl/sysdeps/unix/sysv/solaris2/kopensolaris-gnu/createthread.c137
1 files changed, 137 insertions, 0 deletions
diff --git a/nptl/sysdeps/unix/sysv/solaris2/kopensolaris-gnu/createthread.c b/nptl/sysdeps/unix/sysv/solaris2/kopensolaris-gnu/createthread.c
new file mode 100644
index 0000000000..0bb1b81c0a
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/solaris2/kopensolaris-gnu/createthread.c
@@ -0,0 +1,137 @@
+/* Copyright (C) 2002, 2003, 2004, 2006, 2007, 2008
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+ OpenSolaris bits contributed by David Bartley
+ <dtbartle@csclub.uwaterloo.ca>, 2008.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <tls.h>
+#include <ucontext.h>
+#include <sys/stack.h>
+#include <sys/stack.h>
+#include <sys/regset.h>
+#include <sys/lwp.h>
+#include <inline-syscall.h>
+#include <schedP.h>
+#include <createthread_arch.c>
+
+DECLARE_INLINE_SYSCALL (int, lwp_create, ucontext_t *ucp, int flags,
+ pthread_t *new_lwp);
+DECLARE_INLINE_SYSCALL (int, lwp_continue, pthread_t lwpid);
+DECLARE_INLINE_SYSCALL (int, lwp_kill, pthread_t lwpid, int sig);
+
+#ifndef TLS_MULTIPLE_THREADS_IN_TCB
+/* Pointer to the corresponding variable in libc. */
+int *__libc_multiple_threads_ptr attribute_hidden;
+#endif
+
+static int
+create_thread (struct pthread *pd, const struct pthread_attr *attr,
+ STACK_VARIABLES_PARMS)
+{
+#ifdef TLS_TCB_AT_TP
+ assert (pd->header.tcb != NULL);
+#endif
+
+ /* Do arch-specific creation. */
+ ucontext_t ctx = {0};
+ int errval = create_thread_arch (&ctx, pd, attr, STACK_VARIABLES_ARGS);
+ if (errval != 0)
+ return errval;
+
+ /* Threads inherit the parent's sigmask. */
+ pthread_sigmask (SIG_SETMASK, NULL, &ctx.uc_sigmask);
+
+ /* One more thread. We cannot have the thread do this itself, since it
+ might exist but not have been scheduled yet by the time we've returned
+ and need to check the value to behave correctly. We must do it before
+ creating the thread, in case it does get scheduled first and then
+ might mistakenly think it was the only thread. In the failure case,
+ we momentarily store a false value; this doesn't matter because there
+ is no kosher thing a signal handler interrupting us right here can do
+ that cares whether the thread count is correct. */
+ atomic_increment (&__nptl_nthreads);
+
+ /* We set the thread to be initially suspended so that we can set
+ scheduling magic. */
+ int lwp_flags =
+ ((attr->flags & ATTR_FLAG_DAEMON) ? LWP_DAEMON : 0) |
+ ((attr->flags & ATTR_FLAG_DETACHSTATE) ? LWP_DETACHED : 0);
+ if ((attr->flags & ATTR_FLAG_THR_CREATE) == 0)
+ lwp_flags |= LWP_SUSPENDED;
+ errval = INLINE_SYSCALL (lwp_create, 3, &ctx, lwp_flags, &pd->tid);
+ if (errval == 0 && (attr->flags & ATTR_FLAG_THR_CREATE) == 0)
+ {
+ /* Set scheduling. */
+ if (attr->flags & (ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET))
+ {
+ int policy, priority;
+ errval = __sched_getscheduler_id (P_LWPID, pd->tid,
+ &policy, &priority);
+ if (errval == 0)
+ {
+ if (attr->flags & ATTR_FLAG_SCHED_SET)
+ priority = attr->schedparam.__sched_priority;
+ if (attr->flags & ATTR_FLAG_POLICY_SET)
+ policy = attr->schedpolicy;
+
+ errval = __sched_setscheduler_id (P_LWPID, pd->tid,
+ policy, priority);
+ }
+
+ if (errval != 0)
+ errval = EPERM;
+ }
+
+ /* TODO: remove this hack once scheduling works. */
+ errval = 0;
+
+ if (errval == 0 && !(attr->flags & ATTR_FLAG_SUSPENDED))
+ {
+ errval = INLINE_SYSCALL (lwp_continue, 1, pd->tid);
+ }
+ else if (errval != 0)
+ {
+ pd->flags |= ATTR_FLAG_CREATE_FAILED;
+ INLINE_SYSCALL (lwp_continue, 1, pd->tid);
+
+ if (!IS_DETACHED (pd))
+ {
+ int result;
+ lll_wait_tid (pd->tid);
+ }
+
+ /* Note: if the thread is detached, start_thread will free pd;
+ otherwise the caller of create_thread will free pd. */
+ }
+ }
+
+ if (errval == 0)
+ {
+ /* We now have for sure more than one thread. The main thread might
+ not yet have the flag set. No need to set the global variable
+ again if this is what we use. */
+ THREAD_SETMEM (THREAD_SELF, header.multiple_threads, 1);
+ }
+ else
+ {
+ atomic_decrement (&__nptl_nthreads); /* Oops, we lied for a second. */
+ }
+
+ return errval;
+}