Untitled diff

Created Diff never expires
PHARO-VM (unifdef -DPharoVM)
SQUEAK-VM (unifdef -UPharoVM)
/* sqUnixMain.c -- support for Unix.
/* sqUnixMain.c -- support for Unix.
*
*
* Copyright (C) 1996-2007 by Ian Piumarta and other authors/contributors
* Copyright (C) 1996-2007 by Ian Piumarta and other authors/contributors
* listed elsewhere in this file.
* listed elsewhere in this file.
* All rights reserved.
* All rights reserved.
*
*
* This file is part of Unix Squeak.
* This file is part of Unix Squeak.
*
*
* Permission is hereby granted, free of charge, to any person obtaining a
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
* Software is furnished to do so, subject to the following conditions:
*
*
* The above copyright notice and this permission notice shall be included in
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
* DEALINGS IN THE SOFTWARE.
*/
*/


/* Author: Ian Piumarta <ian.piumarta@squeakland.org>
/* Author: Ian Piumarta <ian.piumarta@squeakland.org>
* Merged with
* Merged with
* http://squeakvm.org/svn/squeak/trunk/platforms/unix/vm/sqUnixMain.c
* http://squeakvm.org/svn/squeak/trunk/platforms/unix/vm/sqUnixMain.c
* Revision: 2148
* Revision: 2148
* Last Changed Rev: 2132
* Last Changed Rev: 2132
* by eliot Wed Jan 20 10:57:26 PST 2010
* by eliot Wed Jan 20 10:57:26 PST 2010
*/
*/


#include "sq.h"
#include "sq.h"
#include "sqAssert.h"
#include "sqAssert.h"
#include "sqMemoryAccess.h"
#include "sqMemoryAccess.h"
#include "sqaio.h"
#include "sqaio.h"
#include "sqUnixCharConv.h"
#include "sqUnixCharConv.h"
#include "sqSCCSVersion.h"
#include "sqSCCSVersion.h"
#include "sqUnixMain.h"
#include "sqUnixMain.h"
#include "debug.h"
#include "debug.h"


#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
#include <string.h>
#include <string.h>
#include <time.h>
#include <time.h>
#include <sys/time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/param.h>
#include <sys/utsname.h>
#include <sys/utsname.h>
#include <sys/stat.h>
#include <sys/stat.h>
#include <unistd.h>
#include <unistd.h>
#include <errno.h>
#include <errno.h>
#include <signal.h>
#include <signal.h>
#include <fcntl.h>
#include <fcntl.h>
#if !defined(NOEXECINFO)
#if !defined(NOEXECINFO)
# include <execinfo.h>
# include <execinfo.h>
# define BACKTRACE_DEPTH 64
# define BACKTRACE_DEPTH 64
#endif
#endif
#if __OpenBSD__
#if __OpenBSD__
# include <sys/signal.h>
# include <sys/signal.h>
#endif
#endif
#if __FreeBSD__
#if __FreeBSD__
# include <sys/ucontext.h>
# include <sys/ucontext.h>
#endif
#endif
# if __sun__
# if __sun__
# include <sys/ucontext.h>
# include <sys/ucontext.h>
# include <limits.h>
# include <limits.h>
# endif
# endif


#if defined(__alpha__) && defined(__osf__)
#if defined(__alpha__) && defined(__osf__)
# include <sys/sysinfo.h>
# include <sys/sysinfo.h>
# include <sys/proc.h>
# include <sys/proc.h>
#endif
#endif


#undef DEBUG_MODULES
#undef DEBUG_MODULES


#undef IMAGE_DUMP /* define to enable SIGHUP and SIGQUIT handling */
#undef IMAGE_DUMP /* define to enable SIGHUP and SIGQUIT handling */


#define IMAGE_NAME_SIZE MAXPATHLEN
#define IMAGE_NAME_SIZE MAXPATHLEN


#define DefaultHeapSize 20 /* megabytes BEYOND actual image size */
#define DefaultHeapSize 20 /* megabytes BEYOND actual image size */
#define DefaultMmapSize 1024 /* megabytes of virtual memory */
#define DefaultMmapSize 1024 /* megabytes of virtual memory */


char *documentName= 0; /* name if launced from document */
char *documentName= 0; /* name if launced from document */
char shortImageName[MAXPATHLEN+1]; /* image name */
char shortImageName[MAXPATHLEN+1]; /* image name */
char imageName[MAXPATHLEN+1]; /* full path to image */
char imageName[MAXPATHLEN+1]; /* full path to image */
static char vmName[MAXPATHLEN+1]; /* full path to vm */
static char vmName[MAXPATHLEN+1]; /* full path to vm */
char vmPath[MAXPATHLEN+1]; /* full path to image directory */
char vmPath[MAXPATHLEN+1]; /* full path to image directory */
static char vmLogDirA[PATH_MAX+1]; /* where to write crash.dmp */
static char vmLogDirA[PATH_MAX+1]; /* where to write crash.dmp */


char *exeName; /* short vm name, e.g. "squeak" */
char *exeName; /* short vm name, e.g. "squeak" */


int argCnt= 0; /* global copies for access from plugins */
int argCnt= 0; /* global copies for access from plugins */
char **argVec= 0;
char **argVec= 0;
char **envVec= 0;
char **envVec= 0;


static int vmArgCnt= 0; /* for getAttributeIntoLength() */
static int vmArgCnt= 0; /* for getAttributeIntoLength() */
static char **vmArgVec= 0;
static char **vmArgVec= 0;
static int squeakArgCnt= 0;
static int squeakArgCnt= 0;
static char **squeakArgVec= 0;
static char **squeakArgVec= 0;


static long extraMemory= 0;
static long extraMemory= 0;
int useMmap= DefaultMmapSize * 1024 * 1024;
int useMmap= DefaultMmapSize * 1024 * 1024;


static int useItimer= 1; /* 0 to disable itimer-based clock */
static int useItimer= 1; /* 0 to disable itimer-based clock */
static int installHandlers= 1; /* 0 to disable sigusr1 & sigsegv handlers */
static int installHandlers= 1; /* 0 to disable sigusr1 & sigsegv handlers */
int noEvents= 0; /* 1 to disable new event handling */
int noEvents= 0; /* 1 to disable new event handling */
int noSoundMixer= 0; /* 1 to disable writing sound mixer levels */
int noSoundMixer= 0; /* 1 to disable writing sound mixer levels */
char *squeakPlugins= 0; /* plugin path */
char *squeakPlugins= 0; /* plugin path */
int runAsSingleInstance=0;
int runAsSingleInstance=0;
#if !STACKVM && !COGVM
#if !STACKVM && !COGVM
int useJit= 0; /* use default */
int useJit= 0; /* use default */
int jitProcs= 0; /* use default */
int jitProcs= 0; /* use default */
int jitMaxPIC= 0; /* use default */
int jitMaxPIC= 0; /* use default */
#else
#else
# define useJit 0
# define useJit 0
#endif
#endif
int withSpy= 0;
int withSpy= 0;


int uxDropFileCount= 0; /* number of dropped items */
int uxDropFileCount= 0; /* number of dropped items */
char **uxDropFileNames= 0; /* dropped filenames */
char **uxDropFileNames= 0; /* dropped filenames */


