Back to index

lightning-sunbird  0.9+nobinonly
Classes | Defines | Functions | Variables
btthread.c File Reference
#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>

Go to the source code of this file.

Classes

struct  _BT_Bookeeping

Defines

#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 */
#define BT_TPD_LIMIT   128 /* number of TPD slots we'll provide (arbitrary) */
#define BT_MILLION   1000000UL

Functions

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)
PRUint32 _bt_mapNativeToNSPRPriority (int32 priority)
static void_bt_root (void *arg)
 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.
 PR_CreateThread (PRThreadType type, void(*start)(void *arg), void *arg, PRThreadPriority priority, PRThreadScope scope, PRThreadState state, PRUint32 stackSize)
 PR_AttachThread (PRThreadType type, PRThreadPriority priority, PRThreadStack *stack)
 PR_DetachThread ()
 PR_JoinThread (PRThread *thred)
 PR_GetCurrentThread ()
 PR_GetThreadScope (const PRThread *thred)
 PR_GetThreadType (const PRThread *thred)
 PR_GetThreadState (const PRThread *thred)
 PR_GetThreadPriority (const PRThread *thred)
 PR_IMPLEMENT (void)
 PR_NewThreadPrivateIndex (PRUintn *newIndex, PRThreadPrivateDTOR destructor)
 PR_SetThreadPrivate (PRUintn index, void *priv)
 PR_GetThreadPrivate (PRUintn index)
 PR_Interrupt (PRThread *thred)
 PR_ClearInterrupt ()
 PR_Yield ()
 PR_Sleep (PRIntervalTime ticks)
 PR_Cleanup ()
 PR_ProcessExit (PRIntn status)

Variables

struct _BT_Bookeeping bt_book
static int32 tpd_beosTLSSlots [BT_TPD_LIMIT]
static PRThreadPrivateDTOR tpd_dtors [BT_TPD_LIMIT]
static vint32 tpd_slotsUsed = 0
static int32 tls_prThreadSlot
static PRLockjoinSemLock

Class Documentation

struct _BT_Bookeeping

Definition at line 55 of file btthread.c.

Collaboration diagram for _BT_Bookeeping:
Class Members
sem_id cleanUpSem
PRLock * ml
PRInt32 threadCount

Define Documentation

#define BT_MILLION   1000000UL

Definition at line 599 of file btthread.c.

#define BT_THREAD_JOINABLE   0x04 /* this is a joinable thread */

Definition at line 53 of file btthread.c.

#define BT_THREAD_PRIMORD   0x01 /* this is the primordial thread */

Definition at line 51 of file btthread.c.

#define BT_THREAD_SYSTEM   0x02 /* this is a system thread */

Definition at line 52 of file btthread.c.

#define BT_TPD_LIMIT   128 /* number of TPD slots we'll provide (arbitrary) */

Definition at line 65 of file btthread.c.


Function Documentation

PRThread * _bt_AttachThread ( ) [static]

Definition at line 653 of file btthread.c.

{
       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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void _bt_CleanupThread ( void arg) [static]

Definition at line 197 of file btthread.c.

{
       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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 172 of file btthread.c.

    {
       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;
}

Here is the caller graph for this function:

Definition at line 184 of file btthread.c.

{
    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 );
    }
}

Definition at line 159 of file btthread.c.

    {
    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 );
    }
}

Here is the caller graph for this function:

static void* _bt_root ( void arg) [static]

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.

Definition at line 270 of file btthread.c.

       {
    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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void _PR_InitThreads ( PRThreadType  type,
PRThreadPriority  priority,
PRUintn  maxPTDs 
)

Definition at line 91 of file btthread.c.

{
    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;
    }
}

Here is the call graph for this function:

PR_AttachThread ( PRThreadType  type,
PRThreadPriority  priority,
PRThreadStack stack 
)

Definition at line 349 of file btthread.c.

{
       /* PR_GetCurrentThread() will attach a thread if necessary */
       return PR_GetCurrentThread();
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 619 of file btthread.c.

{
    PRThread *me = PR_CurrentThread();

    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;
}

Here is the caller graph for this function:

Definition at line 587 of file btthread.c.

{
}

Here is the caller graph for this function:

PR_CreateThread ( PRThreadType  type,
void(*)(void *arg start,
void arg,
PRThreadPriority  priority,
PRThreadScope  scope,
PRThreadState  state,
PRUint32  stackSize 
)

Definition at line 290 of file btthread.c.

{
    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;
    }

Here is the call graph for this function:

Definition at line 357 of file btthread.c.

{
       /* we don't support detaching */
}

Here is the caller graph for this function:

Definition at line 418 of file btthread.c.

{
    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;
}

Here is the call graph for this function:

Definition at line 460 of file btthread.c.

{
    PR_ASSERT(thred != NULL);
    return thred->priority;
}  /* PR_GetThreadPriority */

Here is the caller graph for this function:

PR_GetThreadPrivate ( PRUintn  index)

Definition at line 536 of file btthread.c.

{
       /* 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] );
       }

Here is the caller graph for this function:

Definition at line 437 of file btthread.c.

{
    PR_ASSERT(thred != NULL);
    return PR_GLOBAL_THREAD;
}

Here is the caller graph for this function:

Definition at line 452 of file btthread.c.

Here is the caller graph for this function:

Definition at line 444 of file btthread.c.

{
    PR_ASSERT(thred != NULL);
    return (thred->state & BT_THREAD_SYSTEM) ?
        PR_SYSTEM_THREAD : PR_USER_THREAD;
}

Definition at line 466 of file btthread.c.

{
    PRUint32 bePriority;

    PR_ASSERT( thred != NULL );

    thred->priority = newPri;
    bePriority = _bt_MapNSPRToNativePriority( newPri );
    set_thread_priority( thred->md.tid, bePriority );
}

Here is the call graph for this function:

PR_Interrupt ( PRThread thred)

Definition at line 551 of file btthread.c.

{
    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;
}

Here is the caller graph for this function:

PR_JoinThread ( PRThread thred)

Definition at line 363 of file btthread.c.

{
    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_NewThreadPrivateIndex ( PRUintn *  newIndex,
PRThreadPrivateDTOR  destructor 
)

Definition at line 479 of file btthread.c.

{
       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 );
}

Here is the call graph for this function:

Here is the caller graph for this function:

PR_ProcessExit ( PRIntn  status)

Definition at line 648 of file btthread.c.

{
    exit(status);
}

Here is the call graph for this function:

Here is the caller graph for this function:

PR_SetThreadPrivate ( PRUintn  index,
void priv 
)

Definition at line 509 of file btthread.c.

{
       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 );
       }

Here is the caller graph for this function:

Definition at line 602 of file btthread.c.

{
    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;
}

Here is the call graph for this function:

PR_Yield ( )

Definition at line 592 of file btthread.c.

{
    /* we just sleep for long enough to cause a reschedule (100
       microseconds) */
    snooze(100);
}

Here is the caller graph for this function:


Variable Documentation

PRLock* joinSemLock [static]

Definition at line 83 of file btthread.c.

Definition at line 75 of file btthread.c.

Definition at line 71 of file btthread.c.

Definition at line 72 of file btthread.c.

vint32 tpd_slotsUsed = 0 [static]

Definition at line 74 of file btthread.c.