~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/nsprpub/pr/src/bthreads/btthread.c

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 
2
/* 
 
3
 * The contents of this file are subject to the Mozilla Public
 
4
 * License Version 1.1 (the "License"); you may not use this file
 
5
 * except in compliance with the License. You may obtain a copy of
 
6
 * the License at http://www.mozilla.org/MPL/
 
7
 * 
 
8
 * Software distributed under the License is distributed on an "AS
 
9
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 
10
 * implied. See the License for the specific language governing
 
11
 * rights and limitations under the License.
 
12
 * 
 
13
 * The Original Code is the Netscape Portable Runtime (NSPR).
 
14
 * 
 
15
 * The Initial Developer of the Original Code is Netscape
 
16
 * Communications Corporation.  Portions created by Netscape are 
 
17
 * Copyright (C) 1998-2000 Netscape Communications Corporation.  All
 
18
 * Rights Reserved.
 
19
 * 
 
20
 * Contributor(s):
 
21
 * 
 
22
 * Alternatively, the contents of this file may be used under the
 
23
 * terms of the GNU General Public License Version 2 or later (the
 
24
 * "GPL"), in which case the provisions of the GPL are applicable 
 
25
 * instead of those above.  If you wish to allow use of your 
 
26
 * version of this file only under the terms of the GPL and not to
 
27
 * allow others to use your version of this file under the MPL,
 
28
 * indicate your decision by deleting the provisions above and
 
29
 * replace them with the notice and other provisions required by
 
30
 * the GPL.  If you do not delete the provisions above, a recipient
 
31
 * may use your version of this file under either the MPL or the
 
32
 * GPL.
 
33
 */
 
34
 
 
35
#include <kernel/OS.h>
 
36
#include <support/TLS.h>
 
37
 
 
38
#include "prlog.h"
 
39
#include "primpl.h"
 
40
#include "prcvar.h"
 
41
#include "prpdce.h"
 
42
 
 
43
#include <stdlib.h>
 
44
#include <string.h>
 
45
#include <signal.h>
 
46
 
 
47
/* values for PRThread.state */
 
48
#define BT_THREAD_PRIMORD   0x01    /* this is the primordial thread */
 
49
#define BT_THREAD_SYSTEM    0x02    /* this is a system thread */
 
50
#define BT_THREAD_JOINABLE  0x04        /* this is a joinable thread */
 
51
 
 
52
struct _BT_Bookeeping
 
53
{
 
54
    PRLock *ml;                 /* a lock to protect ourselves */
 
55
        sem_id cleanUpSem;              /* the primoridal thread will block on this
 
56
                                                           sem while waiting for the user threads */
 
57
    PRInt32 threadCount;        /* user thred count */
 
58
 
 
59
} bt_book = { NULL, B_ERROR, 0 };
 
60
 
 
61
 
 
62
#define BT_TPD_LIMIT 128        /* number of TPD slots we'll provide (arbitrary) */
 
63
 
 
64
/* these will be used to map an index returned by PR_NewThreadPrivateIndex()
 
65
   to the corresponding beos native TLS slot number, and to the destructor
 
66
   for that slot - note that, because it is allocated globally, this data
 
67
   will be automatically zeroed for us when the program begins */
 
68
static int32 tpd_beosTLSSlots[BT_TPD_LIMIT];
 
69
static PRThreadPrivateDTOR tpd_dtors[BT_TPD_LIMIT];
 
70
 
 
71
static vint32 tpd_slotsUsed=0;  /* number of currently-allocated TPD slots */
 
72
static int32 tls_prThreadSlot;  /* TLS slot in which PRThread will be stored */
 
73
 
 
74
/* this mutex will be used to synchronize access to every
 
75
   PRThread.md.joinSem and PRThread.md.is_joining (we could
 
76
   actually allocate one per thread, but that seems a bit excessive,
 
77
   especially considering that there will probably be little
 
78
   contention, PR_JoinThread() is allowed to block anyway, and the code
 
79
   protected by the mutex is short/fast) */
 
80
static PRLock *joinSemLock;
 
81
 
 
82
static PRUint32 _bt_MapNSPRToNativePriority( PRThreadPriority priority );
 