int textEncodingUTF8= 1; /* 1 if copy from external selection uses UTF8 */
int textEncodingUTF8= 1; /* 1 if copy from external selection uses UTF8 */


#if defined(IMAGE_DUMP)
#if defined(IMAGE_DUMP)
static int dumpImageFile= 0; /* 1 after SIGHUP received */
static int dumpImageFile= 0; /* 1 after SIGHUP received */
#endif
#endif


#if defined(DARWIN)
#if defined(DARWIN)
int inModalLoop= 0;
int inModalLoop= 0;
#endif
#endif


int sqIgnorePluginErrors = 0;
int sqIgnorePluginErrors = 0;
int runInterpreter = 1;
int runInterpreter = 1;


#include "SqDisplay.h"
#include "SqDisplay.h"
#include "SqSound.h"
#include "SqSound.h"


struct SqDisplay *dpy= 0;
struct SqDisplay *dpy= 0;
struct SqSound *snd= 0;
struct SqSound *snd= 0;


extern void dumpPrimTraceLog(void);
extern void dumpPrimTraceLog(void);
extern void printPhaseTime(int);
extern void printPhaseTime(int);
char *getVersionInfo(int verbose);
char *getVersionInfo(int verbose);


void ioProcessEventsDefault(void);
void (*ioProcessEventsHandler) (void) = ioProcessEventsDefault;


/*
/*
* In the Cog VMs time management is in platforms/unix/vm/sqUnixHeartbeat.c.
* In the Cog VMs time management is in platforms/unix/vm/sqUnixHeartbeat.c.
*/
*/
#if !STACKVM
#if !STACKVM
/*** timer support ***/
/*** timer support ***/


#define LOW_RES_TICK_MSECS 20 /* 1/50 second resolution */
#define LOW_RES_TICK_MSECS 20 /* 1/50 second resolution */


static unsigned int lowResMSecs= 0;
static unsigned int lowResMSecs= 0;
static struct timeval startUpTime;
static struct timeval startUpTime;


static void sigalrm(int signum)
static void sigalrm(int signum)
{
{
lowResMSecs+= LOW_RES_TICK_MSECS;
lowResMSecs+= LOW_RES_TICK_MSECS;
forceInterruptCheck();
forceInterruptCheck();
}
}


void
void
ioInitTime(void)
ioInitTime(void)
{
{
/* set up the micro/millisecond clock */
/* set up the micro/millisecond clock */
gettimeofday(&startUpTime, 0);
gettimeofday(&startUpTime, 0);
if (useItimer)
if (useItimer)
{
{
/* set up the low-res (50th second) millisecond clock */
/* set up the low-res (50th second) millisecond clock */
/* WARNING: all system calls must check for EINTR!!! */
/* WARNING: all system calls must check for EINTR!!! */
{
{
struct sigaction sa;
struct sigaction sa;
sigset_t ss1, ss2;
sigset_t ss1, ss2;
sigemptyset(&ss1);
sigemptyset(&ss1);
sigprocmask(SIG_BLOCK, &ss1, &ss2);
sigprocmask(SIG_BLOCK, &ss1, &ss2);
sa.sa_handler= sigalrm;
sa.sa_handler= sigalrm;
sa.sa_mask= ss2;
sa.sa_mask= ss2;
# ifdef SA_RESTART /* we're probably on Linux */
# ifdef SA_RESTART /* we're probably on Linux */
sa.sa_flags= SA_RESTART;
sa.sa_flags= SA_RESTART;
# else
# else
sa.sa_flags= 0; /* assume we already have BSD behaviour */
sa.sa_flags= 0; /* assume we already have BSD behaviour */
# endif
# endif
# if defined(__linux__) && !defined(__ia64) && !defined(__alpha__)
# if defined(__linux__) && !defined(__ia64) && !defined(__alpha__)
sa.sa_restorer= 0;
sa.sa_restorer= 0;
# endif
# endif
sigaction(SIGALRM, &sa, 0);
sigaction(SIGALRM, &sa, 0);
}
}
{
{
struct itimerval iv;
struct itimerval iv;
iv.it_interval.tv_sec= 0;
iv.it_interval.tv_sec= 0;
iv.it_interval.tv_usec= LOW_RES_TICK_MSECS * 1000;
iv.it_interval.tv_usec= LOW_RES_TICK_MSECS * 1000;
iv.it_value= iv.it_interval;
iv.it_value= iv.it_interval;
setitimer(ITIMER_REAL, &iv, 0);
setitimer(ITIMER_REAL, &iv, 0);
}
}
}
}
}
}




long ioMSecs(void)
long ioMSecs(void)
{
{
struct timeval now;
struct timeval now;
gettimeofday(&now, 0);
gettimeofday(&now, 0);
if ((now.tv_usec-= startUpTime.tv_usec) < 0)
if ((now.tv_usec-= startUpTime.tv_usec) < 0)
{
{
now.tv_usec+= 1000000;
now.tv_usec+= 1000000;
now.tv_sec-= 1;
now.tv_sec-= 1;
}
}
now.tv_sec-= startUpTime.tv_sec;
now.tv_sec-= startUpTime.tv_sec;
return lowResMSecs= (now.tv_usec / 1000 + now.tv_sec * 1000);
return lowResMSecs= (now.tv_usec / 1000 + now.tv_sec * 1000);
}
}


long ioMicroMSecs(void)
long ioMicroMSecs(void)
{
{
/* return the highest available resolution of the millisecond clock */
/* return the highest available resolution of the millisecond clock */
return ioMSecs(); /* this already to the nearest millisecond */
return ioMSecs(); /* this already to the nearest millisecond */
}
}


time_t convertToSqueakTime(time_t unixTime);
time_t convertToSqueakTime(time_t unixTime);


/* returns the local wall clock time */
/* returns the local wall clock time */
sqInt ioSeconds(void)
sqInt ioSeconds(void)
{
{
return convertToSqueakTime(time(0));
return convertToSqueakTime(time(0));
}
}


#define SecondsFrom1901To1970 2177452800ULL
#define SecondsFrom1901To1970 2177452800ULL
#define MicrosecondsFrom1901To1970 2177452800000000ULL
#define MicrosecondsFrom1901To1970 2177452800000000ULL


#define MicrosecondsPerSecond 1000000ULL
#define MicrosecondsPerSecond 1000000ULL
#define MillisecondsPerSecond 1000ULL
#define MillisecondsPerSecond 1000ULL


#define MicrosecondsPerMillisecond 1000ULL
#define MicrosecondsPerMillisecond 1000ULL
/* Compute the current VM time basis, the number of microseconds from 1901. */
/* Compute the current VM time basis, the number of microseconds from 1901. */


static unsigned long long
static unsigned long long
currentUTCMicroseconds()
currentUTCMicroseconds()
{
{
struct timeval utcNow;
struct timeval utcNow;


gettimeofday(&utcNow,0);
gettimeofday(&utcNow,0);
return ((utcNow.tv_sec * MicrosecondsPerSecond) + utcNow.tv_usec)
return ((utcNow.tv_sec * MicrosecondsPerSecond) + utcNow.tv_usec)
+ MicrosecondsFrom1901To1970;
+ MicrosecondsFrom1901To1970;
}
}


usqLong
usqLong
ioUTCMicroseconds() { return currentUTCMicroseconds(); }
ioUTCMicroseconds() { return currentUTCMicroseconds(); }


