| Index: third_party/nspr/mozilla/nsprpub/pr/src/bthreads/btthread.c
|
| diff --git a/third_party/nspr/mozilla/nsprpub/pr/src/bthreads/btthread.c b/third_party/nspr/mozilla/nsprpub/pr/src/bthreads/btthread.c
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..33bdfcc70e77b46812ba8d08509246e441b55037
|
| --- /dev/null
|
| +++ b/third_party/nspr/mozilla/nsprpub/pr/src/bthreads/btthread.c
|
| @@ -0,0 +1,694 @@
|
| +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
| +/* ***** BEGIN LICENSE BLOCK *****
|
| + * Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
| + *
|
| + * The contents of this file are subject to the Mozilla Public License Version
|
| + * 1.1 (the "License"); you may not use this file except in compliance with
|
| + * the License. You may obtain a copy of the License at
|
| + * http://www.mozilla.org/MPL/
|
| + *
|
| + * Software distributed under the License is distributed on an "AS IS" basis,
|
| + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
| + * for the specific language governing rights and limitations under the
|
| + * License.
|
| + *
|
| + * The Original Code is the Netscape Portable Runtime (NSPR).
|
| + *
|
| + * The Initial Developer of the Original Code is
|
| + * Netscape Communications Corporation.
|
| + * Portions created by the Initial Developer are Copyright (C) 1998-2000
|
| + * the Initial Developer. All Rights Reserved.
|
| + *
|
| + * Contributor(s):
|
| + *
|
| + * Alternatively, the contents of this file may be used under the terms of
|
| + * either the GNU General Public License Version 2 or later (the "GPL"), or
|
| + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
| + * in which case the provisions of the GPL or the LGPL are applicable instead
|
| + * of those above. If you wish to allow use of your version of this file only
|
| + * under the terms of either the GPL or the LGPL, and not to allow others to
|
| + * use your version of this file under the terms of the MPL, indicate your
|
| + * decision by deleting the provisions above and replace them with the notice
|
| + * and other provisions required by the GPL or the LGPL. If you do not delete
|
| + * the provisions above, a recipient may use your version of this file under
|
| + * the terms of any one of the MPL, the GPL or the LGPL.
|
| + *
|
| + * ***** END LICENSE BLOCK ***** */
|
| +
|
| +#include <kernel/OS.h>
|
| +#include <support/TLS.h>
|
| +
|
| +#include "prlog.h"
|
| +#include "primpl.h"
|
| +#include "prcvar.h"
|
| +#include "prpdce.h"
|
| +
|
| +#include <stdlib.h>
|
| +#include <string.h>
|
| +#include <signal.h>
|
| +
|
| +/* values for PRThread.state */
|
| +#define BT_THREAD_PRIMORD 0x01 /* this is the primordial thread */
|
| +#define BT_THREAD_SYSTEM 0x02 /* this is a system thread */
|
| +#define BT_THREAD_JOINABLE 0x04 /* this is a joinable thread */
|
| +
|
| +struct _BT_Bookeeping
|
| +{
|
| + PRLock *ml; /* a lock to protect ourselves */
|
| + sem_id cleanUpSem; /* the primoridal thread will block on this
|
| + sem while waiting for the user threads */
|
| + PRInt32 threadCount; /* user thred count */
|
| +
|
| +} bt_book = { NULL, B_ERROR, 0 };
|
| +
|
| +
|
| +#define BT_TPD_LIMIT 128 /* number of TPD slots we'll provide (arbitrary) */
|
| +
|
| +/* these will be used to map an index returned by PR_NewThreadPrivateIndex()
|
| + to the corresponding beos native TLS slot number, and to the destructor
|
| + for that slot - note that, because it is allocated globally, this data
|
| + will be automatically zeroed for us when the program begins */
|
| +static int32 tpd_beosTLSSlots[BT_TPD_LIMIT];
|
| +static PRThreadPrivateDTOR tpd_dtors[BT_TPD_LIMIT];
|
| +
|
| +static vint32 tpd_slotsUsed=0; /* number of currently-allocated TPD slots */
|
| +static int32 tls_prThreadSlot; /* TLS slot in which PRThread will be stored */
|
| +
|
| +/* this mutex will be used to synchronize access to every
|
| + PRThread.md.joinSem and PRThread.md.is_joining (we could
|
| + actually allocate one per thread, but that seems a bit excessive,
|
| + especially considering that there will probably be little
|
| + contention, PR_JoinThread() is allowed to block anyway, and the code
|
| + protected by the mutex is short/fast) */
|
| +static PRLock *joinSemLock;
|
| +
|
| +static PRUint32 _bt_MapNSPRToNativePriority( PRThreadPriority priority );
|
| +static PRThreadPriority _bt_MapNativeToNSPRPriority( PRUint32 priority );
|
| +static void _bt_CleanupThread(void *arg);
|
| +static PRThread *_bt_AttachThread();
|
| +
|
| +void
|
| +_PR_InitThreads (PRThreadType type, PRThreadPriority priority,
|
| + PRUintn maxPTDs)
|
| +{
|
| + PRThread *primordialThread;
|
| + PRUint32 beThreadPriority;
|
| +
|
| + /* allocate joinSem mutex */
|
| + joinSemLock = PR_NewLock();
|
| + if (joinSemLock == NULL)
|
| + {
|
| + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
|
| + return;
|
| + }
|
| +
|
| + /*
|
| + ** Create and initialize NSPR structure for our primordial thread.
|
| + */
|
| +
|
| + primordialThread = PR_NEWZAP(PRThread);
|
| + if( NULL == primordialThread )
|
| + {
|
| + PR_SetError( PR_OUT_OF_MEMORY_ERROR, 0 );
|
| + return;
|
| + }
|
| +
|
| + primordialThread->md.joinSem = B_ERROR;
|
| +
|
| + /*
|
| + ** Set the priority to the desired level.
|
| + */
|
| +
|
| + beThreadPriority = _bt_MapNSPRToNativePriority( priority );
|
| +
|
| + set_thread_priority( find_thread( NULL ), beThreadPriority );
|
| +
|
| + primordialThread->priority = priority;
|
| +
|
| +
|
| + /* set the thread's state - note that the thread is not joinable */
|
| + primordialThread->state |= BT_THREAD_PRIMORD;
|
| + if (type == PR_SYSTEM_THREAD)
|
| + primordialThread->state |= BT_THREAD_SYSTEM;
|
| +
|
| + /*
|
| + ** Allocate a TLS slot for the PRThread structure (just using
|
| + ** native TLS, as opposed to NSPR TPD, will make PR_GetCurrentThread()
|
| + ** somewhat faster, and will leave one more TPD slot for our client)
|
| + */
|
| +
|
| + tls_prThreadSlot = tls_allocate();
|
| +
|
| + /*
|
| + ** Stuff our new PRThread structure into our thread specific
|
| + ** slot.
|
| + */
|
| +
|
| + tls_set(tls_prThreadSlot, primordialThread);
|
| +
|
| + /* allocate lock for bt_book */
|
| + bt_book.ml = PR_NewLock();
|
| + if( NULL == bt_book.ml )
|
| + {
|
| + PR_SetError( PR_OUT_OF_MEMORY_ERROR, 0 );
|
| + return;
|
| + }
|
| +}
|
| +
|
| +PRUint32
|
| +_bt_MapNSPRToNativePriority( PRThreadPriority priority )
|
| + {
|
| + switch( priority )
|
| + {
|
| + case PR_PRIORITY_LOW: return( B_LOW_PRIORITY );
|
| + case PR_PRIORITY_NORMAL: return( B_NORMAL_PRIORITY );
|
| + case PR_PRIORITY_HIGH: return( B_DISPLAY_PRIORITY );
|
| + case PR_PRIORITY_URGENT: return( B_URGENT_DISPLAY_PRIORITY );
|
| + default: return( B_NORMAL_PRIORITY );
|
| + }
|
| +}
|
| +
|
| +PRThreadPriority
|
| +_bt_MapNativeToNSPRPriority(PRUint32 priority)
|
| + {
|
| + if (priority < B_NORMAL_PRIORITY)
|
| + return PR_PRIORITY_LOW;
|
| + if (priority < B_DISPLAY_PRIORITY)
|
| + return PR_PRIORITY_NORMAL;
|
| + if (priority < B_URGENT_DISPLAY_PRIORITY)
|
| + return PR_PRIORITY_HIGH;
|
| + return PR_PRIORITY_URGENT;
|
| +}
|
| +
|
| +PRUint32
|
| +_bt_mapNativeToNSPRPriority( int32 priority )
|
| +{
|
| + switch( priority )
|
| + {
|
| + case PR_PRIORITY_LOW: return( B_LOW_PRIORITY );
|
| + case PR_PRIORITY_NORMAL: return( B_NORMAL_PRIORITY );
|
| + case PR_PRIORITY_HIGH: return( B_DISPLAY_PRIORITY );
|
| + case PR_PRIORITY_URGENT: return( B_URGENT_DISPLAY_PRIORITY );
|
| + default: return( B_NORMAL_PRIORITY );
|
| + }
|
| +}
|
| +
|
| +/* This method is called by all NSPR threads as they exit */
|
| +void _bt_CleanupThread(void *arg)
|
| +{
|
| + PRThread *me = PR_GetCurrentThread();
|
| + int32 i;
|
| +
|
| + /* first, clean up all thread-private data */
|
| + for (i = 0; i < tpd_slotsUsed; i++)
|
| + {
|
| + void *oldValue = tls_get(tpd_beosTLSSlots[i]);
|
| + if ( oldValue != NULL && tpd_dtors[i] != NULL )
|
| + (*tpd_dtors[i])(oldValue);
|
| + }
|
| +
|
| + /* if this thread is joinable, wait for someone to join it */
|
| + if (me->state & BT_THREAD_JOINABLE)
|
| + {
|
| + /* protect access to our joinSem */
|
| + PR_Lock(joinSemLock);
|
| +
|
| + if (me->md.is_joining)
|
| + {
|
| + /* someone is already waiting to join us (they've
|
| + allocated a joinSem for us) - let them know we're
|
| + ready */
|
| + delete_sem(me->md.joinSem);
|
| +
|
| + PR_Unlock(joinSemLock);
|
| +
|
| + }
|
| + else
|
| + {
|
| + /* noone is currently waiting for our demise - it
|
| + is our responsibility to allocate the joinSem
|
| + and block on it */
|
| + me->md.joinSem = create_sem(0, "join sem");
|
| +
|
| + /* we're done accessing our joinSem */
|
| + PR_Unlock(joinSemLock);
|
| +
|
| + /* wait for someone to join us */
|
| + while (acquire_sem(me->md.joinSem) == B_INTERRUPTED);
|
| + }
|
| + }
|
| +
|
| + /* if this is a user thread, we must update our books */
|
| + if ((me->state & BT_THREAD_SYSTEM) == 0)
|
| + {
|
| + /* synchronize access to bt_book */
|
| + PR_Lock( bt_book.ml );
|
| +
|
| + /* decrement the number of currently-alive user threads */
|
| + bt_book.threadCount--;
|
| +
|
| + if (bt_book.threadCount == 0 && bt_book.cleanUpSem != B_ERROR) {
|
| + /* we are the last user thread, and the primordial thread is
|
| + blocked in PR_Cleanup() waiting for us to finish - notify
|
| + it */
|
| + delete_sem(bt_book.cleanUpSem);
|
| + }
|
| +
|
| + PR_Unlock( bt_book.ml );
|
| + }
|
| +
|
| + /* finally, delete this thread's PRThread */
|
| + PR_DELETE(me);
|
| +}
|
| +
|
| +/**
|
| + * This is a wrapper that all threads invoke that allows us to set some
|
| + * things up prior to a thread's invocation and clean up after a thread has
|
| + * exited.
|
| + */
|
| +static void*
|
| +_bt_root (void* arg)
|
| + {
|
| + PRThread *thred = (PRThread*)arg;
|
| + PRIntn rv;
|
| + void *privData;
|
| + status_t result;
|
| + int i;
|
| +
|
| + /* save our PRThread object into our TLS */
|
| + tls_set(tls_prThreadSlot, thred);
|
| +
|
| + thred->startFunc(thred->arg); /* run the dang thing */
|
| +
|
| + /* clean up */
|
| + _bt_CleanupThread(NULL);
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +PR_IMPLEMENT(PRThread*)
|
| + PR_CreateThread (PRThreadType type, void (*start)(void* arg), void* arg,
|
| + PRThreadPriority priority, PRThreadScope scope,
|
| + PRThreadState state, PRUint32 stackSize)
|
| +{
|
| + PRUint32 bePriority;
|
| +
|
| + PRThread* thred;
|
| +
|
| + if (!_pr_initialized) _PR_ImplicitInitialization();
|
| +
|
| + thred = PR_NEWZAP(PRThread);
|
| + if (thred == NULL)
|
| + {
|
| + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
|
| + return NULL;
|
| + }
|
| +
|
| + thred->md.joinSem = B_ERROR;
|
| +
|
| + thred->arg = arg;
|
| + thred->startFunc = start;
|
| + thred->priority = priority;
|
| +
|
| + if( state == PR_JOINABLE_THREAD )
|
| + {
|
| + thred->state |= BT_THREAD_JOINABLE;
|
| + }
|
| +
|
| + /* keep some books */
|
| +
|
| + PR_Lock( bt_book.ml );
|
| +
|
| + if (type == PR_USER_THREAD)
|
| + {
|
| + bt_book.threadCount++;
|
| + }
|
| +
|
| + PR_Unlock( bt_book.ml );
|
| +
|
| + bePriority = _bt_MapNSPRToNativePriority( priority );
|
| +
|
| + thred->md.tid = spawn_thread((thread_func)_bt_root, "moz-thread",
|
| + bePriority, thred);
|
| + if (thred->md.tid < B_OK) {
|
| + PR_SetError(PR_UNKNOWN_ERROR, thred->md.tid);
|
| + PR_DELETE(thred);
|
| + return NULL;
|
| + }
|
| +
|
| + if (resume_thread(thred->md.tid) < B_OK) {
|
| + PR_SetError(PR_UNKNOWN_ERROR, 0);
|
| + PR_DELETE(thred);
|
| + return NULL;
|
| + }
|
| +
|
| + return thred;
|
| + }
|
| +
|
| +PR_IMPLEMENT(PRThread*)
|
| + PR_AttachThread(PRThreadType type, PRThreadPriority priority,
|
| + PRThreadStack *stack)
|
| +{
|
| + /* PR_GetCurrentThread() will attach a thread if necessary */
|
| + return PR_GetCurrentThread();
|
| +}
|
| +
|
| +PR_IMPLEMENT(void)
|
| + PR_DetachThread()
|
| +{
|
| + /* we don't support detaching */
|
| +}
|
| +
|
| +PR_IMPLEMENT(PRStatus)
|
| + PR_JoinThread (PRThread* thred)
|
| +{
|
| + status_t eval, status;
|
| +
|
| + PR_ASSERT(thred != NULL);
|
| +
|
| + if ((thred->state & BT_THREAD_JOINABLE) == 0)
|
| + {
|
| + PR_SetError( PR_INVALID_ARGUMENT_ERROR, 0 );
|
| + return( PR_FAILURE );
|
| + }
|
| +
|
| + /* synchronize access to the thread's joinSem */
|
| + PR_Lock(joinSemLock);
|
| +
|
| + if (thred->md.is_joining)
|
| + {
|
| + /* another thread is already waiting to join the specified
|
| + thread - we must fail */
|
| + PR_Unlock(joinSemLock);
|
| + return PR_FAILURE;
|
| + }
|
| +
|
| + /* let others know we are waiting to join */
|
| + thred->md.is_joining = PR_TRUE;
|
| +
|
| + if (thred->md.joinSem == B_ERROR)
|
| + {
|
| + /* the thread hasn't finished yet - it is our responsibility to
|
| + allocate a joinSem and wait on it */
|
| + thred->md.joinSem = create_sem(0, "join sem");
|
| +
|
| + /* we're done changing the joinSem now */
|
| + PR_Unlock(joinSemLock);
|
| +
|
| + /* wait for the thread to finish */
|
| + while (acquire_sem(thred->md.joinSem) == B_INTERRUPTED);
|
| +
|
| + }
|
| + else
|
| + {
|
| + /* the thread has already finished, and has allocated the
|
| + joinSem itself - let it know it can finally die */
|
| + delete_sem(thred->md.joinSem);
|
| +
|
| + PR_Unlock(joinSemLock);
|
| + }
|
| +
|
| + /* make sure the thread is dead */
|
| + wait_for_thread(thred->md.tid, &eval);
|
| +
|
| + return PR_SUCCESS;
|
| +}
|
| +
|
| +PR_IMPLEMENT(PRThread*)
|
| + PR_GetCurrentThread ()
|
| +{
|
| + PRThread* thred;
|
| +
|
| + if (!_pr_initialized) _PR_ImplicitInitialization();
|
| +
|
| + thred = (PRThread *)tls_get( tls_prThreadSlot);
|
| + if (thred == NULL)
|
| + {
|
| + /* this thread doesn't have a PRThread structure (it must be
|
| + a native thread not created by the NSPR) - assimilate it */
|
| + thred = _bt_AttachThread();
|
| + }
|
| + PR_ASSERT(NULL != thred);
|
| +
|
| + return thred;
|
| +}
|
| +
|
| +PR_IMPLEMENT(PRThreadScope)
|
| + PR_GetThreadScope (const PRThread* thred)
|
| +{
|
| + PR_ASSERT(thred != NULL);
|
| + return PR_GLOBAL_THREAD;
|
| +}
|
| +
|
| +PR_IMPLEMENT(PRThreadType)
|
| + PR_GetThreadType (const PRThread* thred)
|
| +{
|
| + PR_ASSERT(thred != NULL);
|
| + return (thred->state & BT_THREAD_SYSTEM) ?
|
| + PR_SYSTEM_THREAD : PR_USER_THREAD;
|
| +}
|
| +
|
| +PR_IMPLEMENT(PRThreadState)
|
| + PR_GetThreadState (const PRThread* thred)
|
| +{
|
| + PR_ASSERT(thred != NULL);
|
| + return (thred->state & BT_THREAD_JOINABLE)?
|
| + PR_JOINABLE_THREAD: PR_UNJOINABLE_THREAD;
|
| +}
|
| +
|
| +PR_IMPLEMENT(PRThreadPriority)
|
| + PR_GetThreadPriority (const PRThread* thred)
|
| +{
|
| + PR_ASSERT(thred != NULL);
|
| + return thred->priority;
|
| +} /* PR_GetThreadPriority */
|
| +
|
| +PR_IMPLEMENT(void) PR_SetThreadPriority(PRThread *thred,
|
| + PRThreadPriority newPri)
|
| +{
|
| + PRUint32 bePriority;
|
| +
|
| + PR_ASSERT( thred != NULL );
|
| +
|
| + thred->priority = newPri;
|
| + bePriority = _bt_MapNSPRToNativePriority( newPri );
|
| + set_thread_priority( thred->md.tid, bePriority );
|
| +}
|
| +
|
| +PR_IMPLEMENT(PRStatus)
|
| + PR_NewThreadPrivateIndex (PRUintn* newIndex,
|
| + PRThreadPrivateDTOR destructor)
|
| +{
|
| + int32 index;
|
| +
|
| + if (!_pr_initialized) _PR_ImplicitInitialization();
|
| +
|
| + /* reserve the next available tpd slot */
|
| + index = atomic_add( &tpd_slotsUsed, 1 );
|
| + if (index >= BT_TPD_LIMIT)
|
| + {
|
| + /* no slots left - decrement value, then fail */
|
| + atomic_add( &tpd_slotsUsed, -1 );
|
| + PR_SetError( PR_TPD_RANGE_ERROR, 0 );
|
| + return( PR_FAILURE );
|
| + }
|
| +
|
| + /* allocate a beos-native TLS slot for this index (the new slot
|
| + automatically contains NULL) */
|
| + tpd_beosTLSSlots[index] = tls_allocate();
|
| +
|
| + /* remember the destructor */
|
| + tpd_dtors[index] = destructor;
|
| +
|
| + *newIndex = (PRUintn)index;
|
| +
|
| + return( PR_SUCCESS );
|
| +}
|
| +
|
| +PR_IMPLEMENT(PRStatus)
|
| + PR_SetThreadPrivate (PRUintn index, void* priv)
|
| +{
|
| + void *oldValue;
|
| +
|
| + /*
|
| + ** Sanity checking
|
| + */
|
| +
|
| + if(index < 0 || index >= tpd_slotsUsed || index >= BT_TPD_LIMIT)
|
| + {
|
| + PR_SetError( PR_TPD_RANGE_ERROR, 0 );
|
| + return( PR_FAILURE );
|
| + }
|
| +
|
| + /* if the old value isn't NULL, and the dtor for this slot isn't
|
| + NULL, we must destroy the data */
|
| + oldValue = tls_get(tpd_beosTLSSlots[index]);
|
| + if (oldValue != NULL && tpd_dtors[index] != NULL)
|
| + (*tpd_dtors[index])(oldValue);
|
| +
|
| + /* save new value */
|
| + tls_set(tpd_beosTLSSlots[index], priv);
|
| +
|
| + return( PR_SUCCESS );
|
| + }
|
| +
|
| +PR_IMPLEMENT(void*)
|
| + PR_GetThreadPrivate (PRUintn index)
|
| +{
|
| + /* make sure the index is valid */
|
| + if (index < 0 || index >= tpd_slotsUsed || index >= BT_TPD_LIMIT)
|
| + {
|
| + PR_SetError( PR_TPD_RANGE_ERROR, 0 );
|
| + return NULL;
|
| + }
|
| +
|
| + /* return the value */
|
| + return tls_get( tpd_beosTLSSlots[index] );
|
| + }
|
| +
|
| +
|
| +PR_IMPLEMENT(PRStatus)
|
| + PR_Interrupt (PRThread* thred)
|
| +{
|
| + PRIntn rv;
|
| +
|
| + PR_ASSERT(thred != NULL);
|
| +
|
| + /*
|
| + ** there seems to be a bug in beos R5 in which calling
|
| + ** resume_thread() on a blocked thread returns B_OK instead
|
| + ** of B_BAD_THREAD_STATE (beos bug #20000422-19095). as such,
|
| + ** to interrupt a thread, we will simply suspend then resume it
|
| + ** (no longer call resume_thread(), check for B_BAD_THREAD_STATE,
|
| + ** the suspend/resume to wake up a blocked thread). this wakes
|
| + ** up blocked threads properly, and doesn't hurt unblocked threads
|
| + ** (they simply get stopped then re-started immediately)
|
| + */
|
| +
|
| + rv = suspend_thread( thred->md.tid );
|
| + if( rv != B_NO_ERROR )
|
| + {
|
| + /* this doesn't appear to be a valid thread_id */
|
| + PR_SetError( PR_UNKNOWN_ERROR, rv );
|
| + return PR_FAILURE;
|
| + }
|
| +
|
| + rv = resume_thread( thred->md.tid );
|
| + if( rv != B_NO_ERROR )
|
| + {
|
| + PR_SetError( PR_UNKNOWN_ERROR, rv );
|
| + return PR_FAILURE;
|
| + }
|
| +
|
| + return PR_SUCCESS;
|
| +}
|
| +
|
| +PR_IMPLEMENT(void)
|
| + PR_ClearInterrupt ()
|
| +{
|
| +}
|
| +
|
| +PR_IMPLEMENT(PRStatus)
|
| + PR_Yield ()
|
| +{
|
| + /* we just sleep for long enough to cause a reschedule (100
|
| + microseconds) */
|
| + snooze(100);
|
| +}
|
| +
|
| +#define BT_MILLION 1000000UL
|
| +
|
| +PR_IMPLEMENT(PRStatus)
|
| + PR_Sleep (PRIntervalTime ticks)
|
| +{
|
| + bigtime_t tps;
|
| + status_t status;
|
| +
|
| + if (!_pr_initialized) _PR_ImplicitInitialization();
|
| +
|
| + tps = PR_IntervalToMicroseconds( ticks );
|
| +
|
| + status = snooze(tps);
|
| + if (status == B_NO_ERROR) return PR_SUCCESS;
|
| +
|
| + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, status);
|
| + return PR_FAILURE;
|
| +}
|
| +
|
| +PR_IMPLEMENT(PRStatus)
|
| + PR_Cleanup ()
|
| +{
|
| + PRThread *me = PR_GetCurrentThread();
|
| +
|
| + PR_ASSERT(me->state & BT_THREAD_PRIMORD);
|
| + if ((me->state & BT_THREAD_PRIMORD) == 0) {
|
| + return PR_FAILURE;
|
| + }
|
| +
|
| + PR_Lock( bt_book.ml );
|
| +
|
| + if (bt_book.threadCount != 0)
|
| + {
|
| + /* we'll have to wait for some threads to finish - create a
|
| + sem to block on */
|
| + bt_book.cleanUpSem = create_sem(0, "cleanup sem");
|
| + }
|
| +
|
| + PR_Unlock( bt_book.ml );
|
| +
|
| + /* note that, if all the user threads were already dead, we
|
| + wouldn't have created a sem above, so this acquire_sem()
|
| + will fail immediately */
|
| + while (acquire_sem(bt_book.cleanUpSem) == B_INTERRUPTED);
|
| +
|
| + return PR_SUCCESS;
|
| +}
|
| +
|
| +PR_IMPLEMENT(void)
|
| + PR_ProcessExit (PRIntn status)
|
| +{
|
| + exit(status);
|
| +}
|
| +
|
| +PRThread *_bt_AttachThread()
|
| +{
|
| + PRThread *thread;
|
| + thread_info tInfo;
|
| +
|
| + /* make sure this thread doesn't already have a PRThread structure */
|
| + PR_ASSERT(tls_get(tls_prThreadSlot) == NULL);
|
| +
|
| + /* allocate a PRThread structure for this thread */
|
| + thread = PR_NEWZAP(PRThread);
|
| + if (thread == NULL)
|
| + {
|
| + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
|
| + return NULL;
|
| + }
|
| +
|
| + /* get the native thread's current state */
|
| + get_thread_info(find_thread(NULL), &tInfo);
|
| +
|
| + /* initialize new PRThread */
|
| + thread->md.tid = tInfo.thread;
|
| + thread->md.joinSem = B_ERROR;
|
| + thread->priority = _bt_MapNativeToNSPRPriority(tInfo.priority);
|
| +
|
| + /* attached threads are always non-joinable user threads */
|
| + thread->state = 0;
|
| +
|
| + /* increment user thread count */
|
| + PR_Lock(bt_book.ml);
|
| + bt_book.threadCount++;
|
| + PR_Unlock(bt_book.ml);
|
| +
|
| + /* store this thread's PRThread */
|
| + tls_set(tls_prThreadSlot, thread);
|
| +
|
| + /* the thread must call _bt_CleanupThread() before it dies, in order
|
| + to clean up its PRThread, synchronize with the primordial thread,
|
| + etc. */
|
| + on_exit_thread(_bt_CleanupThread, NULL);
|
| +
|
| + return thread;
|
| +}
|
|
|