/* * Swap out an object. Only the program is swapped, not the 'object_t'. * * marion - the swap seems to corrupt the function table */ int swap(object_t * ob) { /* the simuls[] table uses pointers to the functions so the simul_efun * program cannot be relocated. locate_in() could be changed to * correct this or simuls[] could use offsets, but it doesn't seem * worth it just to get the simul_efun object to swap. Maybe later. * * Ditto the master object and master_applies[]. Mudlibs that have * a period TIME_TO_SWAP between successive master applies must be * extremely rare ... */ if (ob == simul_efun_ob || ob == master_ob) return 0; if (ob->flags & O_DESTRUCTED) return 0; debug(d_flag, ("Swap object /%s (ref %d)", ob->name, ob->ref)); if (ob->prog->line_info) swap_line_numbers(ob->prog); /* not always done before we get here */ if ((ob->flags & O_HEART_BEAT) || (ob->flags & O_CLONE)) { debug(d_flag, (" object not swapped - heart beat or cloned.")); return 0; } if (ob->prog->ref > 1 || ob->interactive) { debug(d_flag, (" object not swapped - inherited or interactive or in apply_low() cache.")); return 0; } if (ob->prog->func_ref > 0) { debug(d_flag, (" object not swapped - referenced by functions.")); return 0; } locate_out(ob->prog); /* relocate the internal pointers */ if (swap_out((char *) ob->prog, ob->prog->total_size, (int *) &ob->swap_num)) { num_swapped++; free_prog(ob->prog, 0); /* Do not free the strings */ ob->prog = 0; ob->flags |= O_SWAPPED; return 1; } else { locate_in(ob->prog); return 0; } }
/* * Despite the name, this routine takes care of several things. * It will run once every 15 minutes. * * . It will attempt to reconnect to the address server if the connection has * been lost. * . It will loop through all objects. * * . If an object is found in a state of not having done reset, and the * delay to next reset has passed, then reset() will be done. * * . If the object has a existed more than the time limit given for swapping, * then 'clean_up' will first be called in the object, after which it will * be swapped out if it still exists. * * There are some problems if the object self-destructs in clean_up, so * special care has to be taken of how the linked list is used. */ static void look_for_objects_to_swap() { static int next_time; #ifndef NO_IP_DEMON extern int no_ip_demon; static int next_server_time; #endif object_t *ob; VOLATILE object_t *next_ob; error_context_t econ; #ifndef NO_IP_DEMON if (current_time >= next_server_time) { /* initialize the address server. if it is already initialized, then * this is a nop. this will cause the driver to reattempt connecting * to the address server once every 15 minutes in the event that it * has gone down. */ if (!no_ip_demon && next_server_time) init_addr_server(ADDR_SERVER_IP, ADDR_SERVER_PORT); next_server_time = current_time + 15 * 60; } #endif if (current_time < next_time) return; /* Not time to look yet */ next_time = current_time + 15 * 60; /* Next time is in 15 minutes */ /* * Objects object can be destructed, which means that next object to * investigate is saved in next_ob. If very unlucky, that object can be * destructed too. In that case, the loop is simply restarted. */ next_ob = obj_list; save_context(&econ); if (SETJMP(econ.context)) restore_context(&econ); while ((ob = (object_t *)next_ob)) { int ready_for_swap = 0; int ready_for_clean_up = 0; eval_cost = max_cost; if (ob->flags & O_DESTRUCTED) ob = obj_list; /* restart */ next_ob = ob->next_all; /* * Check reference time before reset() is called. */ if (current_time - ob->time_of_ref > time_to_swap) ready_for_swap = 1; if (current_time - ob->time_of_ref > time_to_clean_up) ready_for_clean_up = 1; #if !defined(NO_RESETS) && !defined(LAZY_RESETS) /* * Should this object have reset(1) called ? */ if ((ob->flags & O_WILL_RESET) && (ob->next_reset < current_time) && !(ob->flags & O_RESET_STATE)) { debug(d_flag, ("RESET /%s\n", ob->name)); reset_object(ob); if (ob->flags & O_DESTRUCTED) continue; } #endif if (time_to_clean_up > 0) { /* * Has enough time passed, to give the object a chance to * self-destruct ? Save the O_RESET_STATE, which will be cleared. * * Only call clean_up in objects that has defined such a function. * * Only if the clean_up returns a non-zero value, will it be called * again. */ if (ready_for_clean_up && (ob->flags & O_WILL_CLEAN_UP)) { int save_reset_state = ob->flags & O_RESET_STATE; svalue_t *svp; debug(d_flag, ("clean up /%s\n", ob->name)); /* * Supply a flag to the object that says if this program is * inherited by other objects. Cloned objects might as well * believe they are not inherited. Swapped objects will not * have a ref count > 1 (and will have an invalid ob->prog * pointer). * * Note that if it is in the apply_low cache, it will also * get a flag of 1, which may cause the mudlib not to clean * up the object. This isn't bad because: * (1) one expects it is rare for objects that have untouched * long enough to clean_up to still be in the cache, especially * on busy MUDs. * (2) the ones that are are the more heavily used ones, so * keeping them around seems justified. */ push_number(ob->flags & (O_CLONE | O_SWAPPED) ? 0 : ob->prog->ref); svp = apply(APPLY_CLEAN_UP, ob, 1, ORIGIN_DRIVER); if (ob->flags & O_DESTRUCTED) continue; if (!svp || (svp->type == T_NUMBER && svp->u.number == 0)) ob->flags &= ~O_WILL_CLEAN_UP; ob->flags |= save_reset_state; } } if (time_to_swap > 0) { /* * At last, there is a possibility that the object can be swapped * out. Always swap out line number information. If already * swapped, not time yet, or the object has a heart_beat, don't * swap. */ if (ob->prog && ob->prog->line_info) swap_line_numbers(ob->prog); if (ob->flags & O_SWAPPED || !ready_for_swap) continue; if (ob->flags & O_HEART_BEAT) continue; debug(d_flag, ("swap /%s\n", ob->name)); swap(ob); /* See if it is possible to swap out to disk */ } } pop_context(&econ); } /* look_for_objects_to_swap() */