/* This is an expensive interface for use by profiling code that wants the time
/* This is an expensive interface for use by profiling code that wants the time
* now rather than as of the last heartbeat.
* now rather than as of the last heartbeat.
*/
*/
usqLong
usqLong
ioUTCMicrosecondsNow() { return currentUTCMicroseconds(); }
ioUTCMicrosecondsNow() { return currentUTCMicroseconds(); }
#endif /* STACKVM */
#endif /* STACKVM */


time_t convertToSqueakTime(time_t unixTime)
time_t convertToSqueakTime(time_t unixTime)
{
{
#ifdef HAVE_TM_GMTOFF
#ifdef HAVE_TM_GMTOFF
unixTime+= localtime(&unixTime)->tm_gmtoff;
unixTime+= localtime(&unixTime)->tm_gmtoff;
#else
#else
# ifdef HAVE_TIMEZONE
# ifdef HAVE_TIMEZONE
unixTime+= ((daylight) * 60*60) - timezone;
unixTime+= ((daylight) * 60*60) - timezone;
# else
# else
# error: cannot determine timezone correction
# error: cannot determine timezone correction
# endif
# endif
#endif
#endif
/* Squeak epoch is Jan 1, 1901. Unix epoch is Jan 1, 1970: 17 leap years
/* Squeak epoch is Jan 1, 1901. Unix epoch is Jan 1, 1970: 17 leap years
and 52 non-leap years later than Squeak. */
and 52 non-leap years later than Squeak. */
return unixTime + ((52*365UL + 17*366UL) * 24*60*60UL);
return unixTime + ((52*365UL + 17*366UL) * 24*60*60UL);
}
}




/*** VM & Image File Naming ***/
/*** VM & Image File Naming ***/




/* copy src filename to target, if src is not an absolute filename,
/* copy src filename to target, if src is not an absolute filename,
* prepend the cwd to make target absolute
* prepend the cwd to make target absolute
*/
*/
static void pathCopyAbs(char *target, const char *src, size_t targetSize)
static void pathCopyAbs(char *target, const char *src, size_t targetSize)
{
{
if (src[0] == '/')
if (src[0] == '/')
strcpy(target, src);
strcpy(target, src);
else
else
{
{
0 == getcwd(target, targetSize);
0 == getcwd(target, targetSize);
strcat(target, "/");
strcat(target, "/");
strcat(target, src);
strcat(target, src);
}
}
}
}




static void
static void
recordPathsForVMName(const char *localVmName)
recordPathsForVMName(const char *localVmName)
{
{
#if defined(__linux__)
#if defined(__linux__)
char name[MAXPATHLEN+1];
char name[MAXPATHLEN+1];
int len;
int len;
#endif
#endif


exeName = strrchr(localVmName,'/')
exeName = strrchr(localVmName,'/')
? strrchr(localVmName,'/') + 1
? strrchr(localVmName,'/') + 1
: (char *)localVmName;
: (char *)localVmName;


#if defined(__linux__)
#if defined(__linux__)
if ((len= readlink("/proc/self/exe", name, sizeof(name))) > 0)
if ((len= readlink("/proc/self/exe", name, sizeof(name))) > 0)
{
{
struct stat st;
struct stat st;
name[len]= '\0';
name[len]= '\0';
if (!stat(name, &st))
if (!stat(name, &st))
localVmName= name;
localVmName= name;
}
}
#endif
#endif


/* get canonical path to vm */
/* get canonical path to vm */
if (realpath(localVmName, vmPath) == 0)
if (realpath(localVmName, vmPath) == 0)
pathCopyAbs(vmPath, localVmName, sizeof(vmPath));
pathCopyAbs(vmPath, localVmName, sizeof(vmPath));


/* truncate vmPath to dirname */
/* truncate vmPath to dirname */
{
{
int i= 0;
int i= 0;
for (i= strlen(vmPath); i >= 0; i--)
for (i= strlen(vmPath); i >= 0; i--)
if ('/' == vmPath[i])
if ('/' == vmPath[i])
{
{
vmPath[i+1]= '\0';
vmPath[i+1]= '\0';
break;
break;
}
}
}
}
}
}


static void
static void
recordFullPathForImageName(const char *localImageName)
recordFullPathForImageName(const char *localImageName)
{
{
struct stat s;
struct stat s;
/* get canonical path to image */
/* get canonical path to image */
if ((stat(localImageName, &s) == -1)
if ((stat(localImageName, &s) == -1)
|| (realpath(localImageName, imageName) == 0))
|| (realpath(localImageName, imageName) == 0))
pathCopyAbs(imageName, localImageName, sizeof(imageName));
pathCopyAbs(imageName, localImageName, sizeof(imageName));


/* Set the directory into which to write the crash.dmp file. */
/* Set the directory into which to write the crash.dmp file. */
/* By default this is the image file's directory (strange but true). */
/* By default this is the image file's directory (strange but true). */
#if CRASH_DUMP_IN_CWD
#if CRASH_DUMP_IN_CWD
getcwd(vmLogDirA,PATH_MAX);
getcwd(vmLogDirA,PATH_MAX);
#else
#else
strcpy(vmLogDirA,imageName);
strcpy(vmLogDirA,imageName);
if (strrchr(vmLogDirA,'/'))
if (strrchr(vmLogDirA,'/'))
*strrchr(vmLogDirA,'/') = 0;
*strrchr(vmLogDirA,'/') = 0;
else
else
getcwd(vmLogDirA,PATH_MAX);
getcwd(vmLogDirA,PATH_MAX);
#endif
#endif
}
}


/* vm access */
/* vm access */


sqInt imageNameSize(void) { return strlen(imageName); }
sqInt imageNameSize(void) { return strlen(imageName); }


sqInt imageNameGetLength(sqInt sqImageNameIndex, sqInt length)
sqInt imageNameGetLength(sqInt sqImageNameIndex, sqInt length)
{
{
char *sqImageName= pointerForOop(sqImageNameIndex);
char *sqImageName= pointerForOop(sqImageNameIndex);
int count, i;
int count, i;


count= strlen(imageName);
count= strlen(imageName);
count= (length < count) ? length : count;
count= (length < count) ? length : count;


/* copy the file name into the Squeak string */
/* copy the file name into the Squeak string */
for (i= 0; i < count; i++)
for (i= 0; i < count; i++)
sqImageName[i]= imageName[i];
sqImageName[i]= imageName[i];


return count;
return count;
}
}




sqInt imageNamePutLength(sqInt sqImageNameIndex, sqInt length)
sqInt imageNamePutLength(sqInt sqImageNameIndex, sqInt length)
{
{
char *sqImageName= pointerForOop(sqImageNameIndex);
char *sqImageName= pointerForOop(sqImageNameIndex);
int count, i;
int count, i;


count= (IMAGE_NAME_SIZE < length) ? IMAGE_NAME_SIZE : length;
count= (IMAGE_NAME_SIZE < length) ? IMAGE_NAME_SIZE : length;


/* copy the file name into a null-terminated C string */
/* copy the file name into a null-terminated C string */
for (i= 0; i < count; i++)
for (i= 0; i < count; i++)
imageName[i]= sqImageName[i];
imageName[i]= sqImageName[i];
imageName[count]= 0;
imageName[count]= 0;


dpy->winSetName(imageName);
dpy->winSetName(imageName);


return count;
return count;
}
}




