/******************************** -*- C -*- ****************************
 *
 * System specific implementation module.
 *
 * This module contains implementations of various operating system
 * specific routines.  This module should encapsulate most (or all) of
 * these calls so that the rest of the code is portable.
 *
 * $Revision: 1.7.5$
 * $Date: 2000/05/28 16:56:52$
 * $Author: pb$
 *
 ***********************************************************************/

/***********************************************************************
 *
 * Copyright 1988-92, 1994-95, 1999, 2000 Free Software Foundation, Inc.
 * Written by Steve Byrne.
 *
 * This file is part of GNU Smalltalk.
 *
 * GNU Smalltalk is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2, or (at your option) any later
 * version.
 *
 * GNU Smalltalk is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * GNU Smalltalk; see the file COPYING.	 If not, write to the Free Software
 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 ***********************************************************************/


#include "gst.h"
#include "sysdep.h"
#include "alloc.h"

#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/times.h>

#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif 

#ifdef HAVE_GETRUSAGE
# include <sys/resource.h>
#endif

#if defined(HAVE_SYS_TIME_H) || defined(TIME_WITH_SYS_TIME)
# include <sys/time.h>
#endif
#if !defined(HAVE_SYS_TIME_H) || defined(TIME_WITH_SYS_TIME)
# include <time.h>
#endif

#ifdef STDC_HEADERS
# include <string.h>
# include <stdlib.h>
#endif /* STDC_HEADERS */

#ifdef HAVE_STDARG_H
#include <stdarg.h>
#else
#include <varargs.h>
#endif

#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
#ifndef WEXITSTATUS
# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
#endif
#ifndef WIFEXITED
# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
#endif

#if !defined(__OS2__) && !defined(_MSC_VER)
#  include <sys/param.h>
#endif
#ifdef WIN32
#  include <windows.h>
#endif

#ifdef __OS2__
#  include <direct.h>
#endif

#ifdef HAVE_IO_H
# include <io.h>
#endif

#ifndef R_OK
# ifdef S_IREAD
#  define R_OK S_IREAD
# else
#  define R_OK 4
# endif
#endif

#ifndef PATH_MAX
#define PATH_MAX  1024 /* max length of a file and path */
#endif

#ifndef SIGALRM
#define SIGALRM		SIGUSR1		/* hmmm... */
#endif

static int	tm_diff ();

#undef INTERRUPTS_DONE
#ifdef SIG_BLOCK
#define INTERRUPTS_DONE
static int disabled = false;

/*
 * IntState disableInterrupts()
 *
 * Description
 *
 * Saves and returns the current state of the software interrupt system.
 * Disables all interrupts.
 *
 * Outputs
 *
 * The old state of the interrupt system (presumably for saving for a
 * later call to enableInterrupts).
 */
IntState
disableInterrupts()
{
  sigset_t	  newSet;
  static sigset_t oldSet;

  if (disabled) {
    /* let only the outermost calls actually block and unblock signals */
    return ((IntState) NULL);
  }
  disabled = true;
  sigfillset(&newSet);
  sigprocmask(SIG_BLOCK, &newSet, &oldSet);
  return ((IntState) &oldSet);
}

/*
 * void enableInterrupts(mask)
 *
 * Description
 *
 * Restores the state of the interrupt system to that which it had when
 * "mask" was created.
 *
 * Inputs
 *
 * mask	 : An interrupt state...should have been returned at some point
 *  from a call to disableInterrupts.
 *
 */
void
enableInterrupts(newSet)
     IntState newSet;
{
  if (newSet) {
    disabled = false;
    sigprocmask(SIG_SETMASK, (sigset_t *) newSet, NULL);
  }
}
#endif

#if defined(HAVE_SIGSETMASK) && !defined(INTERRUPTS_DONE) /* BSD style */
#define INTERRUPTS_DONE
IntState
disableInterrupts()
{
  return (sigsetmask(-1));
}

