delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1997/03/30/12:46:35

Date: Sun, 30 Mar 97 18:32:31 BST
From: Tomas By <T DOT By AT dcs DOT shef DOT ac DOT uk>
Message-Id: <9703301732.AA26061@gw.dcs.shef.ac.uk>
To: eliz AT is DOT elta DOT co DOT il
Subject: Re: Compiling Sicstus Prolog
Cc: djgpp AT delorie DOT com, tomas AT delorie DOT com

----------
X-Sun-Data-Type: text
X-Sun-Data-Description: text
X-Sun-Data-Name: text
X-Sun-Content-Lines: 84

Hi Eli,

Thanks for replying.

> Can you explain what are the holes[].begin and holes[].end used for in
> Sicstus Prolog?

It has something to do with the format of the data file for saving a
state. You can probably find out more than I can from the source file,
so I enclose it. Look for the functions 'write_data_bss' and
'write_segment_with_holes'.

The orignal code (saverest.c) is:

| #if DJGCC
|   {
|     extern edata, _bss_start, _go32_info_block[];
|
|     holes[h].begin = (char *)&edata;
|     holes[h++].end = (char *)&_bss_start;
|     holes[h].begin = (char *)&_go32_info_block;
|     holes[h++].end = (char *)&_go32_info_block+40;
|   }
| #endif

And the suggested change makes it:

| #if DJGCC
|   {
|     extern edata, _go32_info_block[];
|
|     holes[h].begin = (char *)&edata;
|     holes[h++].end = (char *)SP_ALIGN(&edata,0x1000); /* line 538 */
|     holes[h].begin = (char *)&_go32_info_block;
|     holes[h++].end = (char *)&_go32_info_block+40;
|   }
| #endif

This is the only change made to 'saverest.c'. No other files are changed.

> The .bss section indeed begins at `edata' in v2, but

What was edata in v1? The same as _bss_start? Then the orignal code seems
strange.

> I'm not sure about the .end part (if it should give the end of .bss,
> then you should use (char *)&end, I think).

I can try this.

The purpose of SP_ALIGN (which is defined in alloc.h) seems to be that the
'hole' should have a fixed length. How large is the bss section? Has that
size changed between v1 and v2?

> And what about the two
> other variables that reference `_go32_info_block'?  How are they used?

I'm afraid I don't know anything more about this.

> It's possible that the message you've found in the mail archives are
> talking about DJGPP v1.x (the date of the message should tell),

(I tried to search the archive again just now and it didn't turn up
anything at all about 'sicstus' or 'prolog'. Something must have changed
since last week.)

The message I found was concerned with some upgrade of the compiler.
Presuambly the same upgrade when '_bss_start' was removed. I think it
was before v2.

So I'm not aware of anyone who has compiled Sicstus 2.1 successfully
with DJGPP v2.

> in which case the solution might need some tweaking.  But unless
> somebody has already done that and might therefore have an exact answer,
> you will need to explain the use of these values in order to have a
> solution.

I havent got any other replies yet.

It seems to me the main question is the number 0x1000. Can this refer to
anything which might have changed between v1 and v2?

/Tomas
----------
X-Sun-Data-Type: c-file
X-Sun-Data-Description: c-file
X-Sun-Data-Name: saverest.c
X-Sun-Content-Lines: 844

/* Copyright (C) 1988, Swedish Institute of Computer Science. */

/* Support for the predicates save/[1,2], save_program/1 and restore/1. */

#if LOADC
static char *ignore;
#else

#define STDOUT 1
#define STDERR 2

#include "datadefs.h"
#include "support.h"
#if !MACINTOSH
#include <sys/stat.h>
#endif
#ifndef O_RDONLY
# include <fcntl.h>
#endif

    /* MSDOS has BINARY/TEXT file mode. TEXT mode convert NL->CR/NL. So we
       have to use BINARY here. This is a general problem in MSDOS */
#ifndef O_BINARY
# define O_BINARY 0
#endif

#if !DJGCC && !MACINTOSH
#include <sys/errno.h>
#else
#include <errno.h>
#endif
#ifndef EISDIR
# define EISDIR EINVAL
#endif
extern int errno;

