Esempio n. 1
0
void Logger::logError(LogLevel level, char *fmt, ...)
{
    if (level == LOGPASS)
        _pass++;
    if (level == LOGFAILURE)
        _fail++;
    if (level == LOGWARNING)
        _warning++;

    if (level <= _logLevel)
    {
        char buf[1024];
        va_list args;

        va_start(args, fmt);
        vsprintf(buf, fmt, args);
        va_end(args);

        char *module = logLevelStr[level];
        char *threadName = (char *)PR_GetThreadPrivate(_threadNameKey);

        PR_Lock(_logLock);
        if (threadName)
            fprintf(stdout, "%s: (%s) %s\n", module, threadName, buf);
        else
            fprintf(stdout, "%s: %s\n", module, buf);
        PR_Unlock(_logLock);
    };
};
// Asuming we have a valid thread state, release the Python lock.
void PyXPCOM_InterpreterLock_Release()
{
	ThreadData *pData = (ThreadData *)PR_GetThreadPrivate(tlsIndex);
	NS_ABORT_IF_FALSE(pData, "Have no thread data for this thread!");
	PyThreadState *thisThreadState = pData->ts;
	PyEval_ReleaseThread(thisThreadState);
}
Esempio n. 3
0
// static 
void Mark(PRUint32 aType, void * aItem, const char * aText, const char * aText2)
{
#ifdef MOZ_VISUAL_EVENT_TRACER
  if (!gInitialized)
    return;

  if (aType == eNone)
    return;

  if (!CheckEventFilters(aType, aItem, aText)) // Events use just aText
    return;

  RecordBatch * threadLogPrivate = static_cast<RecordBatch *>(
      PR_GetThreadPrivate(gThreadPrivateIndex));
  if (!threadLogPrivate) {
    // Deletion is made by the flushing thread
    threadLogPrivate = new RecordBatch();
    PR_SetThreadPrivate(gThreadPrivateIndex, threadLogPrivate);
  }

  Record * record = threadLogPrivate->mNextRecord;
  record->mType = aType;
  record->mTime = (mozilla::TimeStamp::Now() - gProfilerStart).ToMilliseconds();
  record->mItem = aItem;
  record->mText = PL_strdup(aText);
  record->mText2 = aText2 ? PL_strdup(aText2) : nsnull;

  ++threadLogPrivate->mNextRecord;
  if (threadLogPrivate->mNextRecord == threadLogPrivate->mRecordsTail) {
    // This calls RecordBatch::FlushBatch(threadLogPrivate)
    PR_SetThreadPrivate(gThreadPrivateIndex, nsnull);
  }
#endif
}
Esempio n. 4
0
static TimelineThreadData *GetThisThreadData()
{
    NS_ABORT_IF_FALSE(gTLSIndex!=BAD_TLS_INDEX, "Our TLS not initialized");
    TimelineThreadData *new_data = nsnull;
    TimelineThreadData *data = (TimelineThreadData *)PR_GetThreadPrivate(gTLSIndex);
    if (data == nsnull) {
        // First request for this thread - allocate it.
        new_data = new TimelineThreadData();
        if (!new_data)
            goto done;

        // Fill it
        new_data->timers = PL_NewHashTable(100, PL_HashString, PL_CompareStrings,
                                 PL_CompareValues, NULL, NULL);
        if (new_data->timers==NULL)
            goto done;
        new_data->initTime = PR_Now();
        NS_WARN_IF_FALSE(!gTimelineDisabled,
                         "Why are we creating new state when disabled?");
        new_data->disabled = PR_FALSE;
        data = new_data;
        new_data = nsnull;
        PR_SetThreadPrivate(gTLSIndex, data);
    }
done:
    if (new_data) // eeek - error during creation!
        delete new_data;
    NS_WARN_IF_FALSE(data, "TimelineService could not get thread-local data");
    return data;
}
Esempio n. 5
0
/*
 * Get current thread-local JSThread info, creating one if it doesn't exist.
 * Each thread has a unique JSThread pointer.
 *
 * Since we are dealing with thread-local data, no lock is needed.
 *
 * Return a pointer to the thread local info, NULL if the system runs out
 * of memory, or it failed to set thread private data (neither case is very
 * likely; both are probably due to out-of-memory).  It is up to the caller
 * to report an error, if possible.
 */
