#include <types.h> #include <stat.h> #include <stdio.h> #include "lint.h" #include "interpret.h" #include "object.h" #include "lnode.h" #include "config.h" #include <errno.h> /* * Swap out programs from objects. */ #define SWAP_SIZE 50000 /* Big enough for most objects. */ extern char *xalloc PROT((int)), *string_copy PROT((char *)); static void move_prog_to_swap_area PROT((struct lnode *, int)); void load_prog_swap_area(); static void copy_sub_node PROT((struct lnode *, struct lnode **)); static char *swap_area; static int swap_max_size, swap_size; int num_swapped; int total_bytes_swapped; FILE *swap_file; /* The swap file is opened once */ int total_num_prog_blocks, total_prog_block_size; /* * Used to determine if a pointer is pointing inside a lnode swap * block. */ static int current_buffer_size; /* * Swap out an object. This is done by copying all struct lnodes into * one contiguous area, and replacing all pointers with relative offsets. */ int swap(ob) struct object *ob; { struct lnode_2 swap_node; if (ob->swap_num == -1 && ob->block != 0 && !ob->cloned) { fprintf(stderr, "FATAL: swap(%s) swap_num %d block 0x%x\n", ob->name, ob->swap_num, ob->block); return 0; } if (swap_file == 0) { char file_name[100], host[50]; gethostname(host, sizeof host); sprintf(file_name, "%s.%s", SWAP_FILE, host); swap_file = fopen(file_name, "w+"); if (swap_file == 0) return 0; } if (!ob->prog) { fprintf(stderr, "warning:no program in object %s, don't swap it\n", ob->name); /* It`s no good freeing a NULL pointer */ return 0; } if (NUM_RESET_TO_SWAP == 0) return 0; if (ob->enable_heart_beat || ob->cloned) return 0; if (ob->prog->num_ref > 1 || ob->inherited || ob->interactive) return 0; if (ob->swap_num >= 0) { if (!ob->block) fatal("Object swapped but prog not in block.\n"); if (!free_prog(ob->prog, ob->block, ob->swap_size)) fatal("Failed to release prog block when swap.\n"); ob->prog = 0; ob->status = 0; ob->swapped = 1; ob->heart_beat = 0; /* This pointer has to be set up again */ num_swapped++; total_bytes_swapped += ob->swap_size; return 1; } swap_area = xalloc(SWAP_SIZE); swap_size = 0; swap_max_size = SWAP_SIZE; swap_node.line = L_2; swap_node.expr1 = (struct lnode *)ob->prog; swap_node.expr2 = (struct lnode *)ob->status; move_prog_to_swap_area((struct lnode *)&swap_node, 0); if (fseek(swap_file, 0, 2) == -1) { free(swap_area); return 0; } ob->swap_num = ftell(swap_file); if (fwrite(swap_area, 1, swap_size, swap_file) != swap_size) { debug_message("I/O error in swap.\n"); free(swap_area); return 0; } total_bytes_swapped += swap_size; num_swapped++; free(swap_area); if (ob->block) fprintf(stderr, "FATAL: Object prog already in block: %s, 0x%x.\n", ob->name, ob->block); if (!free_prog(ob->prog, 0, 0)) fatal("Failed to release prog tree when first swap.\n"); if (ob->status) free_sub_part((struct lnode *)ob->status, 1); ob->prog = 0; ob->status = 0; ob->swapped = 1; ob->heart_beat = 0; /* This pointer has to be set up again */ ob->swap_size = swap_size; return 1; } static void ass_size(s) int s; { char *temp; int tempsize; while(s + swap_size > swap_max_size) { tempsize = swap_max_size; swap_max_size += SWAP_SIZE; temp = xalloc (swap_max_size); if (temp == 0) fatal("swap realloc %d\n", swap_max_size); memcpy (temp, swap_area, tempsize); free(swap_area); swap_area = temp; } } #define even(s) ((s+3)&~3) struct lnode_block *lb_glob; struct lnode *p_glob; /* * Move lnode 'p' to the swap area, and convert all pointers to relative * pointers. If 'dest' is non-zero, it is the offset into the swaparea * where 'p' is supposed to be copied. If 'dest', then space is supposed * to have been reserved. */ static void move_prog_to_swap_area(p, dest) struct lnode *p; int dest; { unsigned int s; int beg = swap_size; if (dest) beg = dest - (int)swap_area; switch(p->line & L_MASK) { case L_SINGLE: s = sizeof(struct lnode_single); ass_size(s); memcpy(swap_area + beg, (char *)p, s); if (!dest) swap_size += s; break; case L_NUMBER: s = sizeof(struct lnode_number); ass_size(s); memcpy(swap_area + beg, (char *)p, s); if (!dest) swap_size += s; break; case L_NAME: s = sizeof(struct lnode_name); ass_size(s); memcpy(swap_area + beg, (char *)p, s); if (!dest) swap_size += s; #ifdef SWAP_STRINGS ((struct lnode_name *)(swap_area+beg))->name = (char *)swap_size; s = even(strlen(((struct lnode_name *)p)->name) + 1); ass_size(s); strcpy(swap_area + swap_size, ((struct lnode_name *)p)->name); swap_size += s; #else make_shared_string(((struct lnode_name *)p)->name); #endif break; case L_1: { struct lnode_1 *l = (struct lnode_1 *)p; s = sizeof(struct lnode_1); ass_size(s); memcpy(swap_area + beg, (char *)p, s); if (!dest) swap_size += s; copy_sub_node(l->expr, &((struct lnode_1 *)(swap_area+beg))->expr); break; } case L_2: { struct lnode_2 *l = (struct lnode_2 *)p; s = sizeof(struct lnode_2); ass_size(s); memcpy(swap_area + beg, (char *)p, s); if (!dest) swap_size += s; copy_sub_node(l->expr1, &((struct lnode_2 *)(swap_area+beg))->expr1); copy_sub_node(l->expr2, &((struct lnode_2 *)(swap_area+beg))->expr2); break; } case L_3: { struct lnode_3 *l = (struct lnode_3 *)p; s = sizeof(struct lnode_3); ass_size(s); memcpy(swap_area + beg, (char *)p, s); if (!dest) swap_size += s; copy_sub_node(l->expr1, &((struct lnode_3 *)(swap_area+beg))->expr1); copy_sub_node(l->expr2, &((struct lnode_3 *)(swap_area+beg))->expr2); copy_sub_node(l->expr3, &((struct lnode_3 *)(swap_area+beg))->expr3); break; } case L_DEF: { struct lnode_def *dp; for (dp = (struct lnode_def *)p; dp; dp = dp->next) { beg = swap_size; /* Moved forward for every function. */ s = sizeof(struct lnode_def); ass_size(s); memcpy(swap_area + beg, (char *)dp, s); swap_size += s; #ifdef SWAP_STRINGS ((struct lnode_def *)(swap_area+beg))->name = (char *)swap_size; s = even(strlen(dp->name) + 1); ass_size(s); strcpy(swap_area + swap_size, dp->name); swap_size += s; #else make_shared_string(dp->name); #endif /* The block can be empty ! */ copy_sub_node(dp->block, &((struct lnode_def *)(swap_area+beg))->block); if (dp->next) { ((struct lnode_def *)(swap_area+beg))->next = (struct lnode_def *)swap_size; } else ((struct lnode_def *)(swap_area+beg))->next = 0; } break; } case L_FUNCALL: { struct lnode_funcall *l = (struct lnode_funcall *)p; s = sizeof (struct lnode_funcall); ass_size(s); memcpy(swap_area + beg, (char *)p, s); if (!dest) swap_size += s; #ifdef SWAP_STRINGS ((struct lnode_funcall *)(swap_area+beg))->name = (char *)swap_size; s = even(strlen(((struct lnode_funcall *)p)->name) + 1); ass_size(s); strcpy(swap_area + swap_size, ((struct lnode_funcall *)p)->name); swap_size += s; #else make_shared_string(((struct lnode_funcall *)p)->name); #endif copy_sub_node(l->expr, &((struct lnode_funcall *)(swap_area+beg))->expr); break; } case L_BLOCK: { struct lnode_block *lb = (struct lnode_block *)p; char *block; int i, block2; s = sizeof (struct lnode_block); ass_size(s); memcpy(swap_area + beg, (char *)p, s); if (!dest) swap_size += s; if (lb->num_nodes) { ((struct lnode_block *)(swap_area+beg))->block = (char *)swap_size; } else ((struct lnode_block *)(swap_area+beg))->block = 0; block2 = swap_size; /* * Reserve size for all lnodes in this block. */ for (i=0, block = lb->block; i < lb->num_nodes; i++) { s = lnode_size[((struct lnode *)block)->line >> L_SHIFT]; ass_size(s); swap_size += s; block += s; } /* * Now copy the lnodes in this block. */ for (i=0, block = lb->block; i < lb->num_nodes; i++) { move_prog_to_swap_area((struct lnode *)block, (int)swap_area + block2); s = lnode_size[((struct lnode *)block)->line >> L_SHIFT]; block += s; block2 += s; } break; } case L_VAR_DEF: { struct lnode_var_def *vd; for (vd = (struct lnode_var_def *)p; vd; vd = vd->next) { beg = swap_size; s = sizeof (struct lnode_var_def); ass_size(s); memcpy(swap_area + beg, (char *)vd, s); swap_size += s; #ifdef SWAP_STRINGS ((struct lnode_var_def *)(swap_area+beg))->name = (char *)swap_size; s = even(strlen(vd->name) + 1); ass_size(s); strcpy(swap_area + swap_size, vd->name); swap_size += s; #else make_shared_string(vd->name); #endif if (vd->next) { ((struct lnode_var_def *)(swap_area+beg))->next = (struct lnode_var_def *)swap_size; } else ((struct lnode_var_def *)(swap_area+beg))->next = 0; } break; } case L_VARIABLE: default: fatal("Bad type in free_sub_part(): 0x%x\n", p->line); } } static struct object *tmp_ob; void load_ob_from_swap(ob) struct object *ob; { char *buffer; struct lnode_def *pr; struct lnode_2 *swap_node; extern int errno; tmp_ob = ob; if (ob->swap_num == -1) fatal("Loading not swapped object.\n"); total_prog_block_size += ob->swap_size; total_num_prog_blocks += 1; buffer = xalloc(ob->swap_size); current_buffer_size = ob->swap_size; if (fseek(swap_file, ob->swap_num, 0) == -1) fatal("Couldn't seek the swap file, errno %d, offset %d.\n", errno, ob->swap_num); if (fread(buffer, 1, ob->swap_size, swap_file) != ob->swap_size) fatal("Couldn't read the swap file.\n"); load_prog_swap_area(buffer, buffer); swap_node = (struct lnode_2 *)buffer; ob->block = buffer; ob->prog = (struct lnode_def *)swap_node->expr1; ob->status = (struct lnode_var_def *)swap_node->expr2; /* The reference count will already be 1 ! */ ob->swapped = 0; total_bytes_swapped -= ob->swap_size; num_swapped--; /* * 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; } } if (!ob->heart_beat && ob->inherit) ob->heart_beat = ob->inherit->heart_beat; } char *base_glob, *s_glob; void load_prog_swap_area(base, s) char *base, *s; { struct lnode *p = (struct lnode *)s; base_glob = base; s_glob = s; p_glob = p; if (s < base) fatal("base < s\n"); switch(p->line & L_MASK) { case L_CONSTANT: break; case L_SINGLE: break; case L_NUMBER: break; case L_NAME: { #ifdef SWAP_STRINGS struct lnode_name *pn = (struct lnode_name *)p; pn->name = (char *)(pn->name + (int)base); #endif break; } case L_1: { struct lnode_1 *p1 = (struct lnode_1 *)p; if (p1->expr && (int)p1->expr < current_buffer_size) { p1->expr = (struct lnode *)(base + (int)p1->expr); load_prog_swap_area(base, (char *)p1->expr); } break; } case L_2: { struct lnode_2 *p2 = (struct lnode_2 *)p; if (p2->expr1 && (int)p2->expr1 < current_buffer_size) { p2->expr1 = (struct lnode *)(base + (int)p2->expr1); load_prog_swap_area(base, (char *)p2->expr1); } if (p2->expr2 && (int)p2->expr2 < current_buffer_size) { p2->expr2 = (struct lnode *)(base + (int)p2->expr2); load_prog_swap_area(base, (char *)p2->expr2); } break; } case L_3: { struct lnode_3 *p3 = (struct lnode_3 *)p; if (p3->expr1 && (int)p3->expr1 < current_buffer_size) { p3->expr1 = (struct lnode *)(base + (int)p3->expr1); load_prog_swap_area(base, (char *)p3->expr1); } if (p3->expr2 && (int)p3->expr2 < current_buffer_size) { p3->expr2 = (struct lnode *)(base + (int)p3->expr2); load_prog_swap_area(base, (char *)p3->expr2); } if (p3->expr3 && (int)p3->expr3 < current_buffer_size) { p3->expr3 = (struct lnode *)(base + (int)p3->expr3); load_prog_swap_area(base, (char *)p3->expr3); } break; } case L_DEF: { /* * Unwind all function definitions here, so that recursive call * of load_prog_swap_area() of them not is needed. */ struct lnode_def *dp; for (dp = (struct lnode_def *)p; dp; dp = dp->next) { if (dp->block && (int)dp->block < current_buffer_size) { dp->block = (struct lnode *)(base + (int)dp->block); load_prog_swap_area(base, (char *)dp->block); } #ifdef SWAP_STRINGS dp->name = (char *)(base + (int)dp->name); #endif if (dp->next) dp->next = (struct lnode_def *)(base + (int)dp->next); } break; } case L_FUNCALL: { struct lnode_funcall *pf = (struct lnode_funcall *)p; if (pf->expr && (int)pf->expr < current_buffer_size) { pf->expr = (struct lnode *)(base + (int)pf->expr); load_prog_swap_area(base, (char *)pf->expr); } #ifdef SWAP_STRINGS pf->name = (char *)(base + (int)pf->name); #endif break; } case L_BLOCK: { int size, num; char *block_start; struct lnode *l; struct lnode_block *lb = (struct lnode_block *)p; if (lb->block) { block_start = (char *)(base + (int)lb->block); lb->block = block_start; } for (num = 0, size = 0; num < lb->num_nodes; num++) { l = (struct lnode *)(block_start + size); load_prog_swap_area(base, (char *)l); size += lnode_size[l->line >> L_SHIFT]; } break; } case L_VAR_DEF: { /* * Unwind all variable definitions here, so that recursive call * of load_prog_swap_area() of them not is needed. */ struct lnode_var_def *vd; for (vd = (struct lnode_var_def *)p; vd; vd = vd->next) { #ifdef SWAP_STRINGS vd->name = (char *)(base + (int)vd->name); #endif if (vd->next) vd->next = (struct lnode_var_def *)(base + (int)vd->next); } break; } case L_VARIABLE: default: fprintf(stderr, "swap_area = 0x%x, base = 0x%x\n", swap_area, base); fatal("Bad type in load_prog_swap_area 0x%x\n", p->line); } } void remove_swap_file(ob) struct object *ob; { /* Haven't implemented this yet :-( */ } /* * Warning, this function is not called every time. */ static void copy_sub_node(from, top) struct lnode *from, **top; { if (from) { if (!match_and_replace_lnode(from, top)) { *top = (struct lnode *)swap_size; move_prog_to_swap_area(from, 0); } } else { *top = 0; } }