#ifndef ZSAVE
#define ZSAVE 1
#endif

#if ZSAVE
#include "compress.h"
#define zread(a,b,c)  compress_read((struct zsave *)a,b,c)
#define zwrite(a,b,c) compress_write((struct zsave *)a,b,c)
#define zclose(a)     (compress_close((struct zsave *)a),Sbrk(-sizeof(struct zsave)))
#define TMPSBRK0 ((char *)dumpFile)
#else
#define zread(a,b,c)  read(a,b,c)
#define zwrite(a,b,c) write(a,b,c)
#define zclose(a)     close(a)
#define TMPSBRK0 Sbrk(0)
#endif


/* Format of a dump file:
 *	#! /bin/sh\n
 *	exec SOURCEPATH/Emulator/sp -r $0 -a "$@"\n
 *	version\n
 *	path to emulator\n
 *	top_of_memory
 *	symbol_table
 *	data_segments
 *	stack_segment
 */

#if _AIX && !aiws
#define etext _etext
#endif

extern char **environ;
extern end, etext;

static char char128;		/* Latin-1 or EUC? */

/* segment types */
typedef int segmentType;
#define SYMBOL_TABLE_SEGMENT 1
#define DATA_SEGMENT 2
#define STACK_SEGMENT 3

struct segmentHeader {
    segmentType type;
    unsigned long length;
    char *baseAddress;
};

struct hole {
  char *begin;
  char *end;
};

void (*SP_foreign_reinit_hook)() = NULL;

#if gould || NeXT

BOOL prolog_restore(fileName)
     char *fileName;
{
  return FALSE;			/* give up */
}

BOOL prolog_save(fileName)
     char *fileName;
{
  return FALSE;			/* give up */
}

#else

/* int skip_line(dumpFile)
 * int dumpFile;	The file to read from;
 *
 * Skip over two lines in dumpFile (up to version string).
 */
static int skip_line(dumpFile)
     int dumpFile;
{
  char buf[256];
  char *ch = buf;

  read(dumpFile, buf, 256);
  while (*ch++ != '\n')
    ;
  while (*ch++ != '\n')
    ;
  return lseek(dumpFile, ch-buf, 0)>-1;
}


/* int check_version(dumpFile)
 * int dumpFile;	The file to read from.
 *
 * Check that the dump version agrees with the emulator version.
 */
static int check_version(dumpFile)
     int dumpFile;
{
  char buf[80];
  int len = strlen(emulator_version);
  
  if (read(dumpFile, buf, len+1)!=len+1)
    return 0;
  buf[len] = 0;
  return !strcmp(emulator_version, buf);
}

/* int write_segment_header(dumpFile, type, length, baseAddress)
 * int dumpFile;	The level 1 file on which to output.
 * segmentType type;The type of the segment.
 * unsigned long length;The length of the segment.
 * char *baseAddress;	The base address of the segment.
 *
 * Write a segment header to dumpFile.
 */
static int write_segment_header(dumpFile, type, length, baseAddress)
     int dumpFile;
     segmentType type;
     unsigned long length;
     char *baseAddress;
{
  struct segmentHeader header;
  
  header.type = type;
  header.length = length;
  header.baseAddress = baseAddress;
  return (zwrite(dumpFile, &header, sizeof(header)) > 0);
}

/* int write_segment(dumpFile, type, segmentStart, segmentEnd)
 * int dumpFile;	The level 1 file on which to output.
 * segmentType type;The type of the segment.
 * char *segmentStart;	Start of segment to be written.
 * char *segmentEnd;	End of segment to be written.
 *
 * Write a segment to dumpFile.
 */
static int write_segment(dumpFile, type, segmentStart, segmentEnd)
     int dumpFile;
     segmentType type;
     char *segmentStart;
     char *segmentEnd;
{
  if (!write_segment_header(dumpFile, type, segmentEnd - segmentStart,
			    segmentStart))
    return 0;
  for (; (segmentEnd - segmentStart) >= BUFSIZ; segmentStart += BUFSIZ)
    if (zwrite(dumpFile, segmentStart, BUFSIZ) != BUFSIZ)
      return 0;
  if (segmentStart < segmentEnd)
    return (zwrite(dumpFile, segmentStart, segmentEnd - segmentStart) ==
	    segmentEnd - segmentStart);
  return 1;
}

