123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576 |
- #include <errno.h>
- #include <stdbool.h>
- #include <stdlib.h>
- #include <string.h>
- #include "pthreadP.h"
- #include <ldsodefs.h>
- #include <atomic.h>
- #include <resolv.h>
- #include <bits/kernel-features.h>
- static int start_thread (void *arg);
- int __pthread_debug;
- static td_thr_events_t __nptl_threads_events __attribute_used__;
- static struct pthread *__nptl_last_event __attribute_used__;
- unsigned int __nptl_nthreads = 1;
- #include "allocatestack.c"
- #include <createthread.c>
- struct pthread *
- internal_function
- __find_in_stack_list (
- struct pthread *pd)
- {
- list_t *entry;
- struct pthread *result = NULL;
- lll_lock (stack_cache_lock, LLL_PRIVATE);
- list_for_each (entry, &stack_used)
- {
- struct pthread *curp;
- curp = list_entry (entry, struct pthread, list);
- if (curp == pd)
- {
- result = curp;
- break;
- }
- }
- if (result == NULL)
- list_for_each (entry, &__stack_user)
- {
- struct pthread *curp;
- curp = list_entry (entry, struct pthread, list);
- if (curp == pd)
- {
- result = curp;
- break;
- }
- }
- lll_unlock (stack_cache_lock, LLL_PRIVATE);
- return result;
- }
- void
- attribute_hidden
- __nptl_deallocate_tsd (void)
- {
- struct pthread *self = THREAD_SELF;
-
- if (THREAD_GETMEM (self, specific_used))
- {
- size_t round;
- size_t cnt;
- round = 0;
- do
- {
- size_t idx;
-
- THREAD_SETMEM (self, specific_used, false);
- for (cnt = idx = 0; cnt < PTHREAD_KEY_1STLEVEL_SIZE; ++cnt)
- {
- struct pthread_key_data *level2;
- level2 = THREAD_GETMEM_NC (self, specific, cnt);
- if (level2 != NULL)
- {
- size_t inner;
- for (inner = 0; inner < PTHREAD_KEY_2NDLEVEL_SIZE;
- ++inner, ++idx)
- {
- void *data = level2[inner].data;
- if (data != NULL)
- {
-
- level2[inner].data = NULL;
-
- if (level2[inner].seq
- == __pthread_keys[idx].seq
-
- && __pthread_keys[idx].destr != NULL)
-
- __pthread_keys[idx].destr (data);
- }
- }
- }
- else
- idx += PTHREAD_KEY_1STLEVEL_SIZE;
- }
- if (THREAD_GETMEM (self, specific_used) == 0)
-
- goto just_free;
- }
-
- while (__builtin_expect (++round < PTHREAD_DESTRUCTOR_ITERATIONS, 0));
-
- memset (&THREAD_SELF->specific_1stblock, '\0',
- sizeof (self->specific_1stblock));
- just_free:
-
- for (cnt = 1; cnt < PTHREAD_KEY_1STLEVEL_SIZE; ++cnt)
- {
- struct pthread_key_data *level2;
- level2 = THREAD_GETMEM_NC (self, specific, cnt);
- if (level2 != NULL)
- {
-
- free (level2);
- THREAD_SETMEM_NC (self, specific, cnt, NULL);
- }
- }
- THREAD_SETMEM (self, specific_used, false);
- }
- }
- void
- internal_function
- __free_tcb (struct pthread *pd)
- {
-
- if (__builtin_expect (atomic_bit_test_set (&pd->cancelhandling,
- TERMINATED_BIT) == 0, 1))
- {
-
- if (DEBUGGING_P && __find_in_stack_list (pd) == NULL)
-
- abort ();
-
- if (__builtin_expect (pd->tpp != NULL, 0))
- {
- struct priority_protection_data *tpp = pd->tpp;
- pd->tpp = NULL;
- free (tpp);
- }
-
- __deallocate_stack (pd);
- }
- }
- static int
- start_thread (void *arg)
- {
- struct pthread *pd = (struct pthread *) arg;
- #if defined __UCLIBC_HAS_RESOLVER_SUPPORT__
-
- __resp = &pd->res;
- #endif
- #ifdef __NR_set_robust_list
- # ifndef __ASSUME_SET_ROBUST_LIST
- if (__set_robust_list_avail >= 0)
- # endif
- {
- INTERNAL_SYSCALL_DECL (err);
-
- INTERNAL_SYSCALL (set_robust_list, err, 2, &pd->robust_head,
- sizeof (struct robust_list_head));
- }
- #endif
-
- if (__builtin_expect (pd->parent_cancelhandling & CANCELING_BITMASK, 0))
- {
- INTERNAL_SYSCALL_DECL (err);
- sigset_t mask;
- __sigemptyset (&mask);
- __sigaddset (&mask, SIGCANCEL);
- (void) INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_UNBLOCK, &mask,
- NULL, _NSIG / 8);
- }
-
- struct pthread_unwind_buf unwind_buf;
-
- unwind_buf.priv.data.prev = NULL;
- unwind_buf.priv.data.cleanup = NULL;
- int not_first_call;
- not_first_call = setjmp ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf);
- if (__builtin_expect (! not_first_call, 1))
- {
-
- THREAD_SETMEM (pd, cleanup_jmp_buf, &unwind_buf);
- if (__builtin_expect (pd->stopped_start, 0))
- {
- int oldtype = CANCEL_ASYNC ();
-
- lll_lock (pd->lock, LLL_PRIVATE);
-
- lll_unlock (pd->lock, LLL_PRIVATE);
- CANCEL_RESET (oldtype);
- }
-
- THREAD_SETMEM (pd, result, pd->start_routine (pd->arg));
- }
-
- __nptl_deallocate_tsd ();
-
-
-
- if (__builtin_expect (atomic_decrement_and_test (&__nptl_nthreads), 0))
-
- exit (0);
-
- if (__builtin_expect (pd->report_events, 0))
- {
-
- const int idx = __td_eventword (TD_DEATH);
- const uint32_t mask = __td_eventmask (TD_DEATH);
- if ((mask & (__nptl_threads_events.event_bits[idx]
- | pd->eventbuf.eventmask.event_bits[idx])) != 0)
- {
-
- if (pd->nextevent == NULL)
- {
- pd->eventbuf.eventnum = TD_DEATH;
- pd->eventbuf.eventdata = pd;
- do
- pd->nextevent = __nptl_last_event;
- while (atomic_compare_and_exchange_bool_acq (&__nptl_last_event,
- pd, pd->nextevent));
- }
-
- __nptl_death_event ();
- }
- }
-
- atomic_bit_set (&pd->cancelhandling, EXITING_BIT);
- #ifndef __ASSUME_SET_ROBUST_LIST
-
- # if __WORDSIZE == 64
- void *robust = pd->robust_head.list;
- # else
- __pthread_slist_t *robust = pd->robust_list.__next;
- # endif
-
- if (__set_robust_list_avail < 0
- && __builtin_expect (robust != (void *) &pd->robust_head, 0))
- {
- do
- {
- struct __pthread_mutex_s *this = (struct __pthread_mutex_s *)
- ((char *) robust - offsetof (struct __pthread_mutex_s,
- __list.__next));
- robust = *((void **) robust);
- # ifdef __PTHREAD_MUTEX_HAVE_PREV
- this->__list.__prev = NULL;
- # endif
- this->__list.__next = NULL;
- lll_robust_dead (this->__lock, LLL_SHARED);
- }
- while (robust != (void *) &pd->robust_head);
- }
- #endif
-
- size_t pagesize_m1 = __getpagesize () - 1;
- char *sp = CURRENT_STACK_FRAME;
- #ifdef _STACK_GROWS_DOWN
- size_t freesize = (sp - (char *) pd->stackblock) & ~pagesize_m1;
- #else
- size_t freesize = ((char *) pd->stackblock - sp) & ~pagesize_m1;
- #endif
- assert (freesize < pd->stackblock_size);
-
- #ifdef __ARCH_USE_MMU__
- if (freesize > PTHREAD_STACK_MIN)
- madvise (pd->stackblock, freesize - PTHREAD_STACK_MIN, MADV_DONTNEED);
- #endif
-
- if (IS_DETACHED (pd))
-
- __free_tcb (pd);
- else if (__builtin_expect (pd->cancelhandling & SETXID_BITMASK, 0))
- {
-
- do
- lll_futex_wait (&pd->setxid_futex, 0, LLL_PRIVATE);
- while (pd->cancelhandling & SETXID_BITMASK);
-
- pd->setxid_futex = 0;
- }
-
- __exit_thread_inline (0);
-
- return 0;
- }
- static const struct pthread_attr default_attr =
- {
-
- .guardsize = 1,
- };
- int
- pthread_create (
- pthread_t *newthread,
- const pthread_attr_t *attr,
- void *(*start_routine) (void *),
- void *arg)
- {
- STACK_VARIABLES;
- const struct pthread_attr *iattr = (struct pthread_attr *) attr;
- if (iattr == NULL)
-
- iattr = &default_attr;
- struct pthread *pd = NULL;
- int err = ALLOCATE_STACK (iattr, &pd);
- if (__builtin_expect (err != 0, 0))
-
- return err;
-
- #ifdef TLS_TCB_AT_TP
-
- pd->header.self = pd;
-
- pd->header.tcb = pd;
- #endif
-
- pd->start_routine = start_routine;
- pd->arg = arg;
-
- struct pthread *self = THREAD_SELF;
- pd->flags = ((iattr->flags & ~(ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET))
- | (self->flags & (ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET)));
-
- pd->joinid = iattr->flags & ATTR_FLAG_DETACHSTATE ? pd : NULL;
-
- pd->eventbuf = self->eventbuf;
-
- pd->schedpolicy = self->schedpolicy;
- pd->schedparam = self->schedparam;
-
- #ifdef THREAD_COPY_STACK_GUARD
- THREAD_COPY_STACK_GUARD (pd);
- #endif
-
- #ifdef THREAD_COPY_POINTER_GUARD
- THREAD_COPY_POINTER_GUARD (pd);
- #endif
-
- if (attr != NULL
- && __builtin_expect ((iattr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0, 0)
- && (iattr->flags & (ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET)) != 0)
- {
- INTERNAL_SYSCALL_DECL (scerr);
-
- if (iattr->flags & ATTR_FLAG_POLICY_SET)
- pd->schedpolicy = iattr->schedpolicy;
- else if ((pd->flags & ATTR_FLAG_POLICY_SET) == 0)
- {
- pd->schedpolicy = INTERNAL_SYSCALL (sched_getscheduler, scerr, 1, 0);
- pd->flags |= ATTR_FLAG_POLICY_SET;
- }
- if (iattr->flags & ATTR_FLAG_SCHED_SET)
- memcpy (&pd->schedparam, &iattr->schedparam,
- sizeof (struct sched_param));
- else if ((pd->flags & ATTR_FLAG_SCHED_SET) == 0)
- {
- INTERNAL_SYSCALL (sched_getparam, scerr, 2, 0, &pd->schedparam);
- pd->flags |= ATTR_FLAG_SCHED_SET;
- }
-
- int minprio = INTERNAL_SYSCALL (sched_get_priority_min, scerr, 1,
- iattr->schedpolicy);
- int maxprio = INTERNAL_SYSCALL (sched_get_priority_max, scerr, 1,
- iattr->schedpolicy);
- if (pd->schedparam.sched_priority < minprio
- || pd->schedparam.sched_priority > maxprio)
- {
- err = EINVAL;
- goto errout;
- }
- }
-
- *newthread = (pthread_t) pd;
-
- bool is_detached = IS_DETACHED (pd);
-
- err = create_thread (pd, iattr, STACK_VARIABLES_ARGS);
- if (err != 0)
- {
-
- if (!is_detached)
- {
- errout:
- __deallocate_stack (pd);
- }
- return err;
- }
- return 0;
- }
- #include "../nptl_db/db_info.c"
- PTHREAD_STATIC_FN_REQUIRE (pthread_mutex_lock)
- PTHREAD_STATIC_FN_REQUIRE (pthread_mutex_trylock)
- PTHREAD_STATIC_FN_REQUIRE (pthread_mutex_unlock)
- PTHREAD_STATIC_FN_REQUIRE (pthread_once)
- PTHREAD_STATIC_FN_REQUIRE (pthread_cancel)
- PTHREAD_STATIC_FN_REQUIRE (pthread_key_create)
- PTHREAD_STATIC_FN_REQUIRE (pthread_key_delete)
- PTHREAD_STATIC_FN_REQUIRE (pthread_setspecific)
- PTHREAD_STATIC_FN_REQUIRE (pthread_getspecific)
- PTHREAD_STATIC_FN_REQUIRE (pthread_mutex_init)
- PTHREAD_STATIC_FN_REQUIRE (_pthread_cleanup_push_defer)
- PTHREAD_STATIC_FN_REQUIRE (_pthread_cleanup_pop_restore)
|