Applying Mac changes

This commit is contained in:
mwelch%netscape.com 2000-04-28 09:35:09 +00:00
parent 2c79f59ddf
commit 6fa77f4c37
8 changed files with 344 additions and 315 deletions

View File

@ -61,6 +61,7 @@
#include "profile.h"
#include "prefs.h"
#include "ocsp.h"
#ifdef XP_MAC
#include "macshell.h"
#endif
@ -414,9 +415,6 @@ SSMStatus SSMControlConnection_Shutdown(SSMResource *arg, SSMStatus status)
return rv;
}
#ifdef XP_MAC
extern PRBool gShouldQuit;
#endif
SSMStatus SSMControlConnection_Destroy(SSMResource *res,
PRBool doFree)
@ -468,7 +466,7 @@ SSMStatus SSMControlConnection_Destroy(SSMResource *res,
SSM_ReleaseLockFile();
#endif
#ifdef XP_MAC
gShouldQuit = PR_TRUE; // tell primordial thread to quit
SetQuitFlag(PR_TRUE); // tell primordial thread to quit
#else
exit(0);
#endif
@ -824,7 +822,8 @@ ssm_certdb_name_cb(void *arg, int dbVersion)
#ifdef XP_MAC
/* on Mac, :: means parent directory. does non-Mac get // with Seamonkey? */
return PR_smprintf("%sCertificates%s", configdir, dbver);
PR_ASSERT(configdir[strlen(configdir) - 1] == ':');
return PR_smprintf("%sCertificates%s", configdir, dbver);
#else
return PR_smprintf("%s/cert%s.db", configdir, dbver);
#endif
@ -845,7 +844,8 @@ static char *ssm_keydb_name_cb(void *arg, int dbVersion)
break;
}
#ifdef XP_MAC
return PR_smprintf("%s:Key Database%s", configdir, dbver);
PR_ASSERT(configdir[strlen(configdir) - 1] == ':');
return PR_smprintf("%sKey Database%s", configdir, dbver);
#else
return PR_smprintf("%s/key%s.db", configdir, dbver);
#endif
@ -925,7 +925,8 @@ ssm_OpenSecModDB(const char * configdir)
#ifdef XP_UNIX
secmodname = PR_smprintf("%s/secmodule.db", configdir);
#elif defined(XP_MAC)
secmodname = PR_smprintf("%s:Security Modules", configdir);
PR_ASSERT(configdir[strlen(configdir) - 1] == ':');
secmodname = PR_smprintf("%sSecurity Modules", configdir);
#else
secmodname = PR_smprintf("%s/secmod.db", configdir);
#endif
@ -951,26 +952,7 @@ ssm_ShutdownNSS(SSMControlConnection *ctrl)
SSMPolicyType
SSM_ConvertSVRPlcyToSSMPolicy(PRInt32 policy)
{
SSMPolicyType retVal;
switch (policy) {
#ifdef XP_MAC
default:
#endif
case SVRPLCYDomestic:
retVal = ssmDomestic;
break;
case SVRPLCYExport:
retVal = ssmExport;
break;
case SVRPLCYFrance:
retVal = ssmFrance;
break;
#ifndef XP_MAC
default:
retVal = ssmUnknownPolicy;
#endif
}
return retVal;
return ssmDomestic;
}
#endif

View File

@ -44,6 +44,14 @@
/* How many milliseconds to wait for client input */
#define SSM_READCLIENT_POKE_INTERVAL 30000
/* keep track of the number of data connections pending. used to throttle cpu usage */
static int gNumDataConnections = 0;
PRBool AreConnectionsActive(void)
{
return gNumDataConnections > 0;
}
SSMStatus SSMDataConnection_Create(void *arg, SSMControlConnection * connection,
SSMResource **res)
@ -62,6 +70,7 @@ SSMStatus SSMDataConnection_Create(void *arg, SSMControlConnection * connection,
SSMDataConnection_Invariant(conn);
*res = SSMRESOURCE(conn);
return PR_SUCCESS;
loser:
@ -95,8 +104,11 @@ SSMStatus SSMDataConnection_Init(SSMDataConnection *conn,
goto loser;
}
/* Hang our shutdown func. */
SSMCONNECTION(conn)->m_auth_func = SSMDataConnection_Authenticate;
/* keep track of the number of data connections pending. */
gNumDataConnections++;
/* Hang our shutdown func. */
SSMCONNECTION(conn)->m_auth_func = SSMDataConnection_Authenticate;
return PR_SUCCESS;
@ -416,6 +428,10 @@ SSMDataConnection_Shutdown(SSMResource *res, SSMStatus status)
trv = PR_Close(conn->m_clientSocket);
conn->m_clientSocket = NULL;
SSM_DEBUG("Closed client socket (rv == %d).\n",trv);
/* keep track of the number of data connections pending. */
gNumDataConnections--;
PR_ASSERT(gNumDataConnections >= 0);
}
}