/* int write_header(dumpFile)
 * int dumpFile;	The level 1 file on which to output.
 *
 * Write a header to dumpFile (see dump file format above).
 */
static int write_header(dumpFile)
     int dumpFile;
{
  char buf[MAXPATHLEN+30];
  
#if MSDOS
  /* there are no shells in MSDOS but command.com is ... */
  char *p;
  for (p = EG.persistent.emulator_path; *p = (*p == '/'?'\\':*p) ; p++);
  sprintf(buf,"%s -r %%0.bat -a %%1 %%2 %%3 %%4 %%5 %%6 %%7 %%8 %%9\r\n\032\r\n",
	  EG.persistent.emulator_path);
  for (p = EG.persistent.emulator_path; *p = (*p == '\\'?'/':*p) ; p++);
#else
  sprintf(buf,"#! /bin/sh\nexec %s -r $0 -a \"$@\"\n",
	  EG.persistent.emulator_path);
#endif
  return((write(dumpFile, buf, strlen(buf)) > 0) &&
	 (write(dumpFile, emulator_version, strlen(emulator_version)) > 0) &&
	 (write(dumpFile, "\n", 1) > 0));
}

#if MMAP
#define MEMTOPHEADSIZE (1+3*2)*sizeof(TAGGED)
#else
#define MEMTOPHEADSIZE sizeof(TAGGED)
#endif

/* int set_top_of_memory(dumpfile)
 * int dumpFile;	The file to read from.
 *
 * Set top of allocated memory to the dump time value.
 */
static int set_top_of_memory(dumpFile)
     int dumpFile;
{
  TAGGED buf[MEMTOPHEADSIZE];
  
  if (read(dumpFile, buf, MEMTOPHEADSIZE) != MEMTOPHEADSIZE
      || Sbrk((char *)buf[0]-Sbrk(0)) == (char *)-1)
    return 0;
#if MMAP
# if __svr4__
#  define Getpagesize PAGESIZE
# else
#  define Getpagesize getpagesize()
# endif
  {
    int i;
    int pagesize = Getpagesize;

    for (i=0; i<3; i++)
      {
	unmap(seg[i].start, seg[i].size);
	map((char *)buf[i*2+1], SP_ALIGN(buf[(i+1)*2],pagesize));
      }
  }
#endif
  return (1);
}

/* int write_memory_limits(dumpFile)
 * int dumpFile;	The level 1 file on which to output.
 *
 * Write the value of the upper limit of allocated memory to dumpFile.
 */
static int write_memory_limits(dumpFile)
     int dumpFile;
{
  TAGGED buf[MEMTOPHEADSIZE];
  
  buf[0] = (TAGGED)Sbrk(0);
#if MMAP
  {
    int i;
    for (i=0; i<3; i++)
      {
	buf[i*2+1] = (TAGGED)seg[i].start;
	buf[(i+1)*2] = seg[i].size;
      }
  }
#endif
  if (write(dumpFile, buf, MEMTOPHEADSIZE) != MEMTOPHEADSIZE)
    return 0;
  return 1;
}

/* int read_symbol_table(dumpFile, symbolTablePath)
 * int dumpFile;	The file to read from.
 * char *symbolTablePath; Return path to new symbol table, if any.
 *
 * Check if dump contains a symbol table. If so then create a symbol
 * table file and return the path to the file.
 */
