summaryrefslogtreecommitdiffstats
path: root/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mdmac.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mdmac.c')
-rw-r--r--src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mdmac.c776
1 files changed, 776 insertions, 0 deletions
diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mdmac.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mdmac.c
new file mode 100644
index 00000000..bcbb3f82
--- /dev/null
+++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mdmac.c
@@ -0,0 +1,776 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <Types.h>
+#include <Timer.h>
+#include <Files.h>
+#include <Errors.h>
+#include <Folders.h>
+#include <Gestalt.h>
+#include <Events.h>
+#include <Processes.h>
+#include <TextUtils.h>
+#include <MixedMode.h>
+#include <LowMem.h>
+
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stat.h>
+#include <stdarg.h>
+#include <unix.h>
+
+#include "MacErrorHandling.h"
+
+#include "primpl.h"
+#include "prgc.h"
+
+#include "mactime.h"
+
+#include "mdmac.h"
+
+// undefine getenv, so that _MD_GetEnv can call the version in NSStdLib::nsEnvironment.cpp.
+#undef getenv
+
+//
+// Local routines
+//
+unsigned char GarbageCollectorCacheFlusher(PRUint32 size);
+
+extern PRThread *gPrimaryThread;
+extern ProcessSerialNumber gApplicationProcess; // in macthr.c
+
+
+//##############################################################################
+//##############################################################################
+#pragma mark -
+#pragma mark CREATING MACINTOSH THREAD STACKS
+
+
+enum {
+ uppExitToShellProcInfo = kPascalStackBased,
+ uppStackSpaceProcInfo = kRegisterBased
+ | RESULT_SIZE(SIZE_CODE(sizeof(long)))
+ | REGISTER_RESULT_LOCATION(kRegisterD0)
+ | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(UInt16)))
+};
+
+typedef CALLBACK_API( long , StackSpacePatchPtr )(UInt16 trapNo);
+typedef REGISTER_UPP_TYPE(StackSpacePatchPtr) StackSpacePatchUPP;
+
+StackSpacePatchUPP gStackSpacePatchUPP = NULL;
+UniversalProcPtr gStackSpacePatchCallThru = NULL;
+long (*gCallOSTrapUniversalProc)(UniversalProcPtr,ProcInfoType,...) = NULL;
+
+
+pascal long StackSpacePatch(UInt16 trapNo)
+{
+ char tos;
+ PRThread *thisThread;
+
+ thisThread = PR_CurrentThread();
+
+ // If we are the primary thread, then call through to the
+ // good ol' fashion stack space implementation. Otherwise,
+ // compute it by hand.
+ if ((thisThread == gPrimaryThread) ||
+ (&tos < thisThread->stack->stackBottom) ||
+ (&tos > thisThread->stack->stackTop)) {
+ return gCallOSTrapUniversalProc(gStackSpacePatchCallThru, uppStackSpaceProcInfo, trapNo);
+ }
+ else {
+ return &tos - thisThread->stack->stackBottom;
+ }
+}
+
+
+static void InstallStackSpacePatch(void)
+{
+ long systemVersion;
+ OSErr err;
+ CFragConnectionID connID;
+ Str255 errMessage;
+ Ptr interfaceLibAddr;
+ CFragSymbolClass symClass;
+ UniversalProcPtr (*getOSTrapAddressProc)(UInt16);
+ void (*setOSTrapAddressProc)(StackSpacePatchUPP, UInt16);
+ UniversalProcPtr (*newRoutineDescriptorProc)(ProcPtr,ProcInfoType,ISAType);
+
+
+ err = Gestalt(gestaltSystemVersion,&systemVersion);
+ if (systemVersion >= 0x00000A00) // we don't need to patch StackSpace()
+ return;
+
+ // open connection to "InterfaceLib"
+ err = GetSharedLibrary("\pInterfaceLib", kPowerPCCFragArch, kFindCFrag,
+ &connID, &interfaceLibAddr, errMessage);
+ PR_ASSERT(err == noErr);
+ if (err != noErr)
+ return;
+
+ // get symbol GetOSTrapAddress
+ err = FindSymbol(connID, "\pGetOSTrapAddress", &(Ptr)getOSTrapAddressProc, &symClass);
+ if (err != noErr)
+ return;
+
+ // get symbol SetOSTrapAddress
+ err = FindSymbol(connID, "\pSetOSTrapAddress", &(Ptr)setOSTrapAddressProc, &symClass);
+ if (err != noErr)
+ return;
+
+ // get symbol NewRoutineDescriptor
+ err = FindSymbol(connID, "\pNewRoutineDescriptor", &(Ptr)newRoutineDescriptorProc, &symClass);
+ if (err != noErr)
+ return;
+
+ // get symbol CallOSTrapUniversalProc
+ err = FindSymbol(connID, "\pCallOSTrapUniversalProc", &(Ptr)gCallOSTrapUniversalProc, &symClass);
+ if (err != noErr)
+ return;
+
+ // get and set trap address for StackSpace (A065)
+ gStackSpacePatchCallThru = getOSTrapAddressProc(0x0065);
+ if (gStackSpacePatchCallThru)
+ {
+ gStackSpacePatchUPP =
+ (StackSpacePatchUPP)newRoutineDescriptorProc((ProcPtr)(StackSpacePatch), uppStackSpaceProcInfo, GetCurrentArchitecture());
+ setOSTrapAddressProc(gStackSpacePatchUPP, 0x0065);
+ }
+
+#if DEBUG
+ StackSpace();
+#endif
+}
+
+
+//##############################################################################
+//##############################################################################
+#pragma mark -
+#pragma mark ENVIRONMENT VARIABLES
+
+
+typedef struct EnvVariable EnvVariable;
+
+struct EnvVariable {
+ char *variable;
+ char *value;
+ EnvVariable *next;
+};
+
+EnvVariable *gEnvironmentVariables = NULL;
+
+char *_MD_GetEnv(const char *name)
+{
+ EnvVariable *currentVariable = gEnvironmentVariables;
+
+ while (currentVariable) {
+ if (!strcmp(currentVariable->variable, name))
+ return currentVariable->value;
+
+ currentVariable = currentVariable->next;
+ }
+
+ return getenv(name);
+}
+
+PR_IMPLEMENT(int)
+_MD_PutEnv(const char *string)
+{
+ EnvVariable *currentVariable = gEnvironmentVariables;
+ char *variableCopy,
+ *value,
+ *current;
+
+ variableCopy = strdup(string);
+ PR_ASSERT(variableCopy != NULL);
+
+ current = variableCopy;
+ while (*current != '=')
+ current++;
+
+ *current = 0;
+ current++;
+
+ value = current;
+
+ while (currentVariable) {
+ if (!strcmp(currentVariable->variable, variableCopy))
+ break;
+
+ currentVariable = currentVariable->next;
+ }
+
+ if (currentVariable == NULL) {
+ currentVariable = PR_NEW(EnvVariable);
+
+ if (currentVariable == NULL) {
+ PR_DELETE(variableCopy);
+ return -1;
+ }
+
+ currentVariable->variable = strdup(variableCopy);
+ currentVariable->value = strdup(value);
+ currentVariable->next = gEnvironmentVariables;
+ gEnvironmentVariables = currentVariable;
+ }
+
+ else {
+ PR_DELETE(currentVariable->value);
+ currentVariable->value = strdup(current);
+
+ /* This is a temporary hack. Working on a real fix, remove this when done. */
+ /* OK, there are two ways to access the */
+ /* library path, getenv() and PR_GetLibraryPath(). Take a look at PR_GetLibraryPath(). */
+ /* You'll see that we keep the path in a global which is intialized at startup from */
+ /* a call to getenv(). From then on, they have nothing in common. */
+ /* We need to keep them in synch. */
+ if (strcmp(currentVariable->variable, "LD_LIBRARY_PATH") == 0)
+ PR_SetLibraryPath(currentVariable->value);
+ }
+
+ PR_DELETE(variableCopy);
+ return 0;
+}
+
+
+
+//##############################################################################
+//##############################################################################
+#pragma mark -
+#pragma mark MISCELLANEOUS
+
+PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np)
+{
+ if (isCurrent) {
+ (void) setjmp(t->md.jb);
+ }
+ *np = sizeof(t->md.jb) / sizeof(PRUint32);
+ return (PRWord*) (t->md.jb);
+}
+
+void _MD_GetRegisters(PRUint32 *to)
+{
+ (void) setjmp((void*) to);
+}
+
+void _MD_EarlyInit()
+{
+ Handle environmentVariables;
+
+ GetCurrentProcess(&gApplicationProcess);
+
+ INIT_CRITICAL_REGION();
+ InitIdleSemaphore();
+
+#if !defined(MAC_NSPR_STANDALONE)
+ // MacintoshInitializeMemory(); Moved to mdmacmem.c: AllocateRawMemory(Size blockSize)
+#else
+ MacintoshInitializeMemory();
+#endif
+ MacintoshInitializeTime();
+
+ // Install resource-controlled environment variables.
+
+ environmentVariables = GetResource('Envi', 128);
+ if (environmentVariables != NULL) {
+
+ Size resourceSize;
+ char *currentPutEnvString = (char *)*environmentVariables,
+ *currentScanChar = currentPutEnvString;
+
+ resourceSize = GetHandleSize(environmentVariables);
+ DetachResource(environmentVariables);
+ HLock(environmentVariables);
+
+ while (resourceSize--) {
+
+ if ((*currentScanChar == '\n') || (*currentScanChar == '\r')) {
+ *currentScanChar = 0;
+ _MD_PutEnv (currentPutEnvString);
+ currentPutEnvString = currentScanChar + 1;
+ }
+
+ currentScanChar++;
+
+ }
+
+ DisposeHandle(environmentVariables);
+
+ }
+
+#ifdef PR_INTERNAL_LOGGING
+ _MD_PutEnv ("NSPR_LOG_MODULES=clock:6,cmon:6,io:6,mon:6,linker:6,cvar:6,sched:6,thread:6");
+#endif
+
+ InstallStackSpacePatch();
+}
+
+void _MD_FinalInit()
+{
+ _MD_InitNetAccess();
+}
+
+void PR_InitMemory(void) {
+#ifndef NSPR_AS_SHARED_LIB
+ // Needed for Mac browsers without Java. We don't want them calling PR_INIT, since it
+ // brings in all of the thread support. But we do need to allow them to initialize
+ // the NSPR memory package.
+ // This should go away when all clients of the NSPR want threads AND memory.
+ MacintoshInitializeMemory();
+#endif
+}
+
+//##############################################################################
+//##############################################################################
+#pragma mark -
+#pragma mark TERMINATION
+
+
+// THIS IS *** VERY *** IMPORTANT... our CFM Termination proc.
+// This allows us to deactivate our Time Mananger task even
+// if we are not totally gracefully exited. If this is not
+// done then we will randomly crash at later times when the
+// task is called after the app heap is gone.
+
+#if TARGET_CARBON
+extern OTClientContextPtr clientContext;
+#define CLOSE_OPEN_TRANSPORT() CloseOpenTransportInContext(clientContext)
+
+#else
+
+#define CLOSE_OPEN_TRANSPORT() CloseOpenTransport()
+#endif /* TARGET_CARBON */
+
+extern pascal void __NSTerminate(void);
+
+void CleanupTermProc(void)
+{
+ _MD_StopInterrupts(); // deactive Time Manager task
+
+ CLOSE_OPEN_TRANSPORT();
+ TermIdleSemaphore();
+ TERM_CRITICAL_REGION();
+
+ __NSTerminate();
+}
+
+
+
+//##############################################################################
+//##############################################################################
+#pragma mark -
+#pragma mark STRING OPERATIONS
+
+#if !defined(MAC_NSPR_STANDALONE)
+
+// PStrFromCStr converts the source C string to a destination
+// pascal string as it copies. The dest string will
+// be truncated to fit into an Str255 if necessary.
+// If the C String pointer is NULL, the pascal string's length is set to zero
+//
+void
+PStrFromCStr(const char* src, Str255 dst)
+{
+ short length = 0;
+
+ // handle case of overlapping strings
+ if ( (void*)src == (void*)dst )
+ {
+ unsigned char* curdst = &dst[1];
+ unsigned char thisChar;
+
+ thisChar = *(const unsigned char*)src++;
+ while ( thisChar != '\0' )
+ {
+ unsigned char nextChar;
+
+ // use nextChar so we don't overwrite what we are about to read
+ nextChar = *(const unsigned char*)src++;
+ *curdst++ = thisChar;
+ thisChar = nextChar;
+
+ if ( ++length >= 255 )
+ break;
+ }
+ }
+ else if ( src != NULL )
+ {
+ unsigned char* curdst = &dst[1];
+ short overflow = 255; // count down so test it loop is faster
+ register char temp;
+
+ // Can't do the K&R C thing of "while (*s++ = *t++)" because it will copy trailing zero
+ // which might overrun pascal buffer. Instead we use a temp variable.
+ while ( (temp = *src++) != 0 )
+ {
+ *(char*)curdst++ = temp;
+
+ if ( --overflow <= 0 )
+ break;
+ }
+ length = 255 - overflow;
+ }
+ dst[0] = length;
+}
+
+
+void CStrFromPStr(ConstStr255Param pString, char **cString)
+{
+ // Allocates a cString and copies a Pascal string into it.
+ unsigned int len;
+
+ len = pString[0];
+ *cString = malloc(len+1);
+
+ if (*cString != NULL) {
+ strncpy(*cString, (char *)&pString[1], len);
+ (*cString)[len] = NULL;
+ }
+}
+
+
+void dprintf(const char *format, ...)
+{
+#if DEBUG
+ va_list ap;
+ Str255 buffer;
+
+ va_start(ap, format);
+ buffer[0] = PR_vsnprintf((char *)buffer + 1, sizeof(buffer) - 1, format, ap);
+ va_end(ap);
+
+ DebugStr(buffer);
+#endif /* DEBUG */
+}
+
+#else
+
+void debugstr(const char *debuggerMsg)
+{
+ Str255 pStr;
+
+ PStrFromCStr(debuggerMsg, pStr);
+ DebugStr(pStr);
+}
+
+
+char *strdup(const char *source)
+{
+ char *newAllocation;
+ size_t stringLength;
+
+ PR_ASSERT(source);
+
+ stringLength = strlen(source) + 1;
+
+ newAllocation = (char *)PR_MALLOC(stringLength);
+ if (newAllocation == NULL)
+ return NULL;
+ BlockMoveData(source, newAllocation, stringLength);
+ return newAllocation;
+}
+
+// PStrFromCStr converts the source C string to a destination
+// pascal string as it copies. The dest string will
+// be truncated to fit into an Str255 if necessary.
+// If the C String pointer is NULL, the pascal string's length is set to zero
+//
+void PStrFromCStr(const char* src, Str255 dst)
+{
+ short length = 0;
+
+ // handle case of overlapping strings
+ if ( (void*)src == (void*)dst )
+ {
+ unsigned char* curdst = &dst[1];
+ unsigned char thisChar;
+
+ thisChar = *(const unsigned char*)src++;
+ while ( thisChar != '\0' )
+ {
+ unsigned char nextChar;
+
+ // use nextChar so we don't overwrite what we are about to read
+ nextChar = *(const unsigned char*)src++;
+ *curdst++ = thisChar;
+ thisChar = nextChar;
+
+ if ( ++length >= 255 )
+ break;
+ }
+ }
+ else if ( src != NULL )
+ {
+ unsigned char* curdst = &dst[1];
+ short overflow = 255; // count down so test it loop is faster
+ register char temp;
+
+ // Can't do the K&R C thing of "while (*s++ = *t++)" because it will copy trailing zero
+ // which might overrun pascal buffer. Instead we use a temp variable.
+ while ( (temp = *src++) != 0 )
+ {
+ *(char*)curdst++ = temp;
+
+ if ( --overflow <= 0 )
+ break;
+ }
+ length = 255 - overflow;
+ }
+ dst[0] = length;
+}
+
+
+void CStrFromPStr(ConstStr255Param pString, char **cString)
+{
+ // Allocates a cString and copies a Pascal string into it.
+ unsigned int len;
+
+ len = pString[0];
+ *cString = PR_MALLOC(len+1);
+
+ if (*cString != NULL) {
+ strncpy(*cString, (char *)&pString[1], len);
+ (*cString)[len] = NULL;
+ }
+}
+
+
+size_t strlen(const char *source)
+{
+ size_t currentLength = 0;
+
+ if (source == NULL)
+ return currentLength;
+
+ while (*source++ != '\0')
+ currentLength++;
+
+ return currentLength;
+}
+
+int strcmpcore(const char *str1, const char *str2, int caseSensitive)
+{
+ char currentChar1, currentChar2;
+
+ while (1) {
+
+ currentChar1 = *str1;
+ currentChar2 = *str2;
+
+ if (!caseSensitive) {
+
+ if ((currentChar1 >= 'a') && (currentChar1 <= 'z'))
+ currentChar1 += ('A' - 'a');
+
+ if ((currentChar2 >= 'a') && (currentChar2 <= 'z'))
+ currentChar2 += ('A' - 'a');
+
+ }
+
+ if (currentChar1 == '\0')
+ break;
+
+ if (currentChar1 != currentChar2)
+ return currentChar1 - currentChar2;
+
+ str1++;
+ str2++;
+
+ }
+
+ return currentChar1 - currentChar2;
+}
+
+int strcmp(const char *str1, const char *str2)
+{
+ return strcmpcore(str1, str2, true);
+}
+
+int strcasecmp(const char *str1, const char *str2)
+{
+ return strcmpcore(str1, str2, false);
+}
+
+
+void *memcpy(void *to, const void *from, size_t size)
+{
+ if (size != 0) {
+#if DEBUG
+ if ((UInt32)to < 0x1000)
+ DebugStr("\pmemcpy has illegal to argument");
+ if ((UInt32)from < 0x1000)
+ DebugStr("\pmemcpy has illegal from argument");
+#endif
+ BlockMoveData(from, to, size);
+ }
+ return to;
+}
+
+void dprintf(const char *format, ...)
+{
+ va_list ap;
+ char *buffer;
+
+ va_start(ap, format);
+ buffer = (char *)PR_vsmprintf(format, ap);
+ va_end(ap);
+
+ debugstr(buffer);
+ PR_DELETE(buffer);
+}
+
+void
+exit(int result)
+{
+#pragma unused (result)
+
+ ExitToShell();
+}
+
+void abort(void)
+{
+ exit(-1);
+}
+
+#endif
+
+//##############################################################################
+//##############################################################################
+#pragma mark -
+#pragma mark FLUSHING THE GARBAGE COLLECTOR
+
+#if !defined(MAC_NSPR_STANDALONE)
+
+unsigned char GarbageCollectorCacheFlusher(PRUint32)
+{
+
+ PRIntn is;
+
+ UInt32 oldPriority;
+
+ // If java wasn't completely initialized, then bail
+ // harmlessly.
+
+ if (PR_GetGCInfo()->lock == NULL)
+ return false;
+
+#if DEBUG
+ if (_MD_GET_INTSOFF() == 1)
+ DebugStr("\pGarbageCollectorCacheFlusher at interrupt time!");
+#endif
+
+ // The synchronization here is very tricky. We really
+ // don't want any other threads to run while we are
+ // cleaning up the gc heap... they could call malloc,
+ // and then we would be in trouble in a big way. So,
+ // we jack up our priority and that of the finalizer
+ // so that we won't yield to other threads.
+ // dkc 5/17/96
+
+ oldPriority = PR_GetThreadPriority(PR_GetCurrentThread());
+ _PR_INTSOFF(is);
+ _PR_SetThreadPriority(PR_GetCurrentThread(), (PRThreadPriority)30);
+ _PR_INTSON(is);
+
+ // Garbage collect twice. This will finalize any
+ // dangling AWT resources (images, components), and
+ // then free up their GC space, too.
+ // dkc 2/15/96
+ // interrupts must be on during PR_GC
+
+ PR_GC();
+
+ // By setting the finalizer priority to 31, then we
+ // ensure it will run before us. When it finishes
+ // its list of finalizations, it returns to us
+ // for the second garbage collection.
+
+ PR_Yield();
+
+ PR_GC();
+
+ // Restore our old priorities.
+
+ _PR_INTSOFF(is);
+ _PR_SetThreadPriority(PR_GetCurrentThread(), (PRThreadPriority)oldPriority);
+ _PR_INTSON(is);
+
+ return false;
+}
+
+#endif
+
+//##############################################################################
+//##############################################################################
+#pragma mark -
+#pragma mark MISCELLANEOUS-HACKS
+
+
+//
+// ***** HACK FIX THESE ****
+//
+extern long _MD_GetOSName(char *buf, long count)
+{
+ long len;
+
+ len = PR_snprintf(buf, count, "Mac OS");
+
+ return 0;
+}
+
+extern long _MD_GetOSVersion(char *buf, long count)
+{
+ long len;
+
+ len = PR_snprintf(buf, count, "7.5");
+
+ return 0;
+}
+
+extern long _MD_GetArchitecture(char *buf, long count)
+{
+ long len;
+
+#if defined(TARGET_CPU_PPC) && TARGET_CPU_PPC
+ len = PR_snprintf(buf, count, "PowerPC");
+#else
+ len = PR_snprintf(buf, count, "Motorola68k");
+#endif
+
+ return 0;
+}