JSThread *
js_GetCurrentThread(JSRuntime *rt)
{
    JSThread *thread;

    thread = (JSThread *)PR_GetThreadPrivate(threadTPIndex);
    if (!thread) {
        thread = (JSThread *) calloc(1, sizeof(JSThread));
        if (!thread)
            return NULL;

        if (PR_FAILURE == PR_SetThreadPrivate(threadTPIndex, thread)) {
            free(thread);
            return NULL;
        }

        JS_INIT_CLIST(&thread->contextList);
        thread->id = js_CurrentThreadId();

        /* js_SetContextThread initialize gcFreeLists as necessary. */
#ifdef DEBUG
        memset(thread->gcFreeLists, JS_FREE_PATTERN,
               sizeof(thread->gcFreeLists));
#endif
    }
    return thread;
}
Esempio n. 6
0
// static
XPCPerThreadData*
XPCPerThreadData::GetDataImpl(JSContext *cx)
{
    XPCPerThreadData* data;

    if(!gLock)
    {
        gLock = PR_NewLock();
        if(!gLock)
            return nsnull;
    }

    if(gTLSIndex == BAD_TLS_INDEX)
    {
        nsAutoLock lock(gLock);
        // check again now that we have the lock...
        if(gTLSIndex == BAD_TLS_INDEX)
        {
            if(PR_FAILURE ==
               PR_NewThreadPrivateIndex(&gTLSIndex, xpc_ThreadDataDtorCB))
            {
                NS_ERROR("PR_NewThreadPrivateIndex failed!");
                gTLSIndex = BAD_TLS_INDEX;
                return nsnull;
            }
        }
    }

    data = (XPCPerThreadData*) PR_GetThreadPrivate(gTLSIndex);
    if(!data)
    {
        data = new XPCPerThreadData();
        if(!data || !data->IsValid())
        {
            NS_ERROR("new XPCPerThreadData() failed!");
            if(data)
                delete data;
            return nsnull;
        }
        if(PR_FAILURE == PR_SetThreadPrivate(gTLSIndex, data))
        {
            NS_ERROR("PR_SetThreadPrivate failed!");
            delete data;
            return nsnull;
        }
    }

    if(cx && !sMainJSThread && NS_IsMainThread())
    {
        sMainJSThread = cx->thread;

        sMainThreadData = data;

        sMainThreadData->mThread = PR_GetCurrentThread();
    }

    return data;
}
// Free the thread state for the current thread
// (Presumably previously create with a call to
// PyXPCOM_ThreadState_Ensure)
void PyXPCOM_ThreadState_Free()
{
	ThreadData *pData = (ThreadData *)PR_GetThreadPrivate(tlsIndex);
	if (!pData) return;
	PyThreadState *thisThreadState = pData->ts;
	PyThreadState_Delete(thisThreadState);
	PR_SetThreadPrivate(tlsIndex, NULL);
	nsMemory::Free(pData);
}
Esempio n. 8
0
nsAutoLockBase::nsAutoLockBase(void* addr, nsAutoLockType type)
{
    if (LockStackTPI == PRUintn(-1))
        InitAutoLockStatics();

    nsAutoLockBase* stackTop =
        (nsAutoLockBase*) PR_GetThreadPrivate(LockStackTPI);
    if (stackTop) {
        if (stackTop->mAddr == addr) {
            // Ignore reentry: it's legal for monitors, and NSPR will assert
            // if you reenter a PRLock.
        } else if (!addr) {
            // Ignore null addresses: the caller promises not to use the
            // lock at all, and NSPR will assert if you enter it.
        } else {
            const void* node =
#ifdef NS_TRACE_MALLOC_XXX
                NS_GetStackTrace(1)
#else
                nsnull
#endif
                ;
            nsNamedVector* vec1;
            nsNamedVector* vec2;
            PRUint32 i2;

            if (!WellOrdered(stackTop->mAddr, addr, node, &i2, &vec1, &vec2)) {
                char buf[128];
                PR_snprintf(buf, sizeof buf,
                            "Potential deadlock between %s%s@%p and %s%s@%p",
                            vec1->mName ? vec1->mName : "",
                            LockTypeNames[stackTop->mType],
                            stackTop->mAddr,
                            vec2->mName ? vec2->mName : "",
                            LockTypeNames[type],
                            addr);
#ifdef NS_TRACE_MALLOC_XXX
                fprintf(stderr, "\n*** %s\n\nCurrent stack:\n", buf);
                NS_DumpStackTrace(node, stderr);

                fputs("\nPrevious stack:\n", stderr);
                NS_DumpStackTrace(vec2->mInnerSites.ElementAt(i2), stderr);
                putc('\n', stderr);
#endif
                NS_ERROR(buf);
            }
        }
    }

    mAddr = addr;
    mDown = stackTop;
    mType = type;
    if (mAddr)
        (void) PR_SetThreadPrivate(LockStackTPI, this);
}
Esempio n. 9
0
static void
AssertActivityIsLegal()
{
  if (gActivityTLS == BAD_TLS_INDEX || PR_GetThreadPrivate(gActivityTLS)) {
    if (PR_GetEnv("MOZ_FATAL_STATIC_XPCOM_CTORS_DTORS")) {
      NS_RUNTIMEABORT(kStaticCtorDtorWarning);
    } else {
      NS_WARNING(kStaticCtorDtorWarning);
    }
  }
}
Esempio n. 10
0
//------------------------------------------------------------------------- 
// 
// Return the nsIToolkit for the current thread.  If a toolkit does not 
// yet exist, then one will be created... 
// 
//------------------------------------------------------------------------- 
NS_METHOD NS_GetCurrentToolkit(nsIToolkit* *aResult) 
{ 
  nsIToolkit* toolkit = nsnull; 
  nsresult rv = NS_OK; 
  PRStatus status; 
#ifdef DEBUG
  printf("TK-GetCTK\n");
#endif
  // Create the TLS index the first time through... 
  if (0 == gToolkitTLSIndex)  
  { 
    status = PR_NewThreadPrivateIndex(&gToolkitTLSIndex, NULL); 
    if (PR_FAILURE == status) 
    { 
      rv = NS_ERROR_FAILURE; 
    } 
  } 

  if (NS_SUCCEEDED(rv)) 
  { 
    toolkit = (nsIToolkit*)PR_GetThreadPrivate(gToolkitTLSIndex); 

    // 
    // Create a new toolkit for this thread... 
    // 
    if (!toolkit) 
    { 
      toolkit = new nsToolkit(); 

      if (!toolkit) 
      { 
        rv = NS_ERROR_OUT_OF_MEMORY; 
      } 
      else 
      { 
        NS_ADDREF(toolkit); 
        toolkit->Init(PR_GetCurrentThread()); 
        // 
        // The reference stored in the TLS is weak.  It is removed in the 
        // nsToolkit destructor... 
        // 
        PR_SetThreadPrivate(gToolkitTLSIndex, (void*)toolkit); 
      } 
    } 
    else 
    { 
      NS_ADDREF(toolkit); 
    } 
    *aResult = toolkit; 
  } 

  return rv; 
} 
Esempio n. 11
0
void nsAutoCMonitor::Enter()
{
#ifdef DEBUG
    nsAutoLockBase* stackTop =
        (nsAutoLockBase*) PR_GetThreadPrivate(LockStackTPI);
    NS_ASSERTION(stackTop == mDown, "non-LIFO nsAutoCMonitor::Enter");
    mDown = stackTop;
    (void) PR_SetThreadPrivate(LockStackTPI, this);
#endif
    PR_CEnterMonitor(mLockObject);
    mLockCount += 1;
}
Esempio n. 12
0
void nsAutoLockBase::Hide()
{
    if (!mAddr)
        return;
    nsAutoLockBase* curr = (nsAutoLockBase*) PR_GetThreadPrivate(LockStackTPI);
    nsAutoLockBase* prev = nsnull;
    while (curr != this) {
        prev = curr;
        curr = prev->mDown;
    }
    if (!prev)
        PR_SetThreadPrivate(LockStackTPI, mDown);
    else
        prev->mDown = mDown;
}
Esempio n. 13
0
/*
 * mempool_destroy is a callback which is set to NSPR ThreadPrivateIndex
 */