static int read_symbol_table(dumpFile, symbolTablePath)
     int dumpFile;
     char *symbolTablePath;
{
  unsigned long length;
  char *tmpdir;
  
  if ((tmpdir = getenv("TMPDIR")) == NULL)
    tmpdir = "/usr/tmp";
  
  {
    struct segmentHeader header;
    
    if (zread(dumpFile, &header, sizeof(header)) != sizeof(header))
      return 0;
    if (header.type != SYMBOL_TABLE_SEGMENT)
      return 0;
    if ((length = header.length) == 0)
      {
	*symbolTablePath = 0;
	return 1;
      }
  }
  sprintf(symbolTablePath, "%s/spsymtabXXXXXX", tmpdir);
  mktemp(symbolTablePath);
  {
    int symbolFile;
    char buf[BUFSIZ];
    if ((symbolFile =
	 open(symbolTablePath, O_EXCL|O_CREAT|O_WRONLY|O_BINARY, 0x1b6)) == -1)
      return 0;
    for (; length >= BUFSIZ; length -= BUFSIZ)
      if (BUFSIZ != zread(dumpFile, buf, BUFSIZ) ||
	  write(symbolFile, buf, BUFSIZ) != BUFSIZ)
	{
	  close(symbolFile);
	  return 0;
	}
    if (length > 0)
      if (length != zread(dumpFile, buf, length) ||
	  write(symbolFile, buf, length) != length)
	{
	  close(symbolFile);
	  return 0;
	}
    close(symbolFile);
  }
  return 1;
}

/* int write_symbol_table(dumpFile)
 * int dumpFile;	The level 1 file on which to output.
 *
 * Write the symbol table to dumpFile. The symbol table is written as a
 * segment labelled SYMBOL_TABLE_SEGMENT. The symbol table will not be
 * written if the current symbol table is the original emulator symbol
 * table. In that case an empty segment will be written.
 */
static int write_symbol_table(dumpFile)
     int dumpFile;
{
  int symbolFile;
  int charsRead;
  char buf[BUFSIZ];
  struct stat statbuf;
  
  if (!strlen(EG.incremental_symbol_table_path))
    return(write_segment_header(dumpFile, SYMBOL_TABLE_SEGMENT, 0L,
				(char *)0));
  if ((symbolFile = open(EG.incremental_symbol_table_path,
			 O_RDONLY|O_BINARY, 0)) == -1)
    SYSERROR("save/1", "open");
  if (fstat(symbolFile, &statbuf) == -1)
    goto fstat_err;
  if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
    {				/* not needed for std UNIX, but does no harm
				   and might be needed elsewhere */
      errno = EISDIR;
    fstat_err:
      close(symbolFile);
      SYSERROR("save/1", "fstat");
    }
  if (!write_segment_header(dumpFile, SYMBOL_TABLE_SEGMENT, statbuf.st_size,
			    (char *)0))
    return 0;
  while ((charsRead = read(symbolFile, buf, BUFSIZ)) > 0)
    if (zwrite(dumpFile, buf, charsRead) != charsRead)
      {
	close(symbolFile);
	return 0;
      }
  close(symbolFile);
  return 1;
}


/* int read_data_segment(dumpFile, header)
 * int dumpFile;	The level 1 file on which to output.
 * struct segmentHeader *header; To be filled in.
 *
 * Read a data segment from dumpFile to memory.
 */
static int read_data_segment(dumpFile, header)
     int dumpFile;
     struct segmentHeader *header;
{
  unsigned long length;
  char *cp;
  
  if (zread(dumpFile, header, sizeof(*header)) != sizeof(*header))
    return 0;
  if (header->type != DATA_SEGMENT)
    return 1;
  cp = header->baseAddress;
  length = header->length;
  for (; length >= BUFSIZ; length -= BUFSIZ, cp += BUFSIZ)
    if (zread(dumpFile, cp, BUFSIZ) != BUFSIZ)
      return 0;
  if (length > 0 && zread(dumpFile, cp, length) != length)
    return 0;
  return 1;
}


static void sort_holes(a, l, r)
     register struct hole *a;
     int l, r;			/* first and last index */
{
  register int i, j;
  register char *tmp;
  char *pivot;
  
  i = l; j = r;
  pivot = a[(i+j)>>1].begin;
  do
    {
      while (a[i].begin < pivot) i++;
      while (pivot < a[j].begin) j--;
      if (i <= j)
	{
	  tmp = a[i].begin;
	  a[i].begin = a[j].begin;
	  a[j].begin = tmp;
	  tmp = a[i].end;
	  a[i].end = a[j].end;
	  a[j].end = tmp;
	  i++; j--;
	}
    }
  while (i <= j);
  if (l < j) sort_holes(a, l, j);
  if (i < r) sort_holes(a, i, r);
}