void
enableInterrupts(mask)
     IntState mask;
{
  sigsetmask(mask);
}
#endif

#if defined(HAVE_SIGHOLD) && !defined(INTERRUPTS_DONE) /* SVID style */
#define INTERRUPTS_DONE
static mst_Boolean disabled;

IntState
disableInterrupts()
{
  register int i;

  if (disabled) {
    /* let only the outermost calls actually block and unblock signals */
    return (0);
  }

  disabled = true;
  for (i=1; i <= 8 * SIZEOF_LONG; i++) {
    sighold(i);	 /* want it blocked - ok if it already is */
  }
  return (1);
}

void
enableInterrupts(mask)
     IntState mask;
{
  register int i;

  if (!mask) {
    return;
  }

  disabled = false;
  for (i=1; i <= 8 * SIZEOF_LONG; i++) {
    sigrelse(i); /* want it unblocked if it used to be */
  }
}
#endif

#ifndef INTERRUPTS_DONE
IntState
disableInterrupts()
{
  return ((IntState) 0);   /* no recognized interrupt mechanism */
}

void
enableInterrupts(mask)
     IntState mask;
{
  /* no way dude */
}
#endif

void
setSignalHandler(signum, handlerFunc)
     int signum;
     RETSIGTYPE (*handlerFunc)(SIG_ARG_TYPE);
{
#if defined(_POSIX_VERSION) || defined(__DJGPP__)
  /* If we are running on a posix-compliant system, then do
   * things the Posix way. */
  struct sigaction act;

  act.sa_handler = handlerFunc;
  act.sa_flags = 0;

  sigemptyset (&act.sa_mask);
  sigaction (signum, &act, (struct sigaction *)NULL);
#else
  signal(signum, handlerFunc);
#endif
}




/*
 * unsigned long getMilliTime()
 *
 * Description
 *
 * Returns the local time since midnight in milliseconds
 *
 */
unsigned long
getMilliTime()
{
#undef MILLI_DONE
#ifdef WIN32
#define MILLI_DONE
  /* time() seems not to work... so we hack. This method to 
   * obtain the time is complex, but it is the most precise. */
  static long		frequency = 0, frequencyH, adjust = 0;
  long			milli;
  LARGE_INTEGER		counter;
  SYSTEMTIME		st;

  if (!frequency) {
    if (QueryPerformanceFrequency (&counter)) {
      /* frequencyH = 1000 * 2^32 / frequency */
      frequency = counter.HighPart ? -1 : counter.LowPart;
      frequencyH = MulDiv (1000 * (1 << 16), (1 << 16), frequency);
    } else {
      frequency = -1;
    }
  }

  if (frequency == -1) {
    /* QueryPerformanceCounter not supported, always use GetLocalTime */
    adjust = milli = 0;
  } else {
    QueryPerformanceCounter (&counter);
    /* milli = (high * 2^32 + low) * 1000 / freq
     *       = high * (1000 * 2^32 / freq) + (low * 1000 / freq)
     *       = (high * frequencyH) + (low / 4) * 4000 / freq)
     *
     * Dividing and multiplying counter.LowPart by 4 is needed because
     * MulDiv accepts signed integers but counter.LowPart is unsigned. */
    milli = counter.HighPart * frequencyH;
    milli += MulDiv(counter.LowPart >> 2, 4000, frequency);
  }

  if (!adjust) {
    GetLocalTime(&st);
    adjust = st.wMilliseconds;
    adjust += st.wSecond * 1000;
    adjust += st.wMinute * 60000;
    adjust += st.wHour   * 3600000;
    adjust -= milli;
    milli += adjust;
  } else {
    milli += adjust;
    while (milli > 86400000) {
      milli -= 86400000;
      adjust -= 86400000;
    }
  }
  return (milli);
#endif

#if defined(HAVE_GETTIMEOFDAY) && !defined(MILLI_DONE) /* BSD style */
#define MILLI_DONE
  struct timeval t;

  gettimeofday(&t, nil);
  return (t.tv_sec * 1000 + t.tv_usec / 1000);
#endif

#ifndef MILLI_DONE
  clock_t t;
#ifdef _POSIX_VERSION
  struct tms dummy;
  t = times(&dummy);
#else /* !_POSIX_VERSION */
  t = clock();
#endif /* !_POSIX_VERSION */
  return ( ((double)t) * 1000 / CLOCKS_PER_SEC);
#endif
}