char *getImageName(void) { return imageName; }
char *getImageName(void) { return imageName; }




/*** VM Home Directory Path ***/
/*** VM Home Directory Path ***/


sqInt vmPathSize(void) { return strlen(vmPath); }
sqInt vmPathSize(void) { return strlen(vmPath); }


sqInt vmPathGetLength(sqInt sqVMPathIndex, sqInt length)
sqInt vmPathGetLength(sqInt sqVMPathIndex, sqInt length)
{
{
char *stVMPath= pointerForOop(sqVMPathIndex);
char *stVMPath= pointerForOop(sqVMPathIndex);
int count, i;
int count, i;


count= strlen(vmPath);
count= strlen(vmPath);
count= (length < count) ? length : count;
count= (length < count) ? length : count;


/* copy the file name into the Squeak string */
/* copy the file name into the Squeak string */
for (i= 0; i < count; i++)
for (i= 0; i < count; i++)
stVMPath[i]= vmPath[i];
stVMPath[i]= vmPath[i];


return count;
return count;
}
}


char* ioGetLogDirectory(void) { return ""; };
char* ioGetLogDirectory(void) { return ""; };
sqInt ioSetLogDirectoryOfSize(void* lblIndex, sqInt sz){ return 1; }
sqInt ioSetLogDirectoryOfSize(void* lblIndex, sqInt sz){ return 1; }




/*** power management ***/
/*** power management ***/




sqInt ioDisablePowerManager(sqInt disableIfNonZero)
sqInt ioDisablePowerManager(sqInt disableIfNonZero)
{
{
return true;
return true;
}
}




/*** Access to system attributes and command-line arguments ***/
/*** Access to system attributes and command-line arguments ***/




/* OS_TYPE may be set in configure.in and passed via the Makefile */
/* OS_TYPE may be set in configure.in and passed via the Makefile */


#ifndef OS_TYPE
#ifndef OS_TYPE
# ifdef UNIX
# ifdef UNIX
# define OS_TYPE "unix"
# define OS_TYPE "unix"
# else
# else
# define OS_TYPE "unknown"
# define OS_TYPE "unknown"
# endif
# endif
#endif
#endif


char *
char *
GetAttributeString(sqInt id)
GetAttributeString(sqInt id)
{
{
if (id < 0) /* VM argument */
if (id < 0) /* VM argument */
{
{
if (-id < vmArgCnt)
if (-id < vmArgCnt)
return vmArgVec[-id];
return vmArgVec[-id];
}
}
else
else
switch (id)
switch (id)
{
{
case 0:
case 0:
return vmName[0] ? vmName : vmArgVec[0];
return vmName[0] ? vmName : vmArgVec[0];
case 1:
case 1:
return imageName;
return imageName;
case 1001:
case 1001:
/* OS type: "unix", "win32", "mac", ... */
/* OS type: "unix", "win32", "mac", ... */
return OS_TYPE;
return OS_TYPE;
case 1002:
case 1002:
/* OS name: e.g. "solaris2.5" on unix, "win95" on win32, ... */
/* OS name: e.g. "solaris2.5" on unix, "win95" on win32, ... */
return VM_TARGET_OS;
return VM_TARGET_OS;
case 1003:
case 1003:
/* processor architecture: e.g. "68k", "x86", "PowerPC", ... */
/* processor architecture: e.g. "68k", "x86", "PowerPC", ... */
return VM_TARGET_CPU;
return VM_TARGET_CPU;
case 1004:
case 1004:
/* Interpreter version string */
/* Interpreter version string */
return (char *)interpreterVersion;
return (char *)interpreterVersion;
case 1005:
case 1005:
/* window system name */
/* window system name */
return dpy->winSystemName();
return dpy->winSystemName();
case 1006:
case 1006:
/* vm build string */
/* vm build string */
return VM_BUILD_STRING;
return VM_BUILD_STRING;
#if STACKVM
#if STACKVM
case 1007: { /* interpreter build info */
case 1007: { /* interpreter build info */
extern char *__interpBuildInfo;
extern char *__interpBuildInfo;
return __interpBuildInfo;
return __interpBuildInfo;
}
}
# if COGVM
# if COGVM
case 1008: { /* cogit build info */
case 1008: { /* cogit build info */
extern char *__cogitBuildInfo;
extern char *__cogitBuildInfo;
return __cogitBuildInfo;
return __cogitBuildInfo;
}
}
# endif
# endif
#endif
#endif


case 1009: /* source tree version info */
case 1009: /* source tree version info */
return sourceVersionString(' ');
return sourceVersionString(' ');


default:
default:
if ((id - 2) < squeakArgCnt)
if ((id - 2) < squeakArgCnt)
return squeakArgVec[id - 2];
return squeakArgVec[id - 2];
}
}
success(false);
success(false);
return "";
return "";
}
}


sqInt attributeSize(sqInt id)
sqInt attributeSize(sqInt id)
{
{
return strlen(GetAttributeString(id));
return strlen(GetAttributeString(id));
}
}


sqInt getAttributeIntoLength(sqInt id, sqInt byteArrayIndex, sqInt length)
sqInt getAttributeIntoLength(sqInt id, sqInt byteArrayIndex, sqInt length)
{
{
if (length > 0)
if (length > 0)
strncpy(pointerForOop(byteArrayIndex), GetAttributeString(id), length);
strncpy(pointerForOop(byteArrayIndex), GetAttributeString(id), length);
return 0;
return 0;
}
}




/*** event handling ***/
/*** event handling ***/




sqInt inputEventSemaIndex= 0;
sqInt inputEventSemaIndex= 0;




/* set asynchronous input event semaphore */
/* set asynchronous input event semaphore */


sqInt ioSetInputSemaphore(sqInt semaIndex)
sqInt ioSetInputSemaphore(sqInt semaIndex)
{
{
if ((semaIndex == 0) || (noEvents == 1))
if ((semaIndex == 0) || (noEvents == 1))
success(false);
success(false);
else
else
inputEventSemaIndex= semaIndex;
inputEventSemaIndex= semaIndex;
return true;
return true;
}
}




/*** display functions ***/
/*** display functions ***/


sqInt ioFormPrint(sqInt bitsAddr, sqInt width, sqInt height, sqInt depth, double hScale, double vScale, sqInt landscapeFlag)
sqInt ioFormPrint(sqInt bitsAddr, sqInt width, sqInt height, sqInt depth, double hScale, double vScale, sqInt landscapeFlag)
{
{
return dpy->ioFormPrint(bitsAddr, width, height, depth, hScale, vScale, landscapeFlag);
return dpy->ioFormPrint(bitsAddr, width, height, depth, hScale, vScale, landscapeFlag);
}
}


#if STACKVM
#if STACKVM
sqInt ioRelinquishProcessorForMicroseconds(sqInt us)
sqInt ioRelinquishProcessorForMicroseconds(sqInt us)
{
{
# if ITIMER_HEARTBEAT
# if ITIMER_HEARTBEAT
extern void checkHeartStillBeats();
extern void checkHeartStillBeats();


checkHeartStillBeats();
checkHeartStillBeats();
# endif
# endif
dpy->ioRelinquishProcessorForMicroseconds(us);
dpy->ioRelinquishProcessorForMicroseconds(us);
return 0;
return 0;
}
}
#else /* STACKVM */
#else /* STACKVM */
static int lastInterruptCheck= 0;
static int lastInterruptCheck= 0;