static int write_segment_with_holes(dumpFile, segid,
				    start_of_data, end_of_data, holes, h)
     int dumpFile, segid, h;
     char *start_of_data;
     char *end_of_data;
     struct hole *holes;
{
  register char *bod = start_of_data;
  register char *eod;
  register int i, rc;
  
  sort_holes(holes, 0, h-1);

  for (i=0, rc=1; rc && i<h; i++)
    {
      eod = holes[i].begin;
      if (bod < eod)
	rc = write_segment(dumpFile, segid, bod, eod);
      bod = holes[i].end;
    }
  eod = end_of_data;
  if (rc && bod < eod)
    rc = write_segment(dumpFile, segid, bod, eod);

  return rc;
}

/* int write_data_bss(dumpFile)
 * int dumpFile;	The level 1 file on which to output.
 *
 * Write the emulator data and bss segments to dumpFile.
 */
static int write_data_bss(dumpFile, fd)
     int dumpFile, fd;
{
  struct hole holes[12];
  int h = 0;
  char *start_of_data = (char *)((unsigned int)(&end) & 0xf0000000);
  
  if (start_of_data < (char *)(&etext))
    {
/*if !SP_BSD && !SCO && !bcsocs && !clix && !sysV88 || (i386 && !SCO && !DJGCC) || aegis || masscomp || mips || __convex__ || __convexc__ */
#if (i386 && !SCO && !DJGCC) || aegis || masscomp || mips || __convex__ || __convexc__ || sp_hpux || (__svr4__ && sgi)
      extern char *address_align PROTO((char *));
      
      start_of_data = address_align((char *)(&etext));
#else
#if __svr4__ && (sun || m88k)
      extern char *start_of_savedump;

      start_of_data = (char *)(&start_of_savedump);
#else
      start_of_data = (char *)(&environ);
#endif
#endif
    }

#if sp_hpux
  /* Under HP-UX >= 8.0, [start_of_data,start_of_data+0x1000) is not mapped.
     Under Solaris 2.1,	 [start_of_data,start_of_data+N*0x1000) is not mapped.
   */
  while (write(fd, start_of_data, 4)<0)
    start_of_data += 0x1000;
  lseek(fd, -4, 1);
#endif
  if ((char *)&environ >= start_of_data && (char *)&environ < (char *)&end)
    {
      holes[h].begin = (char *)&environ;
      holes[h++].end = (char *)&environ + sizeof(environ);
    }
  holes[h].begin = (char *)&abort_env;
  holes[h++].end = (char *)&abort_env + sizeof(abort_env);
  holes[h].begin = (char *)&EG.stats;
  holes[h++].end = (char *)&EG.stats + sizeof(EG.stats);
  holes[h].begin = (char *)&EG.persistent;
  holes[h++].end = (char *)&EG.persistent + sizeof(EG.persistent);
  holes[h].begin = (char *)&EG.symbolchar;
  holes[h++].end = (char *)&EG.symbolchar + sizeof(EG.symbolchar);
#if sun && mc68020
  {
    extern fp_switch[];
    
    holes[h].begin = (char *)&fp_switch;
    holes[h++].end = (char *)&fp_switch+28;
  }
#endif
#if DJGCC
  {
    extern edata, _bss_start, _go32_info_block[];
    
    holes[h].begin = (char *)&edata;
    holes[h++].end = (char *)&_bss_start;
    holes[h].begin = (char *)&_go32_info_block;
    holes[h++].end = (char *)&_go32_info_block+40;
  }
#endif
  return
    write_segment_with_holes(dumpFile, DATA_SEGMENT,
			     start_of_data, (char *)&end, holes, h);
}


/* int write_allocated_memory(dumpFile)
 * int dumpFile;	The level 1 file on which to output.
 *
 * Write the allocated memory to dumpFile. We optimize by avoiding to
 * write allocated memory known to be unused.
 */
