#include "config.h" #include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #ifdef HAVE_VALUES_H #include <values.h> #endif #include "lint.h" #include "interpret.h" #include "object.h" #include "exec.h" #ifdef AMIGA #include "hosts/amiga/ixfile.h" #include "hosts/amiga/socket.h" #endif /* * Swap out programs from objects. * Every block, free or allocated, is at least of size sizeof(struct program) . * The start can be interpreted as a struct program that habe at least a valid * total_size and ref field. ref == 0 marks a free block. */ /* How many times should swapbuf be refilled when trying to swap an object * before we conclude that it's better to use fresh space? */ #define REFILL_MAX (2) mp_int num_swapped = 0, num_unswapped = 0; mp_int total_bytes_swapped = 0, total_bytes_unswapped = 0; mp_int num_swapfree = 0; mp_int total_bytes_swapfree = 0; mp_int swapfile_size = 0; /* Number of bytes that have been reused from freed swap prog blocks */ mp_int total_swap_reused = 0; char file_name[100]; FILE *swap_file = (FILE *) 0; /* The swap file is opened once */ mp_int total_num_prog_blocks, total_prog_block_size; extern int d_flag; /* * Free space is kept in a simple linked list. The size field is < 0 * for allocated blocks or > 0 for free blocks. swap_rover walks the * list when allocating and freeing blocks. This is an attempt to * reduce head movement in comparison to normal first fit algorithms. */ struct swap_block { struct swap_block *next; mp_int size; }; struct swap_block swap_list; struct swap_block *swap_rover = 0; /* pointer to the current swap_block */ struct swap_block *swap_previous = &swap_list; /* one prior to swap_rover */ static mp_int current_offset; /* file offset corresponding to swap_rover */ /* * marion - adjust pointers for swap out and later relocate on swap in * program * line_numbers * functions * strings * variable_names * inherit * argument_types * type_start */ int locate_out (prog) struct program *prog; { char *p = 0; /* keep cc happy */ if (!prog) return 0; if (d_flag > 1) { debug_message ("locate_out: %lX %lX %lX %lX %lX %lX %lX %lX\n", prog->program, prog->line_numbers, prog->functions, prog->strings, prog->variable_names, prog->inherit, prog->argument_types, prog->type_start); } prog->program = &p[prog->program - (char *)prog]; prog->line_numbers = (char *) &p[(char *)prog->line_numbers - (char *)prog]; prog->functions = (uint32 *) &p[(char *)prog->functions - (char *)prog]; prog->function_names= (unsigned short *) &p[(char *)prog->function_names - (char *)prog]; prog->strings = (char **) &p[(char *)prog->strings - (char *)prog]; prog->variable_names= (struct variable *) &p[(char *)prog->variable_names - (char *)prog]; prog->inherit = (struct inherit *) &p[(char *)prog->inherit - (char *)prog]; if (prog->type_start) { prog->argument_types = (unsigned short *) &p[(char *)prog->argument_types - (char *)prog]; prog->type_start = (unsigned short *) &p[(char *)prog->type_start - (char *)prog]; } return 1; } /* * marion - relocate pointers after swap in * program * line_numbers * functions * strings * variable_names * inherit * argument_types * type_start */ int locate_in (prog) struct program *prog; { extern int32 current_id_number; char *p = (char *)prog; if (!prog) return 0; prog->id_number = ++current_id_number ? current_id_number : renumber_programs(); prog->program = &p[prog->program - (char *)0]; prog->line_numbers = (char *) &p[(char *)prog->line_numbers - (char *)0]; prog->functions = (uint32 *) &p[(char *)prog->functions - (char *)0]; prog->function_names= (unsigned short *) &p[(char *)prog->function_names - (char *)0]; prog->strings = (char **) &p[(char *)prog->strings - (char *)0]; prog->variable_names= (struct variable *) &p[(char *)prog->variable_names - (char *)0]; prog->inherit = (struct inherit *) &p[(char *)prog->inherit - (char *)0]; if (prog->type_start) { prog->argument_types = (unsigned short *) &p[(char *)prog->argument_types - (char *)0]; prog->type_start = (unsigned short *) &p[(char *)prog->type_start - (char *)0]; } if (d_flag > 1) { debug_message ("locate_in: %lX %lX %lX %lX %lX %lX %lX\n", prog->program, prog->line_numbers, prog->functions, prog->strings, prog->variable_names, prog->inherit, prog->argument_types, prog->type_start); } return 1; } #define SWAP_ABS(a) ((a)>0 ? (a) : (-a)) /* * Find a free block of sufficient size in the swap file and allocate * it. If there is none, add one at the end of the file. Return the * offset from the beginning of the file. */ int swap_alloc(size) mp_int size; { struct swap_block *mark,*last; extern int malloc_privilege; int save_privilege; save_privilege = malloc_privilege; malloc_privilege = MALLOC_SYSTEM; num_swapped++; total_bytes_swapped += size; mark = swap_rover; for (;;) { if (!swap_rover) { swap_rover = &swap_list; swap_previous = 0; current_offset = 0; } if (size <= swap_rover->size) { total_bytes_swapfree -= size; total_swap_reused += size; /* perfect fit? */ if (size == swap_rover->size) { swap_rover->size = -size; num_swapfree--; malloc_privilege = save_privilege; return current_offset; } /* split the block in two */ /* num_swapfree remains unchanged */ mark = (struct swap_block *) permanent_xalloc(sizeof(struct swap_block)); mark->size = swap_rover->size - size; swap_rover->size = -size; mark->next = swap_rover->next; swap_rover->next = mark; malloc_privilege = save_privilege; return current_offset; } current_offset += SWAP_ABS(swap_rover->size); swap_previous = swap_rover; swap_rover = swap_rover->next; if (swap_rover == mark) /* Once around the list without success */ { last = swap_previous; while (mark = last->next) last = mark; mark = (struct swap_block *) permanent_xalloc(sizeof(struct swap_block)); mark->next = 0; last->next = mark; mark->size = -size; if (!swap_rover) swap_rover = mark; swapfile_size += size; malloc_privilege = save_privilege; return swapfile_size - size; } } } void swap_free(offset) mp_int offset; { num_swapped--; if (offset < current_offset) { swap_rover = swap_list.next; swap_previous = &swap_list; current_offset = 0; } while (current_offset < offset && swap_rover) { swap_previous = swap_rover; current_offset += SWAP_ABS(swap_rover->size); swap_rover = swap_rover->next; } if (current_offset != offset || !swap_rover) fatal("Bad swapfile offset.\n"); if (swap_rover->size > 0) fatal("Freeing non-allocated block within swap file.\n"); swap_rover->size = -swap_rover->size; /* Make the size positive */ total_bytes_swapfree += swap_rover->size; total_bytes_swapped -= swap_rover->size; num_swapfree++; /* first skip any allocated block adjacent to the one just freed */ if (swap_previous->size <= 0) { swap_previous = swap_rover; current_offset += swap_rover->size; swap_rover = swap_rover->next; } /* now collapse adjacent free blocks */ while (swap_rover && swap_rover->size > 0) { swap_previous->size += swap_rover->size; current_offset += swap_rover->size; swap_previous->next = swap_rover->next; pfree((char *)swap_rover); num_swapfree--; swap_rover = swap_previous->next; } } void set_swapbuf(buf) char *buf; { /* This space intentionally left blank */ } /* * Swap out an object. Only the program is swapped, not the 'struct object'. * * marion - the swap seems to corrupt the function table */ int swap(ob) struct object *ob; { struct program *prog; mp_int swap_num; char *write_buffer; int write_size; if (ob->flags & O_DESTRUCTED) return 0; if (d_flag > 1) { /* marion */ debug_message("Swap object %s (ref %d)\n", ob->name, ob->ref); } if (swap_file == 0) { #ifndef MSDOS char host[50]; gethostname(host, sizeof host); sprintf(file_name, "%s.%s", SWAP_FILE, host); swap_file = fopen(file_name, "w+b"); #else swap_file = fopen(strcpy(file_name,"LPMUD.SWAP"),"w+b"); #endif /* Leave this file pointer open ! */ if (swap_file == 0) return 0; } if ( !(prog = 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 ((ob->flags & O_HEART_BEAT) || (ob->flags & O_CLONE)) { if (d_flag > 1) { debug_message (" object not swapped - heart beat or cloned.\n"); } return 0; } if (prog->ref > 1 || ob->interactive) { if (d_flag > 1) { debug_message (" object not swapped - inherited or interactive.\n"); } return 0; } /* * Has this object already been swapped, and read in again ? * Then it is very easy to swap it out again. */ if (ob->swap_num >= 0) { total_bytes_unswapped -= prog->total_size; num_unswapped--; free_prog(prog, 0); /* Do not free the strings */ ob->prog = 0; ob->flags |= O_SWAPPED; return 1; } locate_out ((struct program *)prog); write_buffer = (char *)prog; write_size = prog->total_size; swap_num = swap_alloc(write_size); if (fseek(swap_file, swap_num, 0) == -1) { fatal("Couldn't seek the swap file, errno %d, offset %d.\n", errno, swap_num); } if (swap_num != ftell(swap_file)) fatal("seek failure\n"); /* * marion - it is more efficient to write one item the size of the * program to the file than many items of size one. besides, it's * much more reasonable, as the fwrite only fails for the whole * block and not for a part of it. */ ob->swap_num = swap_num; if (fwrite(write_buffer, write_size, 1, swap_file) != 1) { debug_message("I/O error in swap.\n"); ob->swap_num = -1; locate_in(prog); return 0; } free_prog(prog, 0); /* Don't free the shared strings */ ob->prog = 0; ob->flags |= O_SWAPPED; return 1; } void load_ob_from_swap(ob) struct object *ob; { extern int errno; struct program tmp_prog; #ifndef BUG_FREE if (ob->swap_num == -1) fatal("Loading not swapped object.\n"); #endif /* This test is good not only for debugging, but also when the disk is on * fire, to stop subsequent damage. */ if (swapfile_size <= ob->swap_num) fatal("Attempt to swap in from beyond the end of the swapfile.\n"); 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 (d_flag > 1) { /* marion */ debug_message("Unswap object %s (ref %d)\n", ob->name, ob->ref); } /* * The size of the program is unkown, so read first part to * find out. * * marion - again, the read in a block is more efficient */ if (fread((char *)&tmp_prog, sizeof tmp_prog, 1, swap_file) != 1) { fatal("Couldn't read the swap file.\n"); } ob->prog = (struct program *)xalloc(tmp_prog.total_size); memcpy((char *)ob->prog, (char *)&tmp_prog, sizeof tmp_prog); fread((char *)ob->prog + sizeof tmp_prog, tmp_prog.total_size - sizeof tmp_prog, 1, swap_file); /* * to be relocated: * program * line_numbers * functions * strings * variable_names * inherit * argument_types * type_start * to be replaced: id_number */ locate_in (ob->prog); /* relocate the internal pointers */ /* The reference count will already be 1 ! */ ob->flags &= ~O_SWAPPED; if (!(ob->flags & O_DESTRUCTED) && function_exists("clean_up",ob)) { ob->flags |= O_WILL_CLEAN_UP; } total_bytes_unswapped += ob->prog->total_size; num_unswapped++; total_prog_block_size += ob->prog->total_size; total_num_prog_blocks += 1; } int remove_swap_file(ob) struct object *ob; { #ifdef DEBUG if (ob->swap_num == -1) fatal("removing non-existant swap file.\n"); #endif if (ob->flags & O_SWAPPED) load_ob_from_swap(ob); #ifndef BUG_FREE if (!ob->prog) fatal("removing swap file whith no program in object\n"); #endif /* This test is good not only for debugging, but also when the * processor is on fire, to stop subsequent damage. */ if (swapfile_size <= ob->swap_num) fatal("Attempt to remove swap entry beyond the end of the swapfile.\n"); total_bytes_unswapped -= ob->prog->total_size; num_unswapped--; swap_free(ob->swap_num); ob->swap_num = -1; return 1; } /* * This one is called at shutdown. Remove the swap file. */ void unlink_swap_file() { if (swap_file == 0) return; #ifndef MSDOS unlink(file_name); fclose(swap_file); #else fclose(swap_file); unlink(file_name); #endif }