1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 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/
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.
13
* The Original Code is the Netscape Portable Runtime (NSPR).
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
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
42
#include <Processes.h>
43
#include <TextUtils.h>
44
#include <MixedMode.h>
55
#include "MacErrorHandling.h"
64
// undefine getenv, so that _MD_GetEnv can call the version in NSStdLib::nsEnvironment.cpp.
70
unsigned char GarbageCollectorCacheFlusher(PRUint32 size);
72
extern PRThread *gPrimaryThread;
73
extern ProcessSerialNumber gApplicationProcess; // in macthr.c
76
//##############################################################################
77
//##############################################################################
79
#pragma mark CREATING MACINTOSH THREAD STACKS
83
uppExitToShellProcInfo = kPascalStackBased,
84
uppStackSpaceProcInfo = kRegisterBased
85
| RESULT_SIZE(SIZE_CODE(sizeof(long)))
86
| REGISTER_RESULT_LOCATION(kRegisterD0)
87
| REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(UInt16)))
90
typedef CALLBACK_API( long , StackSpacePatchPtr )(UInt16 trapNo);
91
typedef REGISTER_UPP_TYPE(StackSpacePatchPtr) StackSpacePatchUPP;
93
StackSpacePatchUPP gStackSpacePatchUPP = NULL;
94
UniversalProcPtr gStackSpacePatchCallThru = NULL;
95
long (*gCallOSTrapUniversalProc)(UniversalProcPtr,ProcInfoType,...) = NULL;
98
pascal long StackSpacePatch(UInt16 trapNo)
101
PRThread *thisThread;
103
thisThread = PR_CurrentThread();
105
// If we are the primary thread, then call through to the
106
// good ol' fashion stack space implementation. Otherwise,
107
// compute it by hand.
108
if ((thisThread == gPrimaryThread) ||
109
(&tos < thisThread->stack->stackBottom) ||
110
(&tos > thisThread->stack->stackTop)) {
111
return gCallOSTrapUniversalProc(gStackSpacePatchCallThru, uppStackSpaceProcInfo, trapNo);
114
return &tos - thisThread->stack->stackBottom;
119
static void InstallStackSpacePatch(void)
123
CFragConnectionID connID;
125
Ptr interfaceLibAddr;
126
CFragSymbolClass symClass;
127
UniversalProcPtr (*getOSTrapAddressProc)(UInt16);
128
void (*setOSTrapAddressProc)(StackSpacePatchUPP, UInt16);
129
UniversalProcPtr (*newRoutineDescriptorProc)(ProcPtr,ProcInfoType,ISAType);
132
err = Gestalt(gestaltSystemVersion,&systemVersion);
133
if (systemVersion >= 0x00000A00) // we don't need to patch StackSpace()
136
// open connection to "InterfaceLib"
137
err = GetSharedLibrary("\pInterfaceLib", kPowerPCCFragArch, kFindCFrag,
138
&connID, &interfaceLibAddr, errMessage);
139
PR_ASSERT(err == noErr);
143
// get symbol GetOSTrapAddress
144
err = FindSymbol(connID, "\pGetOSTrapAddress", &(Ptr)getOSTrapAddressProc, &symClass);
148
// get symbol SetOSTrapAddress
149
err = FindSymbol(connID, "\pSetOSTrapAddress", &(Ptr)setOSTrapAddressProc, &symClass);
153
// get symbol NewRoutineDescriptor
154
err = FindSymbol(connID, "\pNewRoutineDescriptor", &(Ptr)newRoutineDescriptorProc, &symClass);
158
// get symbol CallOSTrapUniversalProc
159
err = FindSymbol(connID, "\pCallOSTrapUniversalProc", &(Ptr)gCallOSTrapUniversalProc, &symClass);
163
// get and set trap address for StackSpace (A065)
164
gStackSpacePatchCallThru = getOSTrapAddressProc(0x0065);
165
if (gStackSpacePatchCallThru)
167
gStackSpacePatchUPP =
168
(StackSpacePatchUPP)newRoutineDescriptorProc((ProcPtr)(StackSpacePatch), uppStackSpaceProcInfo, GetCurrentArchitecture());
169
setOSTrapAddressProc(gStackSpacePatchUPP, 0x0065);
178
//##############################################################################
179
//##############################################################################
181
#pragma mark ENVIRONMENT VARIABLES
184
typedef struct EnvVariable EnvVariable;
192
EnvVariable *gEnvironmentVariables = NULL;
194
char *_MD_GetEnv(const char *name)
196
EnvVariable *currentVariable = gEnvironmentVariables;
198
while (currentVariable) {
199
if (!strcmp(currentVariable->variable, name))
200
return currentVariable->value;
202
currentVariable = currentVariable->next;
209
_MD_PutEnv(const char *string)
211
EnvVariable *currentVariable = gEnvironmentVariables;
216
variableCopy = strdup(string);
217
PR_ASSERT(variableCopy != NULL);
219
current = variableCopy;
220
while (*current != '=')
228
while (currentVariable) {
229
if (!strcmp(currentVariable->variable, variableCopy))
232
currentVariable = currentVariable->next;
235
if (currentVariable == NULL) {
236
currentVariable = PR_NEW(EnvVariable);
238
if (currentVariable == NULL) {
239
PR_DELETE(variableCopy);
243
currentVariable->variable = strdup(variableCopy);
244
currentVariable->value = strdup(value);
245
currentVariable->next = gEnvironmentVariables;
246
gEnvironmentVariables = currentVariable;
250
PR_DELETE(currentVariable->value);
251
currentVariable->value = strdup(current);
253
/* This is a temporary hack. Working on a real fix, remove this when done. */
254
/* OK, there are two ways to access the */
255
/* library path, getenv() and PR_GetLibraryPath(). Take a look at PR_GetLibraryPath(). */
256
/* You'll see that we keep the path in a global which is intialized at startup from */
257
/* a call to getenv(). From then on, they have nothing in common. */
258
/* We need to keep them in synch. */
259
if (strcmp(currentVariable->variable, "LD_LIBRARY_PATH") == 0)
260
PR_SetLibraryPath(currentVariable->value);
263
PR_DELETE(variableCopy);
269
//##############################################################################
270
//##############################################################################
272
#pragma mark MISCELLANEOUS
274
PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np)
277
(void) setjmp(t->md.jb);
279
*np = sizeof(t->md.jb) / sizeof(PRUint32);
280
return (PRWord*) (t->md.jb);
283
void _MD_GetRegisters(PRUint32 *to)
285
(void) setjmp((void*) to);
290
Handle environmentVariables;
292
GetCurrentProcess(&gApplicationProcess);
294
INIT_CRITICAL_REGION();
297
#if !defined(MAC_NSPR_STANDALONE)
298
// MacintoshInitializeMemory(); Moved to mdmacmem.c: AllocateRawMemory(Size blockSize)
300
MacintoshInitializeMemory();
302
MacintoshInitializeTime();
304
// Install resource-controlled environment variables.
306
environmentVariables = GetResource('Envi', 128);
307
if (environmentVariables != NULL) {
310
char *currentPutEnvString = (char *)*environmentVariables,
311
*currentScanChar = currentPutEnvString;
313
resourceSize = GetHandleSize(environmentVariables);
314
DetachResource(environmentVariables);
315
HLock(environmentVariables);
317
while (resourceSize--) {
319
if ((*currentScanChar == '\n') || (*currentScanChar == '\r')) {
320
*currentScanChar = 0;
321
_MD_PutEnv (currentPutEnvString);
322
currentPutEnvString = currentScanChar + 1;
329
DisposeHandle(environmentVariables);
333
#ifdef PR_INTERNAL_LOGGING
334
_MD_PutEnv ("NSPR_LOG_MODULES=clock:6,cmon:6,io:6,mon:6,linker:6,cvar:6,sched:6,thread:6");
337
InstallStackSpacePatch();
345
void PR_InitMemory(void) {
346
#ifndef NSPR_AS_SHARED_LIB
347
// Needed for Mac browsers without Java. We don't want them calling PR_INIT, since it
348
// brings in all of the thread support. But we do need to allow them to initialize
349
// the NSPR memory package.
350
// This should go away when all clients of the NSPR want threads AND memory.
351
MacintoshInitializeMemory();
355
//##############################################################################
356
//##############################################################################
358
#pragma mark TERMINATION
361
// THIS IS *** VERY *** IMPORTANT... our CFM Termination proc.
362
// This allows us to deactivate our Time Mananger task even
363
// if we are not totally gracefully exited. If this is not
364
// done then we will randomly crash at later times when the
365
// task is called after the app heap is gone.
368
extern OTClientContextPtr clientContext;
369
#define CLOSE_OPEN_TRANSPORT() CloseOpenTransportInContext(clientContext)
373
#define CLOSE_OPEN_TRANSPORT() CloseOpenTransport()
374
#endif /* TARGET_CARBON */
376
extern pascal void __NSTerminate(void);
378
void CleanupTermProc(void)
380
_MD_StopInterrupts(); // deactive Time Manager task
382
CLOSE_OPEN_TRANSPORT();
384
TERM_CRITICAL_REGION();
391
//##############################################################################
392
//##############################################################################
394
#pragma mark STRING OPERATIONS
396
#if !defined(MAC_NSPR_STANDALONE)
398
// PStrFromCStr converts the source C string to a destination
399
// pascal string as it copies. The dest string will
400
// be truncated to fit into an Str255 if necessary.
401
// If the C String pointer is NULL, the pascal string's length is set to zero
404
PStrFromCStr(const char* src, Str255 dst)
408
// handle case of overlapping strings
409
if ( (void*)src == (void*)dst )
411
unsigned char* curdst = &dst[1];
412
unsigned char thisChar;
414
thisChar = *(const unsigned char*)src++;
415
while ( thisChar != '\0' )
417
unsigned char nextChar;
419
// use nextChar so we don't overwrite what we are about to read
420
nextChar = *(const unsigned char*)src++;
421
*curdst++ = thisChar;
424
if ( ++length >= 255 )
428
else if ( src != NULL )
430
unsigned char* curdst = &dst[1];
431
short overflow = 255; // count down so test it loop is faster
434
// Can't do the K&R C thing of "while (*s++ = *t++)" because it will copy trailing zero
435
// which might overrun pascal buffer. Instead we use a temp variable.
436
while ( (temp = *src++) != 0 )
438
*(char*)curdst++ = temp;
440
if ( --overflow <= 0 )
443
length = 255 - overflow;
449
void CStrFromPStr(ConstStr255Param pString, char **cString)
451
// Allocates a cString and copies a Pascal string into it.
455
*cString = malloc(len+1);
457
if (*cString != NULL) {
458
strncpy(*cString, (char *)&pString[1], len);
459
(*cString)[len] = NULL;
464
void dprintf(const char *format, ...)
470
va_start(ap, format);
471
buffer[0] = PR_vsnprintf((char *)buffer + 1, sizeof(buffer) - 1, format, ap);
480
void debugstr(const char *debuggerMsg)
484
PStrFromCStr(debuggerMsg, pStr);
489
char *strdup(const char *source)
496
stringLength = strlen(source) + 1;
498
newAllocation = (char *)PR_MALLOC(stringLength);
499
if (newAllocation == NULL)
501
BlockMoveData(source, newAllocation, stringLength);
502
return newAllocation;
505
// PStrFromCStr converts the source C string to a destination
506
// pascal string as it copies. The dest string will
507
// be truncated to fit into an Str255 if necessary.
508
// If the C String pointer is NULL, the pascal string's length is set to zero
510
void PStrFromCStr(const char* src, Str255 dst)
514
// handle case of overlapping strings
515
if ( (void*)src == (void*)dst )
517
unsigned char* curdst = &dst[1];
518
unsigned char thisChar;
520
thisChar = *(const unsigned char*)src++;
521
while ( thisChar != '\0' )
523
unsigned char nextChar;
525
// use nextChar so we don't overwrite what we are about to read
526
nextChar = *(const unsigned char*)src++;
527
*curdst++ = thisChar;
530
if ( ++length >= 255 )
534
else if ( src != NULL )
536
unsigned char* curdst = &dst[1];
537
short overflow = 255; // count down so test it loop is faster
540
// Can't do the K&R C thing of "while (*s++ = *t++)" because it will copy trailing zero
541
// which might overrun pascal buffer. Instead we use a temp variable.
542
while ( (temp = *src++) != 0 )
544
*(char*)curdst++ = temp;
546
if ( --overflow <= 0 )
549
length = 255 - overflow;
555
void CStrFromPStr(ConstStr255Param pString, char **cString)
557
// Allocates a cString and copies a Pascal string into it.
561
*cString = PR_MALLOC(len+1);
563
if (*cString != NULL) {
564
strncpy(*cString, (char *)&pString[1], len);
565
(*cString)[len] = NULL;
570
size_t strlen(const char *source)
572
size_t currentLength = 0;
575
return currentLength;
577
while (*source++ != '\0')
580
return currentLength;
583
int strcmpcore(const char *str1, const char *str2, int caseSensitive)
585
char currentChar1, currentChar2;
589
currentChar1 = *str1;
590
currentChar2 = *str2;
592
if (!caseSensitive) {
594
if ((currentChar1 >= 'a') && (currentChar1 <= 'z'))
595
currentChar1 += ('A' - 'a');
597
if ((currentChar2 >= 'a') && (currentChar2 <= 'z'))
598
currentChar2 += ('A' - 'a');
602
if (currentChar1 == '\0')
605
if (currentChar1 != currentChar2)
606
return currentChar1 - currentChar2;
613
return currentChar1 - currentChar2;
616
int strcmp(const char *str1, const char *str2)
618
return strcmpcore(str1, str2, true);
621
int strcasecmp(const char *str1, const char *str2)
623
return strcmpcore(str1, str2, false);
627
void *memcpy(void *to, const void *from, size_t size)
631
if ((UInt32)to < 0x1000)
632
DebugStr("\pmemcpy has illegal to argument");
633
if ((UInt32)from < 0x1000)
634
DebugStr("\pmemcpy has illegal from argument");
636
BlockMoveData(from, to, size);
641
void dprintf(const char *format, ...)
646
va_start(ap, format);
647
buffer = (char *)PR_vsmprintf(format, ap);
657
#pragma unused (result)
669
//##############################################################################
670
//##############################################################################
672
#pragma mark FLUSHING THE GARBAGE COLLECTOR
674
#if !defined(MAC_NSPR_STANDALONE)
676
unsigned char GarbageCollectorCacheFlusher(PRUint32)
683
// If java wasn't completely initialized, then bail
686
if (PR_GetGCInfo()->lock == NULL)
690
if (_MD_GET_INTSOFF() == 1)
691
DebugStr("\pGarbageCollectorCacheFlusher at interrupt time!");
694
// The synchronization here is very tricky. We really
695
// don't want any other threads to run while we are
696
// cleaning up the gc heap... they could call malloc,
697
// and then we would be in trouble in a big way. So,
698
// we jack up our priority and that of the finalizer
699
// so that we won't yield to other threads.
702
oldPriority = PR_GetThreadPriority(PR_GetCurrentThread());
704
_PR_SetThreadPriority(PR_GetCurrentThread(), (PRThreadPriority)30);
707
// Garbage collect twice. This will finalize any
708
// dangling AWT resources (images, components), and
709
// then free up their GC space, too.
711
// interrupts must be on during PR_GC
715
// By setting the finalizer priority to 31, then we
716
// ensure it will run before us. When it finishes
717
// its list of finalizations, it returns to us
718
// for the second garbage collection.
724
// Restore our old priorities.
727
_PR_SetThreadPriority(PR_GetCurrentThread(), (PRThreadPriority)oldPriority);
735
//##############################################################################
736
//##############################################################################
738
#pragma mark MISCELLANEOUS-HACKS
742
// ***** HACK FIX THESE ****
744
extern long _MD_GetOSName(char *buf, long count)
748
len = PR_snprintf(buf, count, "Mac OS");
753
extern long _MD_GetOSVersion(char *buf, long count)
757
len = PR_snprintf(buf, count, "7.5");
762
extern long _MD_GetArchitecture(char *buf, long count)
766
#if defined(TARGET_CPU_PPC) && TARGET_CPU_PPC
767
len = PR_snprintf(buf, count, "PowerPC");
769
len = PR_snprintf(buf, count, "Motorola68k");