-/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 2002-2014 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
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. */
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
#include <sched.h>
#include <setjmp.h>
#include <atomic.h>
#include <ldsodefs.h>
#include <tls.h>
+#include <stdint.h>
#include "kernel-features.h"
-#define CLONE_SIGNAL (CLONE_SIGHAND | CLONE_THREAD)
+#define CLONE_SIGNAL (CLONE_SIGHAND | CLONE_THREAD)
/* Unless otherwise specified, the thread "register" is going to be
initialized with a pointer to the TCB. */
#ifndef TLS_MULTIPLE_THREADS_IN_TCB
-/* Variable set to a nonzero value if more than one thread runs or ran. */
-int __pthread_multiple_threads attribute_hidden;
/* Pointer to the corresponding variable in libc. */
int *__libc_multiple_threads_ptr attribute_hidden;
#endif
PREPARE_CREATE;
#endif
- if (stopped)
- /* We Make sure the thread does not run far by forcing it to get a
+ if (__glibc_unlikely (stopped != 0))
+ /* We 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);
+ lll_lock (pd->lock, LLL_PRIVATE);
/* 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
that cares whether the thread count is correct. */
atomic_increment (&__nptl_nthreads);
- if (ARCH_CLONE (fct, STACK_VARIABLES_ARGS, clone_flags,
- pd, &pd->tid, TLS_VALUE, &pd->tid) == -1)
+ int rc = ARCH_CLONE (fct, STACK_VARIABLES_ARGS, clone_flags,
+ pd, &pd->tid, TLS_VALUE, &pd->tid);
+
+ if (__glibc_unlikely (rc == -1))
{
atomic_decrement (&__nptl_nthreads); /* Oops, we lied for a second. */
- /* Failed. If the thread is detached, remove the TCB here since
- the caller cannot do this. The caller remembered the thread
- as detached and cannot reverify that it is not since it must
- not access the thread descriptor again. */
- if (IS_DETACHED (pd))
+ /* Perhaps a thread wants to change the IDs and if waiting
+ for this stillborn thread. */
+ if (__builtin_expect (atomic_exchange_acq (&pd->setxid_futex, 0)
+ == -2, 0))
+ lll_futex_wake (&pd->setxid_futex, 1, LLL_PRIVATE);
+
+ /* Free the resources. */
__deallocate_stack (pd);
- return errno;
+ /* We have to translate error codes. */
+ return errno == ENOMEM ? EAGAIN : errno;
}
/* Now we have the possibility to set scheduling parameters etc. */
- if (__builtin_expect (stopped != 0, 0))
+ if (__glibc_unlikely (stopped != 0))
{
INTERNAL_SYSCALL_DECL (err);
int res = 0;
if (attr->cpuset != NULL)
{
res = INTERNAL_SYSCALL (sched_setaffinity, err, 3, pd->tid,
- sizeof (cpu_set_t), attr->cpuset);
+ attr->cpusetsize, attr->cpuset);
- if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (res, err), 0))
+ if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (res, err)))
{
/* The operation failed. We have to kill the thread. First
send it the cancellation signal. */
INTERNAL_SYSCALL_DECL (err2);
err_out:
-#if __ASSUME_TGKILL
(void) INTERNAL_SYSCALL (tgkill, err2, 3,
THREAD_GETMEM (THREAD_SELF, pid),
pd->tid, SIGCANCEL);
-#else
- (void) INTERNAL_SYSCALL (tkill, err2, 2, pd->tid, SIGCANCEL);
-#endif
+
+ /* We do not free the stack here because the canceled thread
+ itself will do this. */
return (INTERNAL_SYSCALL_ERROR_P (res, err)
? INTERNAL_SYSCALL_ERRNO (res, err)
res = INTERNAL_SYSCALL (sched_setscheduler, err, 3, pd->tid,
pd->schedpolicy, &pd->schedparam);
- if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (res, err), 0))
+ if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (res, err)))
goto err_out;
}
}
sys_exit() in the location pointed to by the seventh parameter
to CLONE.
- 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. */
int clone_flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL
| CLONE_SETTLS | CLONE_PARENT_SETTID
| CLONE_CHILD_CLEARTID | CLONE_SYSVSEM
-#if __ASSUME_NO_CLONE_DETACHED == 0
- | CLONE_DETACHED
-#endif
| 0);
- if (__builtin_expect (THREAD_GETMEM (THREAD_SELF, report_events), 0))
+ if (__glibc_unlikely (THREAD_GETMEM (THREAD_SELF, report_events)))
{
/* The parent thread is supposed to report events. Check whether
the TD_CREATE event is needed, too. */
__nptl_create_event ();
/* And finally restart the new thread. */
- lll_unlock (pd->lock);
+ lll_unlock (pd->lock, LLL_PRIVATE);
}
return res;
|| (attr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0))
stopped = true;
pd->stopped_start = stopped;
+ pd->parent_cancelhandling = THREAD_GETMEM (THREAD_SELF, cancelhandling);
/* Actually create the thread. */
int res = do_clone (pd, attr, clone_flags, start_thread,
if (res == 0 && stopped)
/* And finally restart the new thread. */
- lll_unlock (pd->lock);
+ lll_unlock (pd->lock, LLL_PRIVATE);
return res;
}