nsprpub/pr/src/bthreads/btthread.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/nsprpub/pr/src/bthreads/btthread.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,662 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include <kernel/OS.h>
    1.10 +#include <support/TLS.h>
    1.11 +
    1.12 +#include "prlog.h"
    1.13 +#include "primpl.h"
    1.14 +#include "prcvar.h"
    1.15 +#include "prpdce.h"
    1.16 +
    1.17 +#include <stdlib.h>
    1.18 +#include <string.h>
    1.19 +#include <signal.h>
    1.20 +
    1.21 +/* values for PRThread.state */
    1.22 +#define BT_THREAD_PRIMORD   0x01    /* this is the primordial thread */
    1.23 +#define BT_THREAD_SYSTEM    0x02    /* this is a system thread */
    1.24 +#define BT_THREAD_JOINABLE  0x04	/* this is a joinable thread */
    1.25 +
    1.26 +struct _BT_Bookeeping
    1.27 +{
    1.28 +    PRLock *ml;                 /* a lock to protect ourselves */
    1.29 +	sem_id cleanUpSem;		/* the primoridal thread will block on this
    1.30 +							   sem while waiting for the user threads */
    1.31 +    PRInt32 threadCount;	/* user thred count */
    1.32 +
    1.33 +} bt_book = { NULL, B_ERROR, 0 };
    1.34 +
    1.35 +
    1.36 +#define BT_TPD_LIMIT 128	/* number of TPD slots we'll provide (arbitrary) */
    1.37 +
    1.38 +/* these will be used to map an index returned by PR_NewThreadPrivateIndex()
    1.39 +   to the corresponding beos native TLS slot number, and to the destructor
    1.40 +   for that slot - note that, because it is allocated globally, this data
    1.41 +   will be automatically zeroed for us when the program begins */
    1.42 +static int32 tpd_beosTLSSlots[BT_TPD_LIMIT];
    1.43 +static PRThreadPrivateDTOR tpd_dtors[BT_TPD_LIMIT];
    1.44 +
    1.45 +static vint32 tpd_slotsUsed=0;	/* number of currently-allocated TPD slots */
    1.46 +static int32 tls_prThreadSlot;	/* TLS slot in which PRThread will be stored */
    1.47 +
    1.48 +/* this mutex will be used to synchronize access to every
    1.49 +   PRThread.md.joinSem and PRThread.md.is_joining (we could
    1.50 +   actually allocate one per thread, but that seems a bit excessive,
    1.51 +   especially considering that there will probably be little
    1.52 +   contention, PR_JoinThread() is allowed to block anyway, and the code
    1.53 +   protected by the mutex is short/fast) */
    1.54 +static PRLock *joinSemLock;
    1.55 +
    1.56 +static PRUint32 _bt_MapNSPRToNativePriority( PRThreadPriority priority );
    1.57 +static PRThreadPriority _bt_MapNativeToNSPRPriority( PRUint32 priority );
    1.58 +static void _bt_CleanupThread(void *arg);
    1.59 +static PRThread *_bt_AttachThread();
    1.60 +
    1.61 +void
    1.62 +_PR_InitThreads (PRThreadType type, PRThreadPriority priority,
    1.63 +                 PRUintn maxPTDs)
    1.64 +{
    1.65 +    PRThread *primordialThread;
    1.66 +    PRUint32  beThreadPriority;
    1.67 +
    1.68 +	/* allocate joinSem mutex */
    1.69 +	joinSemLock = PR_NewLock();
    1.70 +	if (joinSemLock == NULL)
    1.71 +	{
    1.72 +		PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
    1.73 +		return;
    1.74 +    }
    1.75 +
    1.76 +    /*
    1.77 +    ** Create and initialize NSPR structure for our primordial thread.
    1.78 +    */
    1.79 +    
    1.80 +    primordialThread = PR_NEWZAP(PRThread);
    1.81 +    if( NULL == primordialThread )
    1.82 +    {
    1.83 +        PR_SetError( PR_OUT_OF_MEMORY_ERROR, 0 );
    1.84 +        return;
    1.85 +    }
    1.86 +
    1.87 +	primordialThread->md.joinSem = B_ERROR;
    1.88 +
    1.89 +    /*
    1.90 +    ** Set the priority to the desired level.
    1.91 +    */
    1.92 +
    1.93 +    beThreadPriority = _bt_MapNSPRToNativePriority( priority );
    1.94 +    
    1.95 +    set_thread_priority( find_thread( NULL ), beThreadPriority );
    1.96 +    
    1.97 +    primordialThread->priority = priority;
    1.98 +
    1.99 +
   1.100 +	/* set the thread's state - note that the thread is not joinable */
   1.101 +    primordialThread->state |= BT_THREAD_PRIMORD;
   1.102 +	if (type == PR_SYSTEM_THREAD)
   1.103 +		primordialThread->state |= BT_THREAD_SYSTEM;
   1.104 +
   1.105 +    /*
   1.106 +    ** Allocate a TLS slot for the PRThread structure (just using
   1.107 +    ** native TLS, as opposed to NSPR TPD, will make PR_GetCurrentThread()
   1.108 +    ** somewhat faster, and will leave one more TPD slot for our client)
   1.109 +    */
   1.110 +	
   1.111 +	tls_prThreadSlot = tls_allocate();
   1.112 +
   1.113 +    /*
   1.114 +    ** Stuff our new PRThread structure into our thread specific
   1.115 +    ** slot.
   1.116 +    */
   1.117 +
   1.118 +	tls_set(tls_prThreadSlot, primordialThread);
   1.119 +    
   1.120 +	/* allocate lock for bt_book */
   1.121 +    bt_book.ml = PR_NewLock();
   1.122 +    if( NULL == bt_book.ml )
   1.123 +    {
   1.124 +    	PR_SetError( PR_OUT_OF_MEMORY_ERROR, 0 );
   1.125 +	return;
   1.126 +    }
   1.127 +}
   1.128 +
   1.129 +PRUint32
   1.130 +_bt_MapNSPRToNativePriority( PRThreadPriority priority )
   1.131 +    {
   1.132 +    switch( priority )
   1.133 +    {
   1.134 +    	case PR_PRIORITY_LOW:	 return( B_LOW_PRIORITY );
   1.135 +	case PR_PRIORITY_NORMAL: return( B_NORMAL_PRIORITY );
   1.136 +	case PR_PRIORITY_HIGH:	 return( B_DISPLAY_PRIORITY );
   1.137 +	case PR_PRIORITY_URGENT: return( B_URGENT_DISPLAY_PRIORITY );
   1.138 +	default:		 return( B_NORMAL_PRIORITY );
   1.139 +    }
   1.140 +}
   1.141 +
   1.142 +PRThreadPriority
   1.143 +_bt_MapNativeToNSPRPriority(PRUint32 priority)
   1.144 +    {
   1.145 +	if (priority < B_NORMAL_PRIORITY)
   1.146 +		return PR_PRIORITY_LOW;
   1.147 +	if (priority < B_DISPLAY_PRIORITY)
   1.148 +		return PR_PRIORITY_NORMAL;
   1.149 +	if (priority < B_URGENT_DISPLAY_PRIORITY)
   1.150 +		return PR_PRIORITY_HIGH;
   1.151 +	return PR_PRIORITY_URGENT;
   1.152 +}
   1.153 +
   1.154 +PRUint32
   1.155 +_bt_mapNativeToNSPRPriority( int32 priority )
   1.156 +{
   1.157 +    switch( priority )
   1.158 +    {
   1.159 +    	case PR_PRIORITY_LOW:	 return( B_LOW_PRIORITY );
   1.160 +	case PR_PRIORITY_NORMAL: return( B_NORMAL_PRIORITY );
   1.161 +	case PR_PRIORITY_HIGH:	 return( B_DISPLAY_PRIORITY );
   1.162 +	case PR_PRIORITY_URGENT: return( B_URGENT_DISPLAY_PRIORITY );
   1.163 +	default:		 return( B_NORMAL_PRIORITY );
   1.164 +    }
   1.165 +}
   1.166 +
   1.167 +/* This method is called by all NSPR threads as they exit */
   1.168 +void _bt_CleanupThread(void *arg)
   1.169 +{
   1.170 +	PRThread *me = PR_GetCurrentThread();
   1.171 +	int32 i;
   1.172 +
   1.173 +	/* first, clean up all thread-private data */
   1.174 +	for (i = 0; i < tpd_slotsUsed; i++)
   1.175 +	{
   1.176 +		void *oldValue = tls_get(tpd_beosTLSSlots[i]);
   1.177 +		if ( oldValue != NULL && tpd_dtors[i] != NULL )
   1.178 +			(*tpd_dtors[i])(oldValue);
   1.179 +	}
   1.180 +
   1.181 +	/* if this thread is joinable, wait for someone to join it */
   1.182 +	if (me->state & BT_THREAD_JOINABLE)
   1.183 +	{
   1.184 +		/* protect access to our joinSem */
   1.185 +		PR_Lock(joinSemLock);
   1.186 +
   1.187 +		if (me->md.is_joining)
   1.188 +		{
   1.189 +			/* someone is already waiting to join us (they've
   1.190 +			   allocated a joinSem for us) - let them know we're
   1.191 +			   ready */
   1.192 +			delete_sem(me->md.joinSem);
   1.193 +
   1.194 +			PR_Unlock(joinSemLock);
   1.195 +
   1.196 +		}
   1.197 +		else
   1.198 +    {
   1.199 +			/* noone is currently waiting for our demise - it
   1.200 +			   is our responsibility to allocate the joinSem
   1.201 +			   and block on it */
   1.202 +			me->md.joinSem = create_sem(0, "join sem");
   1.203 +
   1.204 +			/* we're done accessing our joinSem */
   1.205 +			PR_Unlock(joinSemLock);
   1.206 +
   1.207 +			/* wait for someone to join us */
   1.208 +			while (acquire_sem(me->md.joinSem) == B_INTERRUPTED);
   1.209 +	    }
   1.210 +	}
   1.211 +
   1.212 +	/* if this is a user thread, we must update our books */
   1.213 +	if ((me->state & BT_THREAD_SYSTEM) == 0)
   1.214 +	{
   1.215 +		/* synchronize access to bt_book */
   1.216 +    PR_Lock( bt_book.ml );
   1.217 +
   1.218 +		/* decrement the number of currently-alive user threads */
   1.219 +	bt_book.threadCount--;
   1.220 +
   1.221 +		if (bt_book.threadCount == 0 && bt_book.cleanUpSem != B_ERROR) {
   1.222 +			/* we are the last user thread, and the primordial thread is
   1.223 +			   blocked in PR_Cleanup() waiting for us to finish - notify
   1.224 +			   it */
   1.225 +			delete_sem(bt_book.cleanUpSem);
   1.226 +	}
   1.227 +
   1.228 +    PR_Unlock( bt_book.ml );
   1.229 +	}
   1.230 +
   1.231 +	/* finally, delete this thread's PRThread */
   1.232 +	PR_DELETE(me);
   1.233 +}
   1.234 +
   1.235 +/**
   1.236 + * This is a wrapper that all threads invoke that allows us to set some
   1.237 + * things up prior to a thread's invocation and clean up after a thread has
   1.238 + * exited.
   1.239 + */
   1.240 +static void*
   1.241 +_bt_root (void* arg)
   1.242 +	{
   1.243 +    PRThread *thred = (PRThread*)arg;
   1.244 +    PRIntn rv;
   1.245 +    void *privData;
   1.246 +    status_t result;
   1.247 +    int i;
   1.248 +
   1.249 +	/* save our PRThread object into our TLS */
   1.250 +	tls_set(tls_prThreadSlot, thred);
   1.251 +
   1.252 +    thred->startFunc(thred->arg);  /* run the dang thing */
   1.253 +
   1.254 +	/* clean up */
   1.255 +	_bt_CleanupThread(NULL);
   1.256 +
   1.257 +	return 0;
   1.258 +}
   1.259 +
   1.260 +PR_IMPLEMENT(PRThread*)
   1.261 +    PR_CreateThread (PRThreadType type, void (*start)(void* arg), void* arg,
   1.262 +                     PRThreadPriority priority, PRThreadScope scope,
   1.263 +                     PRThreadState state, PRUint32 stackSize)
   1.264 +{
   1.265 +    PRUint32 bePriority;
   1.266 +
   1.267 +    PRThread* thred;
   1.268 +
   1.269 +    if (!_pr_initialized) _PR_ImplicitInitialization();
   1.270 +
   1.271 +	thred = PR_NEWZAP(PRThread);
   1.272 + 	if (thred == NULL)
   1.273 +	{
   1.274 +        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   1.275 +        return NULL;
   1.276 +    }
   1.277 +
   1.278 +    thred->md.joinSem = B_ERROR;
   1.279 +
   1.280 +        thred->arg = arg;
   1.281 +        thred->startFunc = start;
   1.282 +        thred->priority = priority;
   1.283 +
   1.284 +	if( state == PR_JOINABLE_THREAD )
   1.285 +	{
   1.286 +	    thred->state |= BT_THREAD_JOINABLE;
   1.287 +	}
   1.288 +
   1.289 +        /* keep some books */
   1.290 +
   1.291 +	PR_Lock( bt_book.ml );
   1.292 +
   1.293 +	if (type == PR_USER_THREAD)
   1.294 +	{
   1.295 +	    bt_book.threadCount++;
   1.296 +        }
   1.297 +
   1.298 +	PR_Unlock( bt_book.ml );
   1.299 +
   1.300 +	bePriority = _bt_MapNSPRToNativePriority( priority );
   1.301 +
   1.302 +        thred->md.tid = spawn_thread((thread_func)_bt_root, "moz-thread",
   1.303 +                                     bePriority, thred);
   1.304 +        if (thred->md.tid < B_OK) {
   1.305 +            PR_SetError(PR_UNKNOWN_ERROR, thred->md.tid);
   1.306 +            PR_DELETE(thred);
   1.307 +			return NULL;
   1.308 +        }
   1.309 +
   1.310 +        if (resume_thread(thred->md.tid) < B_OK) {
   1.311 +            PR_SetError(PR_UNKNOWN_ERROR, 0);
   1.312 +            PR_DELETE(thred);
   1.313 +			return NULL;
   1.314 +        }
   1.315 +
   1.316 +    return thred;
   1.317 +    }
   1.318 +
   1.319 +PR_IMPLEMENT(PRThread*)
   1.320 +	PR_AttachThread(PRThreadType type, PRThreadPriority priority,
   1.321 +					PRThreadStack *stack)
   1.322 +{
   1.323 +	/* PR_GetCurrentThread() will attach a thread if necessary */
   1.324 +	return PR_GetCurrentThread();
   1.325 +}
   1.326 +
   1.327 +PR_IMPLEMENT(void)
   1.328 +	PR_DetachThread()
   1.329 +{
   1.330 +	/* we don't support detaching */
   1.331 +}
   1.332 +
   1.333 +PR_IMPLEMENT(PRStatus)
   1.334 +    PR_JoinThread (PRThread* thred)
   1.335 +{
   1.336 +    status_t eval, status;
   1.337 +
   1.338 +    PR_ASSERT(thred != NULL);
   1.339 +
   1.340 +	if ((thred->state & BT_THREAD_JOINABLE) == 0)
   1.341 +    {
   1.342 +	PR_SetError( PR_INVALID_ARGUMENT_ERROR, 0 );
   1.343 +	return( PR_FAILURE );
   1.344 +    }
   1.345 +
   1.346 +	/* synchronize access to the thread's joinSem */
   1.347 +	PR_Lock(joinSemLock);
   1.348 +	
   1.349 +	if (thred->md.is_joining)
   1.350 +	{
   1.351 +		/* another thread is already waiting to join the specified
   1.352 +		   thread - we must fail */
   1.353 +		PR_Unlock(joinSemLock);
   1.354 +		return PR_FAILURE;
   1.355 +	}
   1.356 +
   1.357 +	/* let others know we are waiting to join */
   1.358 +	thred->md.is_joining = PR_TRUE;
   1.359 +
   1.360 +	if (thred->md.joinSem == B_ERROR)
   1.361 +	{
   1.362 +		/* the thread hasn't finished yet - it is our responsibility to
   1.363 +		   allocate a joinSem and wait on it */
   1.364 +		thred->md.joinSem = create_sem(0, "join sem");
   1.365 +
   1.366 +		/* we're done changing the joinSem now */
   1.367 +		PR_Unlock(joinSemLock);
   1.368 +
   1.369 +		/* wait for the thread to finish */
   1.370 +		while (acquire_sem(thred->md.joinSem) == B_INTERRUPTED);
   1.371 +
   1.372 +	}
   1.373 +	else
   1.374 +	{
   1.375 +		/* the thread has already finished, and has allocated the
   1.376 +		   joinSem itself - let it know it can finally die */
   1.377 +		delete_sem(thred->md.joinSem);
   1.378 +		
   1.379 +		PR_Unlock(joinSemLock);
   1.380 +    }
   1.381 +
   1.382 +	/* make sure the thread is dead */
   1.383 +    wait_for_thread(thred->md.tid, &eval);
   1.384 +
   1.385 +    return PR_SUCCESS;
   1.386 +}
   1.387 +
   1.388 +PR_IMPLEMENT(PRThread*)
   1.389 +    PR_GetCurrentThread ()
   1.390 +{
   1.391 +    PRThread* thred;
   1.392 +
   1.393 +    if (!_pr_initialized) _PR_ImplicitInitialization();
   1.394 +
   1.395 +    thred = (PRThread *)tls_get( tls_prThreadSlot);
   1.396 +	if (thred == NULL)
   1.397 +	{
   1.398 +		/* this thread doesn't have a PRThread structure (it must be
   1.399 +		   a native thread not created by the NSPR) - assimilate it */
   1.400 +		thred = _bt_AttachThread();
   1.401 +	}
   1.402 +    PR_ASSERT(NULL != thred);
   1.403 +
   1.404 +    return thred;
   1.405 +}
   1.406 +
   1.407 +PR_IMPLEMENT(PRThreadScope)
   1.408 +    PR_GetThreadScope (const PRThread* thred)
   1.409 +{
   1.410 +    PR_ASSERT(thred != NULL);
   1.411 +    return PR_GLOBAL_THREAD;
   1.412 +}
   1.413 +
   1.414 +PR_IMPLEMENT(PRThreadType)
   1.415 +    PR_GetThreadType (const PRThread* thred)
   1.416 +{
   1.417 +    PR_ASSERT(thred != NULL);
   1.418 +    return (thred->state & BT_THREAD_SYSTEM) ?
   1.419 +        PR_SYSTEM_THREAD : PR_USER_THREAD;
   1.420 +}
   1.421 +
   1.422 +PR_IMPLEMENT(PRThreadState)
   1.423 +    PR_GetThreadState (const PRThread* thred)
   1.424 +{
   1.425 +    PR_ASSERT(thred != NULL);
   1.426 +    return (thred->state & BT_THREAD_JOINABLE)?
   1.427 +    					PR_JOINABLE_THREAD: PR_UNJOINABLE_THREAD;
   1.428 +}
   1.429 +
   1.430 +PR_IMPLEMENT(PRThreadPriority)
   1.431 +    PR_GetThreadPriority (const PRThread* thred)
   1.432 +{
   1.433 +    PR_ASSERT(thred != NULL);
   1.434 +    return thred->priority;
   1.435 +}  /* PR_GetThreadPriority */
   1.436 +
   1.437 +PR_IMPLEMENT(void) PR_SetThreadPriority(PRThread *thred,
   1.438 +                                        PRThreadPriority newPri)
   1.439 +{
   1.440 +    PRUint32 bePriority;
   1.441 +
   1.442 +    PR_ASSERT( thred != NULL );
   1.443 +
   1.444 +    thred->priority = newPri;
   1.445 +    bePriority = _bt_MapNSPRToNativePriority( newPri );
   1.446 +    set_thread_priority( thred->md.tid, bePriority );
   1.447 +}
   1.448 +
   1.449 +PR_IMPLEMENT(PRStatus)
   1.450 +    PR_NewThreadPrivateIndex (PRUintn* newIndex,
   1.451 +                              PRThreadPrivateDTOR destructor)
   1.452 +{
   1.453 +	int32    index;
   1.454 +
   1.455 +    if (!_pr_initialized) _PR_ImplicitInitialization();
   1.456 +
   1.457 +	/* reserve the next available tpd slot */
   1.458 +	index = atomic_add( &tpd_slotsUsed, 1 );
   1.459 +	if (index >= BT_TPD_LIMIT)
   1.460 +	{
   1.461 +		/* no slots left - decrement value, then fail */
   1.462 +		atomic_add( &tpd_slotsUsed, -1 );
   1.463 +		PR_SetError( PR_TPD_RANGE_ERROR, 0 );
   1.464 +	    return( PR_FAILURE );
   1.465 +	}
   1.466 +
   1.467 +	/* allocate a beos-native TLS slot for this index (the new slot
   1.468 +	   automatically contains NULL) */
   1.469 +	tpd_beosTLSSlots[index] = tls_allocate();
   1.470 +
   1.471 +	/* remember the destructor */
   1.472 +	tpd_dtors[index] = destructor;
   1.473 +
   1.474 +    *newIndex = (PRUintn)index;
   1.475 +
   1.476 +    return( PR_SUCCESS );
   1.477 +}
   1.478 +
   1.479 +PR_IMPLEMENT(PRStatus)
   1.480 +    PR_SetThreadPrivate (PRUintn index, void* priv)
   1.481 +{
   1.482 +	void *oldValue;
   1.483 +
   1.484 +    /*
   1.485 +    ** Sanity checking
   1.486 +    */
   1.487 +
   1.488 +    if(index < 0 || index >= tpd_slotsUsed || index >= BT_TPD_LIMIT)
   1.489 +    {
   1.490 +		PR_SetError( PR_TPD_RANGE_ERROR, 0 );
   1.491 +	return( PR_FAILURE );
   1.492 +    }
   1.493 +
   1.494 +	/* if the old value isn't NULL, and the dtor for this slot isn't
   1.495 +	   NULL, we must destroy the data */
   1.496 +	oldValue = tls_get(tpd_beosTLSSlots[index]);
   1.497 +	if (oldValue != NULL && tpd_dtors[index] != NULL)
   1.498 +		(*tpd_dtors[index])(oldValue);
   1.499 +
   1.500 +	/* save new value */
   1.501 +	tls_set(tpd_beosTLSSlots[index], priv);
   1.502 +
   1.503 +	    return( PR_SUCCESS );
   1.504 +	}
   1.505 +
   1.506 +PR_IMPLEMENT(void*)
   1.507 +    PR_GetThreadPrivate (PRUintn index)
   1.508 +{
   1.509 +	/* make sure the index is valid */
   1.510 +	if (index < 0 || index >= tpd_slotsUsed || index >= BT_TPD_LIMIT)
   1.511 +    {   
   1.512 +		PR_SetError( PR_TPD_RANGE_ERROR, 0 );
   1.513 +		return NULL;
   1.514 +    }
   1.515 +
   1.516 +	/* return the value */
   1.517 +	return tls_get( tpd_beosTLSSlots[index] );
   1.518 +	}
   1.519 +
   1.520 +
   1.521 +PR_IMPLEMENT(PRStatus)
   1.522 +    PR_Interrupt (PRThread* thred)
   1.523 +{
   1.524 +    PRIntn rv;
   1.525 +
   1.526 +    PR_ASSERT(thred != NULL);
   1.527 +
   1.528 +    /*
   1.529 +    ** there seems to be a bug in beos R5 in which calling
   1.530 +    ** resume_thread() on a blocked thread returns B_OK instead
   1.531 +    ** of B_BAD_THREAD_STATE (beos bug #20000422-19095).  as such,
   1.532 +    ** to interrupt a thread, we will simply suspend then resume it
   1.533 +    ** (no longer call resume_thread(), check for B_BAD_THREAD_STATE,
   1.534 +    ** the suspend/resume to wake up a blocked thread).  this wakes
   1.535 +    ** up blocked threads properly, and doesn't hurt unblocked threads
   1.536 +    ** (they simply get stopped then re-started immediately)
   1.537 +    */
   1.538 +
   1.539 +    rv = suspend_thread( thred->md.tid );
   1.540 +    if( rv != B_NO_ERROR )
   1.541 +    {
   1.542 +        /* this doesn't appear to be a valid thread_id */
   1.543 +        PR_SetError( PR_UNKNOWN_ERROR, rv );
   1.544 +        return PR_FAILURE;
   1.545 +    }
   1.546 +
   1.547 +    rv = resume_thread( thred->md.tid );
   1.548 +    if( rv != B_NO_ERROR )
   1.549 +    {
   1.550 +        PR_SetError( PR_UNKNOWN_ERROR, rv );
   1.551 +        return PR_FAILURE;
   1.552 +    }
   1.553 +
   1.554 +    return PR_SUCCESS;
   1.555 +}
   1.556 +
   1.557 +PR_IMPLEMENT(void)
   1.558 +    PR_ClearInterrupt ()
   1.559 +{
   1.560 +}
   1.561 +
   1.562 +PR_IMPLEMENT(PRStatus)
   1.563 +    PR_Yield ()
   1.564 +{
   1.565 +    /* we just sleep for long enough to cause a reschedule (100
   1.566 +       microseconds) */
   1.567 +    snooze(100);
   1.568 +}
   1.569 +
   1.570 +#define BT_MILLION 1000000UL
   1.571 +
   1.572 +PR_IMPLEMENT(PRStatus)
   1.573 +    PR_Sleep (PRIntervalTime ticks)
   1.574 +{
   1.575 +    bigtime_t tps;
   1.576 +    status_t status;
   1.577 +
   1.578 +    if (!_pr_initialized) _PR_ImplicitInitialization();
   1.579 +
   1.580 +    tps = PR_IntervalToMicroseconds( ticks );
   1.581 +
   1.582 +    status = snooze(tps);
   1.583 +    if (status == B_NO_ERROR) return PR_SUCCESS;
   1.584 +
   1.585 +    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, status);
   1.586 +    return PR_FAILURE;
   1.587 +}
   1.588 +
   1.589 +PR_IMPLEMENT(PRStatus)
   1.590 +    PR_Cleanup ()
   1.591 +{
   1.592 +    PRThread *me = PR_GetCurrentThread();
   1.593 +
   1.594 +    PR_ASSERT(me->state & BT_THREAD_PRIMORD);
   1.595 +    if ((me->state & BT_THREAD_PRIMORD) == 0) {
   1.596 +        return PR_FAILURE;
   1.597 +    }
   1.598 +
   1.599 +    PR_Lock( bt_book.ml );
   1.600 +
   1.601 +	if (bt_book.threadCount != 0)
   1.602 +    {
   1.603 +		/* we'll have to wait for some threads to finish - create a
   1.604 +		   sem to block on */
   1.605 +		bt_book.cleanUpSem = create_sem(0, "cleanup sem");
   1.606 +    }
   1.607 +
   1.608 +    PR_Unlock( bt_book.ml );
   1.609 +
   1.610 +	/* note that, if all the user threads were already dead, we
   1.611 +	   wouldn't have created a sem above, so this acquire_sem()
   1.612 +	   will fail immediately */
   1.613 +	while (acquire_sem(bt_book.cleanUpSem) == B_INTERRUPTED);
   1.614 +
   1.615 +    return PR_SUCCESS;
   1.616 +}
   1.617 +
   1.618 +PR_IMPLEMENT(void)
   1.619 +    PR_ProcessExit (PRIntn status)
   1.620 +{
   1.621 +    exit(status);
   1.622 +}
   1.623 +
   1.624 +PRThread *_bt_AttachThread()
   1.625 +{
   1.626 +	PRThread *thread;
   1.627 +	thread_info tInfo;
   1.628 +
   1.629 +	/* make sure this thread doesn't already have a PRThread structure */
   1.630 +	PR_ASSERT(tls_get(tls_prThreadSlot) == NULL);
   1.631 +
   1.632 +	/* allocate a PRThread structure for this thread */
   1.633 +	thread = PR_NEWZAP(PRThread);
   1.634 +	if (thread == NULL)
   1.635 +	{
   1.636 +		PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   1.637 +		return NULL;
   1.638 +	}
   1.639 +
   1.640 +	/* get the native thread's current state */
   1.641 +	get_thread_info(find_thread(NULL), &tInfo);
   1.642 +
   1.643 +	/* initialize new PRThread */
   1.644 +	thread->md.tid = tInfo.thread;
   1.645 +	thread->md.joinSem = B_ERROR;
   1.646 +	thread->priority = _bt_MapNativeToNSPRPriority(tInfo.priority);
   1.647 +
   1.648 +	/* attached threads are always non-joinable user threads */
   1.649 +	thread->state = 0;
   1.650 +
   1.651 +	/* increment user thread count */
   1.652 +	PR_Lock(bt_book.ml);
   1.653 +	bt_book.threadCount++;
   1.654 +	PR_Unlock(bt_book.ml);
   1.655 +
   1.656 +	/* store this thread's PRThread */
   1.657 +	tls_set(tls_prThreadSlot, thread);
   1.658 +	
   1.659 +	/* the thread must call _bt_CleanupThread() before it dies, in order
   1.660 +	   to clean up its PRThread, synchronize with the primordial thread,
   1.661 +	   etc. */
   1.662 +	on_exit_thread(_bt_CleanupThread, NULL);
   1.663 +	
   1.664 +	return thread;
   1.665 +}

mercurial