83
static PRThreadPriority _bt_MapNativeToNSPRPriority( PRUint32 priority );
 
84
static void _bt_CleanupThread(void *arg);
 
85
static PRThread *_bt_AttachThread();
 
86
 
 
87
void
 
88
_PR_InitThreads (PRThreadType type, PRThreadPriority priority,
 
89
                 PRUintn maxPTDs)
 
90
{
 
91
    PRThread *primordialThread;
 
92
    PRUint32  beThreadPriority;
 
93
 
 
94
        /* allocate joinSem mutex */
 
95
        joinSemLock = PR_NewLock();
 
96
        if (joinSemLock == NULL)
 
97
        {
 
98
                PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
 
99
                return;
 
100
    }
 
101
 
 
102
    /*
 
103
    ** Create and initialize NSPR structure for our primordial thread.
 
104
    */
 
105
    
 
106
    primordialThread = PR_NEWZAP(PRThread);
 
107
    if( NULL == primordialThread )
 
108
    {
 
109
        PR_SetError( PR_OUT_OF_MEMORY_ERROR, 0 );
 
110
        return;
 
111
    }
 
112
 
 
113
        primordialThread->md.joinSem = B_ERROR;
 
114
 
 
115
    /*
 
116
    ** Set the priority to the desired level.
 
117
    */
 
118
 
 
119
    beThreadPriority = _bt_MapNSPRToNativePriority( priority );
 
120
    
 
121
    set_thread_priority( find_thread( NULL ), beThreadPriority );
 
122
    
 
123
    primordialThread->priority = priority;
 
124
 
 
125
 
 
126
        /* set the thread's state - note that the thread is not joinable */
 
127
    primordialThread->state |= BT_THREAD_PRIMORD;
 
128
        if (type == PR_SYSTEM_THREAD)
 
129
                primordialThread->state |= BT_THREAD_SYSTEM;
 
130
 
 
131
    /*
 
132
    ** Allocate a TLS slot for the PRThread structure (just using
 
133
    ** native TLS, as opposed to NSPR TPD, will make PR_GetCurrentThread()
 
134
    ** somewhat faster, and will leave one more TPD slot for our client)
 
135
    */
 
136
        
 
137
        tls_prThreadSlot = tls_allocate();
 
138
 
 
139
    /*
 
140
    ** Stuff our new PRThread structure into our thread specific
 
141
    ** slot.
 
142
    */
 
143
 
 
144
        tls_set(tls_prThreadSlot, primordialThread);
 
145
    
 
146
        /* allocate lock for bt_book */
 
147
    bt_book.ml = PR_NewLock();
 
148
    if( NULL == bt_book.ml )
 
149
    {
 
150
        PR_SetError( PR_OUT_OF_MEMORY_ERROR, 0 );
 
151
        return;
 
152
    }
 
153
}
 
154
 
 
155
PRUint32
 
156
_bt_MapNSPRToNativePriority( PRThreadPriority priority )
 
157
    {
 
158
    switch( priority )
 
159
    {
 
160
        case PR_PRIORITY_LOW:    return( B_LOW_PRIORITY );
 
161
        case PR_PRIORITY_NORMAL: return( B_NORMAL_PRIORITY );
 
162
        case PR_PRIORITY_HIGH:   return( B_DISPLAY_PRIORITY );
 
163
        case PR_PRIORITY_URGENT: return( B_URGENT_DISPLAY_PRIORITY );
 
164
        default:                 return( B_NORMAL_PRIORITY );
 
165
    }
 
166
}
 
167
 
 
168
PRThreadPriority
 
169
_bt_MapNativeToNSPRPriority(PRUint32 priority)
 
170
    {
 
171
        if (priority < B_NORMAL_PRIORITY)
 
172
                return PR_PRIORITY_LOW;
 
173
        if (priority < B_DISPLAY_PRIORITY)
 
174
                return PR_PRIORITY_NORMAL;
 
175
        if (priority < B_URGENT_DISPLAY_PRIORITY)
 
176
                return PR_PRIORITY_HIGH;
 
177
        return PR_PRIORITY_URGENT;
 
178
}
 