#define TM_YEAR_BASE 1900

/* Yield A - B, measured in seconds.
   This function is copied from the GNU C Library.  */
static int
tm_diff (a, b)
     struct tm *a, *b;
{
  /* Compute intervening leap days correctly even if year is negative.
   * Take care to avoid int overflow in leap day calculations,
   * but it's OK to assume that A and B are close to each other.  */
  int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
  int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
  int a100 = a4 / 25 - (a4 % 25 < 0);
  int b100 = b4 / 25 - (b4 % 25 < 0);
  int a400 = a100 >> 2;
  int b400 = b100 >> 2;
  int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
  int years = a->tm_year - b->tm_year;
  int days = (365 * years + intervening_leap_days
	      + (a->tm_yday - b->tm_yday));
  return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
		+ (a->tm_min - b->tm_min))
	  + (a->tm_sec - b->tm_sec));
}

/*
 * long adjustTimeZone(time_t)
 *
 * Description
 *
 * Converts the given time (expressed in seconds since midnight Jan 1, 1970,
 * and in Universal Coordinated Time) into a local time.
 *
 * Outputs
 *
 * The local time, also expressed in seconds since midnight Jan 1, 1970.
 */
long
adjustTimeZone(t)
     time_t t;
{
  struct tm save_tm, *decoded_time;
  long bias;

#ifdef LOCALTIME_CACHE
  tzset ();
#endif
  decoded_time = localtime(&t);
  save_tm = *decoded_time;
  decoded_time = gmtime (&t);
  bias = tm_diff (&save_tm, decoded_time);

  return(((long) t) + bias);
}

long
currentTimeZoneBias()
{
  time_t now;
  long bias;
  struct tm save_tm, *decoded_time;

  time(&now);

#ifdef LOCALTIME_CACHE
  tzset ();
#endif

  decoded_time = localtime(&now);
  save_tm = *decoded_time;
  decoded_time = gmtime (&now);
  bias = tm_diff (&save_tm, decoded_time);
  return(bias);
}

/*
 * char *currentTimeZoneName()
 *
 * Description
 *
 * Returns the name of the current time zone.
 *
 * Outputs
 *
 * As described above, or XXX if the time zone's name could not be found.
 */
char *
currentTimeZoneName()
{
  char *zone;
  zone = getenv("TZ");
  if (!zone) {
    long bias = currentTimeZoneBias() / 60;
#ifdef _WIN32
    TIME_ZONE_INFORMATION tzi;
    LPCWSTR name;
    static char buffer[32];
    GetTimeZoneInformation(&tzi);
    zone = buffer;
    name = (bias == (tzi.Bias + tzi.StandardBias))
      ? tzi.StandardName : tzi.DaylightName;
    
    WideCharToMultiByte(CP_ACP, 0,
      name, lstrlenW(name), zone, 32,
      NULL, NULL);

#else
    /* Maybe we could guess it */
    zone = "XXX";
#endif
  }

  return strdup(zone);
}

/*
 * long getTime()
 *
 * Description
 *
 * Returns the time in seconds since midnight Jan 1, 1970 (standard UNIX
 * type time).
 *
 * Outputs
 *
 * As described above.
 */
long
getTime()
{
  time_t now;
  time(&now);

  return (adjustTimeZone(now));
}



