source: trunk/source/lisp-kernel/image.c @ 10830

Last change on this file since 10830 was 10830, checked in by gb, 13 years ago

Use writebuf(), not write(), to write a section to disk. (I think
that write() can generally return a positive value smaller than
write()'s last arg; we try to handle this in lisp I/O code, it
can't hurt to be defensive about it here, and may explain why
win64 sometimes writes images that seem to be missing data.)
The code that called write checked to see if the return value
equaled the argument and returned errno if not, but errno would
be 0 on a short write.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.9 KB
Line 
1/*
2   Copyright (C) 2002 Clozure Associates
3   This file is part of OpenMCL. 
4
5   OpenMCL is licensed under the terms of the Lisp Lesser GNU Public
6   License , known as the LLGPL and distributed with OpenMCL as the
7   file "LICENSE".  The LLGPL consists of a preamble and the LGPL,
8   which is distributed with OpenMCL as the file "LGPL".  Where these
9   conflict, the preamble takes precedence. 
10
11   OpenMCL is referenced in the preamble as the "LIBRARY."
12
13   The LLGPL is also available online at
14   http://opensource.franz.com/preamble.html
15*/
16
17#include "lisp.h"
18#include "lisp_globals.h"
19#include "area.h"
20#include "image.h"
21#include "gc.h"
22#include <errno.h>
23#include <unistd.h>
24#ifndef WINDOWS
25#include <sys/mman.h>
26#endif
27#include <stdio.h>
28
29
30
31#if defined(PPC64) || defined(X8632)
32#define RELOCATABLE_FULLTAG_MASK \
33  ((1<<fulltag_cons)|(1<<fulltag_misc))
34#else
35#ifdef X8664
36#define RELOCATABLE_FULLTAG_MASK \
37  ((1<<fulltag_cons)|(1<<fulltag_misc)|(1<<fulltag_symbol)|(1<<fulltag_function))
38#else
39#define RELOCATABLE_FULLTAG_MASK \
40  ((1<<fulltag_cons)|(1<<fulltag_nil)|(1<<fulltag_misc))
41#endif
42#endif
43
44void
45relocate_area_contents(area *a, LispObj bias)
46{
47  LispObj
48    *start = (LispObj *)(a->low), 
49    *end = (LispObj *)(a->active),
50    low = (LispObj)image_base - bias,
51    high = ptr_to_lispobj(active_dynamic_area->active) - bias,
52    w0;
53  int fulltag;
54
55  while (start < end) {
56    w0 = *start;
57    fulltag = fulltag_of(w0);
58    if (immheader_tag_p(fulltag)) {
59      start = (LispObj *)skip_over_ivector((natural)start, w0);
60    } else {
61#ifdef X8664
62      if (header_subtag(w0) == subtag_function) {
63        int skip = (int) start[1];
64     
65        start += skip;
66        if (((LispObj) start) & node_size) {
67          --start;
68        }
69        w0 = *start;
70        fulltag = fulltag_of(w0);
71      }
72#endif
73
74      if ((w0 >= low) && (w0 < high) &&
75          ((1<<fulltag) & RELOCATABLE_FULLTAG_MASK)) {
76        *start = (w0+bias);
77      }
78      w0 = *++start;
79      fulltag = fulltag_of(w0);
80      if ((w0 >= low) && (w0 < high) &&
81          ((1<<fulltag) & RELOCATABLE_FULLTAG_MASK)) {
82        *start = (w0+bias);
83      }
84      ++start;
85    }
86  }
87}
88     
89
90
91
92off_t
93seek_to_next_page(int fd)
94{
95  off_t pos = LSEEK(fd, 0, SEEK_CUR);
96  pos = align_to_power_of_2(pos, log2_page_size);
97  return LSEEK(fd, pos, SEEK_SET);
98}
99 
100/*
101  fd is positioned to EOF; header has been allocated by caller.
102  If we find a trailer (and that leads us to the header), read
103  the header & return true else return false.
104*/
105Boolean
106find_openmcl_image_file_header(int fd, openmcl_image_file_header *header)
107{
108  openmcl_image_file_trailer trailer;
109  int disp;
110  off_t pos;
111  unsigned version, flags;
112
113  pos = LSEEK(fd, 0, SEEK_END);
114  if (pos < 0) {
115    return false;
116  }
117  pos -= sizeof(trailer);
118
119  if (LSEEK(fd, pos, SEEK_SET) < 0) {
120    return false;
121  }
122  if (read(fd, &trailer, sizeof(trailer)) != sizeof(trailer)) {
123    return false;
124  }
125  if ((trailer.sig0 != IMAGE_SIG0) ||
126      (trailer.sig1 != IMAGE_SIG1) ||
127      (trailer.sig2 != IMAGE_SIG2)) {
128    return false;
129  }
130  disp = trailer.delta;
131 
132  if (disp >= 0) {
133    return false;
134  }
135  if (LSEEK(fd, disp, SEEK_CUR) < 0) {
136    return false;
137  }
138  if (read(fd, header, sizeof(openmcl_image_file_header)) !=
139      sizeof(openmcl_image_file_header)) {
140    return false;
141  }
142  if ((header->sig0 != IMAGE_SIG0) ||
143      (header->sig1 != IMAGE_SIG1) ||
144      (header->sig2 != IMAGE_SIG2) ||
145      (header->sig3 != IMAGE_SIG3)) {
146    return false;
147  }
148  version = (header->abi_version) & 0xffff;
149  if (version < ABI_VERSION_MIN) {
150    fprintf(stderr, "Heap image is too old for this kernel.\n");
151    return false;
152  }
153  if (version > ABI_VERSION_MAX) {
154    fprintf(stderr, "Heap image is too new for this kernel.\n");
155    return false;
156  }
157  flags = header->flags;
158  if (flags != PLATFORM) {
159    fprintf(stderr, "Heap image was saved for another platform.\n");
160    return false;
161  }
162  return true;
163}
164
165void
166load_image_section(int fd, openmcl_image_section_header *sect)
167{
168  extern area* allocate_dynamic_area(unsigned);
169  off_t
170    pos = seek_to_next_page(fd), advance;
171  int 
172    mem_size = sect->memory_size;
173  void *addr;
174  area *a;
175
176  advance = mem_size;
177  switch(sect->code) {
178  case AREA_READONLY:
179    if (!MapFile(pure_space_active,
180                 pos,
181                 align_to_power_of_2(mem_size,log2_page_size),
182                 MEMPROTECT_RX,
183                 fd)) {
184      return;
185    }
186    a = new_area(pure_space_active, pure_space_limit, AREA_READONLY);
187    pure_space_active += mem_size;
188    a->active = pure_space_active;
189    sect->area = a;     
190    break;
191
192  case AREA_STATIC:
193    if (!MapFile(static_space_active,
194                 pos,
195                 align_to_power_of_2(mem_size,log2_page_size),
196                 MEMPROTECT_RWX,
197                 fd)) {
198      return;
199    }
200    a = new_area(static_space_active, static_space_limit, AREA_STATIC);
201    static_space_active += mem_size;
202    a->active = static_space_active;
203    sect->area = a;
204    break;
205
206  case AREA_DYNAMIC:
207    a = allocate_dynamic_area(mem_size);
208    if (!MapFile(a->low,
209                 pos,
210                 align_to_power_of_2(mem_size,log2_page_size),
211                 MEMPROTECT_RWX,
212                 fd)) {
213      return;
214    }
215
216    a->static_dnodes = sect->static_dnodes;
217    sect->area = a;
218    break;
219
220  case AREA_MANAGED_STATIC:
221    a = new_area(pure_space_limit, pure_space_limit, AREA_MANAGED_STATIC);
222    sect->area = a;
223    break;
224
225  default:
226    return;
227   
228  }
229  LSEEK(fd, pos+advance, SEEK_SET);
230}
231
232LispObj
233load_openmcl_image(int fd, openmcl_image_file_header *h)
234{
235  LispObj image_nil = 0;
236  area *a;
237  if (find_openmcl_image_file_header(fd, h)) {
238    int i, nsections = h->nsections;
239    openmcl_image_section_header sections[nsections], *sect=sections;
240    LispObj bias = image_base - ACTUAL_IMAGE_BASE(h);
241#if (WORD_SIZE== 64)
242    signed_natural section_data_delta = 
243      ((signed_natural)(h->section_data_offset_high) << 32L) | h->section_data_offset_low;
244#endif
245
246    if (read (fd, sections, nsections*sizeof(openmcl_image_section_header)) !=
247        nsections * sizeof(openmcl_image_section_header)) {
248      return 0;
249    }
250#if WORD_SIZE == 64
251    LSEEK(fd, section_data_delta, SEEK_CUR);
252#endif
253    for (i = 0; i < nsections; i++, sect++) {
254      load_image_section(fd, sect);
255      a = sect->area;
256      if (a == NULL) {
257        return 0;
258      }
259    }
260
261    for (i = 0, sect = sections; i < nsections; i++, sect++) {
262      a = sect->area;
263      switch(sect->code) {
264      case AREA_STATIC:
265        nilreg_area = a;
266#ifdef PPC
267#ifdef PPC64
268        image_nil = ptr_to_lispobj(a->low + (1024*4) + sizeof(lispsymbol) + fulltag_misc);
269#else
270        image_nil = (LispObj)(a->low + 8 + 8 + (1024*4) + fulltag_nil);
271#endif
272#endif
273#ifdef X86
274#ifdef X8664
275        image_nil = (LispObj)(a->low) + (1024*4) + fulltag_nil;
276#else
277        image_nil = (LispObj)(a->low) + (1024*4) + fulltag_cons;
278#endif
279#endif
280        set_nil(image_nil);
281        if (bias) {
282          relocate_area_contents(a, bias);
283        }
284        make_dynamic_heap_executable(a->low, a->active);
285        add_area_holding_area_lock(a);
286        break;
287       
288      case AREA_READONLY:
289        readonly_area = a;
290        add_area_holding_area_lock(a);
291        break;
292      }
293    }
294    for (i = 0, sect = sections; i < nsections; i++, sect++) {
295      a = sect->area;
296      switch(sect->code) {
297      case AREA_MANAGED_STATIC:
298        if (bias) {
299          relocate_area_contents(a, bias);
300        }
301        managed_static_area = a;
302        add_area_holding_area_lock(a);
303        break;
304      case AREA_DYNAMIC:
305        if (bias) {
306          relocate_area_contents(a, bias);
307        }
308        resize_dynamic_heap(a->active, lisp_heap_gc_threshold);
309        xMakeDataExecutable(a->low, a->active - a->low);
310        break;
311      }
312    }
313  }
314  return image_nil;
315}
316 
317void
318prepare_to_write_dynamic_space()
319{
320  area *a = active_dynamic_area;
321  LispObj
322    *start = (LispObj *)(a->low),
323    *end = (LispObj *) (a->active),
324    x1;
325  int tag, subtag, element_count;
326
327  while (start < end) {
328    x1 = *start;
329    tag = fulltag_of(x1);
330    if (immheader_tag_p(tag)) {
331      subtag = header_subtag(x1);
332      if (subtag == subtag_macptr) {
333        if (start[1]) {
334          /* Leave NULL pointers alone */
335          *start = make_header(subtag_dead_macptr,header_element_count(x1));
336        }
337      }
338      start = (LispObj *)skip_over_ivector((natural)start, x1);
339    } else if (nodeheader_tag_p(tag)) {
340      element_count = header_element_count(x1) | 1;
341      start += (element_count+1);
342    } else {
343      start += 2;
344    }
345  }
346}
347
348 
349
350int
351write_file_and_section_headers(int fd, 
352                               openmcl_image_file_header *file_header,
353                               openmcl_image_section_header* section_headers,
354                               int nsections,
355                               off_t *header_pos)
356{
357  *header_pos = seek_to_next_page(fd);
358
359  if (LSEEK (fd, *header_pos, SEEK_SET) < 0) {
360    return errno;
361  }
362  if (write(fd, file_header, sizeof(*file_header)) != sizeof(*file_header)) {
363    return errno;
364  }
365  if (write(fd, section_headers, sizeof(section_headers[0])*nsections)
366      != (sizeof(section_headers[0])*nsections)) {
367    return errno;
368  }
369  return 0;
370}
371 
372natural
373writebuf(int fd, char *bytes, natural n)
374{
375  natural remain = n;
376  int result;
377
378  while (remain) {
379    result = write(fd, bytes, remain);
380    if (result < 0) {
381      return errno;
382    }
383    bytes += result;
384    remain -= result;
385  }
386  return 0;
387}
388
389OSErr
390save_application(unsigned fd)
391{
392  openmcl_image_file_header fh;
393  openmcl_image_section_header sections[NUM_IMAGE_SECTIONS];
394  openmcl_image_file_trailer trailer;
395  area *areas[NUM_IMAGE_SECTIONS], *a;
396  int i, err;
397  off_t header_pos, eof_pos;
398#if WORD_SIZE == 64
399  off_t image_data_pos;
400  signed_natural section_data_delta;
401#endif
402
403  areas[0] = nilreg_area; 
404  areas[1] = active_dynamic_area;
405  areas[2] = readonly_area;
406  areas[3] = managed_static_area;
407  for (i = 0; i < NUM_IMAGE_SECTIONS; i++) {
408    a = areas[i];
409    sections[i].code = a->code;
410    sections[i].area = NULL;
411    sections[i].memory_size  = a->active - a->low;
412    if (a == active_dynamic_area) {
413      sections[i].static_dnodes = tenured_area->static_dnodes;
414    } else {
415      sections[i].static_dnodes = 0;
416    }
417  }
418  fh.sig0 = IMAGE_SIG0;
419  fh.sig1 = IMAGE_SIG1;
420  fh.sig2 = IMAGE_SIG2;
421  fh.sig3 = IMAGE_SIG3;
422  fh.timestamp = time(NULL);
423  CANONICAL_IMAGE_BASE(&fh) = IMAGE_BASE_ADDRESS;
424  ACTUAL_IMAGE_BASE(&fh) = image_base;
425  fh.nsections = NUM_IMAGE_SECTIONS;
426  fh.abi_version=ABI_VERSION_CURRENT;
427#if WORD_SIZE == 64
428  fh.section_data_offset_high = 0;
429  fh.section_data_offset_low = 0;
430#else
431  fh.pad0[0] = fh.pad0[1] = 0;
432  fh.pad1[0] = fh.pad1[1] = fh.pad1[2] = fh.pad1[3] = 0;
433#endif
434  fh.flags = PLATFORM;
435
436#if WORD_SIZE == 64
437  image_data_pos = seek_to_next_page(fd);
438#else
439  err = write_file_and_section_headers(fd, &fh, sections, NUM_IMAGE_SECTIONS, &header_pos);
440  if (err) {
441    return err;
442  }
443#endif
444
445  /*
446    Coerce macptrs to dead_macptrs.
447  */
448 
449  prepare_to_write_dynamic_space(active_dynamic_area);
450
451  /*
452    lisp_global(GC_NUM) and lisp_global(FWDNUM) are persistent,
453    as is DELETED_STATIC_PAIRS.
454    Nothing else is even meaningful at this point.
455  */
456  for (i = MIN_KERNEL_GLOBAL; i < 0; i++) {
457    switch (i) {
458    case FWDNUM:
459    case GC_NUM:
460    case STATIC_CONSES:
461    case WEAK_GC_METHOD:
462      break;
463    default:
464      lisp_global(i) = 0;
465    }
466  }
467
468  for (i = 0; i < NUM_IMAGE_SECTIONS; i++) {
469    natural n;
470    a = areas[i];
471    seek_to_next_page(fd);
472    n = sections[i].memory_size;
473    if (writebuf(fd, a->low, n)) {
474        return errno;
475    }
476  }
477
478#if WORD_SIZE == 64
479  seek_to_next_page(fd);
480  section_data_delta = -((LSEEK(fd,0,SEEK_CUR)+sizeof(fh)+sizeof(sections)) -
481                         image_data_pos);
482  fh.section_data_offset_high = (int)(section_data_delta>>32L);
483  fh.section_data_offset_low = (unsigned)section_data_delta;
484  err =  write_file_and_section_headers(fd, &fh, sections, NUM_IMAGE_SECTIONS, &header_pos);
485  if (err) {
486    return err;
487  } 
488#endif
489
490  trailer.sig0 = IMAGE_SIG0;
491  trailer.sig1 = IMAGE_SIG1;
492  trailer.sig2 = IMAGE_SIG2;
493  eof_pos = LSEEK(fd, 0, SEEK_CUR) + sizeof(trailer);
494  trailer.delta = (int) (header_pos-eof_pos);
495  if (write(fd, &trailer, sizeof(trailer)) == sizeof(trailer)) {
496#ifndef WINDOWS
497    fsync(fd);
498#endif
499    close(fd);
500    return 0;
501  } 
502  i = errno;
503  close(fd);
504  return i;
505}
506     
507
508
509
Note: See TracBrowser for help on using the repository browser.