sqInt ioRelinquishProcessorForMicroseconds(sqInt us)
sqInt ioRelinquishProcessorForMicroseconds(sqInt us)
{
{
int now;
int now;
dpy->ioRelinquishProcessorForMicroseconds(us);
dpy->ioRelinquishProcessorForMicroseconds(us);
now= ioLowResMSecs();
now= ioLowResMSecs();
if (now - lastInterruptCheck > (1000/25)) /* avoid thrashing intr checks from 1ms loop in idle proc */
if (now - lastInterruptCheck > (1000/25)) /* avoid thrashing intr checks from 1ms loop in idle proc */
{
{
forceInterruptCheck(); /* ensure timely poll for semaphore activity */
forceInterruptCheck(); /* ensure timely poll for semaphore activity */
lastInterruptCheck= now;
lastInterruptCheck= now;
}
}
return 0;
return 0;
}
}
#endif /* STACKVM */
#endif /* STACKVM */


sqInt ioBeep(void) { return dpy->ioBeep(); }
sqInt ioBeep(void) { return dpy->ioBeep(); }


#if defined(IMAGE_DUMP)
#if defined(IMAGE_DUMP)


static void emergencyDump(int quit)
static void emergencyDump(int quit)
{
{
extern sqInt preSnapshot(void);
extern sqInt preSnapshot(void);
extern sqInt postSnapshot(void);
extern sqInt postSnapshot(void);
extern void writeImageFile(sqInt);
extern void writeImageFile(sqInt);
char savedName[MAXPATHLEN];
char savedName[MAXPATHLEN];
char baseName[MAXPATHLEN];
char baseName[MAXPATHLEN];
char *term;
char *term;
int dataSize, i;
int dataSize, i;
strncpy(savedName, imageName, MAXPATHLEN);
strncpy(savedName, imageName, MAXPATHLEN);
strncpy(baseName, imageName, MAXPATHLEN);
strncpy(baseName, imageName, MAXPATHLEN);
if ((term= strrchr(baseName, '.')))
if ((term= strrchr(baseName, '.')))
*term= '\0';
*term= '\0';
for (i= 0; ++i;)
for (i= 0; ++i;)
{
{
struct stat sb;
struct stat sb;
snprintf(imageName, sizeof(imageName), "%s-emergency-dump-%d.image",
snprintf(imageName, sizeof(imageName), "%s-emergency-dump-%d.image",
baseName, i);
baseName, i);
if (stat(imageName, &sb))
if (stat(imageName, &sb))
break;
break;
}
}
dataSize= preSnapshot();
dataSize= preSnapshot();
writeImageFile(dataSize);
writeImageFile(dataSize);


#if STACKVM
#if STACKVM
printf("\nMost recent primitives\n");
printf("\nMost recent primitives\n");
dumpPrimTraceLog();
dumpPrimTraceLog();
#endif
#endif
fprintf(stderr, "\n");
fprintf(stderr, "\n");
printCallStack();
printCallStack();
fprintf(stderr, "\nTo recover valuable content from this image:\n");
fprintf(stderr, "\nTo recover valuable content from this image:\n");
fprintf(stderr, " %s %s\n", exeName, imageName);
fprintf(stderr, " %s %s\n", exeName, imageName);
fprintf(stderr, "and then evaluate\n");
fprintf(stderr, "and then evaluate\n");
fprintf(stderr, " Smalltalk processStartUpList: true\n");
fprintf(stderr, " Smalltalk processStartUpList: true\n");
fprintf(stderr, "in a workspace. DESTROY the dumped image after recovering content!");
fprintf(stderr, "in a workspace. DESTROY the dumped image after recovering content!");


if (quit) abort();
if (quit) abort();
strncpy(imageName, savedName, sizeof(imageName));
strncpy(imageName, savedName, sizeof(imageName));
}
}


#endif
#endif




void ioProcessEventsDefault(void)
sqInt ioProcessEvents(void)
{
{
sqInt result;
sqInt result;
extern sqInt inIOProcessEvents;
extern sqInt inIOProcessEvents;


#if defined(IMAGE_DUMP)
#if defined(IMAGE_DUMP)
if (dumpImageFile) {
if (dumpImageFile) {
emergencyDump(0);
emergencyDump(0);
dumpImageFile= 0;
dumpImageFile= 0;
}
}
#endif
#endif
/* inIOProcessEvents controls ioProcessEvents. If negative then
/* inIOProcessEvents controls ioProcessEvents. If negative then
* ioProcessEvents is disabled. If >= 0 inIOProcessEvents is incremented
* ioProcessEvents is disabled. If >= 0 inIOProcessEvents is incremented
* to avoid reentrancy (i.e. for native GUIs).
* to avoid reentrancy (i.e. for native GUIs).
*/
*/
if (inIOProcessEvents) return;
if (inIOProcessEvents) return 0;
inIOProcessEvents += 1;
inIOProcessEvents += 1;


result = dpy->ioProcessEvents();
result = dpy->ioProcessEvents();


if (inIOProcessEvents > 0)
if (inIOProcessEvents > 0)
inIOProcessEvents -= 1;
inIOProcessEvents -= 1;
}


extern void setIoProcessEventsHandler(void * handler) {
return result;
ioProcessEventsHandler = (void(*)()) handler;
}

sqInt ioProcessEvents(void) {
aioPoll(0);
if(ioProcessEventsHandler)
ioProcessEventsHandler();
return 0;
}
}




void ioDrainEventQueue() {}
void ioDrainEventQueue() {}


double ioScreenScaleFactor(void) { return dpy->ioScreenScaleFactor(); }
double ioScreenScaleFactor(void) { return dpy->ioScreenScaleFactor(); }
sqInt ioScreenDepth(void) { return dpy->ioScreenDepth(); }
sqInt ioScreenDepth(void) { return dpy->ioScreenDepth(); }
sqInt ioScreenSize(void) { return dpy->ioScreenSize(); }
sqInt ioScreenSize(void) { return dpy->ioScreenSize(); }


sqInt ioSetCursorWithMask(sqInt cursorBitsIndex, sqInt cursorMaskIndex, sqInt offsetX, sqInt offsetY)
sqInt ioSetCursorWithMask(sqInt cursorBitsIndex, sqInt cursorMaskIndex, sqInt offsetX, sqInt offsetY)
{
{
return dpy->ioSetCursorWithMask(cursorBitsIndex, cursorMaskIndex, offsetX, offsetY);
return dpy->ioSetCursorWithMask(cursorBitsIndex, cursorMaskIndex, offsetX, offsetY);
}
}


sqInt ioSetCursorARGB(sqInt cursorBitsIndex, sqInt extentX, sqInt extentY, sqInt offsetX, sqInt offsetY)
sqInt ioSetCursorARGB(sqInt cursorBitsIndex, sqInt extentX, sqInt extentY, sqInt offsetX, sqInt offsetY)
{
{
return dpy->ioSetCursorARGB(cursorBitsIndex, extentX, extentY, offsetX, offsetY);
return dpy->ioSetCursorARGB(cursorBitsIndex, extentX, extentY, offsetX, offsetY);
}
}