static void 
mempool_destroy()
{
	int i = 0;
	struct mempool *my_mempool;
#ifdef SHARED_MEMPOOL
	for (i = 0; MEMPOOL_END != mempool[i].mempool_name; i++) {
		struct mempool_object *object = NULL;
		if (NULL == mempool[i].mempool_mutex) {
			/* mutex is NULL; this mempool is not enabled */
			continue;
		}
		object = mempool[i].mempool_head;
		mempool[i].mempool_head = NULL;
		while (NULL != object) {
			struct mempool_object *next = object->mempool_next;
			if (NULL != mempool[i].mempool_cleanup_fn) {
				(mempool[i].mempool_cleanup_fn)((void *)object);
			}
			slapi_ch_free((void **)&object);
			object = next;
		}
		PR_DestroyLock(mempool[i].mempool_mutex);
		mempool[i].mempool_mutex = NULL;
	}
#else
	my_mempool = (struct mempool *)PR_GetThreadPrivate(mempool_index);
	if (NULL == my_mempool || my_mempool[0].mempool_name != mempool_names[0]) {
		/* mempool is not initialized */
		return;
	}
	for (i = 0; i < MAX_MEMPOOL; i++) {
		struct mempool_object *object = my_mempool[i].mempool_head;
		while (NULL != object) {
			struct mempool_object *next = object->mempool_next;
			if (NULL != my_mempool[i].mempool_cleanup_fn) {
				(my_mempool[i].mempool_cleanup_fn)((void *)object);
			}
			slapi_ch_free((void **)&object);
			object = next;
		}
		my_mempool[i].mempool_head = NULL;
		my_mempool[i].mempool_count = 0;
	}
	slapi_ch_free((void **)&my_mempool);
	PR_SetThreadPrivate (mempool_index, (void *)NULL);
#endif
}
Esempio n. 14
0
nsAutoUnlockBase::nsAutoUnlockBase(void* addr)
{
    if (addr)
    {
        nsAutoLockBase* curr = (nsAutoLockBase*) PR_GetThreadPrivate(LockStackTPI);
        while (curr && curr->mAddr != addr)
            curr = curr->mDown;

        mLock = curr;
    }
    else
        mLock = nsnull;

    if (mLock)
        mLock->Hide();
}
Esempio n. 15
0
void nsAutoMonitor::Enter()
{
#ifdef DEBUG
    if (!mAddr) {
        NS_ERROR("It is not legal to enter a null monitor");
        return;
    }
    nsAutoLockBase* stackTop =
        (nsAutoLockBase*) PR_GetThreadPrivate(LockStackTPI);
    NS_ASSERTION(stackTop == mDown, "non-LIFO nsAutoMonitor::Enter");
    mDown = stackTop;
    (void) PR_SetThreadPrivate(LockStackTPI, this);
#endif
    PR_EnterMonitor(mMonitor);
    mLockCount += 1;
}
Esempio n. 16
0
/* readonly attribute nsIExceptionManager currentExceptionManager; */
NS_IMETHODIMP nsExceptionService::GetCurrentExceptionManager(nsIExceptionManager * *aCurrentScriptManager)
{
    CHECK_SERVICE_USE_OK();
    nsExceptionManager *mgr = (nsExceptionManager *)PR_GetThreadPrivate(tlsIndex);
    if (mgr == nsnull) {
        // Stick the new exception object in with no reference count.
        mgr = new nsExceptionManager(this);
        if (mgr == nsnull)
            return NS_ERROR_OUT_OF_MEMORY;
        PR_SetThreadPrivate(tlsIndex, mgr);
        // The reference count is held in the thread-list
        AddThread(mgr);
    }
    *aCurrentScriptManager = mgr;
    NS_ADDREF(*aCurrentScriptManager);
    return NS_OK;
}
Esempio n. 17
0
/*
 * Function: prldap_get_thread_private()
 * Description: retrieve a piece of thread-private data.  If not set,
 *	NULL is returned.
 * Returns: 0 if successful and -1 if not.
 */
