123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611 |
- /*++
- Copyright (c) 2015 Minoca Corp.
- This file is licensed under the terms of the GNU General Public License
- version 3. Alternative licensing terms are available. Contact
- info@minocacorp.com for details. See the LICENSE file at the root of this
- project for complete licensing information.
- Module Name:
- pthread.c
- Abstract:
- This module implements support for POSIX threads.
- Author:
- Evan Green 29-Apr-2015
- Environment:
- User Mode C Library
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include "pthreadp.h"
- #include <assert.h>
- #include <limits.h>
- #include <sys/mman.h>
- #include <unistd.h>
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- /*++
- Structure Description:
- This structure stores a thread-local destructor entry.
- Members:
- ListEntry - Stores pointers to the next and previous elements in the
- destructor entry.
- DestructorRoutine - Stores a pointer to the routine to call.
- Argument - Stores a pointer to the argument to pass to the routine.
- SharedObjectHandle - Stores the shared object handle this destructor is
- associated with.
- --*/
- typedef struct _THREAD_DESTRUCTOR {
- LIST_ENTRY ListEntry;
- PTHREAD_ENTRY_ROUTINE DestructorRoutine;
- PVOID Argument;
- PVOID SharedObjectHandle;
- } THREAD_DESTRUCTOR, *PTHREAD_DESTRUCTOR;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- VOID
- ClpThreadStart (
- PVOID Parameter
- );
- VOID
- ClpInitializeThreading (
- VOID
- );
- void
- ClpThreadSignalHandler (
- int Signal
- );
- int
- ClpAllocateThread (
- const pthread_attr_t *Attribute,
- void *(*StartRoutine)(void *),
- void *Argument,
- PPTHREAD *Thread
- );
- void
- ClpDestroyThread (
- PPTHREAD Thread
- );
- VOID
- ClpCallThreadDestructors (
- VOID
- );
- PPTHREAD
- ClpGetThreadFromId (
- pthread_t ThreadId
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // Store the global thread list.
- //
- LIST_ENTRY ClThreadList;
- pthread_mutex_t ClThreadListMutex = PTHREAD_MUTEX_INITIALIZER;
- //
- // Store a thread-local pointer to the current thread.
- //
- __THREAD PPTHREAD ClCurrentThread;
- //
- // Store a thread-local list of destructor functions registered by the
- // compiler.
- //
- __THREAD LIST_ENTRY ClThreadDestructors;
- //
- // ------------------------------------------------------------------ Functions
- //
- PTHREAD_API
- pthread_t
- pthread_self (
- void
- )
- /*++
- Routine Description:
- This routine returns the thread ID for the current thread.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- PPTHREAD Thread;
- Thread = ClCurrentThread;
- //
- // If there is no current thread, then this must be the main thread.
- // Lazily allocate a new thread structure for it.
- //
- if (Thread == NULL) {
- ClpInitializeThreading();
- Thread = ClCurrentThread;
- }
- return (pthread_t)Thread;
- }
- PTHREAD_API
- int
- pthread_create (
- pthread_t *CreatedThread,
- const pthread_attr_t *Attribute,
- void *(*StartRoutine)(void *),
- void *Argument
- )
- /*++
- Routine Description:
- This routine creates and starts a new thread. The signal mask of the new
- thread is inherited from the current thread. The set of pending signals in
- the new thread will be initially empty.
- Arguments:
- CreatedThread - Supplies a pointer where the identifier of the new thread
- will be returned on success.
- Attribute - Supplies an optional pointer to the attributes of the thread.
- StartRoutine - Supplies a pointer to the routine to call on the new thread.
- Argument - Supplies the argument to pass to the start routine.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- SIGNAL_SET InternalSignals;
- KSTATUS KernelStatus;
- pthread_attr_t LocalAttributes;
- PPTHREAD NewThread;
- int Status;
- //
- // Initialize the default attributes if none were supplied.
- //
- if (Attribute == NULL) {
- pthread_attr_init(&LocalAttributes);
- Attribute = &LocalAttributes;
- }
- Status = ClpAllocateThread(Attribute, StartRoutine, Argument, &NewThread);
- if (Status != 0) {
- return Status;
- }
- //
- // Force the main thread to get with the program in case this is the first
- // thread created.
- //
- pthread_self();
- pthread_mutex_lock(&(NewThread->StartMutex));
- //
- // Block all possible signals in the new thread while it sets itself up,
- // including the internal signals.
- //
- FILL_SIGNAL_SET(InternalSignals);
- NewThread->SignalMask = OsSetSignalBehavior(SignalMaskBlocked,
- SignalMaskOperationOverwrite,
- &InternalSignals);
- KernelStatus = OsCreateThread(NULL,
- 0,
- ClpThreadStart,
- NewThread,
- NewThread->Attribute.StackBase,
- NewThread->Attribute.StackSize,
- NewThread->OsData,
- &(NewThread->ThreadId));
- OsSetSignalBehavior(SignalMaskBlocked,
- SignalMaskOperationOverwrite,
- &(NewThread->SignalMask));
- if (!KSUCCESS(KernelStatus)) {
- Status = ClConvertKstatusToErrorNumber(KernelStatus);
- ClpDestroyThreadKeyData(NewThread);
- ClpDestroyThread(NewThread);
- return Status;
- }
- if ((NewThread->Attribute.Flags & PTHREAD_FLAG_DETACHED) != 0) {
- NewThread->State = PthreadStateDetached;
- } else {
- NewThread->State = PthreadStateNotJoined;
- }
- //
- // Add the thread to the global list.
- //
- pthread_mutex_lock(&ClThreadListMutex);
- INSERT_BEFORE(&(NewThread->ListEntry), &ClThreadList);
- pthread_mutex_unlock(&ClThreadListMutex);
- //
- // Let the thread run.
- //
- pthread_mutex_unlock(&(NewThread->StartMutex));
- *CreatedThread = (pthread_t)NewThread;
- return 0;
- }
- PTHREAD_API
- int
- pthread_detach (
- pthread_t ThreadId
- )
- /*++
- Routine Description:
- This routine marks the given thread as detached, which means that when it
- exits, its resources are automatically released without needing another
- thread to call join on it. It is illegal to call join on a detached thread,
- as the thread ID may be already released and reused.
- Arguments:
- ThreadId - Supplies the thread ID to detach.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- ULONG OldState;
- PPTHREAD Thread;
- Thread = ClpGetThreadFromId(ThreadId);
- if (Thread == NULL) {
- return ESRCH;
- }
- //
- // Try to detach the thread.
- //
- OldState = RtlAtomicCompareExchange32(&(Thread->State),
- PthreadStateDetached,
- PthreadStateNotJoined);
- //
- // If the compare exchange was won, then the thread was successfully
- // detached.
- //
- if (OldState == PthreadStateNotJoined) {
- return 0;
- }
- //
- // If the thread has already exited, call join to clean up the remaining
- // thread resources.
- //
- if (OldState == PthreadStateExited) {
- return pthread_join(ThreadId, NULL);
- }
- //
- // The thread is either all funky or has already been joined in which case
- // the user is on drugs.
- //
- assert((OldState == PthreadStateJoined) ||
- (OldState == PthreadStateDetached));
- return EINVAL;
- }
- PTHREAD_API
- int
- pthread_join (
- pthread_t ThreadId,
- void **ReturnValue
- )
- /*++
- Routine Description:
- This routine waits for the given thread to exit and collects its return
- value. Detached threads cannot be joined.
- Arguments:
- ThreadId - Supplies the identifier of the thread to join with.
- ReturnValue - Supplies a pointer where the thread return value will be
- returned on success.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- ULONG NewState;
- ULONG OldState;
- THREAD_ID OsThreadId;
- PPTHREAD Thread;
- pthread_testcancel();
- //
- // Don't be ridiculous.
- //
- if (ThreadId == pthread_self()) {
- return EDEADLK;
- }
- Thread = ClpGetThreadFromId(ThreadId);
- if (Thread == NULL) {
- return ESRCH;
- }
- //
- // Try to change the state from not joined or exited to joined. This may
- // race with other calls to join (weird), detach, and the thread exiting.
- //
- OldState = PthreadStateNotJoined;
- while ((OldState == PthreadStateNotJoined) ||
- (OldState == PthreadStateExited)) {
- NewState = RtlAtomicCompareExchange32(&(Thread->State),
- PthreadStateJoined,
- OldState);
- if (OldState == NewState) {
- break;
- }
- OldState = NewState;
- }
- if ((OldState == PthreadStateDetached) ||
- (OldState == PthreadStateJoined)) {
- return EINVAL;
- }
- //
- // Wait for the thread to exit.
- //
- OsThreadId = Thread->ThreadId;
- while (Thread->ThreadId != 0) {
- OsUserLock(&(Thread->ThreadId),
- UserLockWait,
- (PULONG)&OsThreadId,
- SYS_WAIT_TIME_INDEFINITE);
- }
- //
- // Get the return value if requested.
- //
- if (ReturnValue != NULL) {
- *ReturnValue = Thread->ReturnValue;
- }
- //
- // Remove and clean up the thread structure.
- //
- pthread_mutex_lock(&ClThreadListMutex);
- LIST_REMOVE(&(Thread->ListEntry));
- Thread->ListEntry.Next = NULL;
- pthread_mutex_unlock(&ClThreadListMutex);
- if (Thread->KeyData != NULL) {
- ClpDestroyThreadKeyData(Thread);
- }
- ClpDestroyThread(Thread);
- return 0;
- }
- PTHREAD_API
- __NO_RETURN
- void
- pthread_exit (
- void *ReturnValue
- )
- /*++
- Routine Description:
- This routine exits the current thread. If this is a detached thread, then
- all thread resources are destroyed immediately. If this is a joinable
- thread, then some state is kept around until another thread calls join to
- collect the return value.
- Arguments:
- ReturnValue - Supplies an optional return value to give to anyone that
- calls join.
- Return Value:
- None. This routine does not return.
- --*/
- {
- __pthread_cleanup_t *CleanupItem;
- PVOID DestroyRegion;
- UINTN DestroyRegionSize;
- ULONG OldState;
- SIGNAL_SET SignalMask;
- PPTHREAD Thread;
- //
- // Call C++ thread_local destructors.
- //
- Thread = (PPTHREAD)pthread_self();
- ClpCallThreadDestructors();
- Thread->ReturnValue = ReturnValue;
- //
- // Call the cleanup handlers as well.
- //
- while (Thread->CleanupStack != NULL) {
- CleanupItem = Thread->CleanupStack;
- Thread->CleanupStack = CleanupItem->__cleanup_prev;
- CleanupItem->__cleanup_routine(CleanupItem->__cleanup_arg);
- }
- //
- // Clean up all thread local keys.
- //
- ClpDestroyThreadKeyData(Thread);
- DestroyRegion = NULL;
- DestroyRegionSize = 0;
- //
- // Mask out all signals, as this thread will not be handling anything else,
- // and then exit. This may touch errno so it must be done before the thread
- // is torn down.
- //
- FILL_SIGNAL_SET(SignalMask);
- OsSetSignalBehavior(SignalMaskBlocked,
- SignalMaskOperationOverwrite,
- &SignalMask);
- //
- // Indicate that the thread has exited.
- //
- OldState = RtlAtomicCompareExchange32(&(Thread->State),
- PthreadStateExited,
- PthreadStateNotJoined);
- if (OldState == PthreadStateDetached) {
- //
- // No one will be joining this thread, it must clean itself up. The
- // kernel will help with the last deallocation since it is the stack.
- //
- pthread_mutex_lock(&ClThreadListMutex);
- LIST_REMOVE(&(Thread->ListEntry));
- Thread->ListEntry.Next = NULL;
- pthread_mutex_unlock(&ClThreadListMutex);
- DestroyRegion = Thread->ThreadAllocation;
- DestroyRegionSize = Thread->ThreadAllocationSize;
- Thread->ThreadAllocationSize = 0;
- ClpDestroyThread(Thread);
- }
- OsExitThread(DestroyRegion, DestroyRegionSize);
- abort();
- }
- PTHREAD_API
- int
- pthread_equal (
- pthread_t FirstThread,
- pthread_t SecondThread
- )
- /*++
- Routine Description:
- This routine compares two thread identifiers.
- Arguments:
- FirstThread - Supplies the first thread identifier to compare.
- SecondThread - Supplies the second thread identifier to compare.
- Return Value:
- Returns non-zero if the two thread IDs are equal.
- 0 if the thread IDs are not equal.
- --*/
- {
- return FirstThread == SecondThread;
- }
- PTHREAD_API
- int
- pthread_kill (
- pthread_t ThreadId,
- int Signal
- )
- /*++
- Routine Description:
- This routine sends a signal to the given thread.
- Arguments:
- ThreadId - Supplies the identifier of the thread to send the signal to.
- Signal - Supplies the signal number to send. Supply 0 to test if a signal
- can be sent, but not actually send any signal.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- THREAD_ID KernelThreadId;
- KSTATUS Status;
- PPTHREAD Thread;
- Thread = ClpGetThreadFromId(ThreadId);
- if (Thread == NULL) {
- return ESRCH;
- }
- KernelThreadId = Thread->ThreadId;
- if (KernelThreadId == 0) {
- return ESRCH;
- }
- Status = OsSendSignal(SignalTargetThread,
- KernelThreadId,
- Signal,
- SIGNAL_CODE_THREAD_KILL,
- 0);
- if (!KSUCCESS(Status)) {
- return ClConvertKstatusToErrorNumber(Status);
- }
- return 0;
- }
- PTHREAD_API
- int
- pthread_sigqueue (
- pthread_t ThreadId,
- int Signal,
- const union sigval Value
- )
- /*++
- Routine Description:
- This routine queues a signal with data the given thread.
- Arguments:
- ThreadId - Supplies the identifier of the thread to send the signal to.
- Signal - Supplies the signal number to send. Supply 0 to test if a signal
- can be sent, but not actually send any signal.
- Value - Supplies the signal value to send.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- KSTATUS Status;
- PPTHREAD Thread;
- ASSERT(sizeof(void *) >= sizeof(int));
- Thread = ClpGetThreadFromId(ThreadId);
- if (Thread == NULL) {
- return ESRCH;
- }
- Status = OsSendSignal(SignalTargetThread,
- Thread->ThreadId,
- Signal,
- SIGNAL_CODE_QUEUE,
- (UINTN)(Value.sival_ptr));
- if (!KSUCCESS(Status)) {
- return ClConvertKstatusToErrorNumber(Status);
- }
- return 0;
- }
- PTHREAD_API
- int
- pthread_cancel (
- pthread_t ThreadId
- )
- /*++
- Routine Description:
- This routine attempts to cancel (terminate) the thread with the given
- thread ID. This may not terminate the thread immediately if it has disabled
- or deferred cancellation.
- Arguments:
- ThreadId - Supplies the identifier of the thread to cancel.
- Return Value:
- 0 on success.
- ESRCH if a thread with the given ID could not be found.
- --*/
- {
- PPTHREAD Thread;
- Thread = ClpGetThreadFromId(ThreadId);
- if (Thread == NULL) {
- return ESRCH;
- }
- Thread->CancelRequested = TRUE;
- pthread_kill(ThreadId, SIGNAL_PTHREAD);
- return 0;
- }
- PTHREAD_API
- int
- pthread_setcancelstate (
- int State,
- int *OldState
- )
- /*++
- Routine Description:
- This routine atomically sets the thread cancellation state for the current
- thread and returns the old state. By default, new threads are created with
- cancellation enabled.
- Arguments:
- State - Supplies the new state to set. Valid values are
- PTHREAD_CANCEL_ENABLE and PTHREAD_CANCEL_DISABLE.
- OldState - Supplies the previously set cancellation state.
- Return Value:
- 0 on success.
- EINVAL if an invalid new state was supplied.
- --*/
- {
- ULONG PreviousState;
- PPTHREAD Thread;
- if ((State != PTHREAD_CANCEL_ENABLE) && (State != PTHREAD_CANCEL_DISABLE)) {
- return EINVAL;
- }
- Thread = (PPTHREAD)pthread_self();
- PreviousState = RtlAtomicExchange32(&(Thread->CancelState), State);
- if (OldState != NULL) {
- *OldState = PreviousState;
- }
- if (State == PTHREAD_CANCEL_ENABLE) {
- pthread_testcancel();
- }
- return 0;
- }
- PTHREAD_API
- int
- pthread_setcanceltype (
- int Type,
- int *OldType
- )
- /*++
- Routine Description:
- This routine atomically sets the thread cancellation type for the current
- thread and returns the old type. By default, new threads are created with
- deferred cancellation.
- Arguments:
- Type - Supplies the new type to set. Valid values are
- PTHREAD_CANCEL_DEFERRED and PTHREAD_CANCEL_ASYNCHRONOUS.
- OldType - Supplies the previously set cancellation type.
- Return Value:
- 0 on success.
- EINVAL if an invalid new type was supplied.
- --*/
- {
- ULONG PreviousType;
- PPTHREAD Thread;
- if ((Type != PTHREAD_CANCEL_DEFERRED) &&
- (Type != PTHREAD_CANCEL_ASYNCHRONOUS)) {
- return EINVAL;
- }
- Thread = (PPTHREAD)pthread_self();
- PreviousType = RtlAtomicExchange32(&(Thread->CancelType), Type);
- if (OldType != NULL) {
- *OldType = PreviousType;
- }
- if (Type == PTHREAD_CANCEL_ASYNCHRONOUS) {
- pthread_testcancel();
- }
- return 0;
- }
- PTHREAD_API
- void
- pthread_testcancel (
- void
- )
- /*++
- Routine Description:
- This routine creates a cancellation point in the calling thread. If
- cancellation is currently disabled, this does nothing.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- PPTHREAD Thread;
- Thread = (PPTHREAD)pthread_self();
- if (Thread->CancelState != PTHREAD_CANCEL_ENABLE) {
- return;
- }
- if (Thread->CancelRequested != FALSE) {
- pthread_exit(PTHREAD_CANCELED);
- }
- return;
- }
- PTHREAD_API
- pid_t
- pthread_gettid_np (
- pthread_t ThreadId
- )
- /*++
- Routine Description:
- This routine returns the kernel thread ID for the given POSIX thread ID.
- Arguments:
- ThreadId - Supplies the POSIX thread ID.
- Return Value:
- Returns the kernel thread ID.
- --*/
- {
- PPTHREAD Thread;
- Thread = (PPTHREAD)ThreadId;
- return Thread->ThreadId;
- }
- PTHREAD_API
- pid_t
- pthread_getthreadid_np (
- void
- )
- /*++
- Routine Description:
- This routine returns the kernel thread ID for the current thread.
- Arguments:
- None.
- Return Value:
- Returns the kernel thread ID.
- --*/
- {
- return pthread_gettid_np(pthread_self());
- }
- PTHREAD_API
- int
- pthread_getattr_np (
- pthread_t ThreadId,
- pthread_attr_t *Attribute
- )
- /*++
- Routine Description:
- This routine returns the current attributes for a given thread.
- Arguments:
- ThreadId - Supplies the thread to get attributes for.
- Attribute - Supplies a pointer where the attributes will be returned. The
- detach state, stack size, stack base, and guard size may be different
- from when the thread was created to reflect their actual values.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- PPROCESS_ENVIRONMENT Environment;
- int Error;
- struct rlimit Limit;
- int OldError;
- PPTHREAD Thread;
- Thread = (PPTHREAD)ThreadId;
- if (Thread->State == PthreadStateDetached) {
- Thread->Attribute.Flags |= PTHREAD_FLAG_DETACHED;
- }
- //
- // For the main thread, try to get the stack size.
- //
- if (Thread->Attribute.StackSize == 0) {
- OldError = errno;
- if (getrlimit(RLIMIT_STACK, &Limit) < 0) {
- Error = errno;
- errno = OldError;
- return Error;
- }
- Thread->Attribute.StackSize = Limit.rlim_cur;
- if (Thread->Attribute.StackBase == NULL) {
- Environment = OsGetCurrentEnvironment();
- Thread->Attribute.StackBase = Environment->StartData->StackBase;
- }
- }
- memcpy(Attribute, &(Thread->Attribute), sizeof(PTHREAD_ATTRIBUTE));
- return 0;
- }
- PTHREAD_API
- void
- __pthread_cleanup_push (
- __pthread_cleanup_t *CleanupItem,
- __pthread_cleanup_func_t CleanupRoutine,
- void *Argument
- )
- /*++
- Routine Description:
- This routine pushes a new element onto the cleanup stack for the current
- thread.
- Arguments:
- CleanupItem - Supplies a pointer to the cleanup item context. This routine
- uses this buffer, so it cannot be freed until the cleanup item is
- popped.
- CleanupRoutine - Supplies a pointer to the routine to call if the thread
- exits.
- Argument - Supplies a pointer to pass to the cleanup routine.
- Return Value:
- None.
- --*/
- {
- PPTHREAD Thread;
- Thread = (PPTHREAD)pthread_self();
- CleanupItem->__cleanup_routine = CleanupRoutine;
- CleanupItem->__cleanup_arg = Argument;
- CleanupItem->__cleanup_prev = Thread->CleanupStack;
- Thread->CleanupStack = CleanupItem;
- return;
- }
- PTHREAD_API
- void
- __pthread_cleanup_pop (
- __pthread_cleanup_t *CleanupItem,
- int Execute
- )
- /*++
- Routine Description:
- This routine potentially pops an element from the cleanup stack.
- Arguments:
- CleanupItem - Supplies a pointer to the cleanup item to pop.
- Execute - Supplies an integer that is non-zero if the cleanup routine
- should be run, or zero if it should just be popped.
- Return Value:
- None.
- --*/
- {
- PPTHREAD Thread;
- Thread = (PPTHREAD)pthread_self();
- Thread->CleanupStack = CleanupItem->__cleanup_prev;
- if (Execute != 0) {
- CleanupItem->__cleanup_routine(CleanupItem->__cleanup_arg);
- }
- return;
- }
- LIBC_API
- int
- __cxa_thread_atexit_impl (
- PTHREAD_ENTRY_ROUTINE DestructorRoutine,
- void *Argument,
- void *DynamicObjectHandle
- )
- /*++
- Routine Description:
- This routine registers a new thread-local destructor, that is called when
- the thread is destroyed.
- Arguments:
- DestructorRoutine - Supplies a pointer to the routine to call when the
- thread is destroyed.
- Argument - Supplies an argument to pass to the destructor routine.
- DynamicObjectHandle - Supplies a pointer to the dynamic object this
- destructor is associated with.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- PTHREAD_DESTRUCTOR Destructor;
- Destructor = malloc(sizeof(THREAD_DESTRUCTOR));
- if (Destructor == NULL) {
- return ENOMEM;
- }
- Destructor->DestructorRoutine = DestructorRoutine;
- Destructor->Argument = Argument;
- Destructor->SharedObjectHandle = DynamicObjectHandle;
- if (ClThreadDestructors.Next == NULL) {
- INITIALIZE_LIST_HEAD(&ClThreadDestructors);
- }
- INSERT_AFTER(&(Destructor->ListEntry), &ClThreadDestructors);
- return 0;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- VOID
- ClpThreadStart (
- PVOID Parameter
- )
- /*++
- Routine Description:
- This routine implements the initial routine for a POSIX thread.
- Arguments:
- Parameter - Supplies a pointer to the parameter, which in this case is a
- pointer to the PTHREAD structure for this thread.
- Return Value:
- None. Actually, this routine never returns.
- --*/
- {
- PVOID Result;
- PPTHREAD Thread;
- Thread = Parameter;
- //
- // Acquire the start mutex to synchronize with the thread that created this
- // thread.
- //
- ClCurrentThread = Thread;
- pthread_mutex_lock(&(Thread->StartMutex));
- OsSetSignalBehavior(SignalMaskBlocked,
- SignalMaskOperationOverwrite,
- &(Thread->SignalMask));
- pthread_testcancel();
- Result = Thread->ThreadRoutine(Thread->ThreadParameter);
- pthread_exit(Result);
- return;
- }
- VOID
- ClpInitializeThreading (
- VOID
- )
- /*++
- Routine Description:
- This routine is called to initialize threading support, mostly performing
- some initialization tasks on the main thread that were deferred for
- better performance on non-threaded applications. This code must be called
- on the main thread.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- struct sigaction Action;
- UINTN AllocationSize;
- PPTHREAD Thread;
- AllocationSize = sizeof(PTHREAD) +
- (PTHREAD_KEYS_MAX * sizeof(PTHREAD_KEY_DATA));
- Thread = OsHeapAllocate(AllocationSize, PTHREAD_ALLOCATION_TAG);
- if (Thread == NULL) {
- return;
- }
- memset(Thread, 0, AllocationSize);
- pthread_mutex_init(&(Thread->StartMutex), NULL);
- Thread->KeyData = (PPTHREAD_KEY_DATA)(Thread + 1);
- //
- // Set the thread ID pointer of the main thread in the kernel so that
- // other threads can join the main thread if desired.
- //
- OsSetThreadIdPointer(&(Thread->ThreadId));
- Thread->State = PthreadStateNotJoined;
- ClCurrentThread = Thread;
- //
- // Add the thread to the global list.
- //
- pthread_mutex_lock(&ClThreadListMutex);
- ASSERT(ClThreadList.Next == NULL);
- INITIALIZE_LIST_HEAD(&ClThreadList);
- INSERT_AFTER(&(Thread->ListEntry), &ClThreadList);
- pthread_mutex_unlock(&ClThreadListMutex);
- //
- // Also register the thread signal handler and the set ID signal handler.
- //
- sigemptyset(&(Action.sa_mask));
- Action.sa_flags = 0;
- Action.sa_handler = ClpThreadSignalHandler;
- ClpSetSignalAction(SIGNAL_PTHREAD, &Action, NULL);
- Action.sa_handler = ClpSetIdSignalHandler;
- ClpSetSignalAction(SIGNAL_SETID, &Action, NULL);
- //
- // Make sure the PLT entry for the exit thread routine is wired up.
- // Detached threads carefully tear themselves down, and cannot handle a
- // PLT lookup by the time they call exit thread.
- //
- // This does not actually exit the current thread, it simply returns.
- //
- OsExitThread(NULL, -1);
- return;
- }
- void
- ClpThreadSignalHandler (
- int Signal
- )
- /*++
- Routine Description:
- This routine implements the thread signal handler, which manages
- cancellation requests.
- Arguments:
- Signal - Supplies the signal number that occurred.
- Return Value:
- None.
- --*/
- {
- PPTHREAD Thread;
- Thread = (PPTHREAD)pthread_self();
- ASSERT(Thread->CancelRequested != FALSE);
- if (Thread->CancelType == PTHREAD_CANCEL_ASYNCHRONOUS) {
- pthread_testcancel();
- }
- return;
- }
- int
- ClpAllocateThread (
- const pthread_attr_t *Attribute,
- void *(*StartRoutine)(void *),
- void *Argument,
- PPTHREAD *Thread
- )
- /*++
- Routine Description:
- This routine allocates and initializes a new thread structure.
- Arguments:
- Attribute - Supplies a required pointer to the attributes of the thread.
- StartRoutine - Supplies a pointer to the routine to call on the new thread.
- Argument - Supplies the argument to pass to the start routine.
- Thread - Supplies a pointer where a pointer to the thread will be returned
- on success.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- PVOID Allocation;
- PPTHREAD_ATTRIBUTE AttributeInternal;
- UINTN GuardSize;
- KSTATUS KernelStatus;
- ULONG MapFlags;
- UINTN MapSize;
- PPTHREAD NewThread;
- UINTN PageSize;
- PVOID Stack;
- UINTN StackSize;
- int Status;
- Allocation = NULL;
- //
- // If the caller wants something non-standard for a stack, then allocate
- // the stack.
- //
- GuardSize = 0;
- NewThread = NULL;
- PageSize = sysconf(_SC_PAGE_SIZE);
- AttributeInternal = (PPTHREAD_ATTRIBUTE)Attribute;
- Stack = AttributeInternal->StackBase;
- StackSize = 0;
- MapSize = sizeof(PTHREAD) + (PTHREAD_KEYS_MAX * sizeof(PTHREAD_KEY_DATA));
- //
- // Also allocate a stack if none was supplied but a weird guard size was
- // requested.
- //
- if ((Stack == NULL) && (AttributeInternal->GuardSize != PageSize)) {
- StackSize = ALIGN_RANGE_UP(AttributeInternal->StackSize, 16);
- MapSize += StackSize;
- MapSize = ALIGN_RANGE_UP(MapSize, PageSize);
- GuardSize = ALIGN_RANGE_UP(AttributeInternal->GuardSize, PageSize);
- MapSize += GuardSize;
- }
- MapFlags = MAP_PRIVATE | MAP_ANONYMOUS;
- Allocation = mmap(Stack, MapSize, PROT_READ | PROT_WRITE, MapFlags, -1, 0);
- if (Allocation == MAP_FAILED) {
- Status = errno;
- goto AllocateThreadEnd;
- }
- if ((Stack == NULL) && (AttributeInternal->GuardSize != PageSize)) {
- if (GuardSize != 0) {
- if (mprotect(Stack, GuardSize, PROT_NONE) < 0) {
- Status = errno;
- goto AllocateThreadEnd;
- }
- }
- }
- NewThread = Allocation + GuardSize + StackSize;
- memcpy(&(NewThread->Attribute),
- AttributeInternal,
- sizeof(PTHREAD_ATTRIBUTE));
- NewThread->Attribute.StackBase = Stack;
- if (StackSize != 0) {
- NewThread->Attribute.StackSize = StackSize;
- }
- NewThread->ThreadRoutine = StartRoutine;
- NewThread->ThreadParameter = Argument;
- NewThread->ThreadAllocation = Allocation;
- NewThread->ThreadAllocationSize = MapSize;
- NewThread->KeyData = (PPTHREAD_KEY_DATA)(NewThread + 1);
- pthread_mutex_init(&(NewThread->StartMutex), NULL);
- KernelStatus = OsCreateThreadData(&(NewThread->OsData));
- if (!KSUCCESS(KernelStatus)) {
- Status = ClConvertKstatusToErrorNumber(KernelStatus);
- goto AllocateThreadEnd;
- }
- Status = 0;
- AllocateThreadEnd:
- if (Status != 0) {
- if (Allocation != NULL) {
- munmap(Allocation, MapSize);
- }
- NewThread = NULL;
- }
- *Thread = NewThread;
- return Status;
- }
- void
- ClpDestroyThread (
- PPTHREAD Thread
- )
- /*++
- Routine Description:
- This routine frees a thread structure. The thread better not be alive there.
- Arguments:
- Thread - Supplies a pointer to the thread structure to destroy.
- Return Value:
- None.
- --*/
- {
- assert(Thread->KeyData == NULL);
- pthread_mutex_destroy(&(Thread->StartMutex));
- if (Thread->OsData != NULL) {
- OsDestroyThreadData(Thread->OsData);
- Thread->OsData = NULL;
- }
- if (Thread->ThreadAllocationSize != 0) {
- munmap(Thread->ThreadAllocation, Thread->ThreadAllocationSize);
- }
- return;
- }
- VOID
- ClpCallThreadDestructors (
- VOID
- )
- /*++
- Routine Description:
- This routine calls all the thread destructor routines in the reverse order
- as they were registered.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PTHREAD_DESTRUCTOR Destructor;
- if (ClThreadDestructors.Next == NULL) {
- return;
- }
- CurrentEntry = ClThreadDestructors.Next;
- while (CurrentEntry != &ClThreadDestructors) {
- Destructor = LIST_VALUE(CurrentEntry, THREAD_DESTRUCTOR, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- Destructor->DestructorRoutine(Destructor->Argument);
- free(Destructor);
- }
- return;
- }
- PPTHREAD
- ClpGetThreadFromId (
- pthread_t ThreadId
- )
- /*++
- Routine Description:
- This routine looks up the given thread based on its thread ID.
- Arguments:
- ThreadId - Supplies the thread ID to look up.
- Return Value:
- Returns a pointer to the internal thread structure on success.
- NULL on failure.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PPTHREAD CurrentThread;
- PPTHREAD FoundThread;
- if (ClThreadList.Next == NULL) {
- pthread_self();
- }
- FoundThread = NULL;
- pthread_mutex_lock(&ClThreadListMutex);
- CurrentEntry = ClThreadList.Next;
- while (CurrentEntry != &ClThreadList) {
- CurrentThread = LIST_VALUE(CurrentEntry, PTHREAD, ListEntry);
- if (CurrentThread == (PPTHREAD)ThreadId) {
- FoundThread = CurrentThread;
- break;
- }
- CurrentEntry = CurrentEntry->Next;
- }
- pthread_mutex_unlock(&ClThreadListMutex);
- return FoundThread;
- }
|