static int write_allocated_memory(dumpFile)
     int dumpFile;
{
  
#define MIN_SIZE_INDEX_NOT_TO_SAVE 8
#define MAX_HOLES 512
  
  struct hole arr[MAX_HOLES];
  struct hole *p;
  int i=0, j;
  
#if !MMAP
  {
    WAMENV;
    
    ComputeA(w->local_top, w->node);
    arr[i].begin = (char *)w->global_top;
    arr[i++].end = (char *)w->heap_end;
    arr[i].begin = (char *)w->local_top;
    arr[i++].end = (char *)w->stack_end;
    arr[i].begin = (char *)w->trail_top;
    arr[i++].end = (char *)w->node;
  }
#endif
#if MEMMAN
  {
    struct free_block *p;
    
    for (j=SIZE_CLASSES-1; j >= MIN_SIZE_INDEX_NOT_TO_SAVE; j--)
      for (p=EG.memman.free_arr[j]; p && i<MAX_HOLES; p = p->next)
	arr[i].begin = (char *)p + sizeof(struct free_block),
	arr[i++].end = (char *)p + p->size - sizeof(struct free_block);
  }
#endif
  return
    write_segment_with_holes(dumpFile, DATA_SEGMENT,
			     EG.mem_start, TMPSBRK0, arr, i);
}

/* int write_stack(dumpFile)
 * int dumpFile;	The level 1 file on which to output.
 *
 * Write the stack to dumpFile.
 */
static int write_stack(dumpFile)
     int dumpFile;
{
  return write_segment(dumpFile, STACK_SEGMENT, &dumpFile, &dumpFile);
}

#if MMAP
static int write_prolog_stacks(dumpFile)
     int dumpFile;
{
  WAMENV;

  ComputeA(w->local_top, w->node);
  return
    write_segment(dumpFile, DATA_SEGMENT, w->heap_start, w->global_top) &&
    write_segment(dumpFile, DATA_SEGMENT, w->stack_start, w->local_top) &&
    write_segment(dumpFile, DATA_SEGMENT, w->trail_start, w->trail_top) &&
    write_segment(dumpFile, DATA_SEGMENT, w->node, w->choice_start);
}
#endif

  /* Close stdio buffers before save/restore to ensure a consistent state
   * after restore. Open again after.
   */

struct stdbuf_info {
  int si_in, si_out, si_err, si_offset;
};

static void close_stdbufs(bufinfo)
     struct stdbuf_info *bufinfo;
{
  bufinfo->si_in = dup(0);
  bufinfo->si_out = dup(1);
  bufinfo->si_err = dup(2);
  bufinfo->si_offset = ftell(stdin);
  fclose(stdin); fclose(stdout); fclose(stderr);
}

static void open_stdbufs(bufinfo)
     struct stdbuf_info *bufinfo;
{
  dup2(bufinfo->si_in, 0); close(bufinfo->si_in); fdopen(0, "r");
  dup2(bufinfo->si_out, 1); close(bufinfo->si_out); fdopen(1, "a");
  dup2(bufinfo->si_err, 2); close(bufinfo->si_err); fdopen(2, "a"); 
  if (isatty(2)) 
    setbuf(stderr, NULL);
  fseek(stdin, bufinfo->si_offset, 0);
}


/* BOOL prolog_save(+fileName)
 * string fileName;	The file on which to save.
 *
 * Save the complete executable state as a dump on file fileName. Save
 * followed by a restore will behave essentially as if the program had been
 * stopped with ^Z and the restarted with the csh fg command.
 * Succeed with X1=0.
 *
 */