static void *
prldap_get_thread_private( PRInt32 tpdindex )
{
    PRLDAP_TPDHeader	*tsdhdr;

    tsdhdr = (PRLDAP_TPDHeader *)PR_GetThreadPrivate( prldap_tpdindex );
    if ( tsdhdr == NULL ) {
	return( NULL );	/* no thread private data */
    }

    if ( tpdindex >= tsdhdr->ptpdh_tpd_count
		|| tsdhdr->ptpdh_dataitems == NULL ) {
	return( NULL );	/* fewer data items than requested index */
    }

    return( tsdhdr->ptpdh_dataitems[ tpdindex ] );
}
Esempio n. 18
0
/*
 * return memory to memory pool
 * (Callback cleanup function was intented to release nested memory in the 
 *  memory area.  Initially, memory had its structure which could point
 *  other memory area.  But the current code (#else) expects no structure.
 *  Thus, the cleanup callback is not needed)
 *  The current code (#else) uses the memory pool stored in the 
 *  per-thread-private data.
 */
int
mempool_return(int type, void *object, mempool_cleanup_callback cleanup)
{
	PR_ASSERT(type >= 0 && type < MEMPOOL_END);

	if (!config_get_mempool_switch()) {
		return LDAP_SUCCESS;	/* memory pool: off */
	}
#ifdef SHARED_MEMPOOL
	if (NULL == mempool[type].mempool_mutex) {
		/* mutex is NULL; this mempool is not enabled */
		return LDAP_SUCCESS;
	}
	PR_Lock(mempool[type].mempool_mutex);
	((struct mempool_object *)object)->mempool_next = mempool[type].mempool_head;
	mempool[type].mempool_head = (struct mempool_object *)object;
	mempool[type].mempool_cleanup_fn = cleanup;
	mempool[type].mempool_count++;
	PR_Unlock(mempool[type].mempool_mutex);
	return LDAP_SUCCESS;
#else
	{
	struct mempool *my_mempool;
	int maxfreelist;
	my_mempool = (struct mempool *)PR_GetThreadPrivate(mempool_index);
	if (NULL == my_mempool || my_mempool[0].mempool_name != mempool_names[0]) {
		/* mempool is not initialized */
		mempool_init(&my_mempool);
	} 
	((struct mempool_object *)object)->mempool_next = my_mempool[type].mempool_head;
	maxfreelist = config_get_mempool_maxfreelist();
	if ((maxfreelist > 0) && (my_mempool[type].mempool_count > maxfreelist)) {
		return LDAP_UNWILLING_TO_PERFORM;
	} else {
		((struct mempool_object *)object)->mempool_next = mempool[type].mempool_head;
		my_mempool[type].mempool_head = (struct mempool_object *)object;
		my_mempool[type].mempool_cleanup_fn = cleanup;
		my_mempool[type].mempool_count++;
		PR_SetThreadPrivate (mempool_index, (void *)my_mempool);
		return LDAP_SUCCESS;
	}
	}
#endif
}
Esempio n. 19
0
static error_stack *
error_get_my_stack ( void)
{
  PRStatus st;
  error_stack *rv;
  PRUintn new_size;
  PRUint32 new_bytes;
  error_stack *new_stack;

  if( INVALID_TPD_INDEX == error_stack_index ) {
    st = PR_CallOnce(&error_call_once, error_once_function);
    if( PR_SUCCESS != st ) {
      return (error_stack *)NULL;
    }
  }

  rv = (error_stack *)PR_GetThreadPrivate(error_stack_index);
  if( (error_stack *)NULL == rv ) {
    /* Doesn't exist; create one */
    new_size = 16;
  } else if( rv->header.count == rv->header.space  &&
             rv->header.count  < NSS_MAX_ERROR_STACK_COUNT ) {
    /* Too small, expand it */
    new_size = PR_MIN( rv->header.space * 2, NSS_MAX_ERROR_STACK_COUNT);
  } else {
    /* Okay, return it */
    return rv;
  }

  new_bytes = (new_size * sizeof(PRInt32)) + sizeof(error_stack);
  /* Use NSPR's calloc/realloc, not NSS's, to avoid loops! */
  new_stack = PR_Calloc(1, new_bytes);
  
  if( (error_stack *)NULL != new_stack ) {
    if( (error_stack *)NULL != rv ) {
	(void)nsslibc_memcpy(new_stack,rv,rv->header.space);
    }
    new_stack->header.space = new_size;
  }

  /* Set the value, whether or not the allocation worked */
  PR_SetThreadPrivate(error_stack_index, new_stack);
  return new_stack;
}
Esempio n. 20
0
nsThread *
nsThreadManager::GetCurrentThread()
{
  // read thread local storage
  void *data = PR_GetThreadPrivate(mCurThreadIndex);
  if (data)
    return static_cast<nsThread *>(data);

  if (!mInitialized) {
    return nsnull;
  }

  // OK, that's fine.  We'll dynamically create one :-)
  nsRefPtr<nsThread> thread = new nsThread();
  if (!thread || NS_FAILED(thread->InitCurrentThread()))
    return nsnull;

  return thread.get();  // reference held in TLS
}
Esempio n. 21
0
/*
 * Function: prldap_set_thread_private()
 * Description: store a piece of thread-private data.
 * Returns: 0 if successful and -1 if not.
 */