179
 
 
180
PRUint32
 
181
_bt_mapNativeToNSPRPriority( int32 priority )
 
182
{
 
183
    switch( priority )
 
184
    {
 
185
        case PR_PRIORITY_LOW:    return( B_LOW_PRIORITY );
 
186
        case PR_PRIORITY_NORMAL: return( B_NORMAL_PRIORITY );
 
187
        case PR_PRIORITY_HIGH:   return( B_DISPLAY_PRIORITY );
 
188
        case PR_PRIORITY_URGENT: return( B_URGENT_DISPLAY_PRIORITY );
 
189
        default:                 return( B_NORMAL_PRIORITY );
 
190
    }
 
191
}
 
192
 
 
193
/* This method is called by all NSPR threads as they exit */
 
194
void _bt_CleanupThread(void *arg)
 
195
{
 
196
        PRThread *me = PR_GetCurrentThread();
 
197
        int32 i;
 
198
 
 
199
        /* first, clean up all thread-private data */
 
200
        for (i = 0; i < tpd_slotsUsed; i++)
 
201
        {
 
202
                void *oldValue = tls_get(tpd_beosTLSSlots[i]);
 
203
                if ( oldValue != NULL && tpd_dtors[i] != NULL )
 
204
                        (*tpd_dtors[i])(oldValue);
 
205
        }
 
206
 
 
207
        /* if this thread is joinable, wait for someone to join it */
 
208
        if (me->state & BT_THREAD_JOINABLE)
 
209
        {
 
210
                /* protect access to our joinSem */
 
211
                PR_Lock(joinSemLock);
 
212
 
 
213
                if (me->md.is_joining)
 
214
                {
 
215
                        /* someone is already waiting to join us (they've
 
216
                           allocated a joinSem for us) - let them know we're
 
217
                           ready */
 
218
                        delete_sem(me->md.joinSem);
 
219
 
 
220
                        PR_Unlock(joinSemLock);
 
221
 
 
222
                }
 
223
                else
 
224
    {
 
225
                        /* noone is currently waiting for our demise - it
 
226
                           is our responsibility to allocate the joinSem
 
227
                           and block on it */
 
228
                        me->md.joinSem = create_sem(0, "join sem");
 
229
 
 
230
                        /* we're done accessing our joinSem */
 
231
                        PR_Unlock(joinSemLock);
 
232
 
 
233
                        /* wait for someone to join us */
 
234
                        while (acquire_sem(me->md.joinSem) == B_INTERRUPTED);
 
235
            }
 
236
        }
 
237
 
 
238
        /* if this is a user thread, we must update our books */
 
239
        if ((me->state & BT_THREAD_SYSTEM) == 0)
 
240
        {
 
241
                /* synchronize access to bt_book */
 
242
    PR_Lock( bt_book.ml );
 
243
 
 
244
                /* decrement the number of currently-alive user threads */
 
245
        bt_book.threadCount--;
 
246
 
 
247
                if (bt_book.threadCount == 0 && bt_book.cleanUpSem != B_ERROR) {
 
248
                        /* we are the last user thread, and the primordial thread is
 
249
                           blocked in PR_Cleanup() waiting for us to finish - notify
 
250
                           it */
 
251
                        delete_sem(bt_book.cleanUpSem);
 
252
        }
 
253
 
 
254
    PR_Unlock( bt_book.ml );
 
255
        }
 
256
 
 
257
        /* finally, delete this thread's PRThread */
 
258
        PR_DELETE(me);
 
259
}
 
260
 
 
261
/**
 
262
 * This is a wrapper that all threads invoke that allows us to set some
 
263
 * things up prior to a thread's invocation and clean up after a thread has
 
264
 * exited.
 
265
 */
 
266
static void*
 
267
_bt_root (void* arg)
 
268
        {
 
269
    PRThread *thred = (PRThread*)arg;
 
270
    PRIntn rv;
 
271
    void *privData;
 
272
    status_t result;
 
273
    int i;
 
274
 
 
275
        /* save our PRThread object into our TLS */
 
276
        tls_set(tls_prThreadSlot, thred);
 
277
 
 
278
    thred->startFunc(thred->arg);  /* run the dang thing */
 
279
 
 
280
        /* clean up */
 
281
        _bt_CleanupThread(NULL);
 
282
 
 
283
        return 0;
 
284
}
 
