Logo Search packages:      
Sourcecode: virtualbox-ose version File versions  Download package

mdmac.c

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

Generated by  Doxygen 1.6.0   Back to index