View File

@ -83,6 +83,10 @@ typedef struct SSMDataConnection
(usage depends on subclass) */
} SSMDataConnection;
PRBool AreConnectionsActive(void);
SSMStatus SSMDataConnection_Create(void *arg, SSMControlConnection * conn,
SSMResource **res);
SSMStatus SSMDataConnection_Init(SSMDataConnection *conn,

View File

@ -30,8 +30,12 @@
* may use your version of this file under either the MPL or the
* GPL.
*/
#include "TArray.h"
#include "TArrayIterator.h"
//#include "TArray.h"
//#include "TArrayIterator.h"
#include "nsError.h"
#include "nsVoidArray.h"
#include "prthread.h"
#include "prlog.h"
#include "prmem.h"
@ -43,31 +47,75 @@ typedef struct SSMThreadPrivateData
PRUintn indx;
} SSMThreadPrivateData;
TArray<PRThread *>* myThreads = NULL;
PRUintn thdIndex = 0;
static nsVoidArray* gThreadsList = NULL;
static PRUintn gThreadIndex = 0;
#ifdef DEBUG
// just here to satisfy linkage in debug mode. nsTraceRefcnt is a class used for tracking
// memory usage in debug builds. This is fragile, and a hack.
class nsTraceRefcnt
{
static NS_COM void LogCtor(void* aPtr, const char* aTypeName,
PRUint32 aInstanceSize);
static NS_COM void LogDtor(void* aPtr, const char* aTypeName,
PRUint32 aInstanceSize);
};
void nsTraceRefcnt::LogCtor(void* aPtr, const char* aTypeName,
PRUint32 aInstanceSize)
{}
void nsTraceRefcnt::LogDtor(void* aPtr, const char* aTypeName,
PRUint32 aInstanceSize)
{}
#endif
PRUintn GetThreadIndex()
{
return gThreadIndex;
}
void
SSM_MacDelistThread(void *priv)
{
// remove this lump from the list of active threads
myThreads->Remove((PRThread *) priv);
PR_ASSERT(gThreadsList);
PRBool removed = gThreadsList->RemoveElement(priv);
PR_ASSERT(removed);
if (gThreadsList->Count() == 0)
{
delete gThreadsList;
gThreadsList = NULL;
}
}
static PRBool InterruptThreadEnumerator(void* aElement, void *aData)
{
PRThread* theThread = (PRThread *)aElement;
nsresult rv = PR_Interrupt(theThread); // thread data dtor will deallocate (*priv)
PR_ASSERT(rv == PR_SUCCESS);
return PR_TRUE; // continue
}
void
SSM_KillAllThreads(void)
{
int i;
SSMThreadPrivateData *priv = NULL;
PRStatus rv;
if (myThreads != nil) {
TArrayIterator<PRThread*> iterator(*myThreads);
PRThread *thd;
while (iterator.Next(thd)) {
rv = PR_Interrupt(thd); // thread data dtor will deallocate (*priv)
PR_ASSERT(rv == PR_SUCCESS);
}
}
if (gThreadsList)
{
gThreadsList->EnumerateForwards(InterruptThreadEnumerator, NULL);
}
}
PRThread *
@ -79,19 +127,20 @@ SSM_CreateAndRegisterThread(PRThreadType type,
PRThreadState state,
PRUint32 stackSize)
{
PRThread *thd;
if (!myThreads)
if (!gThreadsList)
{
PR_NewThreadPrivateIndex(&thdIndex, SSM_MacDelistThread);
myThreads = new TArray<PRThread*>;
PR_NewThreadPrivateIndex(&gThreadIndex, SSM_MacDelistThread);
gThreadsList = new nsVoidArray;
}
thd = PR_CreateThread(type, start, arg, priority, scope, state, stackSize);
if (thd)
PRThread *newThread = PR_CreateThread(type, start, arg, priority, scope, state, stackSize);
if (newThread)
{
/* Add this thread to our list of threads */
myThreads->AddItem(thd);
gThreadsList->AppendElement((void *)newThread);
}
return newThread;
}