285
 
 
286
PR_IMPLEMENT(PRThread*)
 
287
    PR_CreateThread (PRThreadType type, void (*start)(void* arg), void* arg,
 
288
                     PRThreadPriority priority, PRThreadScope scope,
 
289
                     PRThreadState state, PRUint32 stackSize)
 
290
{
 
291
    PRUint32 bePriority;
 
292
 
 
293
    PRThread* thred;
 
294
 
 
295
    if (!_pr_initialized) _PR_ImplicitInitialization();
 
296
 
 
297
        thred = PR_NEWZAP(PRThread);
 
298
        if (thred == NULL)
 
299
        {
 
300
        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
 
301
        return NULL;
 
302
    }
 
303
 
 
304
    thred->md.joinSem = B_ERROR;
 
305
 
 
306
        thred->arg = arg;
 
307
        thred->startFunc = start;
 
308
        thred->priority = priority;
 
309
 
 
310
        if( state == PR_JOINABLE_THREAD )
 
311
        {
 
312
            thred->state |= BT_THREAD_JOINABLE;
 
313
        }
 
314
 
 
315
        /* keep some books */
 
316
 
 
317
        PR_Lock( bt_book.ml );
 
318
 
 
319
        if (type == PR_USER_THREAD)
 
320
        {
 
321
            bt_book.threadCount++;
 
322
        }
 
323
 
 
324
        PR_Unlock( bt_book.ml );
 
325
 
 
326
        bePriority = _bt_MapNSPRToNativePriority( priority );
 
327
 
 
328
        thred->md.tid = spawn_thread((thread_func)_bt_root, "moz-thread",
 
329
                                     bePriority, thred);
 
330
        if (thred->md.tid < B_OK) {
 
331
            PR_SetError(PR_UNKNOWN_ERROR, thred->md.tid);
 
332
            PR_DELETE(thred);
 
333
                        return NULL;
 
334
        }
 
335
 
 
336
        if (resume_thread(thred->md.tid) < B_OK) {
 
337
            PR_SetError(PR_UNKNOWN_ERROR, 0);
 
338
            PR_DELETE(thred);
 
339
                        return NULL;
 
340
        }
 
341
 
 
342
    return thred;
 
343
    }
 
344
 
 
345
PR_IMPLEMENT(PRThread*)
 
346
        PR_AttachThread(PRThreadType type, PRThreadPriority priority,
 
347
                                        PRThreadStack *stack)
 
348
{
 
349
        /* PR_GetCurrentThread() will attach a thread if necessary */
 
350
        return PR_GetCurrentThread();
 
351
}
 
352
 
 
353
PR_IMPLEMENT(void)
 
354
        PR_DetachThread()
 
355
{
 
356
        /* we don't support detaching */
 
357
}
 
358
 
 
359
PR_IMPLEMENT(PRStatus)
 
360
    PR_JoinThread (PRThread* thred)
 
361
{
 
362
    status_t eval, status;
 
363
 
 
364
    PR_ASSERT(thred != NULL);
 
365
 
 
366
        if ((thred->state & BT_THREAD_JOINABLE) == 0)
 
367
    {
 
368
        PR_SetError( PR_INVALID_ARGUMENT_ERROR, 0 );
 
369
        return( PR_FAILURE );
 
370
    }
 
371
 
 
372
        /* synchronize access to the thread's joinSem */
 
373
        PR_Lock(joinSemLock);
 
374
        
 
375
        if (thred->md.is_joining)
 
376
        {
 
377
                /* another thread is already waiting to join the specified
 
378
                   thread - we must fail */
 
379
                PR_Unlock(joinSemLock);
 
380
                return PR_FAILURE;
 
381
        }
 
382
 
 
383
        /* let others know we are waiting to join */
 
384
        thred->md.is_joining = PR_TRUE;
 
385
 
 
386
        if (thred->md.joinSem == B_ERROR)
 
387
        {
 
388
                /* the thread hasn't finished yet - it is our responsibility to
 
389
                   allocate a joinSem and wait on it */
 
390
                thred->md.joinSem = create_sem(0, "join sem");
 
391
 
 
392
                /* we're done changing the joinSem now */
 
393
                PR_Unlock(joinSemLock);
 
394
 
 
395
                /* wait for the thread to finish */
 
396
                while (acquire_sem(thred->md.joinSem) == B_INTERRUPTED);
 
397
 
 
398
        }
 
399
        else
 
400
        {
 
401
                /* the thread has already finished, and has allocated the
 
402
                   joinSem itself - let it know it can finally die */
 
403
                delete_sem(thred->md.joinSem);
 
404
                
 
405
                PR_Unlock(joinSemLock);
 
406
    }
 
407
 
 
408
        /* make sure the thread is dead */
 
409
    wait_for_thread(thred->md.tid, &eval);
 
410
 
 
411
    return PR_SUCCESS;
 
412
}
 