/*
 * void signalAfter(deltaMilli, func)
 *
 * Description
 *
 * Set up func as a signal handler to be called after deltaMilli
 * milliseconds.
 *
 * Inputs
 *
 * deltaMilli:
 * 	Time in milliseconds before the function is invoked.  Rounded
 * 	up to nearest second for machines without higher precision
 * 	timers.
 * func:
 *	Signal handling function invoked when interval expires
 *
 * Outputs
 *
 * None.
 */

#ifdef WIN32
struct {
  HANDLE	hNewWaitEvent;
  HANDLE	hCritEvent;
  long		sleepTime;
} alarms;

/* thread for precise alarm callbacks */
void CALLBACK
alarmThread(unused)
     LPVOID unused;
{
  WaitForSingleObject(alarms.hNewWaitEvent, INFINITE);
  for(;;) {
    int sleepTime;

    WaitForSingleObject(alarms.hCritEvent, INFINITE);
    sleepTime = alarms.sleepTime;
    SetEvent(alarms.hCritEvent);

    if (sleepTime > 0) {
      if (WaitForSingleObject(alarms.hNewWaitEvent, sleepTime) != WAIT_TIMEOUT) {
	/* The old wait was canceled by a new one */
	continue;
      }
    }
    kill(getpid(), SIGALRM);
    WaitForSingleObject(alarms.hNewWaitEvent, INFINITE);
  }
}

static void
initializeAlarms()
{
  HANDLE hthread;
  DWORD tid;

  /* Starts as non-signaled, so alarmThread will wait */
  alarms.hNewWaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

  /* Starts as signaled (i.e. the first wait won't block) */
  alarms.hCritEvent = CreateEvent(NULL, FALSE, TRUE, NULL);

  /* Start alarmThread with a 1024 bytes stack */
  hthread = CreateThread(NULL,
    1024,
    (LPTHREAD_START_ROUTINE) alarmThread,
    NULL, 0, &tid);

  /* This does not terminate the thread - it only releases our handle */
  CloseHandle(hthread);
}

#else
static void
initializeAlarms()
{
}
#endif

void
signalAfter(deltaMilli, func)
     int deltaMilli;
     RETSIGTYPE (*func)();
{
/* Please feel free to make this more accurate for your operating system
 * and send me the changes.
 */
  setSignalHandler(SIGALRM, func);

  if (deltaMilli <= 0) {
    kill(getpid(), SIGALRM);
  } else {

#ifdef WIN32
#define ALARM_DONE
    WaitForSingleObject(alarms.hCritEvent, INFINITE);
    alarms.sleepTime = deltaMilli;
    SetEvent(alarms.hCritEvent);
    SetEvent(alarms.hNewWaitEvent);
#endif

#if defined(ITIMER_REAL) && !defined(ALARM_DONE)
#define ALARM_DONE
    struct itimerval value;
    value.it_interval.tv_sec = value.it_interval.tv_usec = 0;
    value.it_value.tv_sec = deltaMilli/1000;
    value.it_value.tv_usec = (deltaMilli%1000) * 1000;
    setitimer(ITIMER_REAL, &value, (struct itimerval *)0);
#endif

#if defined(HAVE_FORK) && !defined(ALARM_DONE)
#define ALARM_DONE
    static pid_t pid = -1;
    long end, ticks;
    if (pid != -1) {
      kill(pid, SIGTERM);
    }
    setSignalHandler(SIGCHLD, SIG_IGN);
    switch(pid = fork()) {
      case -1:
	/* Error, try to recover */
	kill(getpid(), SIGALRM);
	break;

      case 0:
	/* Child process */
	end = getMilliTime() + deltaMilli;
	do {
	  ticks = end - getMilliTime();
	  if (ticks > 1100) {		/* +100 is arbitrary */
	    sleep((int) (ticks / 1000))
	  }
	} while (ticks > 0);
	kill (getppid(), SIGALRM)
	_exit(0);
    }
#endif

#if defined(HAVE_ALARM) && !defined(ALARM_DONE)
#define ALARM_DONE
    alarm(deltaMilli / 1000);
#endif

#if defined(ALARM_DONE)
#undef ALARM_DONE
#else
    /* Cannot do anything better than this */
    kill(getpid(), SIGALRM);
#endif
  }
}

