YAP 7.1.0
save.c
1/*************************************************************************
2 * *
3 * YAP Prolog *
4 * *
5 * Yap Prolog was developed at NCCUP - Universidade do Porto *
6 * *
7 * Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 *
8 * *
9 **************************************************************************
10 * *
11 * File: save.c * Last
12 *rev: * mods:
13 ** comments: saving and restoring a Prolog computation *
14 * *
15 *************************************************************************/
16#ifdef SCCS
17static char SccsId[] = "@(#)save.c 1.3 3/15/90";
18#endif
19
20#include "absmi.h"
21#include "alloc.h"
22#if _MSC_VER || defined(__MINGW32__)
23#if HAVE_WINSOCK2_H
24#include <winsock2.h>
25#endif
26#include <psapi.h>
27#include <windows.h>
28#endif
29#if USE_DL_MALLOC
30#include "dlmalloc.h"
31#endif
32#include "Foreign.h"
33#include "YapText.h"
34#include "sshift.h"
35#include "yapio.h"
36#if HAVE_STRING_H
37#include <string.h>
38#endif
39#if !HAVE_STRNCAT
40#define strncat(X, Y, Z) strcat(X, Y)
41#endif
42#if !HAVE_STRNCPY
43#define strncpy(X, Y, Z) strcpy(X, Y)
44#endif
45
46#if HAVE_FCNTL_H
47#include <fcntl.h>
48#endif
49#ifdef HAVE_UNISTD_H
50#include <unistd.h>
51#endif
52#ifdef HAVE_SYS_TYPES_H
53#include <sys/types.h>
54#endif
55#ifdef HAVE_SYS_STAT_H
56#include <sys/stat.h>
57#endif
58#include "iopreds.h"
59
60/********* hack for accesing several kinds of terms. Should be cleaned **/
61
62static char end_msg[256] = "*** End of YAP saved state *****";
63
64/* SWI IO, must be restarted after restore */
65void initIO(void);
66
67#ifdef DEBUG
68
69/*
70 *
71 #FOR DEBUGGING define DEBUG_RESTORE0 to check the file stuff,
72 #define DEBUG_RESTORE1 to see if it is able to prepare the chain,
73 #define DEBUG_RESTORE2 to see how things are going,
74 #define DEBUG_RESTORE3 to check if the atom chain is still a working chain,
75 * define DEBUG_RESTORE4 if you want to set the output for some
76 * particular file,
77 * define DEBUG_RESTORE5 if you want to see how the stacks are being
78 * cleaned up,
79 * define DEBUG_RESTORE6 if you want to follow the execution in
80 *
81 * Also a file is defined where you can write things, by default stderr
82 *
83 * Good Luck
84 */
85
86#endif
87
88static int myread(FILE *, char *, Int);
89static Int mywrite(FILE *, char *, Int);
90static FILE *open_file(const char *, int);
91static int close_file(void);
92static Int putout(CELL);
93static Int putcellptr(CELL *);
94static CELL get_cell(void);
95static CELL *get_cellptr(/* CELL * */ void);
96static int put_info(int, int CACHE_TYPE);
97static int save_regs(int CACHE_TYPE);
98static int save_code_info(void);
99static int save_heap(void);
100static int save_stacks(int CACHE_TYPE);
101static int save_crc(void);
102static Int do_save(int CACHE_TYPE);
103static Int p_save2(CACHE_TYPE1);
104static Int p_save_program(CACHE_TYPE1);
105static int check_header(CELL *, CELL *, CELL *, CELL *CACHE_TYPE);
106static int get_heap_info(CACHE_TYPE1);
107static int get_regs(int CACHE_TYPE);
108static int get_insts(OPCODE[]);
109static int get_hash(void);
110static int CopyCode(CACHE_TYPE1);
111static int CopyStacks(CACHE_TYPE1);
112static int get_coded(int, OPCODE[] CACHE_TYPE);
113static void restore_codes(void);
114static void RestoreDB(DBEntry *CACHE_TYPE);
115static void RestoreDBTerm(DBTerm *, bool, int CACHE_TYPE);
116static void CleanClauses(yamop *First, yamop *Last, PredEntry *pp USES_REGS);
117static void rehash(CELL *, int, int CACHE_TYPE);
118static void CleanCode(PredEntry *CACHE_TYPE);
119static void RestoreEntries(PropEntry *, int CACHE_TYPE);
120static void RestoreFreeSpace(CACHE_TYPE1);
121static void restore_heap(void);
122#ifdef DEBUG_RESTORE3
123static void ShowAtoms(void);
124static void ShowEntries(PropEntry *);
125#endif
126static int OpenRestore(const char *, CELL *, CELL *, CELL *,
127 CELL *, FILE **);
128static void CloseRestore(void);
129#ifndef _WIN32
130static int check_opcodes(OPCODE[]);
131#endif
132static void RestoreHeap(OPCODE[] CACHE_TYPE);
133static Int p_restore(CACHE_TYPE1);
134static void restore_heap_regs(CACHE_TYPE1);
135static void restore_regs(int CACHE_TYPE);
136#ifdef MACYAP
137static void NewFileInfo(long, long);
138extern int DefVol;
139#endif
140
141#ifdef _WIN32
142#if HAVE_IO_H
143#include <io.h>
144#endif
145#endif
146
147#ifdef LIGHT
148
149#include <strings.h>
150#include <unix.h>
151
152void LightBug(char *);
153
154static void LightBug(s) char *s;
155{}
156
157#endif /* LIGHT */
158
159inline static int myread(FILE *fd, char *buffer, Int len) {
160 size_t nread;
161
162 while (len > 0) {
163 nread = fread(buffer, 1, (int)len, fd);
164 if (nread < 1) {
165 Yap_ThrowError(PERMISSION_ERROR_INPUT_PAST_END_OF_STREAM,ARG1,
166 "bad read on saved state: %s", strerror(errno));
167 }
168 buffer += nread;
169 len -= nread;
170 }
171 return len;
172}
173
174inline static Int mywrite(FILE *fd, char *buff, Int len) {
175 size_t nwritten;
176
177 while (len > 0) {
178 nwritten = fwrite(buff, 1, (size_t)len, fd);
179 if ((long int)nwritten < 0) {
180 Yap_ThrowError(SYSTEM_ERROR_OPERATING_SYSTEM,ARG1,
181 "bad write on saved state: %s",strerror(errno));
182 }
183 buff += nwritten;
184 len -= nwritten;
185 }
186 return len;
187}
188
189#define FullSaved 1
190
191/* Where the code was before */
192
193typedef CELL *CELLPOINTER;
194
195static FILE *splfild = NULL;
196
197#ifdef DEBUG
198
199#ifdef DEBUG_RESTORE4
200static FILE *errout;
201#else
202#define errout GLOBAL_stderr
203#endif
204
205#endif /* DEBUG */
206
207static Int OldHeapUsed;
208
209static CELL which_save;
210
211/* Open a file to read or to write */
212static FILE *open_file(const char *my_file, int flag) {
213 FILE *splfild;
214 char flags[6];
215 int i = 0;
216
217 if (flag & O_RDONLY) {
218 flags[i++] = 'r';
219 }
220 if (flag & O_CREAT) {
221 flags[i++] = 'w';
222 }
223 if (flag & O_WRONLY) {
224 flags[i++] = 'w';
225 }
226 if (flag & O_APPEND) {
227 flags[i++] = 'a';
228 }
229#if _WIN32
230 if (flag & O_BINARY) {
231 flags[i++] = 'b';
232 }
233#endif
234 flags[i] = '\0';
235 splfild = fopen(my_file, flags);
236#ifdef undf0
237 fprintf(errout, "Opened file %s\n", my_file);
238#endif
239 return splfild;
240}
241
242static int close_file(void) {
243 if (splfild == 0)
244 return 0;
245 if (fclose(splfild) < 0)
246 Yap_ThrowError(SYSTEM_ERROR_SAVED_STATE,ARG1,
247 "bad close on saved state: %s",strerror(errno));
248 splfild = 0;
249 return 1;
250}
251
252/* stores a cell in a file */
253static Int putout(CELL l) { return mywrite(splfild, (char *)&l, sizeof(CELL)); }
254
255/* stores a pointer to a cell in a file */
256static Int putcellptr(CELL *l) {
257 return mywrite(splfild, (char *)&l, sizeof(CELLPOINTER));
258}
259
260/* gets a cell from a file */
261static CELL get_cell(void) {
262 CELL l;
263 myread(splfild, (char *)&l, Unsigned(sizeof(CELL)));
264 return (l);
265}
266
267/* gets a cell from a file */
268static CELL get_header_cell(void) {
269 CELL l;
270 size_t count = 0;
271 int n;
272 while (count < sizeof(CELL)) {
273 if ((n = fread(&l, 1, sizeof(CELL) - count, splfild)) < 0) {
274 Yap_ThrowError(PERMISSION_ERROR_INPUT_PAST_END_OF_STREAM,ARG1,
275 "failed to read saved state header");
276 return 0L;
277 }
278 count += n;
279 }
280 return l;
281}
282
283/* gets a pointer to cell from a file */
284static CELL *get_cellptr(void) {
285 CELL *l;
286
287 if (myread(splfild, (char *)&l, Unsigned(sizeof(CELLPOINTER))) < 0)
288 return NULL;
289 return (l);
290}
291
292/*
293 * writes the header (at the moment YAPV*), info about what kind of saved
294 * set, the work size, and the space ocuppied
295 */
296static int put_info(int info, int mode USES_REGS) {
297 char msg[256 * 16];
298
299 sprintf(msg,
300 "#!/bin/sh\nexec_dir=${YAPBINDIR:-%s}\nexec $exec_dir/yap $0 "
301 "\"$@\"\n%cYAP-%s",
302 YAP_BINDIR, 1, YAP_FULL_VERSION);
303 if (mywrite(splfild, msg, strlen(msg) + 1))
304 return -1;
305 if (putout(Unsigned(info)) < 0)
306 return -1;
307 /* say whether we just saved the heap or everything */
308 if (putout(mode) < 0)
309 return -1;
310 /* current state of stacks, to be used by SavedInfo */
311 /* space available in heap area */
312 if (putout(Unsigned(LOCAL_GlobalBase) - Unsigned(Yap_HeapBase)) < 0)
313 return -1;
314 /* space available for stacks */
315 if (putout(Unsigned(LOCAL_LocalBase) - Unsigned(LOCAL_GlobalBase)) < 0)
316 return -1;
317 /* space available for trail */
318 if (putout(Unsigned(LOCAL_TrailTop) - Unsigned(LOCAL_TrailBase)) < 0)
319 return -1;
320 /* Space used in heap area */
321 if (putout(Unsigned(HeapTop) - Unsigned(Yap_HeapBase)) < 0)
322 return -1;
323 /* Space used for local stack */
324 if (putout(Unsigned(LCL0) - Unsigned(ASP)) < 0)
325 return -1;
326 /* Space used for global stack */
327 if (putout(Unsigned(HR) - Unsigned(LOCAL_GlobalBase)) < 0)
328 return -1;
329 /* Space used for trail */
330 if (putout(Unsigned(TR) - Unsigned(LOCAL_TrailBase)) < 0)
331 return -1;
332 return 0;
333}
334
335static int save_regs(int mode USES_REGS) {
336 /* save all registers */
337 if (putout((CELL)compile_arrays) < 0)
338 return -1;
339 if (mode == DO_EVERYTHING) {
340 if (putcellptr((CELL *)CP) < 0)
341 return -1;
342 if (putcellptr(ENV) < 0)
343 return -1;
344 if (putcellptr(ASP) < 0)
345 return -1;
346 /* if (putout((CELL)N) < 0)
347 return -1; */
348 if (putcellptr(H0) < 0)
349 return -1;
350 if (putcellptr(LCL0) < 0)
351 return -1;
352 if (putcellptr(HR) < 0)
353 return -1;
354 if (putcellptr(HB) < 0)
355 return -1;
356 if (putcellptr((CELL *)B) < 0)
357 return -1;
358 if (putcellptr((CELL *)TR) < 0)
359 return -1;
360 if (putcellptr(YENV) < 0)
361 return -1;
362 if (putcellptr(S) < 0)
363 return -1;
364 if (putcellptr((CELL *)P) < 0)
365 return -1;
366 if (putout(CreepFlag) < 0)
367 return -1;
368 if (putout(EventFlag) < 0)
369 return -1;
370#if defined(YAPOR_SBA) || defined(TABLING)
371 if (putcellptr(H_FZ) < 0)
372 return -1;
373 if (putcellptr((CELL *)B_FZ) < 0)
374 return -1;
375 if (putcellptr((CELL *)TR_FZ) < 0)
376 return -1;
377#endif /* YAPOR_SBA || TABLING */
378 }
379 if (putout(CurrentModule) < 0)
380 return -1;
381 if (mode == DO_EVERYTHING) {
382#ifdef COROUTINING
383 if (putout(LOCAL_WokenGoals) < 0)
384 return -1;
385#endif
386#ifdef DEPTH_LIMIT
387 if (putout(DEPTH) < 0)
388 return -1;
389#endif
390 if (putout(LOCAL_GcGeneration) < 0)
391 return -1;
392 if (putout(LOCAL_GcPhase) < 0)
393 return -1;
394 if (putout(LOCAL_GcCurrentPhase) < 0)
395 return -1;
396 }
397 /* The operand base */
398 if (putcellptr(CellPtr(XREGS)) < 0)
399 return -1;
400 if (putout(which_save) < 0)
401 return -1;
402 /* Now start by saving the code */
403 /* the heap boundaries */
404 if (putcellptr(CellPtr(Yap_HeapBase)) < 0)
405 return -1;
406 if (putcellptr(CellPtr(HeapTop)) < 0)
407 return -1;
408 /* and the space it ocuppies */
409 if (putout(Unsigned(HeapUsed)) < 0)
410 return -1;
411 /* Then the start of the free code */
412 if (putcellptr(CellPtr(FreeBlocks)) < 0)
413 return -1;
414 if (putcellptr(CellPtr(AuxBase)) < 0)
415 return -1;
416 if (putcellptr(AuxSp) < 0)
417 return -1;
418 if (putcellptr(CellPtr(AuxTop)) < 0)
419 return -1;
420 if (putcellptr(CellPtr(LOCAL_ScratchPad.ptr)) < 0)
421 return -1;
422 if (putout(LOCAL_ScratchPad.sz) < 0)
423 return -1;
424 if (putout(LOCAL_ScratchPad.msz) < 0)
425 return -1;
426 if (mode == DO_EVERYTHING) {
427 /* put the old trail base, just in case it moves again */
428 if (putout(ARG1) < 0)
429 return -1;
430 if (which_save == 2) {
431 if (putout(ARG2) < 0)
432 return -1;
433 }
434 if (putcellptr(CellPtr(LOCAL_TrailBase)) < 0)
435 return -1;
436 }
437 return 0;
438}
439
440static int save_code_info(void) {
441
442 /* First the instructions */
443 {
444 op_numbers i;
445
446 OPCODE my_ops[_std_top + 1];
447 for (i = _Ystop; i <= _std_top; ++i)
448 my_ops[i] = Yap_opcode(i);
449 if (mywrite(splfild, (char *)my_ops, sizeof(OPCODE) * (_std_top + 1)) < 0)
450 return -1;
451 }
452 /* and the current character codes */
453 if (mywrite(splfild, (char *)Yap_chtype,
454 NUMBER_OF_CHARS * sizeof(char_kind_t)) < 0)
455 return -1;
456 return 0;
457}
458
459static int save_heap(void) {
460#ifdef USE_SYSTEM_MALLOC
461 return -1;
462#endif
463 int j;
464 /* Then save the whole heap */
465 Yap_ResetConsultStack();
466 j = Unsigned(HeapTop) - Unsigned(Yap_HeapBase);
467 /* store 10 more cells because of the memory manager */
468 if (mywrite(splfild, (char *)Yap_HeapBase, j) < 0)
469 return -1;
470 return 0;
471}
472
473static int save_stacks(int mode USES_REGS) {
474 int j;
475
476 switch (mode) {
477 case DO_EVERYTHING:
478 /* Now, go and save the state */
479 /* Save the local stack */
480 j = Unsigned(LCL0) - Unsigned(ASP);
481 if (mywrite(splfild, (char *)ASP, j) < 0)
482 return -1;
483 /* Save the global stack */
484 j = Unsigned(HR) - Unsigned(LOCAL_GlobalBase);
485 if (mywrite(splfild, (char *)LOCAL_GlobalBase, j) < 0)
486 return -1;
487 /* Save the trail */
488 j = Unsigned(TR) - Unsigned(LOCAL_TrailBase);
489 if (mywrite(splfild, (char *)LOCAL_TrailBase, j) < 0)
490 return -1;
491 break;
492 case DO_ONLY_CODE: {
493 tr_fr_ptr tr_ptr = TR;
494 while (tr_ptr != (tr_fr_ptr)LOCAL_TrailBase) {
495 CELL val = TrailTerm(tr_ptr - 1);
496 if (IsVarTerm(val)) {
497 CELL *d1 = VarOfTerm(val);
498 if (d1 < (CELL *)HeapTop) {
499 if (putout(val) < 0)
500 return -1;
501 }
502 } else if (IsPairTerm(val)) {
503 CELL *d1 = RepPair(val);
504 if (d1 < (CELL *)HeapTop) {
505 if (putout(val) < 0)
506 return -1;
507 }
508 }
509 tr_ptr--;
510 }
511 }
512 if (putcellptr(NULL) < 0)
513 return -1;
514 break;
515 }
516 return 0;
517}
518
519static int save_crc(void) {
520 /* Save a CRC */
521 return mywrite(splfild, end_msg, 256);
522}
523
524static Int do_save(int mode USES_REGS) {
525 Term t1 = Deref(ARG1);
526 char *buf;
527 if (Yap_HoleSize) {
528 Yap_ThrowError(SYSTEM_ERROR_INTERNAL,
529 ARG1,
530 "restore/1: address space has holes of size %ld, cannot save",
531 (long int)Yap_HoleSize);
532 return FALSE;
533 }
534 if (!Yap_GetName((buf=malloc(MAX_PATH+1)), MAX_PATH, t1)) {
535 Yap_Error(TYPE_ERROR_LIST, t1, "save/1");
536 return FALSE;
537 }
538 Yap_CloseStreams();
539 if ((splfild = open_file(buf, O_WRONLY | O_CREAT)) < 0) {
540 Yap_ThrowError(SYSTEM_ERROR_OPERATING_SYSTEM,
541 MkAtomTerm(Yap_LookupAtom(buf)),
542 "restore/1, open(%s)", strerror(errno));
543 return (FALSE);
544 }
545 if (put_info(FullSaved, mode PASS_REGS) < 0)
546 return -1;
547 if (save_regs(mode PASS_REGS) < 0)
548 return -1;
549 if (save_code_info() < 0)
550 return -1;
551 if (save_heap() < 0)
552 return -1;
553 if (save_stacks(mode PASS_REGS) < 0)
554 return -1;
555 if (save_crc() < 0)
556 return -1;
557 close_file();
558 return (TRUE);
559}
560
561/* Saves a complete prolog environment */
562static Int p_save2(USES_REGS1) {
563 Int res;
564 yhandle_t CurSlot = Yap_StartSlots();
565
566 Term t;
567#ifdef YAPOR
568 if (GLOBAL_number_workers != 1) {
569 Yap_Error(SYSTEM_ERROR, TermNil,
570 "cannot perform save: more than a worker/thread running");
571 return (FALSE);
572 }
573#endif /* YAPOR */
574#ifdef THREADS
575 if (GLOBAL_NOfThreads != 1) {
576 Yap_Error(SYSTEM_ERROR, TermNil,
577 "cannot perform save: more than a worker/thread running");
578 return (FALSE);
579 }
580#endif /* THREADS */
581 /* avoid double saves */
582 if (IsNonVarTerm(t = Deref(ARG2)))
583 return TRUE;
584 if (!Yap_unify(ARG2, MkIntTerm(1)))
585 return FALSE;
586 which_save = 2;
587 CurSlot = Yap_StartSlots();
588 res = do_save(DO_EVERYTHING PASS_REGS);
589 Yap_CloseSlots(CurSlot);
590 return res;
591}
592
593/* Just save the program, not the stacks */
594static Int p_save_program(USES_REGS1) {
595 which_save = 0;
596 return do_save(DO_ONLY_CODE PASS_REGS);
597}
598
599/* Now, to restore the saved code */
600
601/* First check out if we are dealing with a valid file */
602static int check_header(CELL *info, CELL *ATrail, CELL *AStack,
603 CELL *AHeap USES_REGS) {
604 char pp[256];
605 char msg[256];
606 CELL hp_size, gb_size, lc_size, tr_size, mode;
607 int n;
608
609 /* make sure we always check if there are enough bytes */
610 /* skip the first line */
611 pp[0] = '\0';
612 do {
613 if ((n = fread(pp, 1, 1, splfild)) <= 0) {
614 Yap_ThrowError(PERMISSION_ERROR_INPUT_PAST_END_OF_STREAM,
615 ARG1,
616 "failed to scan first line from saved state");
617 return FAIL_RESTORE;
618 }
619 } while (pp[0] != 1);
620 /* now check the version */
621 sprintf(msg, "YAP-%s", YAP_FULL_VERSION);
622 {
623 int count = 0, n, to_read = Unsigned(strlen(msg) + 1);
624 while (count < to_read) {
625 if ((n = fread(pp, 1, to_read - count, splfild)) <= 0) {
626 Yap_ThrowError(
627 ARG1,
628 PERMISSION_ERROR_INPUT_PAST_END_OF_STREAM,
629 "failed to scan version info from saved state");
630 return FAIL_RESTORE;
631 }
632 count += n;
633 }
634 }
635 if (strcmp(pp, msg) != 0) {
636 strncpy(LOCAL_ErrorMessage, "saved state %s failed to match version ID",PATH_MAX);
637 return FAIL_RESTORE;
638 }
639 /* check info on header */
640 /* ignore info on saved state */
641 *info = get_header_cell();
642 if (LOCAL_ErrorMessage)
643 return FAIL_RESTORE;
644 /* check the restore mode */
645 mode = get_header_cell();
646 if (LOCAL_ErrorMessage)
647 return FAIL_RESTORE;
648 if (mode != DO_EVERYTHING && mode != DO_ONLY_CODE) {
649 return FAIL_RESTORE;
650 }
651 /* ignore info on stacks size */
652 *AHeap = get_header_cell();
653 if (LOCAL_ErrorMessage) {
654 return FAIL_RESTORE;
655 }
656 *AStack = get_header_cell();
657 if (LOCAL_ErrorMessage) {
658 return FAIL_RESTORE;
659 }
660 *ATrail = get_header_cell();
661 if (LOCAL_ErrorMessage) {
662 return FAIL_RESTORE;
663 }
664 /* now, check whether we got enough enough space to load the
665 saved space */
666 hp_size = get_cell();
667 if (LOCAL_ErrorMessage)
668 return FAIL_RESTORE;
669 while (Yap_HeapBase != NULL &&
670 hp_size > Unsigned(HeapLim) - Unsigned(Yap_HeapBase)) {
671 if (!Yap_growheap(FALSE, hp_size, NULL)) {
672 return FAIL_RESTORE;
673 }
674 }
675 if (mode == DO_EVERYTHING) {
676 lc_size = get_cell();
677 if (LOCAL_ErrorMessage)
678 return FAIL_RESTORE;
679 gb_size = get_cell();
680 if (LOCAL_ErrorMessage)
681 return FAIL_RESTORE;
682 if (Yap_HeapBase != NULL &&
683 lc_size + gb_size >
684 Unsigned(LOCAL_LocalBase) - Unsigned(LOCAL_GlobalBase)) {
685 if (LOCAL_ErrorMessage != NULL)
686 LOCAL_ErrorMessage = "could not allocate enough stack space";
687 return FAIL_RESTORE;
688 }
689 if (Yap_HeapBase != NULL &&
690 (tr_size = get_cell()) >
691 Unsigned(LOCAL_TrailTop) - Unsigned(LOCAL_TrailBase)) {
692 if (LOCAL_ErrorMessage != NULL)
693 LOCAL_ErrorMessage = "could not allocate enough trail space";
694 return FAIL_RESTORE;
695 }
696 } else {
697 /* skip cell size */
698 get_header_cell();
699 if (LOCAL_ErrorMessage)
700 return FAIL_RESTORE;
701 get_header_cell();
702 if (LOCAL_ErrorMessage)
703 return FAIL_RESTORE;
704 get_header_cell();
705 if (LOCAL_ErrorMessage)
706 return FAIL_RESTORE;
707 }
708 return (mode);
709}
710
711/* Gets the state of the heap, and evaluates the related variables */
712static int get_heap_info(USES_REGS1) {
713 LOCAL_OldHeapBase = (ADDR)get_cellptr();
714 if (LOCAL_ErrorMessage)
715 return -1;
716 LOCAL_OldHeapTop = (ADDR)get_cellptr();
717
718 if (LOCAL_ErrorMessage)
719 return -1;
720 OldHeapUsed = (Int)get_cell();
721 if (LOCAL_ErrorMessage)
722 return -1;
723 FreeBlocks = (BlockHeader *)get_cellptr();
724 if (LOCAL_ErrorMessage)
725 return -1;
726 AuxBase = (ADDR)get_cellptr();
727 if (LOCAL_ErrorMessage)
728 return -1;
729 AuxSp = get_cellptr();
730 if (LOCAL_ErrorMessage)
731 return -1;
732 AuxTop = (ADDR)get_cellptr();
733 if (LOCAL_ErrorMessage)
734 return -1;
735 LOCAL_ScratchPad.ptr = (ADDR)get_cellptr();
736 if (LOCAL_ErrorMessage)
737 return -1;
738 LOCAL_ScratchPad.sz = get_cell();
739 if (LOCAL_ErrorMessage)
740 return -1;
741 LOCAL_ScratchPad.msz = get_cell();
742 if (LOCAL_ErrorMessage)
743 return -1;
744 LOCAL_HDiff = Unsigned(Yap_HeapBase) - Unsigned(LOCAL_OldHeapBase);
745 return 1;
746}
747
748/* Gets the register array */
749/* Saves the old bases for the work areas */
750/* and evaluates the difference from the old areas to the new ones */
751static int get_regs(int flag USES_REGS) {
752 CELL *NewGlobalBase = (CELL *)LOCAL_GlobalBase;
753 CELL *NewLCL0 = LCL0;
754 CELL *OldXREGS;
755
756 /* Get regs */
757 compile_arrays = (int)get_cell();
758 if (LOCAL_ErrorMessage)
759 return -1;
760 if (flag == DO_EVERYTHING) {
761 CP = (yamop *)get_cellptr();
762 if (LOCAL_ErrorMessage)
763 return -1;
764 ENV = get_cellptr();
765 if (LOCAL_ErrorMessage)
766 return -1;
767 ASP = get_cellptr();
768 if (LOCAL_ErrorMessage)
769 return -1;
770 /* N = get_cell(); */
771 H0 = get_cellptr();
772 if (LOCAL_ErrorMessage)
773 return -1;
774 LCL0 = get_cellptr();
775 if (LOCAL_ErrorMessage)
776 return -1;
777 HR = get_cellptr();
778 if (LOCAL_ErrorMessage)
779 return -1;
780 HB = get_cellptr();
781 if (LOCAL_ErrorMessage)
782 return -1;
783 B = (choiceptr)get_cellptr();
784 if (LOCAL_ErrorMessage)
785 return -1;
786 TR = (tr_fr_ptr)get_cellptr();
787 if (LOCAL_ErrorMessage)
788 return -1;
789 YENV = get_cellptr();
790 if (LOCAL_ErrorMessage)
791 return -1;
792 S = get_cellptr();
793 if (LOCAL_ErrorMessage)
794 return -1;
795 P = (yamop *)get_cellptr();
796 if (LOCAL_ErrorMessage)
797 return -1;
798 CreepFlag = get_cell();
799 if (LOCAL_ErrorMessage)
800 return -1;
801 EventFlag = get_cell();
802 if (LOCAL_ErrorMessage)
803 return -1;
804#if defined(YAPOR_SBA) || defined(TABLING)
805 H_FZ = get_cellptr();
806 if (LOCAL_ErrorMessage)
807 return -1;
808 B_FZ = (choiceptr)get_cellptr();
809 if (LOCAL_ErrorMessage)
810 return -1;
811 TR_FZ = (tr_fr_ptr)get_cellptr();
812 if (LOCAL_ErrorMessage)
813 return -1;
814#endif /* YAPOR_SBA || TABLING */
815 }
816 CurrentModule = get_cell();
817 if (LOCAL_ErrorMessage)
818 return -1;
819 if (flag == DO_EVERYTHING) {
820#ifdef COROUTINING
821 LOCAL_WokenGoals = get_cell();
822 if (LOCAL_ErrorMessage)
823 return -1;
824#endif
825#ifdef DEPTH_LIMIT
826 DEPTH = get_cell();
827 if (LOCAL_ErrorMessage)
828 return -1;
829#endif
830 LOCAL_GcGeneration = get_cell();
831 if (LOCAL_ErrorMessage)
832 return -1;
833 LOCAL_GcPhase = get_cell();
834 if (LOCAL_ErrorMessage)
835 return -1;
836 LOCAL_GcCurrentPhase = get_cell();
837 if (LOCAL_ErrorMessage)
838 return -1;
839 }
840 /* Get the old bases */
841 OldXREGS = get_cellptr();
842 if (LOCAL_ErrorMessage)
843 return -1;
844 which_save = get_cell();
845 if (LOCAL_ErrorMessage)
846 return -1;
847 LOCAL_XDiff = (CELL)XREGS - (CELL)OldXREGS;
848 if (LOCAL_ErrorMessage)
849 return -1;
850 if (get_heap_info(PASS_REGS1) < 0)
851 return -1;
852 if (flag == DO_EVERYTHING) {
853 ARG1 = get_cell();
854 if (LOCAL_ErrorMessage)
855 return -1;
856 if (which_save == 2) {
857 ARG2 = get_cell();
858 if (LOCAL_ErrorMessage)
859 return -1;
860 }
861 /* get old trail base */
862 LOCAL_OldTrailBase = (ADDR)get_cellptr();
863 if (LOCAL_ErrorMessage)
864 return -1;
865 /* Save the old register where we can easily access them */
866 LOCAL_OldASP = ASP;
867 LOCAL_OldLCL0 = LCL0;
868 LOCAL_OldGlobalBase = (CELL *)LOCAL_GlobalBase;
869 LOCAL_OldH = HR;
870 LOCAL_OldTR = TR;
871 LOCAL_GDiff = Unsigned(NewGlobalBase) - Unsigned(LOCAL_GlobalBase);
872 LOCAL_GDiff0 = 0;
873 LOCAL_LDiff = Unsigned(NewLCL0) - Unsigned(LCL0);
874 LOCAL_TrDiff = LOCAL_LDiff;
875 LOCAL_GlobalBase = (ADDR)NewGlobalBase;
876 LCL0 = NewLCL0;
877 }
878 return 1;
879}
880
881/* Get the old opcodes and place them in a hash table */
882static int get_insts(OPCODE old_ops[]) {
883 return myread(splfild, (char *)old_ops, sizeof(OPCODE) * (_std_top + 1));
884}
885
886/* Get the old atoms hash table */
887static int get_hash(void) {
888 return myread(splfild, (char *)Yap_chtype,
889 NUMBER_OF_CHARS * sizeof(char_kind_t));
890}
891
892/* Copy all of the old code to the new Heap */
893static int CopyCode(USES_REGS1) {
894 if (myread(splfild, (char *)Yap_HeapBase,
895 (Unsigned(LOCAL_OldHeapTop) - Unsigned(LOCAL_OldHeapBase))) < 0) {
896 return -1;
897 }
898 return 1;
899}
900
901/* Copy the local and global stack and also the trail to their new home */
902/* In REGS we still have nonadjusted values !! */
903static int CopyStacks(USES_REGS1) {
904 Int j;
905 char *NewASP;
906
907 j = Unsigned(LOCAL_OldLCL0) - Unsigned(ASP);
908 NewASP = (char *)(Unsigned(ASP) + (Unsigned(LCL0) - Unsigned(LOCAL_OldLCL0)));
909 if (myread(splfild, (char *)NewASP, j) < 0)
910 return -1;
911 j = Unsigned(HR) - Unsigned(LOCAL_OldGlobalBase);
912 if (myread(splfild, (char *)LOCAL_GlobalBase, j) < 0)
913 return -1;
914 j = Unsigned(TR) - Unsigned(LOCAL_OldTrailBase);
915 if (myread(splfild, LOCAL_TrailBase, j))
916 return -1;
917 return 1;
918}
919
920/* Copy the local and global stack and also the trail to their new home */
921/* In REGS we still have nonadjusted values !! */
922static int CopyTrailEntries(USES_REGS1) {
923 CELL entry, *Entries;
924
925 Entries = (CELL *)LOCAL_TrailBase;
926 do {
927 *Entries++ = entry = get_cell();
928 if (LOCAL_ErrorMessage)
929 return -1;
930 } while ((CODEADDR)entry != NULL);
931 return 1;
932}
933
934/* get things which are saved in the file */
935static int get_coded(int flag, OPCODE old_ops[] USES_REGS) {
936 char my_end_msg[256];
937
938 if (get_regs(flag PASS_REGS) < 0)
939 return -1;
940 if (get_insts(old_ops) < 0)
941 return -1;
942 if (get_hash() < 0)
943 return -1;
944 if (CopyCode(PASS_REGS1) < 0)
945 return -1;
946 switch (flag) {
947 case DO_EVERYTHING:
948 if (CopyStacks(PASS_REGS1) < 0)
949 return -1;
950 break;
951 case DO_ONLY_CODE:
952 if (CopyTrailEntries(PASS_REGS1) < 0)
953 return -1;
954 break;
955 }
956 /* Check CRC */
957 if (myread(splfild, my_end_msg, 256) < 0)
958 return -1;
959 if (strcmp(end_msg, my_end_msg) != 0) {
960 LOCAL_ErrorMessage = "bad trailing CRC in saved state";
961 return -1;
962 }
963 return 1;
964}
965
966/* restore some heap registers */
967static void restore_heap_regs(USES_REGS1) {
968 if (HeapTop) {
969 HeapTop = AddrAdjust(HeapTop);
970 *((YAP_SEG_SIZE *)HeapTop) = InUseFlag;
971 }
972 // HeapMax = HeapUsed = OldHeapUsed;
973 HeapLim = LOCAL_GlobalBase;
974}
975
976/* adjust abstract machine registers */
977static void restore_regs(int flag USES_REGS) {
978 restore_heap_regs(PASS_REGS1);
979 if (CurrentModule) {
980 CurrentModule = AtomTermAdjust(CurrentModule);
981 ;
982 }
983 if (flag == DO_EVERYTHING) {
984 CP = PtoOpAdjust(CP);
985 ENV = PtoLocAdjust(ENV);
986 ASP = PtoLocAdjust(ASP);
987 HR = PtoGloAdjust(HR);
988 B = (choiceptr)PtoLocAdjust(CellPtr(B));
989 TR = PtoTRAdjust(TR);
990 P = PtoOpAdjust(P);
991 HB = PtoLocAdjust(HB);
992 YENV = PtoLocAdjust(YENV);
993 S = PtoGloAdjust(S);
994 LOCAL_WokenGoals = AbsAppl(PtoGloAdjust(RepAppl(LOCAL_WokenGoals)));
995 }
996}
997
998static void recompute_mask(DBRef dbr) {
999 if (dbr->Flags & DBNoVars) {
1000 dbr->Mask = Yap_EvalMasks((Term)dbr->DBT.Entry, &(dbr->Key));
1001 } else if (dbr->Flags & DBComplex) {
1002 /* This is quite nasty, we want to recalculate the mask but
1003 we don't want to rebuild the whole term. We'll just build whatever we
1004 need to recompute the mask.
1005 */
1006 CELL *x = (CELL *)HeapTop, *tp;
1007 unsigned int Arity, i;
1008 Term out;
1009 char *tbase = CharP(dbr->DBT.Contents - 1);
1010
1011 if (IsPairTerm(dbr->DBT.Entry)) {
1012
1013 out = AbsPair(x);
1014 Arity = 2;
1015 tp = (CELL *)(tbase + (CELL)RepPair(dbr->DBT.Entry));
1016 } else {
1017 Functor f;
1018
1019 tp = (CELL *)(tbase + (CELL)RepAppl(dbr->DBT.Entry));
1020 f = (Functor)(*tp++);
1021 out = AbsAppl(x);
1022 Arity = ArityOfFunctor(f);
1023 *x++ = (CELL)f;
1024 if (Arity > 3)
1025 Arity = 3;
1026 }
1027 for (i = 0; i < Arity; i++) {
1028 register Term tw = *tp++;
1029 if (IsVarTerm(tw)) {
1030 RESET_VARIABLE(x);
1031 } else if (IsApplTerm(tw)) {
1032 /* just fetch the functor from where it is in the data-base.
1033 This guarantees we have access to references and friends. */
1034 CELL offset = (CELL)RepAppl(tw);
1035 if (offset > dbr->DBT.NOfCells * sizeof(CELL))
1036 *x = tw;
1037 else
1038 *x = AbsAppl((CELL *)(tbase + offset));
1039 } else if (IsAtomicTerm(tw)) {
1040 *x = tw;
1041 } else if (IsPairTerm(tw)) {
1042 *x = AbsPair(x);
1043 }
1044 x++;
1045 }
1046 dbr->Mask = Yap_EvalMasks(out, &(dbr->Key));
1047 }
1048}
1049
1050#define HASH_SHIFT 6
1051
1052/*
1053 * This is used to make an hash table correct, after displacing its elements,
1054 * HCEnd should point to an area of free space, usually in the heap. The
1055 * routine is very dependent on the hash function used, and it destroys the
1056 * previous "hit" order
1057 */
1058static void rehash(CELL *oldcode, int NOfE, int KindOfEntries USES_REGS) {
1059 register CELL *savep, *basep;
1060 CELL *oldp = oldcode;
1061 int TableSize = NOfE - 1, NOfEntries;
1062 register int i;
1063 int hash;
1064 CELL WorkTerm, failplace = 0;
1065 CELL *Base = oldcode;
1066
1067 if (LOCAL_HDiff == 0)
1068 return;
1069 basep = HR;
1070 if (HR + (NOfE * 2) > ASP) {
1071 basep = (CELL *)TR;
1072 if (basep + (NOfE * 2) > (CELL *)LOCAL_TrailTop) {
1073 if (!Yap_growtrail((ADDR)(basep + (NOfE * 2)) - LOCAL_TrailTop, TRUE)) {
1074 Yap_Error(RESOURCE_ERROR_TRAIL, TermNil,
1075 "not enough space to restore hash tables for indexing");
1076 Yap_exit(1);
1077 }
1078 }
1079 }
1080 for (i = 0; i < NOfE; ++i) {
1081 if (*oldp == 0) {
1082 failplace = oldp[1];
1083 break;
1084 }
1085 oldp += 2;
1086 }
1087 savep = basep;
1088 oldp = oldcode;
1089 for (i = 0; i < NOfE; ++i) {
1090 if (*oldp != 0) {
1091 savep[0] = oldp[0];
1092 savep[1] = oldp[1];
1093 oldp[0] = 0;
1094 oldp[1] = failplace;
1095 savep += 2;
1096 }
1097 oldp += 2;
1098 }
1099 NOfEntries = (savep - basep) / 2;
1100 savep = basep;
1101 for (i = 0; i < NOfEntries; ++i) {
1102 register Int d;
1103 CELL *hentry;
1104
1105 WorkTerm = savep[i * 2];
1106 hash = (Unsigned(WorkTerm) >> HASH_SHIFT) & TableSize;
1107 hentry = Base + hash * 2;
1108 d = TableSize & (Unsigned(WorkTerm) | 1);
1109 while (*hentry) {
1110#ifdef DEBUG
1111#ifdef CLASHES
1112 ++clashes;
1113#endif /* CLASHES */
1114#endif /* DEBUG */
1115 hash = (hash + d) & TableSize;
1116 hentry = Base + hash * 2;
1117 }
1118 hentry[0] = WorkTerm;
1119 hentry[1] = savep[i * 2 + 1];
1120 }
1121}
1122
1123static void RestoreFlags(UInt NFlags) {}
1124
1125#include "rheap.h"
1126
1127/* restore the atom entries which are invisible for the user */
1128static void RestoreIOStructures(void) { Yap_InitStdStreams(); }
1129
1130static void RestoreFreeSpace(USES_REGS1) {
1131#if USE_DL_MALLOC
1132 Yap_av = (struct malloc_state *)AddrAdjust((ADDR)Yap_av);
1133 Yap_RestoreDLMalloc();
1134 if (AuxSp != NULL) {
1135 if (AuxBase < LOCAL_OldHeapBase || AuxBase > LOCAL_OldHeapTop) {
1136 AuxSp = NULL;
1137 AuxBase = NULL;
1138 AuxTop = NULL;
1139 } else {
1140 AuxSp = PtoHeapCellAdjust(AuxSp);
1141 AuxBase = AddrAdjust(AuxBase);
1142 AuxTop = AddrAdjust(AuxTop);
1143 LOCAL_ScratchPad.ptr = AddrAdjust(LOCAL_ScratchPad.ptr);
1144 }
1145 }
1146#else
1147 /* restores the list of free space, with its curious structure */
1148 BlockHeader *bpt, *bsz;
1149
1150 if (FreeBlocks != NULL)
1151 FreeBlocks = BlockAdjust(FreeBlocks);
1152 bpt = FreeBlocks;
1153 if (AuxSp != NULL)
1154 AuxSp = CellPtoHeapAdjust(AuxSp);
1155 if (AuxTop != NULL)
1156 AuxTop = AddrAdjust(AuxTop);
1157 while (bpt != NULL) {
1158 if (bpt->b_next != NULL) {
1159 bsz = bpt->b_next = BlockAdjust(bpt->b_next);
1160 while (bsz != NULL) {
1161 if (bsz->b_next_size != NULL)
1162 bsz->b_next_size = BlockAdjust(bsz->b_next_size);
1163 if (bsz->b_next != NULL)
1164 bsz->b_next = BlockAdjust(bsz->b_next);
1165 bsz = bsz->b_next;
1166 }
1167 }
1168 if (bpt->b_next_size != NULL)
1169 bpt->b_next_size = BlockAdjust(bpt->b_next_size);
1170 bpt = bpt->b_next_size;
1171 }
1172 *((YAP_SEG_SIZE *)HeapTop) = InUseFlag;
1173#endif
1174}
1175
1176static void RestoreAtomList(Atom atm USES_REGS) {
1177 AtomEntry *at;
1178
1179 at = RepAtom(atm);
1180 if (EndOfPAEntr(at))
1181 return;
1182 do {
1183 RestoreAtom(at PASS_REGS);
1184 at = RepAtom(at->NextOfAE);
1185 } while (!EndOfPAEntr(at));
1186}
1187
1188static void RestoreHashPreds(USES_REGS1) {
1189 UInt size = PredHashTableSize;
1190 bool malloced = FALSE;
1191 PredEntry **np;
1192 UInt i;
1193 PredEntry **oldp = PredHash;
1194
1195 np = (PredEntry **)Yap_AllocAtomSpace(sizeof(PredEntry *) * size);
1196 if (!np) {
1197 if (!(np = (PredEntry **)malloc(sizeof(PredEntry *) * size))) {
1198 Yap_Error(SYSTEM_ERROR_FATAL, TermNil,
1199 "Could not allocate space for pred table");
1200 return;
1201 }
1202 malloced = TRUE;
1203 }
1204 for (i = 0; i < size; i++) {
1205 np[i] = NULL;
1206 }
1207 for (i = 0; i < PredHashTableSize; i++) {
1208 PredEntry *p = oldp[i];
1209
1210 if (p)
1211 p = PredEntryAdjust(p);
1212 while (p) {
1213 Prop nextp;
1214 UInt hsh;
1215
1216 if (p->NextOfPE)
1217 p->NextOfPE = PropAdjust(p->NextOfPE);
1218 nextp = p->NextOfPE;
1219 CleanCode(p PASS_REGS);
1220 hsh = PRED_HASH(p->FunctorOfPred, p->ModuleOfPred, size);
1221 p->NextOfPE = AbsPredProp(np[hsh]);
1222 np[hsh] = p;
1223 p = RepPredProp(nextp);
1224 }
1225 }
1226 for (i = 0; i < size; i++) {
1227 PredHash[i] = np[i];
1228 }
1229 if (malloced)
1230 free((ADDR)np);
1231 else
1232 Yap_FreeAtomSpace((ADDR)np);
1233}
1234
1235/*
1236 * This is the really tough part, to restore the whole of the heap
1237 */
1238static void restore_heap(void) {
1239 restore_codes();
1240 RestoreIOStructures();
1241}
1242
1243#ifdef DEBUG_RESTORE3
1244static void ShowEntries(pp) PropEntry *pp;
1245{
1246 while (!EndOfPAEntr(pp)) {
1247 fprintf(GLOBAL_stderr, "Estou a ver a prop %x em %x\n", pp->KindOfPE, pp);
1248 pp = RepProp(pp->NextOfPE);
1249 }
1250}
1251
1252static void ShowAtoms() {
1253 AtomHashEntry *HashPtr = HashChain;
1254 register int i;
1255 for (i = 0; i < AtomHashTableSize; ++i) {
1256 if (HashPtr->Entry != NIL) {
1257 AtomEntry *at;
1258 at = RepAtom(HashPtr->Entry);
1259 do {
1260 fprintf(GLOBAL_stderr, "Passei ao %s em %x\n", at->StrOfAE, at);
1261 ShowEntries(RepProp(at->PropsOfAE));
1262 } while (!EndOfPAEntr(at = RepAtom(at->NextOfAE)));
1263 }
1264 HashPtr++;
1265 }
1266 HashPtr = WideHashChain;
1267 for (i = 0; i < WideAtomHashTableSize; ++i) {
1268 if (HashPtr->Entry != NIL) {
1269 AtomEntry *at;
1270 at = RepAtom(HashPtr->Entry);
1271 do {
1272 fprintf(GLOBAL_stderr, "Passei ao %s em %x\n", at->StrOfAE, at);
1273 ShowEntries(RepProp(at->PropsOfAE));
1274 } while (!EndOfPAEntr(at = RepAtom(at->NextOfAE)));
1275 }
1276 HashPtr++;
1277 }
1278}
1279
1280#endif /* DEBUG_RESTORE3 */
1281
1282#include <stdio.h>
1283
1284static int commit_to_saved_state(const char *s, CELL *Astate, CELL *ATrail,
1285 CELL *AStack, CELL *AHeap) {
1286 CACHE_REGS
1287 int mode;
1288 char tmp[MAX_PATH+1];
1289
1290 if ((mode = check_header(Astate, ATrail, AStack, AHeap PASS_REGS)) ==
1291 FAIL_RESTORE)
1292 return (FAIL_RESTORE);
1293 LOCAL_PrologMode = BootMode;
1294 if (Yap_HeapBase) {
1295 if (falseGlobalPrologFlag(HALT_AFTER_CONSULT_FLAG) && !silentMode()) {
1296 strcpy(tmp, Yap_AbsoluteFile(s, true));
1297 fprintf(stderr, "%% Restoring file %s\n", tmp);
1298 }
1299 Yap_CloseStreams();
1300 }
1301#ifdef DEBUG_RESTORE4
1302 /*
1303 * This should be another file, like the log file
1304 */
1305 errout = GLOBAL_stderr;
1306#endif
1307 return mode;
1308}
1309
1310static int try_open(const char *inpf, CELL *Astate, CELL *ATrail, CELL *AStack,
1311 CELL *AHeap, FILE **streamp) {
1312 int mode;
1313
1314 if (streamp) {
1315 if ((*streamp = fopen(inpf, "rb"))) {
1316 return DO_ONLY_CODE;
1317 }
1318 return FAIL_RESTORE;
1319 }
1320 if ((splfild = open_file(inpf, O_RDONLY)) < 0) {
1321 return FAIL_RESTORE;
1322 }
1323 if ((mode = commit_to_saved_state(inpf, Astate, ATrail, AStack, AHeap)) !=
1324 FAIL_RESTORE) {
1325 CACHE_REGS
1326 LOCAL_ErrorMessage = NULL;
1327 return mode;
1328 }
1329 return mode;
1330}
1331
1332static int OpenRestore(const char *fname, CELL *Astate,
1333 CELL *ATrail, CELL *AStack, CELL *AHeap,
1334 FILE **streamp) {
1335 CACHE_REGS
1336
1337 int mode;
1338 if (fname && fname[0] && (mode = try_open(fname, Astate, ATrail, AStack, AHeap,
1339 streamp)) != FAIL_RESTORE) {
1340 setAtomicGlobalPrologFlag(RESOURCE_DATABASE_FLAG,
1341 MkAtomTerm(Yap_LookupAtom(fname)));
1342 return mode;
1343 }
1344 /* try to open from current directory */
1345 /* could not open file */
1346 if (LOCAL_ErrorMessage == NULL) {
1347 Yap_ThrowError(PERMISSION_ERROR_OPEN_SOURCE_SINK,
1348 ARG1,
1349 "incorrect saved state ");
1350 } else {
1351 Yap_ThrowError(PERMISSION_ERROR_OPEN_SOURCE_SINK,
1352 ARG1, "could not open saved state %s", fname);
1353 }
1354 return FAIL_RESTORE;
1355}
1356
1357FILE *Yap_OpenRestore(const char *inpf) {
1358 FILE *stream = NULL;
1359
1360 if (!inpf)
1361 inpf = "startup.yss";
1362 OpenRestore(inpf, NULL, NULL, NULL, NULL, &stream);
1363 return stream;
1364}
1365
1366static void CloseRestore(void) {
1367 CACHE_REGS
1368#ifdef DEBUG_RESTORE3
1369 ShowAtoms();
1370#endif
1371 close_file();
1372 LOCAL_PrologMode = UserMode;
1373}
1374
1375#if !defined(_WIN32)
1376static int check_opcodes(OPCODE old_ops[]) {
1377#if USE_THREADED_CODE
1378 bool have_shifted = FALSE;
1379 op_numbers op = _Ystop;
1380 for (op = _Ystop; op < _std_top; op++) {
1381 if (Yap_opcode(op) != old_ops[op]) {
1382 have_shifted = TRUE;
1383 break;
1384 }
1385 }
1386 return have_shifted;
1387#else
1388 /* be conservative */
1389 return TRUE;
1390#endif
1391}
1392#endif
1393
1394static void RestoreHeap(OPCODE old_ops[] USES_REGS) {
1395 bool heap_moved = (LOCAL_OldHeapBase != Yap_HeapBase || LOCAL_XDiff),
1396 opcodes_moved;
1397 Term mod = CurrentModule;
1398
1399 CurrentModule = PROLOG_MODULE;
1400#if defined(_WIN32)
1401 /* It seems that under WIN32 opcodes may not have moved but the
1402 remaining code may have bmoved */
1403 opcodes_moved = TRUE;
1404#else
1405 opcodes_moved = check_opcodes(old_ops);
1406#endif
1407 /* opcodes_moved has side-effects and should be tried first */
1408 if (heap_moved) {
1409 opcodes_moved = TRUE;
1410 RestoreFreeSpace(PASS_REGS1);
1411 }
1412 if (heap_moved || opcodes_moved) {
1413 restore_heap();
1414 }
1415 /* This must be done after restore_heap */
1416 Yap_InitAbsmi();
1417 if (opcodes_moved) {
1419 Yap_InitBackCPreds();
1420 }
1421 if (!(Yap_ReInitConstExps() && Yap_ReInitUnaryExps() &&
1422 Yap_ReInitBinaryExps())) {
1423 Yap_Error(SYSTEM_ERROR_INTERNAL, TermNil,
1424 "arithmetic operator not in saved state");
1425 }
1426#ifdef DEBUG_RESTORE1
1427 fprintf(errout, "phase 1 done\n");
1428#endif
1429 CurrentModule = mod;
1430}
1431
1432/*
1433 * This function is called to know about the parameters of the last saved
1434 * state
1435 */
1436int Yap_SavedInfo(const char *FileName, CELL *ATrail,
1437 CELL *AStack, CELL *AHeap) {
1438 return DO_ONLY_CODE;
1439
1440 CELL MyTrail, MyStack, MyHeap, MyState;
1441 int mode;
1442
1443 mode = OpenRestore(FileName, &MyState, &MyTrail, &MyStack, &MyHeap,
1444 NULL);
1445 if (mode == FAIL_RESTORE) {
1446 return -1;
1447 }
1448 close_file();
1449 if (!*AHeap)
1450 *AHeap = MyHeap / 1024;
1451 if (mode != DO_ONLY_CODE && *AStack)
1452 *AStack = MyStack / 1024;
1453 if (mode != DO_ONLY_CODE && *ATrail)
1454 *ATrail = MyTrail / 1024;
1455 return (MyState);
1456}
1457
1458static void UnmarkTrEntries(USES_REGS1) {
1459 CELL entry, *Entries;
1460
1461 /* initialize a choice point */
1462 B = (choiceptr)LCL0;
1463 B--;
1464 B->cp_ap = NOCODE;
1465 Entries = (CELL *)LOCAL_TrailBase;
1466 while ((entry = *Entries++) != (CELL)NULL) {
1467 if (!IsVarTerm(entry)) {
1468 if (IsPairTerm(entry)) {
1469 CELL *ent = CellPtoHeapAdjust(RepPair(entry));
1470 register CELL flags;
1471
1472 flags = *ent;
1473 ResetFlag(InUseMask, flags);
1474 *ent = flags;
1475 if (FlagOn((DirtyMask | ErasedMask), flags)) {
1476 if (FlagOn(DBClMask, flags)) {
1477 Yap_ErDBE(DBStructFlagsToDBStruct(ent));
1478 } else {
1479 if (flags & LogUpdMask) {
1480 if (flags & IndexMask) {
1481 if (FlagOn(ErasedMask, flags))
1482 Yap_ErLogUpdIndex(ClauseFlagsToLogUpdIndex(ent));
1483 else
1484 Yap_CleanUpIndex(ClauseFlagsToLogUpdIndex(ent));
1485 } else {
1486 Yap_ErLogUpdCl(ClauseFlagsToLogUpdClause(ent));
1487 }
1488 } else {
1489 Yap_ErCl(ClauseFlagsToDynamicClause(ent));
1490 }
1491 }
1492 }
1493#ifdef MULTI_ASSIGNMENT_VARIABLES
1494 } else /* if (IsApplTerm(d1)) */ {
1495 Entries += 2;
1496#endif
1497 }
1498 }
1499 }
1500 B = NULL;
1501}
1502
1503int in_limbo = FALSE;
1504
1505/* cleanup any records we had in the saved state. They are now inaccessible */
1506static void FreeRecords(void) {
1507 struct record_list *ptr;
1508
1509 ptr = Yap_Records;
1510 Yap_Records = NULL;
1511 while (ptr) {
1512 struct record_list *optr = ptr;
1513 Yap_ReleaseTermFromDB(ptr->dbrecord);
1514 ptr = ptr->next_rec;
1515 Yap_FreeCodeSpace((void *)optr);
1516 }
1517}
1518
1519/*
1520 * This function is called when wanting only to restore the heap and
1521 * associated registers
1522 */
1523static int Restore(char *s_dir USES_REGS) {
1524 int restore_mode;
1525
1526 OPCODE old_ops[_std_top + 1];
1527 CELL MyTrail, MyStack, MyHeap, MyState;
1528
1529 if ((restore_mode = OpenRestore(s_dir, &MyState, &MyTrail, &MyStack,
1530 &MyHeap, NULL)) == FAIL_RESTORE)
1531 return (FALSE);
1532 Yap_ShutdownLoadForeign();
1533 in_limbo = TRUE;
1534 if (get_coded(restore_mode, old_ops PASS_REGS) < 0)
1535 return FAIL_RESTORE;
1536 restore_regs(restore_mode PASS_REGS);
1537 in_limbo = FALSE;
1538 /*#endif*/
1539 RestoreHeap(old_ops PASS_REGS);
1540 switch (restore_mode) {
1541 case DO_EVERYTHING:
1542 if (LOCAL_OldHeapBase != Yap_HeapBase || LOCAL_OldLCL0 != LCL0 ||
1543 LOCAL_OldGlobalBase != (CELL *)LOCAL_GlobalBase ||
1544 LOCAL_OldTrailBase != LOCAL_TrailBase) {
1545 Yap_AdjustStacksAndTrail();
1546 if (which_save == 2) {
1547 Yap_AdjustRegs(2);
1548 } else {
1549 Yap_AdjustRegs(1);
1550 }
1551 break;
1552#ifdef DEBUG_RESTORE2
1553 fprintf(errout, "phase 2 done\n");
1554#endif
1555 }
1556 break;
1557 case DO_ONLY_CODE:
1558 UnmarkTrEntries(PASS_REGS1);
1559 Yap_InitYaamRegs(0, true);
1560 break;
1561 }
1562
1563 Yap_ReOpenLoadForeign();
1564 FreeRecords();
1565 /* restart IO */
1566 // initIO();
1567 /* reset time */
1568 Yap_ReInitWTime();
1569#if USE_DL_MALLOC || USE_SYSTEM_MALLOC
1570 if (!AuxSp) {
1571 Yap_InitPreAllocCodeSpace(0);
1572 }
1573#endif
1574 CloseRestore();
1575 if (which_save == 2) {
1576 Yap_unify(ARG2, MkIntTerm(0));
1577 }
1578 return restore_mode;
1579}
1580
1581int Yap_SavedStateRestore(char *s) {
1582 CACHE_REGS
1583 return Restore(s PASS_REGS);
1584}
1585
1586static Int p_restore(USES_REGS1) {
1587 int mode;
1588 char s[MAX_PATH + 1];
1589
1590 Term t1 = Deref(ARG1);
1591#ifdef YAPOR
1592 if (GLOBAL_number_workers != 1) {
1593 Yap_Error(SYSTEM_ERROR, TermNil,
1594 "cannot perform save: more than a worker/thread running");
1595 return (FALSE);
1596 }
1597#endif /* YAPOR */
1598#ifdef THREADS
1599 if (GLOBAL_NOfThreads != 1) {
1600 Yap_Error(SYSTEM_ERROR, TermNil,
1601 "cannot perform save: more than a worker/thread running");
1602 return (FALSE);
1603 }
1604#endif /* THREADS */
1605 if (!Yap_GetName(s, MAX_PATH, t1)) {
1606 Yap_Error(TYPE_ERROR_LIST, t1, "restore/1");
1607 return (FALSE);
1608 }
1609 if ((mode = Restore(s PASS_REGS)) == DO_ONLY_CODE) {
1610 Yap_RestartYap(3);
1611 }
1612 return (mode != FAIL_RESTORE);
1613}
1614
1615void Yap_InitSavePreds(void) {
1616 Yap_InitCPred("$save", 2, p_save2, SyncPredFlag);
1617 Yap_InitCPred("$save_program", 1, p_save_program, SyncPredFlag);
1618 Yap_InitCPred("$restore", 1, p_restore, SyncPredFlag);
1619}
load_foreign_files/3 has works for the following configurations:
const char * Yap_AbsoluteFile(const char *spec, bool ok)
generate absolute path, if ok first expand SICStus Prolog style
Definition: absf.c:145
CELL YAP_SEG_SIZE
definitions required by saver/restorer and memory manager
Definition: alloc.h:61
Definition: alloc.h:63
Definition: Yatom.h:689
Definition: YapHeap.h:81
Definition: Yatom.h:544
Definition: amidefs.h:264