413
 
 
414
PR_IMPLEMENT(PRThread*)
 
415
    PR_GetCurrentThread ()
 
416
{
 
417
    PRThread* thred;
 
418
 
 
419
    if (!_pr_initialized) _PR_ImplicitInitialization();
 
420
 
 
421
    thred = (PRThread *)tls_get( tls_prThreadSlot);
 
422
        if (thred == NULL)
 
423
        {
 
424
                /* this thread doesn't have a PRThread structure (it must be
 
425
                   a native thread not created by the NSPR) - assimilate it */
 
426
                thred = _bt_AttachThread();
 
427
        }
 
428
    PR_ASSERT(NULL != thred);
 
429
 
 
430
    return thred;
 
431
}
 
432
 
 
433
PR_IMPLEMENT(PRThreadScope)
 
434
    PR_GetThreadScope (const PRThread* thred)
 
435
{
 
436
    PR_ASSERT(thred != NULL);
 
437
    return PR_GLOBAL_THREAD;
 
438
}
 
439
 
 
440
PR_IMPLEMENT(PRThreadType)
 
441
    PR_GetThreadType (const PRThread* thred)
 
442
{
 
443
    PR_ASSERT(thred != NULL);
 
444
    return (thred->state & BT_THREAD_SYSTEM) ?
 
445
        PR_SYSTEM_THREAD : PR_USER_THREAD;
 
446
}
 
447
 
 
448
PR_IMPLEMENT(PRThreadState)
 
449
    PR_GetThreadState (const PRThread* thred)
 
450
{
 
451
    PR_ASSERT(thred != NULL);
 
452
    return (thred->state & BT_THREAD_JOINABLE)?
 
453
                                        PR_JOINABLE_THREAD: PR_UNJOINABLE_THREAD;
 
454
}
 
455
 
 
456
PR_IMPLEMENT(PRThreadPriority)
 
457
    PR_GetThreadPriority (const PRThread* thred)
 
458
{
 
459
    PR_ASSERT(thred != NULL);
 
460
    return thred->priority;
 
461
}  /* PR_GetThreadPriority */
 
462
 
 
463
PR_IMPLEMENT(void) PR_SetThreadPriority(PRThread *thred,
 
464
                                        PRThreadPriority newPri)
 
465
{
 
466
    PRUint32 bePriority;
 
467
 
 
468
    PR_ASSERT( thred != NULL );
 
469
 
 
470
    thred->priority = newPri;
 
471
    bePriority = _bt_MapNSPRToNativePriority( newPri );
 
472
    set_thread_priority( thred->md.tid, bePriority );
 
473
}
 
474
 
 
475
PR_IMPLEMENT(PRStatus)
 
476
    PR_NewThreadPrivateIndex (PRUintn* newIndex,
 
477
                              PRThreadPrivateDTOR destructor)
 