void
relinquish(usecs)
     int usecs;
{
/* Please feel free to make this more accurate for your operating system
 * and send me the changes.
 */
#if defined(WIN32)
  Sleep((usecs + 999) / 1000);
#elif defined(__DJGPP__)
  usleep(usecs);
#else
#ifdef HAVE_SELECT
  struct timeval time;
  time.tv_sec = usecs / 1000000;
  time.tv_usec = usecs % 1000000;

  select(0, NULL, NULL, NULL, &time);
#endif
#endif
}


/*
 * char *getCurDirName()
 *
 * Description
 *
 * Returns the path name for the current directory, without trailing
 * delimiter (?).
 *
 * Outputs
 *
 * Pointer to allocated string for current path name.  Caller has
 * responsibility for freeing the returned value when through.
 */
char *
getCurDirName()
{
#ifdef HAVE_GETCWD
  char *cwd;
  char *ret;
  unsigned path_max;
  int save_errno;

  path_max = (unsigned) PATH_MAX;
  path_max += 2;  /* The getcwd docs say to do this. */

  cwd = xmalloc (path_max);

  errno = 0;
  do {
    ret = getcwd (cwd, path_max);
    if (ret) {
      return (cwd);
    }
    if (errno != ERANGE) {
      break;
    }
    errno = 0;
    path_max += 128;
    cwd = xrealloc (cwd, path_max);
  } while (!errno);

  save_errno = errno;
  xfree (cwd);
  errno = save_errno;
  return (NULL);
#else
  char	name[PATH_MAX+2];
  getwd(name);
  return (strdup(name));
#endif
}


/*
 * char *getFullFileName(fileName)
 *
 * Description
 *
 * Returns the full path name for a given file.
 *
 * Inputs
 *
 * fileName:
 *  Pointer to file name, can be relative or absolute
 *
 * Outputs
 *
 * Full path name string.  Caller has the responsibility for freeing the
 * returned string.
 */
char *
getFullFileName(fileName)
     char *fileName;
{
  char	*fullFileName;
  static char *fullPath = NULL;

  if (fileName[0] == '/'
#if defined(MSDOS)
      || fileName[0] == '\\'
      || (fileName[0] && fileName[1] == ':' &&
	  (fileName[2] == '/' || fileName[2] == '\\'))
#endif
      )
    /* absolute, so don't need to change */
    return (strdup(fileName));

  if (fullPath == NULL) {
    /* Only need to do this once, then cache the result */
    fullPath = getCurDirName();
  }

  /*
   * ### canonicalize filename and full path here in the future (remove any
   * extraneous .. or . directories, etc.)
   */

  fullFileName = (char *)xmalloc(strlen(fullPath) + strlen(fileName)
    + 1 /* slash */
    + 1 /* trailing nul */);
  sprintf(fullFileName, "%s/%s", fullPath, fileName);
  return (fullFileName);
}



/*
 * long getFileModifyTime(fileName)
 *
 * Description
 *
 * Returns the time the file "fileName" was last modified.  On UNIX
 * machines, this is the number of seconds since midnight Jan 1 1970 GMT.
 * On other platforms/environments, it's probably not important exactly
 * what it returns as long as it's unites consistent with other accesses
 * that client code may do to the file system.
 *
 * Inputs
 *
 * fileName:
 *  Name of the file to be checked.
 *
 * Outputs
 *
 * Time the file was last modified, in some reasonable units for the local
 * operating system.
 */
long
getFileModifyTime(fileName)
     char *fileName;
{
  struct stat st;

  if (stat(fileName, &st) < 0) {
    return ((unsigned long)0);
  } else {
    return (adjustTimeZone(st.st_mtime));
  }
}


