#include "os.h" #include "object.h" #include "lnode.h" #include "config.h" #define SWAP_SIZE 50000 /* Big enough for most objects. */ /* simulate.c */ extern void fatal(char *fmt, ...); /* lnode.c */ extern int tot_lnode_block; /* main.c */ extern void *xalloc(int size); extern char *string_copy(char *str); extern void debug_message(char *a, ...); extern char *escape_path (char *str); static int swap_number = 1; static char *swap_area; static int swap_max_size, swap_size; int num_swapped; int total_bytes_swapped; /* swap.c */ int swap(struct object *ob); void load_ob_from_swap(struct object *ob); void remove_swap_file(struct object *ob); static void ass_size (unsigned int s); static void move_prog_to_swap_area (struct lnode *p); static struct lnode *load_prog_swap_area (char *base, char *s); int swap (struct object *ob) { char *file; FILE *f; if (NUM_RESET_TO_SWAP == 0) return 0; if (ob->heart_beat && ob->enable_heart_beat) return 0; if (ob->prog->num_ref > 1) return 0; file = xalloc (strlen (SWAP_DIR) + strlen ("/LPMUDswapXXXXXXXX") + 1); sprintf (file, "%s/LPMUDswap%d", SWAP_DIR, swap_number++); escape_path (file); if (ob->swap_num > 0) { struct stat st; /* There is already a swap file for this object. */ free_prog (ob->prog); ob->prog = 0; ob->swapped = 1; ob->heart_beat = 0; /* This pointer has to be set up again */ num_swapped++; if (stat (file, &st) == -1) { perror (file); fatal ("Coulnd't stat a swap file.\n"); } total_bytes_swapped += st.st_size; free (file); return 1; } f = fopen (file, "wb"); if (f == 0) { perror (file); debug_message ("Couldn't open swap file %s for write\n", file); free (file); return 0; } swap_area = xalloc (SWAP_SIZE); swap_size = 0; swap_max_size = SWAP_SIZE; move_prog_to_swap_area ((struct lnode *) ob->prog); if (fwrite (swap_area, 1, swap_size, f) != (unsigned int) swap_size) { debug_message ("Error in writing to swap.\n"); free (swap_area); free (file); return 0; } total_bytes_swapped += swap_size; fclose (f); free (swap_area); free (file); free_prog (ob->prog); ob->prog = 0; ob->swapped = 1; num_swapped++; ob->swap_num = swap_number - 1; ob->heart_beat = 0; /* This pointer has to be set up again */ return 1; } static void ass_size (unsigned int s) { while (s + swap_size > (unsigned int) swap_max_size) { swap_max_size *= 2; swap_area = realloc (swap_area, swap_max_size); if (swap_area == 0) fatal ("swap realloc %d\n", swap_max_size); } } static void move_prog_to_swap_area (struct lnode *p) { unsigned int s; int beg = swap_size; switch (p->line & L_MASK) { case L_SINGLE: s = sizeof (struct lnode_single); ass_size (s); memcpy (swap_area + swap_size, (char *) p, s); swap_size += s; break; case L_NUMBER: s = sizeof (struct lnode_number); ass_size (s); memcpy (swap_area + swap_size, (char *) p, s); swap_size += s; break; case L_NAME: s = sizeof (struct lnode_name); ass_size (s); memcpy (swap_area + swap_size, (char *) p, s); swap_size += s; ((struct lnode_name *) (swap_area + beg))->name = (char *) swap_size; s = strlen (((struct lnode_name *) p)->name) + 1; ass_size (s); strcpy (swap_area + swap_size, ((struct lnode_name *) p)->name); swap_size += s; break; case L_1: s = sizeof (struct lnode_1); ass_size (s); memcpy (swap_area + swap_size, (char *) p, s); swap_size += s; if (((struct lnode_1 *) p)->expr) { ((struct lnode_1 *) (swap_area + beg))->expr = (struct lnode *) swap_size; move_prog_to_swap_area (((struct lnode_1 *) p)->expr); } break; case L_2: s = sizeof (struct lnode_2); ass_size (s); memcpy (swap_area + swap_size, (char *) p, s); swap_size += s; if (((struct lnode_2 *) p)->expr1) { ((struct lnode_2 *) (swap_area + beg))->expr1 = (struct lnode *) swap_size; move_prog_to_swap_area (((struct lnode_2 *) p)->expr1); } if (((struct lnode_2 *) p)->expr2) { ((struct lnode_2 *) (swap_area + beg))->expr2 = (struct lnode *) swap_size; move_prog_to_swap_area (((struct lnode_2 *) p)->expr2); } break; case L_3: s = sizeof (struct lnode_3); ass_size (s); memcpy (swap_area + swap_size, (char *) p, s); swap_size += s; if (((struct lnode_3 *) p)->expr1) { ((struct lnode_3 *) (swap_area + beg))->expr1 = (struct lnode *) swap_size; move_prog_to_swap_area (((struct lnode_3 *) p)->expr1); } if (((struct lnode_3 *) p)->expr2) { ((struct lnode_3 *) (swap_area + beg))->expr2 = (struct lnode *) swap_size; move_prog_to_swap_area (((struct lnode_3 *) p)->expr2); } if (((struct lnode_3 *) p)->expr3) { ((struct lnode_3 *) (swap_area + beg))->expr3 = (struct lnode *) swap_size; move_prog_to_swap_area (((struct lnode_3 *) p)->expr3); } break; case L_DEF: { struct lnode_def *dp = (struct lnode_def *) p; s = sizeof (struct lnode_def); ass_size (s); memcpy (swap_area + swap_size, (char *) p, s); swap_size += s; ((struct lnode_def *) (swap_area + beg))->name = (char *) swap_size; s = strlen (dp->name) + 1; ass_size (s); strcpy (swap_area + swap_size, dp->name); swap_size += s; ((struct lnode_def *) (swap_area + beg))->block = (struct lnode *) swap_size; move_prog_to_swap_area (dp->block); if (dp->next) { ((struct lnode_def *) (swap_area + beg))->next = (struct lnode_def *) swap_size; move_prog_to_swap_area ((struct lnode *) dp->next); } break; } case L_FUNCALL: s = sizeof (struct lnode_funcall); ass_size (s); memcpy (swap_area + swap_size, (char *) p, s); swap_size += s; ((struct lnode_funcall *) (swap_area + beg))->name = (char *) swap_size; s = strlen (((struct lnode_funcall *) p)->name) + 1; ass_size (s); strcpy (swap_area + swap_size, ((struct lnode_funcall *) p)->name); swap_size += s; if (((struct lnode_funcall *) p)->expr) { ((struct lnode_funcall *) (swap_area + beg))->expr = (struct lnode *) swap_size; move_prog_to_swap_area (((struct lnode_funcall *) p)->expr); } break; case L_BLOCK: { struct lnode_block *lb = (struct lnode_block *) p; char *block = lb->block; int i, *block_start; s = sizeof (struct lnode_block); ass_size (s); memcpy (swap_area + swap_size, (char *) p, s); swap_size += s; if (lb->num_nodes) { block_start = (int *) (swap_area + swap_size); ((struct lnode_block *) (swap_area + beg))->block = (char *) swap_size; ass_size (lb->num_nodes * sizeof (int)); swap_size += lb->num_nodes * sizeof (int); for (i = 0; i < lb->num_nodes; i++) { block_start[i] = swap_size; move_prog_to_swap_area ((struct lnode *) block); block += lnode_size[((struct lnode *) block)->line >> L_SHIFT]; } } break; } case L_VAR_DEF: case L_VARIABLE: default: fatal ("Bad type in free_sub_part(): 0x%x\n", p->line & L_MASK); } } void load_ob_from_swap (struct object *ob) { FILE *f; char file[250]; struct stat st; char *buffer; struct lnode_def *pr; sprintf (file, "%s/LPMUDswap%d", SWAP_DIR, ob->swap_num); escape_path (file); f = fopen (file, "rb"); if (f == 0) { perror (file); fatal ("Can't open swap file %s\n", file); } if (fstat (fileno (f), &st) == -1) { perror (file); fatal ("Can't fstat swap file %s\n", file); } buffer = xalloc (st.st_size); if (fread (buffer, 1, st.st_size, f) != st.st_size) fatal ("Couldn't read the swap file.\n"); ob->prog = (struct lnode_def *) load_prog_swap_area (buffer, buffer); add_prog_ref (ob->prog); ob->swapped = 0; free (buffer); num_swapped--; total_bytes_swapped -= st.st_size; /* * Now we have to restore the heart_beat pointer. */ for (pr = ob->prog; pr; pr = pr->next) { if (strcmp (pr->name, "heart_beat") == 0) { ob->heart_beat = (struct lnode *) pr; break; } } } static struct lnode *load_prog_swap_area (char *base, char *s) { struct lnode *p = (struct lnode *) s; struct lnode *new = NULL, *e1, *e2, *e3; switch (p->line & L_MASK) { case L_SINGLE: new = (struct lnode *) alloc_lnode_single (p->type); new->line = p->line; break; case L_NUMBER: new = (struct lnode *) alloc_lnode_number (p->type, ((struct lnode_number *) p)->number); new->line = p->line; break; case L_NAME: new = (struct lnode *) alloc_lnode_name (p->type, string_copy ((int) (((struct lnode_name *) p)->name) + base)); new->line = p->line; break; case L_1: if (((struct lnode_1 *) p)->expr) e1 = (struct lnode *) load_prog_swap_area (base, base + (int) ((struct lnode_1 *) p)->expr); else e1 = 0; new = (struct lnode *) alloc_lnode_1 (p->type, e1); new->line = p->line; break; case L_2: if (((struct lnode_2 *) p)->expr1) e1 = load_prog_swap_area (base, base + (int) ((struct lnode_2 *) p)->expr1); else e1 = 0; if (((struct lnode_2 *) p)->expr2) e2 = load_prog_swap_area (base, base + (int) ((struct lnode_2 *) p)->expr2); else e2 = 0; new = (struct lnode *) alloc_lnode_2 (p->type, e1, e2); new->line = p->line; break; case L_3: if (((struct lnode_3 *) p)->expr1) e1 = load_prog_swap_area (base, base + (int) ((struct lnode_3 *) p)->expr1); else e1 = 0; if (((struct lnode_3 *) p)->expr2) e2 = load_prog_swap_area (base, base + (int) ((struct lnode_3 *) p)->expr2); else e2 = 0; if (((struct lnode_3 *) p)->expr3) e3 = load_prog_swap_area (base, base + (int) ((struct lnode_3 *) p)->expr3); else e3 = 0; new = (struct lnode *) alloc_lnode_3 (p->type, e1, e2, e3); new->line = p->line; break; case L_DEF: { struct lnode_def *dp = (struct lnode_def *) p; e1 = load_prog_swap_area (base, base + (int) dp->block); new = (struct lnode *) alloc_lnode_def (p->type, string_copy (base + (int) dp->name), e1, dp->num_var); new->line = p->line; if (dp->next) ((struct lnode_def *) new)->next = (struct lnode_def *) load_prog_swap_area (base, base + (int) dp->next); break; } case L_FUNCALL: if (((struct lnode_funcall *) p)->expr) e1 = load_prog_swap_area (base, base + (int) ((struct lnode_funcall *) p)->expr); else e1 = 0; new = (struct lnode *) alloc_lnode_funcall (p->type, string_copy (base + (int) ((struct lnode_funcall *) p)->name), e1); new->line = p->line; break; case L_BLOCK: { int size, num, *block_start; char *block, *block2; struct lnode *l; struct lnode_block *lb = (struct lnode_block *) p; block_start = (int *) (base + (int) lb->block); for (num = 0, size = 0; num < lb->num_nodes; num++) { l = load_prog_swap_area (base, base + block_start[num]); *((struct lnode **) (base + block_start[num])) = l; size += lnode_size[l->line >> L_SHIFT]; } new = (struct lnode *) xalloc (sizeof (struct lnode_block)); tot_lnode_block++; block = xalloc (size); ((struct lnode_block *) new)->block = block; ((struct lnode_block *) new)->num_nodes = lb->num_nodes; new->type = p->type; new->line = p->line; for (num = 0, block2 = block; num < lb->num_nodes; num++) { int size; l = (struct lnode *) *(int *) (base + block_start[num]); size = lnode_size[l->line >> L_SHIFT]; memcpy (block2, (char *) l, size); block2 += size; free_lnode (l, 1); /* Should the second argument be 1 here? */ } break; } case L_VAR_DEF: case L_VARIABLE: default: fatal ("Bad type in free_sub_part(): 0x%x\n", p->line & L_MASK); } return new; } void remove_swap_file (struct object *ob) { char file[250]; if (!ob->swap_num) fatal ("Remove non-existing swap file.\n"); sprintf (file, "%s/LPMUDswap%d", SWAP_DIR, ob->swap_num); escape_path (file); if (unlink (file) == -1) { perror (file); debug_message ("Could not unlink swap file %s\n", file); } ob->swap_num = 0; }