sqInt ioSetCursor(sqInt cursorBitsIndex, sqInt offsetX, sqInt offsetY)
sqInt ioSetCursor(sqInt cursorBitsIndex, sqInt offsetX, sqInt offsetY)
{
{
return ioSetCursorWithMask(cursorBitsIndex, 0, offsetX, offsetY);
return ioSetCursorWithMask(cursorBitsIndex, 0, offsetX, offsetY);
}
}


sqInt ioSetFullScreen(sqInt fullScreen) { return dpy->ioSetFullScreen(fullScreen); }
sqInt ioSetFullScreen(sqInt fullScreen) { return dpy->ioSetFullScreen(fullScreen); }
sqInt ioForceDisplayUpdate(void) { return dpy->ioForceDisplayUpdate(); }
sqInt ioForceDisplayUpdate(void) { return dpy->ioForceDisplayUpdate(); }


sqInt ioShowDisplay(sqInt dispBitsIndex, sqInt width, sqInt height, sqInt depth, sqInt l, sqInt r, sqInt t, sqInt b)
sqInt ioShowDisplay(sqInt dispBitsIndex, sqInt width, sqInt height, sqInt depth, sqInt l, sqInt r, sqInt t, sqInt b)
{
{
return dpy->ioShowDisplay(dispBitsIndex, width, height, depth, l, r, t, b);
return dpy->ioShowDisplay(dispBitsIndex, width, height, depth, l, r, t, b);
}
}


sqInt ioHasDisplayDepth(sqInt i) { return dpy->ioHasDisplayDepth(i); }
sqInt ioHasDisplayDepth(sqInt i) { return dpy->ioHasDisplayDepth(i); }


sqInt ioSetDisplayMode(sqInt width, sqInt height, sqInt depth, sqInt fullscreenFlag)
sqInt ioSetDisplayMode(sqInt width, sqInt height, sqInt depth, sqInt fullscreenFlag)
{
{
return dpy->ioSetDisplayMode(width, height, depth, fullscreenFlag);
return dpy->ioSetDisplayMode(width, height, depth, fullscreenFlag);
}
}


sqInt clipboardSize(void)
sqInt clipboardSize(void)
{
{
return dpy->clipboardSize();
return dpy->clipboardSize();
}
}


sqInt clipboardWriteFromAt(sqInt count, sqInt byteArrayIndex, sqInt startIndex)
sqInt clipboardWriteFromAt(sqInt count, sqInt byteArrayIndex, sqInt startIndex)
{
{
return dpy->clipboardWriteFromAt(count, byteArrayIndex, startIndex);
return dpy->clipboardWriteFromAt(count, byteArrayIndex, startIndex);
}
}


sqInt clipboardReadIntoAt(sqInt count, sqInt byteArrayIndex, sqInt startIndex)
sqInt clipboardReadIntoAt(sqInt count, sqInt byteArrayIndex, sqInt startIndex)
{
{
return dpy->clipboardReadIntoAt(count, byteArrayIndex, startIndex);
return dpy->clipboardReadIntoAt(count, byteArrayIndex, startIndex);
}
}


char **clipboardGetTypeNames(void)
char **clipboardGetTypeNames(void)
{
{
return dpy->clipboardGetTypeNames();
return dpy->clipboardGetTypeNames();
}
}


sqInt clipboardSizeWithType(char *typeName, int ntypeName)
sqInt clipboardSizeWithType(char *typeName, int ntypeName)
{
{
return dpy->clipboardSizeWithType(typeName, ntypeName);
return dpy->clipboardSizeWithType(typeName, ntypeName);
}
}


void clipboardWriteWithType(char *data, size_t nData, char *typeName, size_t nTypeNames, int isDnd, int isClaiming)
void clipboardWriteWithType(char *data, size_t nData, char *typeName, size_t nTypeNames, int isDnd, int isClaiming)
{
{
dpy->clipboardWriteWithType(data, nData, typeName, nTypeNames, isDnd, isClaiming);
dpy->clipboardWriteWithType(data, nData, typeName, nTypeNames, isDnd, isClaiming);
}
}


sqInt ioGetButtonState(void) { return dpy->ioGetButtonState(); }
sqInt ioGetButtonState(void) { return dpy->ioGetButtonState(); }
sqInt ioPeekKeystroke(void) { return dpy->ioPeekKeystroke(); }
sqInt ioPeekKeystroke(void) { return dpy->ioPeekKeystroke(); }
sqInt ioGetKeystroke(void) { return dpy->ioGetKeystroke(); }
sqInt ioGetKeystroke(void) { return dpy->ioGetKeystroke(); }
sqInt ioGetNextEvent(sqInputEvent *evt) { return dpy->ioGetNextEvent(evt); }
sqInt ioGetNextEvent(sqInputEvent *evt) { return dpy->ioGetNextEvent(evt); }
sqInt ioMousePoint(void) { return dpy->ioMousePoint(); }
sqInt ioMousePoint(void) { return dpy->ioMousePoint(); }


/*** Window labeling ***/
/*** Window labeling ***/
char* ioGetWindowLabel(void) {return "";}
char* ioGetWindowLabel(void) {return "";}


sqInt ioSetWindowLabelOfSize(void* lbl, sqInt size)
sqInt ioSetWindowLabelOfSize(void* lbl, sqInt size)
{ return dpy->hostWindowSetTitle((long)dpy->ioGetWindowHandle(), lbl, size); }
{ return dpy->hostWindowSetTitle((long)dpy->ioGetWindowHandle(), lbl, size); }


sqInt ioIsWindowObscured(void) {return false;}
sqInt ioIsWindowObscured(void) {return false;}


/** Misplaced Window-Size stubs, so the VM will link. **/
/** Misplaced Window-Size stubs, so the VM will link. **/
sqInt ioGetWindowWidth()
sqInt ioGetWindowWidth()
{ int wh = dpy->hostWindowGetSize((long)dpy->ioGetWindowHandle());
{ int wh = dpy->hostWindowGetSize((long)dpy->ioGetWindowHandle());
return wh >> 16; }
return wh >> 16; }


sqInt ioGetWindowHeight()
sqInt ioGetWindowHeight()
{ int wh = dpy->hostWindowGetSize((long)dpy->ioGetWindowHandle());
{ int wh = dpy->hostWindowGetSize((long)dpy->ioGetWindowHandle());
return (short)wh; }
return (short)wh; }


void* ioGetWindowHandle(void) { return dpy->ioGetWindowHandle(); }
void* ioGetWindowHandle(void) { return dpy->ioGetWindowHandle(); }


sqInt ioSetWindowWidthHeight(sqInt w, sqInt h)
sqInt ioSetWindowWidthHeight(sqInt w, sqInt h)
{ return dpy->hostWindowSetSize((long)dpy->ioGetWindowHandle(),w,h); }
{ return dpy->hostWindowSetSize((long)dpy->ioGetWindowHandle(),w,h); }


/*** Drag and Drop ***/
/*** Drag and Drop ***/