/*
 * mst_Boolean fileIsReadable(fileName)
 * mst_Boolean fileIsWriteable(fileName)
 *
 * Description
 *
 * Returns true if the file named "fileName" exists and is readable or
 * writable by the current process.  Returns false otherwise.
 *
 * Inputs
 *
 * fileName:
 *  The name of the file to check on.
 *
 * Outputs
 *
 * True if the file exists and is readable/writeable, false otherwise.
 */
mst_Boolean
fileIsReadable(fileName)
     char *fileName;
{
  return (access(fileName, R_OK) == 0);
}

mst_Boolean
fileIsWriteable(fileName)
     char *fileName;
{
  return (access(fileName, W_OK) == 0);
}


FILE *
openPipe(command, mode)
     char *command, *mode;
{
#ifdef HAVE_POPEN
  return (popen(command, mode));
#else
#if defined(HAVE_PIPE) && defined(HAVE_WAITPID)

  int fildes[2];
  int parent_pipe_end, child_pipe_end;

  if (mode[1]) {
    return (NULL);	/* Must be a single character long */
  } else if (mode[0] == 'w') {
    parent_pipe_end = 1; child_pipe_end = 0;
  } else if (mode[0] == 'r') {
    parent_pipe_end = 0; child_pipe_end = 1;
  } else {
    return (NULL);
  }

  if (pipe(fildes) != 0) {
    /* Cannot create pipe */
    return (NULL);
  }

  switch (fork()) {
  case -1:
    /* Error */
    break;

  case 0:
    /* Child process */
    if ((close(fildes[parent_pipe_end]) != 0)
	|| (close(child_pipe_end) != 0)
	|| (dup(fildes[child_pipe_end]) != child_pipe_end)) {
      _exit(1);
    }

    /* Write a single byte through the pipe to establish it */
    if (child_pipe_end == 1) {
      write(fildes[child_pipe_end],"z",1);
    } else {
      char buff[1];
      read(fildes[child_pipe_end],buff,1);
      if (*buff != 'z') {
        _exit(1);
      }
    }

    _exit (system(command) >= 0);
    /*NOTREACHED*/

  default:
    /* Parent process */
    if (close(fildes[child_pipe_end]) != 0) {
      break;
    }

    /* Write a single byte through the pipe to establish it */
    if (parent_pipe_end == 1) {
      write(fildes[parent_pipe_end],"z",1);
    } else {
      char buff[1];
      read(fildes[parent_pipe_end],buff,1);
      if (*buff != 'z') {
        break;
      }
    }

    return fdopen(fildes[parent_pipe_end], mode);
  }

  /* Error */
  close(fildes[0]);
  close(fildes[1]);
  return (NULL);
#endif
#endif
}

/*
 * int closePipe(file)
 *
 * Description
 *
 * Closes the given pipe (if it is a pipe).
 *
 * Inputs
 *
 * file	 : A stdio type FILE pointer.
 *
 * Outputs
 *
 * Returns -1 on error.
 */
int
closePipe(file)
     FILE *file;
{
#ifdef HAVE_POPEN
  return (pclose(file));
#else
#if defined(HAVE_PIPE) && defined(HAVE_WAITPID)
  int statloc;
  /* need to call fclose() to deallocate FILE buffer */
  close(fileno(file));
  fclose(file);

  while((waitpid((pid_t) -1, &statloc, 0) == -1) && (errno == EINTR)) ;
  return (statloc);
#endif
#endif
}


FILE *
openFile(fileName, fileMode)
     char *fileName, *fileMode;
{
#if defined(WIN32) || defined(__OS2__) || defined(MSDOS)
  char *fileModeBinary;
  fileModeBinary = alloca(strlen(fileMode) + 2);
  strcpy(fileModeBinary, fileMode);
  strcat(fileModeBinary, "b");
  return (fopen(fileName, fileModeBinary));
#else
  return (fopen(fileName, fileMode));
#endif
}