478
{
 
479
        int32    index;
 
480
 
 
481
    if (!_pr_initialized) _PR_ImplicitInitialization();
 
482
 
 
483
        /* reserve the next available tpd slot */
 
484
        index = atomic_add( &tpd_slotsUsed, 1 );
 
485
        if (index >= BT_TPD_LIMIT)
 
486
        {
 
487
                /* no slots left - decrement value, then fail */
 
488
                atomic_add( &tpd_slotsUsed, -1 );
 
489
                PR_SetError( PR_TPD_RANGE_ERROR, 0 );
 
490
            return( PR_FAILURE );
 
491
        }
 
492
 
 
493
        /* allocate a beos-native TLS slot for this index (the new slot
 
494
           automatically contains NULL) */
 
495
        tpd_beosTLSSlots[index] = tls_allocate();
 
496
 
 
497
        /* remember the destructor */
 
498
        tpd_dtors[index] = destructor;
 
499
 
 
500
    *newIndex = (PRUintn)index;
 
501
 
 
502
    return( PR_SUCCESS );
 
503
}
 
504
 
 
505
PR_IMPLEMENT(PRStatus)
 
506
    PR_SetThreadPrivate (PRUintn index, void* priv)
 
507
{
 
508
        void *oldValue;
 
509
 
 
510
    /*
 
511
    ** Sanity checking
 
512
    */
 
513
 
 
514
    if(index < 0 || index >= tpd_slotsUsed || index >= BT_TPD_LIMIT)
 
515
    {
 
516
                PR_SetError( PR_TPD_RANGE_ERROR, 0 );
 
517
        return( PR_FAILURE );
 
518
    }
 
519
 
 
520
        /* if the old value isn't NULL, and the dtor for this slot isn't
 
521
           NULL, we must destroy the data */
 
522
        oldValue = tls_get(tpd_beosTLSSlots[index]);
 
523
        if (oldValue != NULL && tpd_dtors[index] != NULL)
 
524
                (*tpd_dtors[index])(oldValue);
 
525
 
 
526
        /* save new value */
 
527
        tls_set(tpd_beosTLSSlots[index], priv);
 
528
 
 
529
            return( PR_SUCCESS );
 
530
        }
 
531
 
 
532
PR_IMPLEMENT(void*)
 
533
    PR_GetThreadPrivate (PRUintn index)
 
534
{
 
535
        /* make sure the index is valid */
 
536
        if (index < 0 || index >= tpd_slotsUsed || index >= BT_TPD_LIMIT)
 
537
    {   
 
538
                PR_SetError( PR_TPD_RANGE_ERROR, 0 );
 
539
                return NULL;
 
540
    }
 
541
 
 
542
        /* return the value */
 
543
        return tls_get( tpd_beosTLSSlots[index] );
 
544
        }
 
545
 
 
546
 
 
547
PR_IMPLEMENT(PRStatus)
 
548
    PR_Interrupt (PRThread* thred)
 
549
{
 
550
    PRIntn rv;
 
551
 
 
552
    PR_ASSERT(thred != NULL);
 
553
 
 
554
    /*
 
555
    ** there seems to be a bug in beos R5 in which calling
 
556
    ** resume_thread() on a blocked thread returns B_OK instead
 
557
    ** of B_BAD_THREAD_STATE (beos bug #20000422-19095).  as such,
 
558
    ** to interrupt a thread, we will simply suspend then resume it
 
559
    ** (no longer call resume_thread(), check for B_BAD_THREAD_STATE,
 
560
    ** the suspend/resume to wake up a blocked thread).  this wakes
 
561
    ** up blocked threads properly, and doesn't hurt unblocked threads
 
562
    ** (they simply get stopped then re-started immediately)
 
563
    */
 
564
 
 
565
    rv = suspend_thread( thred->md.tid );
 
566
    if( rv != B_NO_ERROR )
 
567
    {
 
568
        /* this doesn't appear to be a valid thread_id */
 
569
        PR_SetError( PR_UNKNOWN_ERROR, rv );
 
570
        return PR_FAILURE;
 
571
    }
 
572
 
 
573
    rv = resume_thread( thred->md.tid );
 
574
    if( rv != B_NO_ERROR )
 
575
    {
 
576
        PR_SetError( PR_UNKNOWN_ERROR, rv );
 
577
        return PR_FAILURE;
 
578
    }
 
579
 
 
580
    return PR_SUCCESS;
 
581
}
 
582
 
 
583
PR_IMPLEMENT(void)
 