View File

@ -30,249 +30,264 @@
* may use your version of this file under either the MPL or the
* GPL.
*/
// ===========================================================================
// CCompleteApp.cp ©1994-1998 Metrowerks Inc. All rights reserved.
// ===========================================================================
// This file contains the starter code for a complete PowerPlant project that
// includes precompiled headers and both debug and release targets.
#include "macshell.h"
/*
* See <http://developer.apple.com/technotes/tn/tn1070.html> for information about BOAs
*
*/
#include <AppleEvents.h>
#include <Gestalt.h>
#include <Errors.h>
#include <LowMem.h>
#include <LGrowZone.h>
#include <LWindow.h>
#include <PP_Messages.h>
#include <PP_Resources.h>
#include <PPobClasses.h>
#include <UDrawingState.h>
#include <UMemoryMgr.h>
#include <URegistrar.h>
#include "macstdlibextras.h"
#include "prthread.h"
#include "prinit.h"
#include "prlog.h"
#include "serv.h"
#include "dataconn.h"
// put declarations for resource ids (ResIDTs) here
#include "macshell.h"
const PP_PowerPlant::ResIDT wind_SampleWindow = 128; // EXAMPLE, create a new window
#define kSleepMax 20
//
// NSPR repeater
//
static PRBool gQuitFlag;
static long gSleepVal;
class CNSPRRepeater : public LPeriodical
{
public:
CNSPRRepeater();
virtual void SpendTime(const EventRecord& inEvent);
};
CNSPRRepeater::CNSPRRepeater(void)
: LPeriodical()
//----------------------------------------------------------------------------
PRBool GetQuitFlag()
{
return gQuitFlag;
}
CNSPRRepeater *gNSPRRepeater;
PRBool gShouldQuit = PR_FALSE;
void
CNSPRRepeater::SpendTime(const EventRecord& inEvent)
//----------------------------------------------------------------------------
void SetQuitFlag(PRBool quitNow)
{
/*
Can't just exit on the Mac, because otherwise the NSPR threads
will keep spinning forever. We have to send the app a
Quit command so that all the threads will shut down in an orderly
way.
On top of that, NSPR threads can't send a Quit Apple Event, because
that causes the threads to close improperly. So, we keep a flag and allow
threads to raise it. We check for that flag here.
*/
gQuitFlag = quitNow;
}
if (gShouldQuit)
// Apple event handlers to be installed
//----------------------------------------------------------------------------
static pascal OSErr DoAEOpenApplication(AppleEvent * theAppleEvent, AppleEvent * replyAppleEvent, long refCon)
{
return noErr;
}
//----------------------------------------------------------------------------
static pascal OSErr DoAEOpenDocuments(AppleEvent * theAppleEvent, AppleEvent * replyAppleEvent, long refCon)
{
return errAEEventNotHandled;
}
//----------------------------------------------------------------------------
static pascal OSErr DoAEPrintDocuments(AppleEvent * theAppleEvent, AppleEvent * replyAppleEvent, long refCon)
{
return errAEEventNotHandled;
}
//----------------------------------------------------------------------------
static pascal OSErr DoAEQuitApplication(AppleEvent * theAppleEvent, AppleEvent * replyAppleEvent, long refCon)
{
gQuitFlag = PR_TRUE;
return noErr;
}
// install Apple event handlers
//----------------------------------------------------------------------------
static void InitAppleEventsStuff(void)
{
OSErr err;
err = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, NewAEEventHandlerProc(DoAEOpenApplication), 0, false);
if (err == noErr)
err = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, NewAEEventHandlerProc(DoAEOpenDocuments), 0, false);
if (err == noErr)
err = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments, NewAEEventHandlerProc(DoAEPrintDocuments), 0, false);
if (err == noErr)
err = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, NewAEEventHandlerProc(DoAEQuitApplication), 0, false);
#if DEBUG
if (err != noErr)
DebugStr("\pInstall event handler failed");
#endif
}
// high-level event dispatching
//----------------------------------------------------------------------------
static void DoHighLevelEvent(EventRecord * theEventRecPtr)
{
(void) AEProcessAppleEvent(theEventRecPtr);
}
#pragma mark -
//----------------------------------------------------------------------------
// Increase the space allocated for the background only application stack.
//
// Warning: SetApplLimit always sets the stack to at least as large as the
// default stack for the machine (8K on machines with original QuickDraw,
// 24K on machines with Color QuickDraw), so the application partition
// must be large enough to accommodate an appropriate stack and heap.
// Call this only once, at the beginning of the BOA.
//
// Another warning:
// Don't bother trying to set the stack size to something lower than 24K.
// If SetApplLimit is called to do this, it will silently lower ApplLimit
// to a 24K stack. (The limit is 8K on machines without Color QuickDraw.
// In this sample, we don't allow an increment less than 24K.)
static OSErr IncreaseBOAStack(Size additionalStackSize)
{
OSErr err;
// Check that we aren't running with a corrupt heap. If we are,
// fix the problem. This was a bug with FBA's before System 7.5.5.
// With System Software later than 7.5.5, this "fix" is harmless.
THz myZone = GetZone();
if (myZone->bkLim != LMGetHeapEnd())
LMSetHeapEnd(myZone->bkLim);
// Increase the stack size by lowering the heap limit.
SetApplLimit((Ptr) ((unsigned long) GetApplLimit() - additionalStackSize));
err = MemError();
if (err == noErr) MaxApplZone();
return err;
}
//----------------------------------------------------------------------------
static void MemoryInit(long numMasterBlocks)
{
IncreaseBOAStack(1024 * 64);
for (long i = 0; i < numMasterBlocks; i ++)
MoreMasters();
}
#pragma mark -
//----------------------------------------------------------------------------
static void DoIdleProcessing()
{
PR_Sleep(PR_INTERVAL_NO_WAIT); // give time to NSPR threads
}
//----------------------------------------------------------------------------
static OSErr HandleOneEvent()
{
EventRecord theEvent;
Boolean gotEvent;
OSErr err = noErr;
// tweak the sleep time depending on whether cartman is doing anything or not
gSleepVal = AreConnectionsActive() ? 0 : kSleepMax;
gotEvent = WaitNextEvent(everyEvent, &theEvent, gSleepVal, nil);
if (gotEvent)
{
if (gNSPRRepeater)
gNSPRRepeater->StopIdling();
// PR_Interrupt all threads (other than the primordial one)
SSM_KillAllThreads();
gTheApp->SendAEQuit(); // will cause this repeater to stop repeating
switch (theEvent.what)
{
case kHighLevelEvent:
DoHighLevelEvent(&theEvent);
break;
}
}
else
PR_Sleep(PR_INTERVAL_NO_WAIT); // give time to NSPR threads
{
DoIdleProcessing();
}
return noErr;
}
// ===========================================================================
// ¥ Main Program
// ===========================================================================
PRIntn MacPSMMain(PRIntn argc, char **argv);
int main()
//----------------------------------------------------------------------------
static void DoApplicationCleanup()
{
char *fakeArgv[] = { NULL, NULL };
#ifndef NDEBUG
SetDebugThrow_(PP_PowerPlant::debugAction_Alert); // Set Debugging options
SetDebugSignal_(PP_PowerPlant::debugAction_Alert);
#endif
PP_PowerPlant::InitializeHeap(3); // Initialize Memory Manager
// Parameter is number of Master Pointer
// blocks to allocate
#ifdef DEBUG
InitializeSIOUX(false); // prevent us from getting double menus, etc.
#endif
PP_PowerPlant::UQDGlobals::InitializeToolbox(&qd); // Initialize standard Toolbox managers
new PP_PowerPlant::LGrowZone(20000); // Install a GrowZone function to catch
// low memory situations.
PR_Initialize(MacPSMMain, 0, fakeArgv, 0);
return 0;
}
CBasicApp *gTheApp;
PRIntn MacPSMMain(PRIntn argc, char **argv)
{
gNSPRRepeater = new CNSPRRepeater;
PR_ASSERT(gNSPRRepeater != NULL);
gNSPRRepeater->StartIdling();
CBasicApp theApp; // create instance of your application
gTheApp = &theApp;
theApp.Run();
return 0;
}
// ---------------------------------------------------------------------------
// ¥ CBasicApp
// ---------------------------------------------------------------------------
// Constructor
CBasicApp::CBasicApp()
{
#ifndef NDEBUG
PP_PowerPlant::RegisterAllPPClasses(); // Register functions to create core
#else // PowerPlant classes
RegisterClass_(PP_PowerPlant::LWindow);
RegisterClass_(PP_PowerPlant::LCaption);
#endif
SSM_KillAllThreads();
}
// ---------------------------------------------------------------------------
// ¥ ~CBasicApp
// ---------------------------------------------------------------------------
// Destructor
CBasicApp::~CBasicApp()
{
}
// ---------------------------------------------------------------------------
// ¥ StartUp
// ---------------------------------------------------------------------------
// This method lets you do something when the application starts up
// without a document. For example, you could issue your own new command.
// this is in main.c
extern void RunMacPSM(void *);
void
CBasicApp::StartUp()
//----------------------------------------------------------------------------
static PRIntn DoMainEventLoop(PRIntn argc, char **argv)
{
// ObeyCommand(PP_PowerPlant::cmd_New, nil); // EXAMPLE, create a new window
/*
The Unix/Win32 main function (which we call RunMacPSM) blocks on
PR_Accept(), listening for control connections. Since we cannot
block from the main thread, we have to spin a separate NSPR thread
for RunMacPSM.
*/
SSM_CreateAndRegisterThread(PR_USER_THREAD,
RunMacPSM,
NULL,
PR_PRIORITY_NORMAL,
PR_LOCAL_THREAD,
PR_UNJOINABLE_THREAD, 0);
}
// ---------------------------------------------------------------------------
// ¥ ObeyCommand
// ---------------------------------------------------------------------------
// This method lets the application respond to commands like Menu commands
SSM_CreateAndRegisterThread(PR_USER_THREAD,
RunMacPSM,
NULL,
PR_PRIORITY_NORMAL,
PR_LOCAL_THREAD,
PR_UNJOINABLE_THREAD, 0);
Boolean
CBasicApp::ObeyCommand(
PP_PowerPlant::CommandT inCommand,
void *ioParam)
{
Boolean cmdHandled = true;
// let's let NSPR threads start off
PR_Sleep(PR_INTERVAL_NO_WAIT); // give time to NSPR threads
switch (inCommand) {
// Handle command messages (defined in PP_Messages.h).
case PP_PowerPlant::cmd_New:
#if 0
PP_PowerPlant::LWindow *theWindow =
PP_PowerPlant::LWindow::CreateWindow(wind_SampleWindow, this);
ThrowIfNil_(theWindow);
// LWindow is not initially visible in PPob resource
theWindow->Show();
break;
#endif
case PP_PowerPlant::cmd_Quit:
if (!gShouldQuit) // do this only if repeater hasn't done it for us
{
if (gNSPRRepeater)
gNSPRRepeater->StopIdling();
// PR_Interrupt all threads (other than the primordial one)
SSM_KillAllThreads();
}
// fall through to default Quit behavior
// Any that you don't handle, such as cmd_About and cmd_Quit,
// will be passed up to LApplication
default:
cmdHandled = PP_PowerPlant::LApplication::ObeyCommand(inCommand, ioParam);
break;
// main event loop
while (!gQuitFlag)
{
OSErr err = HandleOneEvent();
}
return cmdHandled;
DoApplicationCleanup();
return 0;
}
// ---------------------------------------------------------------------------
// ¥ FindCommandStatus
// ---------------------------------------------------------------------------
// This method enables menu items.
void
CBasicApp::FindCommandStatus(
PP_PowerPlant::CommandT inCommand,
Boolean &outEnabled,
Boolean &outUsesMark,
PP_PowerPlant::Char16 &outMark,
Str255 outName)
//----------------------------------------------------------------------------
static void DoApplicationSetup()
{
char *fakeArgv[] = { NULL, NULL }; // do we need to add the application name in argv[0] ?
switch (inCommand) {
// Return menu item status according to command messages.
case PP_PowerPlant::cmd_New:
case PP_PowerPlant::cmd_Quit:
outEnabled = true;
break;
// Any that you don't handle, such as cmd_About and cmd_Quit,
// will be passed up to LApplication
default:
PP_PowerPlant::LApplication::FindCommandStatus(inCommand, outEnabled,
outUsesMark, outMark, outName);
break;
}
PR_Initialize(DoMainEventLoop, 0, fakeArgv, 0);
}
#pragma mark -
//----------------------------------------------------------------------------
void main(void)
{
// initialize QuickDraw globals. This is the only Toolbox init that we
// should do for an FBA
InitGraf(&qd.thePort);
MemoryInit(10);
// initialize application globals
gQuitFlag = PR_FALSE;
gSleepVal = kSleepMax;
// is the Apple Event Manager available?
long gestResponse;
Boolean haveAppleEvents;
OSErr err = Gestalt(gestaltAppleEventsAttr, &gestResponse);
if (err == noErr && (gestResponse & (1 << gestaltAppleEventsPresent)) != 0)
haveAppleEvents = true;
if (!haveAppleEvents) return;
// install Apple event handlers
InitAppleEventsStuff();
// setup the app. This calls into NSPR, which calls our DoMainEventLoop() function.
DoApplicationSetup();
}

View File

@ -30,36 +30,12 @@
* may use your version of this file under either the MPL or the
* GPL.
*/
// ===========================================================================
// CCompleteApp.h ©1994-1998 Metrowerks Inc. All rights reserved.
// ===========================================================================
#pragma once
#include <PP_Prefix.h>
#include <LApplication.h>
class CBasicApp : public PP_PowerPlant::LApplication {
public:
CBasicApp(); // constructor registers PPobs
virtual ~CBasicApp(); // stub destructor
// this overriding method handles application commands
virtual Boolean ObeyCommand(PP_PowerPlant::CommandT inCommand, void* ioParam);
// this overriding method returns the status of menu items
virtual void FindCommandStatus(PP_PowerPlant::CommandT inCommand,
Boolean &outEnabled, Boolean &outUsesMark,
PP_PowerPlant::Char16 &outMark, Str255 outName);
protected:
PR_BEGIN_EXTERN_C
virtual void StartUp(); // override startup functions
PRBool GetQuitFlag();
void SetQuitFlag(PRBool quitNow);
};
extern CBasicApp *gTheApp;
PR_END_EXTERN_C

View File

@ -156,23 +156,7 @@ static SSMStatus SSM_InstallSMIMEPolicy(void)
*/
SECStatus Utility_SetPolicy(long which, int policy)
{
if (which == POLICY_TYPE_INDEX) {
switch (policy) {
case SVRPLCYDomestic:
policyType = ssmDomestic;
break;
case SVRPLCYExport:
policyType = ssmExport;
break;
case SVRPLCYFrance:
policyType = ssmFrance;
break;
default:
/* This is an unknown policy type. */
PR_ASSERT(0);
break;
}
}
policyType = ssmDomestic;
return SECSuccess;
}
#endif

View File

@ -231,7 +231,7 @@ ssm_DrainAndDestroyChildCollection(SSMCollection **coll)
/* Drain the collection. Don't block; presumably this is
being done at destruction time. */
while(SSM_Dequeue(v, SSM_PRIORITY_ANY, (void **) &conn, PR_FALSE) == PR_SUCCESS);
while(SSM_Dequeue(v, SSM_PRIORITY_ANY, (void **) &conn, PR_FALSE) == PR_SUCCESS) {;}
/* Destroy the collection. */
SSM_DestroyCollection(v);
@ -282,13 +282,7 @@ SSM_AddLogSocket(PRFileDesc *fd)
}
#ifdef XP_MAC
/*
Each thread, when registering itself using one of the two functions
below, assigns itself as private data at index (thdIndex). This is
necessary because when a thread exits, we want it to delete itself
from the list of threads we need to kill at exit time.
*/
extern PRUintn thdIndex;
#include "macglue.h"
#endif
/* Called by a newly created thread, this associates a name with the thread. */
@ -300,8 +294,17 @@ SSM_RegisterThread(char *threadName, SSMResource *ptr)
char *value;
#ifdef XP_MAC
if (thdIndex > 0)
PR_SetThreadPrivate(thdIndex, PR_GetCurrentThread());
/*
Each thread, when registering itself using one of the two functions
below, assigns itself as private data at index (thdIndex). This is
necessary because when a thread exits, we want it to delete itself
from the list of threads we need to kill at exit time.
*/
{
PRUintn threadIndex = GetThreadIndex();
if (threadIndex > 0)
PR_SetThreadPrivate(threadIndex, PR_GetCurrentThread());
}
#endif
if (ptr)