BOOL prolog_save(fileName)
     char *fileName;
{
  int dumpFile, fd;
  struct stdbuf_info save_buf_info;
  
  /*
   * Do not use stdio for the dump file. Stdio will otherwise be
   * inconsistent after a restore. We assume that the only open stdio files
   * are stdin, stdout and stderr.
   */
  char128 = EG.symbolchar[128];
  unlink(fileName);		/* to ensure the right protection */
  if ((dumpFile = fd = open(fileName, O_CREAT|O_WRONLY|O_BINARY, 0x1ff)) == -1)
    SYSERROR("save/1", "open");

  close_stdbufs(&save_buf_info);
  trimcore();

  if (!write_header(dumpFile) ||
      !write_memory_limits(dumpFile))
    {
      close(dumpFile);goto save_fail;
    }

#if ZSAVE
 /* Prepare compressing data area, but do no compression */
 /* Do compression by an external compresser */
  {
    char *ztmp;
    /* temporaly data area for compress, very large */
    char *zsave = Sbrk(sizeof(struct zsave));

    if (zsave == (char *)(-1) ||
	!compress_write_init(zsave,
			     (ztmp = getenv("SP_COMPRESS_SAVE")) &&
			     strcmp(ztmp, "0"),
			     dumpFile))
      {
	close(dumpFile);goto save_fail;
      }
    else
      dumpFile = (int)zsave;
  }
#endif

  if (!write_symbol_table(dumpFile) ||
      !write_data_bss(dumpFile, fd) ||
      !write_allocated_memory(dumpFile) ||
#if MMAP
      !write_prolog_stacks(dumpFile) ||
#endif
      !write_stack(dumpFile))
    {
      zclose(dumpFile);
    save_fail:
      unlink(fileName);
      open_stdbufs(&save_buf_info);
      SYSERROR("save/1", "write");
      return FALSE;
    }
  
  open_stdbufs(&save_buf_info);
  
  zclose(dumpFile);
  {
    WAMENV;
    Unify_constant(MakeSmall(0),X(1));
  }
  return TRUE;
}


/* BOOL prolog_restore(+fileName)
 * string fileName;	Restore from this file.
 *
 * Restore a state saved by $save/2.
 * We assume that the only open files are stdin, stdout and stderr.
 * The top of allocated memory is set to the value at the time of the dump.
 * The data segments and allocated memory are read in from the dump file
 * and overwrite our current memory. A few global values are patched.  
 * Afterwards, it is as if $save/2 succeeded with X1=1.
 */
BOOL prolog_restore(fileName)
     char *fileName;
{
  char symbolTablePath[MAXPATHLEN];
  struct segmentHeader header;
  struct stat statbuf;
  struct stdbuf_info save_buf_info;
  int i, dumpFile;
  
  close_stdbufs(&save_buf_info);

  if ((dumpFile = open(fileName, O_RDONLY|O_BINARY, 0)) == -1)
    {
      open_stdbufs(&save_buf_info);
      SYSERROR("restore/1", "open");
    }
  if (fstat(dumpFile, &statbuf) == -1)
    goto fstat_err;
  if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
    {
      errno = EISDIR;
    fstat_err:
      close(dumpFile);
      open_stdbufs(&save_buf_info);
      SYSERROR("restore/1", "fstat");
    }

  if (!skip_line(dumpFile))
    {
      close(dumpFile);
      open_stdbufs(&save_buf_info);
      SYSTEM_FAULT("restore/1: bad file format");
    }
  if (!check_version(dumpFile))
    {
      close(dumpFile);
      open_stdbufs(&save_buf_info);
      SYSTEM_FAULT("restore/1: dump not created with this emulator");
    }
  if (!set_top_of_memory(dumpFile))
    {
      close(dumpFile);
      open_stdbufs(&save_buf_info);
      SYSTEM_FAULT("restore/1: unable to adjust top of memory");
    }
#if ZSAVE
  {
    char *zsave = Sbrk(sizeof(struct zsave));

    if (zsave == (char *)(-1))
      goto noarea;
    if (!compress_read_init(zsave,1,dumpFile))
      {
	zclose(dumpFile);
      noarea:
	open_stdbufs(&save_buf_info);
	SYSTEM_FAULT("restore/1: unable to find area for uncompress");
      }
    else
      dumpFile = (int)zsave;
  }
#endif
  remove_symbol_table(1);
  if (!read_symbol_table(dumpFile, symbolTablePath))
    {
      zclose(dumpFile);
      open_stdbufs(&save_buf_info);
      SYSTEM_FAULT("restore/1: error while restoring symbol table");
    }
  header.type = DATA_SEGMENT;
  while (header.type!=STACK_SEGMENT)
    if (!read_data_segment(dumpFile, &header))
      {
	zclose(dumpFile);
	open_stdbufs(&save_buf_info);
	SYSTEM_FAULT("restore/1: error while reading data segments");
      }
  zclose(dumpFile);
  if (strlen(symbolTablePath) > 0)
    strcpy(EG.incremental_symbol_table_path, symbolTablePath);
  
  if (char128 != EG.symbolchar[128]) /* new character set restored */
    reclassify_atoms();
#if DJGCC
  /* usertime returns absolute time in DJGCC */
  EG.stats.lasttime = EG.stats.starttime = usertime();
#endif
  reactivate_code();
  open_stdbufs(&save_buf_info);
  update_std_streams();
  signals_init();		/* Do at abort, reinitialise, restore */
  event_queue_init();		/* Do at abort, reinitialise, restore */
  compute_cwd();
  if (SP_foreign_reinit_hook != NULL)
    (*SP_foreign_reinit_hook)(EG.persistent.argc, EG.persistent.argv);
  {
    WAMENV;
    Unify_constant(MakeSmall(1),X(1));
  }
  return TRUE;
}
#endif /* gould || NeXT */
#endif /* !LOADC */
----------
X-Sun-Data-Type: h-file
X-Sun-Data-Description: h-file
X-Sun-Data-Name: alloc.h
X-Sun-Content-Lines: 84