sqInt dndOutStart(char *types, int ntypes) { return dpy->dndOutStart(types, ntypes); }
sqInt dndOutStart(char *types, int ntypes) { return dpy->dndOutStart(types, ntypes); }
sqInt dndOutAcceptedType(char *type, int ntype) { return dpy->dndOutAcceptedType(type, ntype); }
sqInt dndOutAcceptedType(char *type, int ntype) { return dpy->dndOutAcceptedType(type, ntype); }
void dndOutSend(char *bytes, int nbytes) { dpy->dndOutSend(bytes, nbytes); }
void dndOutSend(char *bytes, int nbytes) { dpy->dndOutSend(bytes, nbytes); }
void dndReceived(char *fileName) { dpy->dndReceived(fileName); }
void dndReceived(char *fileName) { dpy->dndReceived(fileName); }


/*** OpenGL ***/
/*** OpenGL ***/


int verboseLevel= 1;
int verboseLevel= 1;


struct SqDisplay *ioGetDisplayModule(void) { return dpy; }
struct SqDisplay *ioGetDisplayModule(void) { return dpy; }


void *ioGetDisplay(void) { return dpy->ioGetDisplay(); }
void *ioGetDisplay(void) { return dpy->ioGetDisplay(); }
void *ioGetWindow(void) { return dpy->ioGetWindow(); }
void *ioGetWindow(void) { return dpy->ioGetWindow(); }
sqInt ioGLinitialise(void) { return dpy->ioGLinitialise(); }
sqInt ioGLinitialise(void) { return dpy->ioGLinitialise(); }


sqInt ioGLcreateRenderer(glRenderer *r, sqInt x, sqInt y, sqInt w, sqInt h, sqInt flags)
sqInt ioGLcreateRenderer(glRenderer *r, sqInt x, sqInt y, sqInt w, sqInt h, sqInt flags)
{
{
return dpy->ioGLcreateRenderer(r, x, y, w, h, flags);
return dpy->ioGLcreateRenderer(r, x, y, w, h, flags);
}
}


sqInt ioGLmakeCurrentRenderer(glRenderer *r) { return dpy->ioGLmakeCurrentRenderer(r); }
sqInt ioGLmakeCurrentRenderer(glRenderer *r) { return dpy->ioGLmakeCurrentRenderer(r); }
void ioGLdestroyRenderer(glRenderer *r) { dpy->ioGLdestroyRenderer(r); }
void ioGLdestroyRenderer(glRenderer *r) { dpy->ioGLdestroyRenderer(r); }
void ioGLswapBuffers(glRenderer *r) { dpy->ioGLswapBuffers(r); }
void ioGLswapBuffers(glRenderer *r) { dpy->ioGLswapBuffers(r); }


void ioGLsetBufferRect(glRenderer *r, sqInt x, sqInt y, sqInt w, sqInt h)
void ioGLsetBufferRect(glRenderer *r, sqInt x, sqInt y, sqInt w, sqInt h)
{
{
dpy->ioGLsetBufferRect(r, x, y, w, h);
dpy->ioGLsetBufferRect(r, x, y, w, h);
}
}




sqInt primitivePluginBrowserReady(void) { return dpy->primitivePluginBrowserReady(); }
sqInt primitivePluginBrowserReady(void) { return dpy->primitivePluginBrowserReady(); }
sqInt primitivePluginRequestURLStream(void) { return dpy->primitivePluginRequestURLStream(); }
sqInt primitivePluginRequestURLStream(void) { return dpy->primitivePluginRequestURLStream(); }
sqInt primitivePluginRequestURL(void) { return dpy->primitivePluginRequestURL(); }
sqInt primitivePluginRequestURL(void) { return dpy->primitivePluginRequestURL(); }
sqInt primitivePluginPostURL(void) { return dpy->primitivePluginPostURL(); }
sqInt primitivePluginPostURL(void) { return dpy->primitivePluginPostURL(); }
sqInt primitivePluginRequestFileHandle(void) { return dpy->primitivePluginRequestFileHandle(); }
sqInt primitivePluginRequestFileHandle(void) { return dpy->primitivePluginRequestFileHandle(); }
sqInt primitivePluginDestroyRequest(void) { return dpy->primitivePluginDestroyRequest(); }
sqInt primitivePluginDestroyRequest(void) { return dpy->primitivePluginDestroyRequest(); }
sqInt primitivePluginRequestState(void) { return dpy->primitivePluginRequestState(); }
sqInt primitivePluginRequestState(void) { return dpy->primitivePluginRequestState(); }




/*** errors ***/
/*** errors ***/


static void outOfMemory(void)
static void outOfMemory(void)
{
{
/* pushing stderr outputs the error report on stderr instead of stdout */
/* pushing stderr outputs the error report on stderr instead of stdout */
pushOutputFile((char *)STDERR_FILENO);
pushOutputFile((char *)STDERR_FILENO);
error("out of memory\n");
error("out of memory\n");
}
}


/* Print an error message, possibly a stack trace, do /not/ exit.
/* Print an error message, possibly a stack trace, do /not/ exit.
* Allows e.g. writing to a log file and stderr.
* Allows e.g. writing to a log file and stderr.
*/
*/
static void *printRegisterState(ucontext_t *uap);
static void *printRegisterState(ucontext_t *uap);