static int
prldap_set_thread_private( PRInt32 tpdindex, void *priv )
{
    PRLDAP_TPDHeader	*tsdhdr;

    if ( tpdindex > prldap_tpd_maxindex ) {
	return( -1 );	/* bad index */ 
    }

    tsdhdr = (PRLDAP_TPDHeader *)PR_GetThreadPrivate( prldap_tpdindex );
    if ( tsdhdr == NULL || tpdindex >= tsdhdr->ptpdh_tpd_count ) {
	tsdhdr = prldap_tsd_realloc( tsdhdr, tpdindex );
	if ( tsdhdr == NULL ) {
	    return( -1 );	/* realloc failed */
	}
    }

    tsdhdr->ptpdh_dataitems[ tpdindex ] = priv;
    return( 0 );
}
// Ensure that we have a Python thread state available to use.
// If this is called for the first time on a thread, it will allocate
// the thread state.  This does NOT change the state of the Python lock.
// Returns TRUE if a new thread state was created, or FALSE if a
// thread state already existed.
PRBool PyXPCOM_ThreadState_Ensure()
{
	ThreadData *pData = (ThreadData *)PR_GetThreadPrivate(tlsIndex);
	if (pData==NULL) { /* First request on this thread */
		/* Check we have an interpreter state */
		if (PyXPCOM_InterpreterState==NULL) {
				Py_FatalError("Can not setup thread state, as have no interpreter state");
		}
		pData = (ThreadData *)nsMemory::Alloc(sizeof(ThreadData));
		if (!pData)
			Py_FatalError("Out of memory allocating thread state.");
		memset(pData, 0, sizeof(*pData));
		if (NS_FAILED( PR_SetThreadPrivate( tlsIndex, pData ) ) ) {
			NS_ABORT_IF_FALSE(0, "Could not create thread data for this thread!");
			Py_FatalError("Could not thread private thread data!");
		}
		pData->ts = PyThreadState_New(PyXPCOM_InterpreterState);
		return PR_TRUE; // Did create a thread state state
	}
	return PR_FALSE; // Thread state was previously created
}
Esempio n. 23
0
/*
 * get memory from memory pool
 *  The current code (#else) uses the memory pool stored in the 
 *  per-thread-private data.
 */
