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