static void
static void
reportStackState(char *msg, char *date, int printAll, ucontext_t *uap)
reportStackState(char *msg, char *date, int printAll, ucontext_t *uap)
{
{
#if !defined(NOEXECINFO)
#if !defined(NOEXECINFO)
void *addrs[BACKTRACE_DEPTH];
void *addrs[BACKTRACE_DEPTH];
void *pc;
void *pc;
int depth;
int depth;
#endif
#endif
/* flag prevents recursive error when trying to print a broken stack */
/* flag prevents recursive error when trying to print a broken stack */
static sqInt printingStack = false;
static sqInt printingStack = false;


#if COGVM
#if COGVM
/* Testing stackLimit tells us whether the VM is initialized. */
/* Testing stackLimit tells us whether the VM is initialized. */
extern usqInt stackLimitAddress(void);
extern usqInt stackLimitAddress(void);
#endif
#endif


printf("\n%s%s%s\n\n", msg, date ? " " : "", date ? date : "");
printf("\n%s%s%s\n\n", msg, date ? " " : "", date ? date : "");
printf("%s\n%s\n\n", GetAttributeString(0), getVersionInfo(1));
printf("%s\n%s\n\n", GetAttributeString(0), getVersionInfo(1));


#if COGVM
#if COGVM
/* Do not attempt to report the stack until the VM is initialized!! */
/* Do not attempt to report the stack until the VM is initialized!! */
if (!*(char **)stackLimitAddress())
if (!*(char **)stackLimitAddress())
return;
return;
#endif
#endif


#if !defined(NOEXECINFO)
#if !defined(NOEXECINFO)
printf("C stack backtrace & registers:\n");
printf("C stack backtrace & registers:\n");
if (uap) {
if (uap) {
addrs[0] = printRegisterState(uap);
addrs[0] = printRegisterState(uap);
depth = 1 + backtrace(addrs + 1, BACKTRACE_DEPTH);
depth = 1 + backtrace(addrs + 1, BACKTRACE_DEPTH);
}
}
else
else
depth = backtrace(addrs, BACKTRACE_DEPTH);
depth = backtrace(addrs, BACKTRACE_DEPTH);
putchar('*'); /* indicate where pc is */
putchar('*'); /* indicate where pc is */
fflush(stdout); /* backtrace_symbols_fd uses unbuffered i/o */
fflush(stdout); /* backtrace_symbols_fd uses unbuffered i/o */
backtrace_symbols_fd(addrs, depth + 1, fileno(stdout));
backtrace_symbols_fd(addrs, depth + 1, fileno(stdout));
#endif
#endif


if (ioOSThreadsEqual(ioCurrentOSThread(),getVMOSThread())) {
if (ioOSThreadsEqual(ioCurrentOSThread(),getVMOSThread())) {
if (!printingStack) {
if (!printingStack) {
#if COGVM
#if COGVM
/* If we're in generated machine code then the only way the stack
/* If we're in generated machine code then the only way the stack
* dump machinery has of giving us an accurate report is if we set
* dump machinery has of giving us an accurate report is if we set
* stackPointer & framePointer to the native stack & frame pointers.
* stackPointer & framePointer to the native stack & frame pointers.
*/
*/
# if __APPLE__ && __MACH__ && __i386__
# if __APPLE__ && __MACH__ && __i386__
void *fp = (void *)(uap ? uap->uc_mcontext->ss.ebp: 0);
void *fp = (void *)(uap ? uap->uc_mcontext->ss.ebp: 0);
void *sp = (void *)(uap ? uap->uc_mcontext->ss.esp: 0);
void *sp = (void *)(uap ? uap->uc_mcontext->ss.esp: 0);
# elif __linux__ && __i386__
# elif __linux__ && __i386__
void *fp = (void *)(uap ? uap->uc_mcontext.gregs[REG_EBP]: 0);
void *fp = (void *)(uap ? uap->uc_mcontext.gregs[REG_EBP]: 0);
void *sp = (void *)(uap ? uap->uc_mcontext.gregs[REG_ESP]: 0);
void *sp = (void *)(uap ? uap->uc_mcontext.gregs[REG_ESP]: 0);
# elif __linux__ && __x86_64__
# elif __linux__ && __x86_64__
void *fp = (void *)(uap ? uap->uc_mcontext.gregs[REG_RBP]: 0);
void *fp = (void *)(uap ? uap->uc_mcontext.gregs[REG_RBP]: 0);
void *sp = (void *)(uap ? uap->uc_mcontext.gregs[REG_RSP]: 0);
void *sp = (void *)(uap ? uap->uc_mcontext.gregs[REG_RSP]: 0);
# elif __FreeBSD__ && __i386__
# elif __FreeBSD__ && __i386__
void *fp = (void *)(uap ? uap->uc_mcontext.mc_ebp: 0);
void *fp = (void *)(uap ? uap->uc_mcontext.mc_ebp: 0);
void *sp = (void *)(uap ? uap->uc_mcontext.mc_esp: 0);
void *sp = (void *)(uap ? uap->uc_mcontext.mc_esp: 0);
# elif __OpenBSD__
# elif __OpenBSD__
void *fp = (void *)(uap ? uap->sc_rbp: 0);
void *fp = (void *)(uap ? uap->sc_rbp: 0);
void *sp = (void *)(uap ? uap->sc_rsp: 0);
void *sp = (void *)(uap ? uap->sc_rsp: 0);
# elif __sun__ && __i386__
# elif __sun__ && __i386__
void *fp = (void *)(uap ? uap->uc_mcontext.gregs[REG_FP]: 0);
void *fp = (void *)(uap ? uap->uc_mcontext.gregs[REG_FP]: 0);
void *sp = (void *)(uap ? uap->uc_mcontext.gregs[REG_SP]: 0);
void *sp = (void *)(uap ? uap->uc_mcontext.gregs[REG_SP]: 0);
# elif defined(__arm__) || defined(__arm32__) || defined(ARM32)
# elif defined(__arm__) || defined(__arm32__) || defined(ARM32)
void *fp = (void *)(uap ? uap->uc_mcontext.arm_fp: 0);
void *fp = (void *)(uap ? uap->uc_mcontext.arm_fp: 0);
void *sp = (void *)(uap ? uap->uc_mcontext.arm_sp: 0);
void *sp = (void *)(uap ? uap->uc_mcontext.arm_sp: 0);
# else
# else
# error need to implement extracting pc from a ucontext_t on this system
# error need to implement extracting pc from a ucontext_t on this system
# endif
# endif
char *savedSP, *savedFP;
char *savedSP, *savedFP;


ifValidWriteBackStackPointersSaveTo(fp,sp,&savedFP,&savedSP);
ifValidWriteBackStackPointersSaveTo(fp,sp,&savedFP,&savedSP);
#endif /* COGVM */
#endif /* COGVM */


printingStack = true;
printingStack = true;
if (printAll) {
if (printAll) {
printf("\n\nAll Smalltalk process stacks (active first):\n");
printf("\n\nAll Smalltalk process stacks (active first):\n");
printAllStacks();
printAllStacks();
}
}
else {
else {
printf("\n\nSmalltalk stack dump:\n");
printf("\n\nSmalltalk stack dump:\n");
printCallStack();
printCallStack();
}
}
printingStack = false;
printingStack = false;
#if COGVM
#if COGVM
/* Now restore framePointer and stackPointer via same function */
/* Now restore framePointer and stackPointer via same function */
ifValidWriteBackStackPointersSaveTo(savedFP,savedSP,0,0);
ifValidWriteBackStackPointersSaveTo(savedFP,savedSP,0,0);
#endif
#endif
}
}
}
}
else
else
printf("\nCan't dump Smalltalk stack(s). Not in VM thread\n");
printf("\nCan't dump Smalltalk stack(s). Not in VM thread\n");
#if STACKVM
#if STACKVM
printf("\nMost recent primitives\n");
printf("\nMost recent primitives\n");
dumpPrimTraceLog();
dumpPrimTraceLog();
# if COGVM
# if COGVM
printf("\n");
printf("\n");
reportMinimumUnusedHeadroom();
reportMinimumUnusedHeadroom();
# endif
# endif
#endif
#endif
printf("\n\t(%s)\n", msg);
printf("\n\t(%s)\n", msg);
fflush(stdout);
fflush(stdout);
}
}


/* Attempt to dump the registers to stdout. Only do so if we know how. */
/* Attempt to dump the registers to stdout. Only do so if we know how. */
static void *
static void *
printRegisterState(ucontext_t *uap)
printRegisterState(ucontext_t *uap)
{
{
#if __linux__ && __i386__
#if __linux__ && __i386__
gregset_t *regs = &uap->uc_mcontext.gregs;
gregset_t *regs = &uap->uc_mcontext.gregs;
printf( "\teax 0x%08x ebx 0x%08x ecx 0x%08x edx 0x%08x\n"
printf( "\teax 0x%08x ebx 0x%08x ecx 0x%08x edx 0x%08x\n"
"\
"\tedi 0x%08x esi 0x%08x ebp 0x%08x esp 0x%08x\n"
"\teip 0x%08x\n",
regs[REG_EAX], regs[REG_EBX], regs[REG_ECX], regs[REG_EDX],
regs[REG_EDI], regs[REG_EDI], regs[REG_EBP], regs[REG_ESP],
regs[REG_EIP]);
return regs[REG_EIP];
#elif __FreeBSD__ && __i386__
struct mcontext *regs = &uap->uc_mcontext;
printf( "\