void *
mempool_get(int type)
{
	struct mempool_object *object = NULL;
	struct mempool *my_mempool;
	PR_ASSERT(type >= 0 && type < MEMPOOL_END);

	if (!config_get_mempool_switch()) {
		return NULL;	/* memory pool: off */
	}
#ifdef SHARED_MEMPOOL
	if (NULL == mempool[type].mempool_mutex) {
		/* mutex is NULL; this mempool is not enabled */
		return NULL;
	}

	PR_Lock(mempool[type].mempool_mutex);
	object = mempool[type].mempool_head;
	if (NULL != object) {
		mempool[type].mempool_head = object->mempool_next;
		mempool[type].mempool_count--;
		object->mempool_next = NULL;
	}
	PR_Unlock(mempool[type].mempool_mutex);
#else
	my_mempool = (struct mempool *)PR_GetThreadPrivate(mempool_index);
	if (NULL == my_mempool || my_mempool[0].mempool_name != mempool_names[0]) {	/* mempool is not initialized */
		return NULL;
	} 

	object = my_mempool[type].mempool_head;
	if (NULL != object) {
		my_mempool[type].mempool_head = object->mempool_next;
		my_mempool[type].mempool_count--;
		object->mempool_next = NULL;
		PR_SetThreadPrivate (mempool_index, (void *)my_mempool);
	}
#endif
	return object;
}
Esempio n. 24
0
/*
 * Get current thread-local JSThread info, creating one if it doesn't exist.
 * Each thread has a unique JSThread pointer.
 *
 * Since we are dealing with thread-local data, no lock is needed.
 *
 * Return a pointer to the thread local info, NULL if the system runs out
 * of memory, or it failed to set thread private data (neither case is very
 * likely; both are probably due to out-of-memory).  It is up to the caller
 * to report an error, if possible.
 */