584
    PR_ClearInterrupt ()
 
585
{
 
586
}
 
587
 
 
588
PR_IMPLEMENT(PRStatus)
 
589
    PR_Yield ()
 
590
{
 
591
    /* we just sleep for long enough to cause a reschedule (100
 
592
       microseconds) */
 
593
    snooze(100);
 
594
}
 
595
 
 
596
#define BT_MILLION 1000000UL
 
597
 
 
598
PR_IMPLEMENT(PRStatus)
 
599
    PR_Sleep (PRIntervalTime ticks)
 
600
{
 
601
    bigtime_t tps;
 
602
    status_t status;
 
603
 
 
604
    if (!_pr_initialized) _PR_ImplicitInitialization();
 
605
 
 
606
    tps = PR_IntervalToMicroseconds( ticks );
 
607
 
 
608
    status = snooze(tps);
 
609
    if (status == B_NO_ERROR) return PR_SUCCESS;
 
610
 
 
611
    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, status);
 
612
    return PR_FAILURE;
 
613
}
 
614
 
 
615
PR_IMPLEMENT(PRStatus)
 
616
    PR_Cleanup ()
 
617
{
 
618
    PRThread *me = PR_CurrentThread();
 
619
 
 
620
    PR_ASSERT(me->state & BT_THREAD_PRIMORD);
 
621
    if ((me->state & BT_THREAD_PRIMORD) == 0) {
 
622
        return PR_FAILURE;
 
623
    }
 
624
 
 
625
    PR_Lock( bt_book.ml );
 
626
 
 
627
        if (bt_book.threadCount != 0)
 
628
    {
 
629
                /* we'll have to wait for some threads to finish - create a
 
630
                   sem to block on */
 
631
                bt_book.cleanUpSem = create_sem(0, "cleanup sem");
 
632
    }
 
633
 
 
634
    PR_Unlock( bt_book.ml );
 
635
 
 
636
        /* note that, if all the user threads were already dead, we
 
637
           wouldn't have created a sem above, so this acquire_sem()
 
638
           will fail immediately */
 
639
        while (acquire_sem(bt_book.cleanUpSem) == B_INTERRUPTED);
 
640
 
 
641
    return PR_SUCCESS;
 
642
}
 
643
 
 
644
PR_IMPLEMENT(void)
 
645
    PR_ProcessExit (PRIntn status)
 
646
{
 
647
    exit(status);
 
648
}
 
649
 
 
650
PRThread *_bt_AttachThread()
 
651
{
 
652
        PRThread *thread;
 
653
        thread_info tInfo;
 
654
 
 
655
        /* make sure this thread doesn't already have a PRThread structure */
 
656
        PR_ASSERT(tls_get(tls_prThreadSlot) == NULL);
 
657
 
 
658
        /* allocate a PRThread structure for this thread */
 
659
        thread = PR_NEWZAP(PRThread);
 
660
        if (thread == NULL)
 
661
        {
 
662
                PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
 
663
                return NULL;
 
664
        }
 
665
 
 
666
        /* get the native thread's current state */
 
667
        get_thread_info(find_thread(NULL), &tInfo);
 
668
 
 
669
        /* initialize new PRThread */
 
670
        thread->md.tid = tInfo.thread;
 
671
        thread->md.joinSem = B_ERROR;
 
672
        thread->priority = _bt_MapNativeToNSPRPriority(tInfo.priority);
 
673
 
 
674
        /* attached threads are always non-joinable user threads */
 
675
        thread->state = 0;
 
676
 
 
677
        /* increment user thread count */
 
678
        PR_Lock(bt_book.ml);
 
679
        bt_book.threadCount++;
 
680
        PR_Unlock(bt_book.ml);
 
681
 
 
682
        /* store this thread's PRThread */
 
683
        tls_set(tls_prThreadSlot, thread);
 
684
        
 
685
        /* the thread must call _bt_CleanupThread() before it dies, in order
 
686
           to clean up its PRThread, synchronize with the primordial thread,
 
687
           etc. */
 
688
        on_exit_thread(_bt_CleanupThread, NULL);
 
689
        
 
690
        return thread;
 
691
}