#ifndef HAVE_GETDTABLESIZE
int
getdtablesize()
{
  int tableSize = -1;

#ifdef  _SC_OPEN_MAX            /* POSIX -- preferred */
  tableSize = sysconf(_SC_OPEN_MAX);
#else
#ifdef RLIMIT_NOFILE           /* who is non POSIX but has this? */
  if (getrlimit(RLIMIT_NOFILE, &rlimit) != -1) {
    tableSize = rlimit.rlim_max;
#endif
#endif

  /* If something went wrong, choose a safe >>>hack<<< value */
  return (tableSize == -1) ? sizeof(short) * 8 : tableSize;
}

#endif /* ! HAVE_GETDTABLESIZE */


/*
 * void initSysdep()
 *
 * Description
 *
 * Perform any system dependent initializations that are required.
 *
 */
void
initSysdep()
{
#ifdef SIGCHLD
  setSignalHandler (SIGCHLD, SIG_IGN);
#endif
  initializeAlarms();
  tzset ();
}

void
flushCode(dest, len)
     char 	*dest;
     int	len;
{
#ifdef __GNUC__
#ifdef PPC
  for (; len > 0; dest += SIZEOF_CHAR_P, len -= SIZEOF_CHAR_P) {
    __asm__ __volatile__ ("dcbst 0,%0; sync; icbi 0,%0; isync"::"r"(dest));
  }
#endif

#ifdef __sparc__
  __asm__ __volatile__ ("stbar");
  for (; len > 0; dest += SIZEOF_CHAR_P, len -= SIZEOF_CHAR_P) {
    __asm__ __volatile__ ("flush %0"::"r"(dest));
  }

  /* [SPARC Architecture Manual v8, page 139, implementation note #5] */
  __asm__ __volatile__ ("nop; nop; nop; nop; nop");

#endif

#ifdef __alpha__
  __asm__ __volatile__ ("call_pal 0x86");
#endif

#ifdef __mc68000__
  /* On the 68040 (and 060 I presume) we need to flush the instruction
   * cache before running new code.  Stupidly, Motorola made cpush a
   * privledged instruction, so we have to get operating system help
   * for this.  Don't bother asking: there is no standard there. 
   * 
   * We are partially rescued by gcc, which must be taught how to do this
   * in order to build bound-function trampolines.  This works at least
   * for A/UX, Linux and NeXT.  The rest of you with 040's should
   * consider fixing gcc, as you are broken there too.  
   * 
   * For those with 020's and 030's, this is effectively a no-op.  */

  __clear_cache(dest, dest + len)
#endif

#endif /* __GNUC__ */
}

#ifdef HAVE_STDARG_H
void debugf (const char *fmt, ...)
#else
void
debugf(va_alist)
     va_dcl
#endif
{
  char buf[1024];
  va_list args;
#ifndef HAVE_STDARG_H
  char  *fmt;
  va_start(args);
  fmt = va_arg(args, char *);
#else /* !HAVE_STDARG_H */
  va_start (args, fmt);
#endif /* !HAVE_STDARG_H */

  vsprintf (buf, fmt, args);

#if defined(WIN32) && !defined(__CYGWIN__)&& !defined(__CYGWIN32__)
  /* VC++ has a Win32-friendly debugger, otherwise winning Cygwin has not */
  OutputDebugString (buf);
#else /* !WIN32 */
  {
    static FILE *debFile = NULL;
    if (debFile == NULL) {
      debFile = fopen("mst.deb", "w");
    }
    fputs(buf, debFile);
    fflush(debFile);
  }
#endif /* !WIN32 */

  va_end(args);
}

/*
 *	void debug()
 *
 * Description
 *
 *	Used for debugging.  You set a breakpoint in the debug routine in the
 *	debugger, and have code call it when you want it to stop.  Performs no
 *	action normally.
 *
 */
void
debug()
{
/* kill(getpid(), SIGTRAP); */
/* getchar(); */
}