JSThread *
js_GetCurrentThread(JSRuntime *rt)
{
    JSThread *thread;

    thread = (JSThread *)PR_GetThreadPrivate(rt->threadTPIndex);
    if (!thread) {
        /* New memory is set to 0 so that elements in gcFreeLists are NULL. */
        thread = (JSThread *) calloc(1, sizeof(JSThread));
        if (!thread)
            return NULL;

        if (PR_FAILURE == PR_SetThreadPrivate(rt->threadTPIndex, thread)) {
            free(thread);
            return NULL;
        }

        JS_INIT_CLIST(&thread->contextList);
        thread->id = js_CurrentThreadId();
    }
    return thread;
}
static inline SessionThreadData *find_thread_data(Session *sn)
{
    NSAPISession *nsn = (NSAPISession *)sn;

    if (nsn && nsn->thread_data)
        return nsn->thread_data;

    HttpRequest *hrq = HttpRequest::CurrentRequest();
    if (hrq) {
        DaemonSession &dsn = hrq->GetDaemonSession();
        if (nsn)
            nsn->thread_data = &dsn.thread_data;
        return &dsn.thread_data;
    }

    // We're being called from a non-DaemonSession thread
    void *data = PR_GetThreadPrivate(_session_thread_key);
    if (!data) {
        data = PERM_CALLOC(sizeof(SessionThreadData));
        PR_SetThreadPrivate(_session_thread_key, data);
    }

    return (SessionThreadData *)data;
}
static PRIntn PR_CALLBACK Tpd(PRIntn argc, char **argv)
{
    void *pd;
    PRStatus rv;
    PRUintn keys;
    PRThread *thread;
    char *key_string[] = {
        "Key #0", "Key #1", "Key #2", "Key #3",
        "Bogus #5", "Bogus #6", "Bogus #7", "Bogus #8"};
    
    fout = PR_STDOUT;

    did = should = PR_FALSE;
    for (keys = 0; keys < 4; ++keys)
    {
        rv = PR_NewThreadPrivateIndex(&key[keys], Destructor);
        MY_ASSERT(PR_SUCCESS == rv);
    }
    PrintProgress(__LINE__);

    did = should = PR_FALSE;
    for (keys = 0; keys < 8; ++keys)
    {
        pd = PR_GetThreadPrivate(key[keys]);
        MY_ASSERT(NULL == pd);
    }
    PrintProgress(__LINE__);

    did = should = PR_FALSE;
    for (keys = 0; keys < 4; ++keys)
    {
        rv = PR_SetThreadPrivate(key[keys], key_string[keys]);
        MY_ASSERT(PR_SUCCESS == rv);
    }
    PrintProgress(__LINE__);

    for (keys = 4; keys < 8; ++keys)
		key[keys] = 4096;		/* set to invalid value */
    did = should = PR_FALSE;
    for (keys = 4; keys < 8; ++keys)
    {
        rv = PR_SetThreadPrivate(key[keys], key_string[keys]);
        MY_ASSERT(PR_FAILURE == rv);
    }
    PrintProgress(__LINE__);
    
    did = PR_FALSE; should = PR_TRUE;
    for (keys = 0; keys < 4; ++keys)
    {
        rv = PR_SetThreadPrivate(key[keys], key_string[keys]);
        MY_ASSERT(PR_SUCCESS == rv);
    }
    PrintProgress(__LINE__);

    did = PR_FALSE; should = PR_TRUE;
    for (keys = 0; keys < 4; ++keys)
    {
        rv = PR_SetThreadPrivate(key[keys], NULL);
        MY_ASSERT(PR_SUCCESS == rv);
    }
    PrintProgress(__LINE__);

    did = should = PR_FALSE;
    for (keys = 0; keys < 4; ++keys)
    {
        rv = PR_SetThreadPrivate(key[keys], NULL);
        MY_ASSERT(PR_SUCCESS == rv);
    }
    PrintProgress(__LINE__);

    did = should = PR_FALSE;
    for (keys = 8; keys < 127; ++keys)
    {
        rv = PR_NewThreadPrivateIndex(&key[keys], Destructor);
        MY_ASSERT(PR_SUCCESS == rv);
        rv = PR_SetThreadPrivate(key[keys], "EXTENSION");
        MY_ASSERT(PR_SUCCESS == rv);
    }
    PrintProgress(__LINE__);

    did = PR_FALSE; should = PR_TRUE;
    for (keys = 8; keys < 127; ++keys)
    {
        rv = PR_SetThreadPrivate(key[keys], NULL);
        MY_ASSERT(PR_SUCCESS == rv);
    }
    PrintProgress(__LINE__);

    did = should = PR_FALSE;
    for (keys = 8; keys < 127; ++keys)
    {
        rv = PR_SetThreadPrivate(key[keys], NULL);
        MY_ASSERT(PR_SUCCESS == rv);
    }

    thread = PR_CreateThread(
        PR_USER_THREAD, Thread, NULL, PR_PRIORITY_NORMAL,
        PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);

    (void)PR_JoinThread(thread);

    PrintProgress(__LINE__);

#if defined(WIN16)
    printf(
        "%s\n",((PR_TRUE == failed) ? "FAILED" : "PASSED"));
#else
    (void)PR_fprintf(
        fout, "%s\n",((PR_TRUE == failed) ? "FAILED" : "PASSED"));
#endif    

    return 0;

}  /* Tpd */
static void PR_CALLBACK Thread(void *null)
{
    void *pd;
    PRStatus rv;
    PRUintn keys;
    char *key_string[] = {
        "Key #0", "Key #1", "Key #2", "Key #3",
        "Bogus #5", "Bogus #6", "Bogus #7", "Bogus #8"};
    
    did = should = PR_FALSE;
    for (keys = 0; keys < 8; ++keys)
    {
        pd = PR_GetThreadPrivate(key[keys]);
        MY_ASSERT(NULL == pd);
    }
    PrintProgress(__LINE__);

    did = should = PR_FALSE;
    for (keys = 0; keys < 4; ++keys)
    {
        rv = PR_SetThreadPrivate(key[keys], key_string[keys]);
        MY_ASSERT(PR_SUCCESS == rv);
    }
    PrintProgress(__LINE__);

    did = should = PR_FALSE;
    for (keys = 4; keys < 8; ++keys)
    {
        rv = PR_SetThreadPrivate(key[keys], key_string[keys]);
        MY_ASSERT(PR_FAILURE == rv);
    }
    PrintProgress(__LINE__);
    
    did = PR_FALSE; should = PR_TRUE;
    for (keys = 0; keys < 4; ++keys)
    {
        rv = PR_SetThreadPrivate(key[keys], key_string[keys]);
        MY_ASSERT(PR_SUCCESS == rv);
    }
    PrintProgress(__LINE__);

    did = PR_FALSE; should = PR_TRUE;
    for (keys = 0; keys < 4; ++keys)
    {
        rv = PR_SetThreadPrivate(key[keys], NULL);
        MY_ASSERT(PR_SUCCESS == rv);
    }
    PrintProgress(__LINE__);

    did = should = PR_FALSE;
    for (keys = 0; keys < 4; ++keys)
    {
        rv = PR_SetThreadPrivate(key[keys], NULL);
        MY_ASSERT(PR_SUCCESS == rv);
    }
    PrintProgress(__LINE__);

    did = should = PR_FALSE;
    for (keys = 8; keys < 127; ++keys)
    {
        rv = PR_SetThreadPrivate(key[keys], "EXTENSION");
        MY_ASSERT(PR_SUCCESS == rv);
    }
    PrintProgress(__LINE__);

    did = PR_FALSE; should = PR_TRUE;
    for (keys = 8; keys < 127; ++keys)
    {
        rv = PR_SetThreadPrivate(key[keys], NULL);
        MY_ASSERT(PR_SUCCESS == rv);
    }
    PrintProgress(__LINE__);

    did = should = PR_FALSE;
    for (keys = 8; keys < 127; ++keys)
    {
        rv = PR_SetThreadPrivate(key[keys], NULL);
        MY_ASSERT(PR_SUCCESS == rv);
    }

    /* put in keys and leave them there for thread exit */
    did = should = PR_FALSE;
    for (keys = 0; keys < 4; ++keys)
    {
        rv = PR_SetThreadPrivate(key[keys], key_string[keys]);
        MY_ASSERT(PR_SUCCESS == rv);
    }
    PrintProgress(__LINE__);
    did = PR_FALSE; should = PR_TRUE;

}  /* Thread */
void PyXPCOM_ThreadState_Clear()
{
	ThreadData *pData = (ThreadData *)PR_GetThreadPrivate(tlsIndex);
	PyThreadState *thisThreadState = pData->ts;
	PyThreadState_Clear(thisThreadState);
}
NSAPI_PUBLIC void *systhread_getdata(int key)
{
    return PR_GetThreadPrivate(key);
}
RCThreadPrivateData* RCThread::GetPrivateData(PRUintn index)
    { return (RCThreadPrivateData*)PR_GetThreadPrivate(index); }