/* Copyright (C) 1988, Swedish Institute of Computer Science. */

#define kB       1024
#define kCells   1024

#define ABUFSIZE  512

#define MEMMAN (!LOADC && !NeXT && !CMALLOC)

#ifndef MMAP
# define MMAP (sun && !LOADC)
#endif

#define SP_ALIGN(Value, Alignment) \
  (((unsigned long)(Value) + Alignment-1) & ~(unsigned)(Alignment-1))

#if MEMMAN
#define INITMEMSIZE  (512*kB)  /* initial memory size */
#define MEMINCSIZE  (64*kB)   /* size of increment */

struct free_block {
    struct free_block *next;
    int size;
};

#define SIZE_CLASSES 16
#endif

#define CONTPAD 128		/* min. amount of heap at proceed */
#define CALLPAD (1024 + CONTPAD) /* min. amount of heap at call */

#define STACKPAD (2*ARITYLIMIT + 16) /* min. amount of stack at allocate */

				/* min. amount of trail/choice at try */
#define CHOICEPAD (2*ARITYLIMIT)


#define ATMTABSIZE  (4*kCells)	/* size of global atom table  */
#define QLOADSIZE   (2*kCells)	/* plenty at present */

#if MEMMAN || MMAP
#define MEMBLOCKTRIM 0
#else
#define MEMBLOCKTRIM 1
#endif

#if MACINTOSH
# define GLOBALSTKSIZE   (32*kCells-MEMBLOCKTRIM) /* less fragmentation */
#else
# define GLOBALSTKSIZE   (4*kCells-MEMBLOCKTRIM) /* approx. twice Quintus */
#endif
#define LOCALSTKSIZE    (4*kCells-MEMBLOCKTRIM)
#define CHOICESTKSIZE   (4*kCells-MEMBLOCKTRIM)
#define TRAILSTKSIZE    (4*kCells-MEMBLOCKTRIM)
#define XREGBANKSIZE    ARITYLIMIT

/* The ...STKSIZE constants may be overridden by env. variables.
   This macro first looks for one, and if not found, uses the default. */
#define GETENV(VALUE,WORK,STRING,VAR) \
  if ((WORK = getenv(STRING))) \
    VALUE = atoi(WORK); \
  else \
    VALUE = VAR;

#if MEMMAN
extern void organize_free_space PROTO((int));
extern void return_memory PROTO((void));
#endif

#if MMAP
#define Stackalloc(Seg, Size) stackalloc(Seg, Size)
#define Stackrealloc(Seg, Ptr, Decr, Size) stackrealloc(Seg, Ptr, Decr, Size)

struct mmap_segment {
    char *start;
    unsigned int size;
};

extern struct mmap_segment seg[];

#else
#define Stackalloc(Seg, Size) checkalloc(Size)
#define Stackrealloc(Seg, Ptr, Decr, Size) checkrealloc(Ptr, Decr, Size)
#endif

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019