1 /*---------------------------------------------------------------------------
2 * Gamedriver - Garbage Collection
3 *
4 *---------------------------------------------------------------------------
5 * The garbage collection is used in times of memory shortage (or on request)
6 * to find and deallocate any unused objects, arrays, memory blocks, or
7 * whatever. The purpose is to detect and get rid of unreachable data (like
8 * circular array references), but the collector is also a last line of
9 * defense against bug-introduced memory leaks.
10 *
11 * This facility is available currently only when using the 'smalloc'
12 * memory allocator. When using a different allocator, all garbage_collect()
13 * does is freeing as much memory as possible.
14 *
15 * Additionally this module also offers a couple of functions to 'clean up'
16 * an object, ie. to scan all data referenced by this object for destructed
17 * objects and remove those references, and to change all untabled strings
18 * into tabled strings. These functions are used by the garbage collector
19 * to deallocate as much memory by normal means as possible; but they
20 * are also called from the backend as part of the regular reset/swap/cleanup
21 * handling.
22 *
23 #ifdef GC_SUPPORT
24 * The garbage collector is a simple mark-and-sweep collector. First, all
25 * references (refcounts and memory block markers) are cleared, then in
26 * a second pass, all reachable references are recreated (refcounts are
27 * incremented, memory blocks marked as used). The last pass then looks
28 * for all allocated but unmarked memory blocks: these are provably
29 * garbage and can be given back to the allocator. For debugging purposes,
30 * the collected memory blocks can be printed onto a file for closer
31 * inspection.
32 *
33 * In order to do its job, the garbage collector calls functions clear_...
34 * and count_... in all the other driver modules, where they are supposed
35 * to perform their clearing and counting operations. To aid the other
36 * modules in this, the collector offers a set of primitives to clearing
37 * and marking:
38 *
39 * int clear_memory_reference(void *p)
40 * Clear the memory block marker for <p>.
41 *
42 * void note_malloced_block_ref(void *p)
43 * Note the reference to memory block <p>.
44 *
45 * void clear_program_ref(program_t *p, Bool clear_ref)
46 * Clear the refcounts of all inherited programs and other
47 * data of <p>. If <clear_ref> is TRUE, the refcounts of
48 * <p> itself and of <p>->name are cleared, too.
49 *
50 * void clear_object_ref(object_t *p)
51 * Make sure that the refcounts in object <p> are cleared.
52 *
53 * void mark_program_ref(program_t *p);
54 * Set the marker of program <p> and of all data referenced by <p>.
55 *
56 * void reference_destructed_object(object_t *ob)
57 * Note the reference to a destructed object <ob>.
58 *
59 * void clear_string_ref(string_t *p)
60 * Clear the refcount in string <p>.
61 *
62 * void count_ref_from_string(string_t *p);
63 * Count the reference to string <p>.
64 *
65 * void clear_ref_in_vector(svalue_t *svp, size_t num);
66 * Clear the refs of the <num> elements of vector <svp>.
67 *
68 * void count_ref_in_vector(svalue_t *svp, size_t num)
69 * Count the references the <num> elements of vector <p>.
70 *
71 * The referencing code for dynamic data should mirror the destructor code,
72 * thus, memory leaks can show up as soon as the memory is allocated.
73 *
74 * TODO: Allow to deactivate the dump of unreferenced memory on freeing.
75 #endif
76 *---------------------------------------------------------------------------
77 */
78
79 #include "driver.h"
80 #include "typedefs.h"
81
82 #include <sys/types.h>
83 #ifdef HAVE_SYS_TIME_H
84 #include <sys/time.h>
85 #endif
86 #include <time.h>
87 #include <stdio.h>
88
89 #include "gcollect.h"
90 #include "actions.h"
91 #include "array.h"
92 #include "backend.h"
93 #include "call_out.h"
94 #include "closure.h"
95 #include "comm.h"
96 #include "efuns.h"
97 #include "filestat.h"
98 #include "heartbeat.h"
99 #include "interpret.h"
100 #if defined(GC_SUPPORT) && defined(MALLOC_TRACE)
101 #include "instrs.h" /* Need F_ALLOCATE for setting up print dispatcher */
102 #endif
103 #include "lex.h"
104 #include "main.h"
105 #include "mapping.h"
106 #include "mempools.h"
107 #include "mregex.h"
108 #include "mstrings.h"
109 #include "object.h"
110 #include "otable.h"
111 #include "parse.h"
112 #include "pkg-pgsql.h"
113 #include "prolang.h"
114 #include "ptrtable.h"
115 #include "random.h"
116 #include "sent.h"
117 #include "simulate.h"
118 #include "simul_efun.h"
119 #include "stdstrings.h"
120 #ifdef USE_STRUCTS
121 #include "structs.h"
122 #endif /* USE_STRUCTS */
123 #include "swap.h"
124 #include "wiz_list.h"
125 #include "xalloc.h"
126
127 #include "i-eval_cost.h"
128
129 #include "../mudlib/sys/driver_hook.h"
130
131 /*-------------------------------------------------------------------------*/
132
133 time_t time_last_gc = 0;
134 /* Time of last gc, used by the backend to avoid repeated collections
135 * when the memory usage is at the edge of a shortage.
136 */
137
138
139 #if defined(GC_SUPPORT)
140
141 int default_gcollect_outfd = 2;
142 /* The default file (default is stderr) to dump the reclaimed blocks on.
143 */
144
145 int gcollect_outfd = 2;
146 #define gout gcollect_outfd
147 /* The current file (default is stderr) to dump the reclaimed blocks on.
148 * After the GC, this will be reset to <default_gcollect_outfd>.
149 */
150
151 gc_status_t gc_status = gcInactive;
152 /* The current state of the garbage collection.
153 * swap uses this information when swapping in objects.
154 */
155
156 object_t *gc_obj_list_destructed;
157 /* List of referenced but destructed objects.
158 * Scope is global so that the GC support functions in mapping.c can
159 * add their share of information.
160 */
161
162 lambda_t *stale_misc_closures;
163 /* List of non-lambda closures bound to a destructed object.
164 * The now irrelevant .ob pointer is used to link the list elements.
165 * Scope is global so that the GC support functions in mapping.c can
166 * add their share of information.
167 */
168
169 static lambda_t *stale_lambda_closures;
170 /* List of lambda closures bound to a destructed object.
171 * The now irrelevant .ob pointer is used to link the list elements.
172 */
173
174 #endif /* GC_SUPPORT */
175
176 /*-------------------------------------------------------------------------*/
177
178 /*=========================================================================*/
179
180 /* Object clean up
181 */
182
183 #ifdef NEW_CLEANUP
184
185 typedef struct cleanup_s cleanup_t;
186 typedef struct cleanup_map_extra_s cleanup_map_extra_t;
187
188
189 /* --- struct cleanup: The cleanup context information
190 *
191 * The controlling instance of this struct is passed to all cleanup functions.
192 */
193 struct cleanup_s
194 {
195 ptrtable_t * ptable;
196 /* Pointertable to catch loops in the variable values.
197 * This table is re-allocated whenever the object cleant up is
198 * swapped, as the swapper can re-use the already listed memory
199 * blocks.
200 */
201 unsigned long numValues; /* Number of values examined. */
202 Bool mcompact; /* TRUE: mappings are forcibly compacted */
203 ptrtable_t * mtable;
204 /* Pointertable of mappings to compact.
205 * This table holds all mappings listed in mlist so that multiple
206 * encounters of the same dirty mapping are easily recognized.
207 */
208 mapping_t * mlist;
209 /* List of mappings to compact. The list is linked through
210 * the map->next field.
211 * The references are counted to prevent premature freeing.
212 */
213 };
214
215
216 /* --- struct cleanup_map_extra: Info needed to clean up a mapping.
217 *
218 * A pointer to an instance of this structure is passed to the
219 * cleanup_mapping_filter() callback function.
220 */
221
222 struct cleanup_map_extra_s
223 {
224 p_int width; /* Width of the mapping */
225 cleanup_t *context; /* The cleanup context */
226 };
227
228
229 /* Forward declarations */
230 static void cleanup_vector (svalue_t *svp, size_t num, cleanup_t * context);
231
232 /*-------------------------------------------------------------------------*/
233 static cleanup_t *
cleanup_new(Bool mcompact)234 cleanup_new (Bool mcompact)
235
236 /* Create a new cleanup_t context and return it. <mcompact> is the
237 * .mcompact setting.
238 */
239
240 {
241 cleanup_t * rc;
242
243 rc = xalloc(sizeof(*rc));
244 if (rc == NULL)
245 {
246 outofmemory("object cleanup context");
247 return NULL;
248 }
249
250 rc->ptable = new_pointer_table();
251 if (rc->ptable == NULL)
252 {
253 xfree(rc);
254 outofmemory("object cleanup pointertable");
255 return NULL;
256 }
257
258 rc->mtable = new_pointer_table();
259 if (rc->mtable == NULL)
260 {
261 free_pointer_table(rc->ptable);
262 xfree(rc);
263 outofmemory("object cleanup pointertable");
264 return NULL;
265 }
266
267 rc->mcompact = mcompact;
268 rc->mlist = NULL;
269 rc->numValues = 0;
270
271 return rc;
272 } /* cleanup_new() */
273
274 /*-------------------------------------------------------------------------*/
275 static Bool
cleanup_reset(cleanup_t * context)276 cleanup_reset (cleanup_t * context)
277
278 /* Reallocate the pointertable in the context.
279 * Return TRUE if successful, and FALSE when out of memory.
280 */
281
282 {
283 if (context->ptable)
284 free_pointer_table(context->ptable);
285
286 context->ptable = new_pointer_table();
287 if (context->ptable == NULL)
288 {
289 outofmemory("object cleanup pointertable");
290 return MY_FALSE;
291 }
292
293 return MY_TRUE;
294 } /* cleanup_reset() */
295
296 /*-------------------------------------------------------------------------*/
297 static void
cleanup_free(cleanup_t * context)298 cleanup_free (cleanup_t * context)
299
300 /* Deallocate the cleanup context <context>.
301 */
302
303 {
304 if (context->ptable)
305 free_pointer_table(context->ptable);
306 free_pointer_table(context->mtable);
307 xfree(context);
308 } /* cleanup_free() */
309
310 /*-------------------------------------------------------------------------*/
311 static void
cleanup_mapping_filter(svalue_t * key,svalue_t * data,void * extra)312 cleanup_mapping_filter (svalue_t *key, svalue_t *data, void *extra)
313
314 /* Clean up a single mapping element, <extra> points to
315 * a cleanup_map_extra_t instance.
316 */
317
318 {
319 cleanup_map_extra_t * pData = (cleanup_map_extra_t*)extra;
320 cleanup_vector(key, 1, pData->context);
321 cleanup_vector(data, pData->width, pData->context);
322 } /* cleanup_mapping_filter() */
323
324 /*-------------------------------------------------------------------------*/
325 static void
cleanup_closure(svalue_t * csvp,cleanup_t * context)326 cleanup_closure (svalue_t *csvp, cleanup_t * context)
327
328 /* Cleanup the closure <csvp>, using <context> as cleanup context.
329 * This may change *<csvp> to svalue-0.
330 */
331
332 {
333 ph_int type = csvp->x.closure_type;
334 lambda_t *l = csvp->u.lambda;
335
336 /* If this closure is bound to or defined in a destructed object, zero it
337 * out.
338 */
339 if (destructed_object_ref(csvp))
340 {
341 free_closure(csvp);
342 put_number(csvp, 0);
343 return;
344 }
345
346 if (!CLOSURE_MALLOCED(type)
347 || register_pointer(context->ptable, l) == NULL
348 )
349 return;
350
351 /* If the creating program has been destructed, zero out the reference.
352 */
353 if (CLOSURE_MALLOCED(type)
354 && l->prog_ob
355 && (l->prog_ob->flags & O_DESTRUCTED))
356 {
357 free_object(l->prog_ob, "cleanup_closure");
358 l->prog_ob = NULL;
359 l->prog_pc = 0;
360 }
361
362 if (CLOSURE_HAS_CODE(type))
363 {
364 mp_int num_values;
365 svalue_t *svp;
366
367 svp = (svalue_t *)l;
368 if ( (num_values = EXTRACT_UCHAR(l->function.code)) == 0xff)
369 num_values = svp[-0x100].u.number;
370 svp -= num_values;
371 cleanup_vector(svp, (size_t)num_values, context);
372 }
373 else if (type == CLOSURE_BOUND_LAMBDA)
374 {
375 svalue_t dummy;
376
377 dummy.type = T_CLOSURE;
378 dummy.x.closure_type = CLOSURE_UNBOUND_LAMBDA;
379 dummy.u.lambda = l->function.lambda;
380
381 cleanup_closure(&dummy, context);
382 }
383
384 #ifdef USE_NEW_INLINES
385 if (type == CLOSURE_LFUN && l->function.lfun.context_size != 0)
386 {
387 unsigned short size = l->function.lfun.context_size;
388 cleanup_vector(l->context, size, context);
389 }
390 #endif /* USE_NEW_INLINES */
391 } /* cleanup_closure() */
392
393 /*-------------------------------------------------------------------------*/
394 static void
cleanup_vector(svalue_t * svp,size_t num,cleanup_t * context)395 cleanup_vector (svalue_t *svp, size_t num, cleanup_t * context)
396
397 /* Cleanup the <num> svalues in vector/svalue block <svp>.
398 * <context> is used to keep track which complex values we already
399 * cleaned up.
400 */
401
402 {
403 svalue_t *p;
404
405 if (!svp) /* e.g. when called for obj->variables */
406 return;
407
408 if (register_pointer(context->ptable, svp) == NULL) /* already cleaned up */
409 return;
410
411 for (p = svp; p < svp+num; p++)
412 {
413 context->numValues++;
414 switch(p->type)
415 {
416 case T_OBJECT:
417 {
418 if (p->u.ob->flags & O_DESTRUCTED)
419 {
420 free_object(p->u.ob, "cleanup svalues");
421 put_number(p, 0);
422 }
423 break;
424 }
425
426 case T_POINTER:
427 case T_QUOTED_ARRAY:
428 /* Don't clean the null vector */
429 if (p->u.vec != &null_vector)
430 {
431 cleanup_vector(&p->u.vec->item[0], VEC_SIZE(p->u.vec), context);
432 }
433 break;
434
435 #ifdef USE_STRUCTS
436 case T_STRUCT:
437 cleanup_vector(&p->u.strct->member[0], struct_size(p->u.strct), context);
438 break;
439 #endif /* USE_STRUCTS */
440
441 case T_MAPPING:
442 if (register_pointer(context->ptable, p->u.map) != NULL)
443 {
444 cleanup_map_extra_t extra;
445
446 extra.width = p->u.map->num_values;
447 extra.context = context;
448 check_map_for_destr(p->u.map);
449 walk_mapping(p->u.map, cleanup_mapping_filter, &extra);
450
451 /* Remember the mapping for later compaction (unless
452 * we have it already).
453 * Only 'dirty' mappings need to be listed, as the cleanup
454 * can't cause a mapping to add a hash part.
455 */
456 if (p->u.map->hash
457 && NULL != register_pointer(context->mtable, p->u.map)
458 )
459 {
460 p->u.map->next = context->mlist;
461 context->mlist = ref_mapping(p->u.map);
462 }
463 }
464 break;
465
466 case T_STRING:
467 if (!mstr_tabled(p->u.str))
468 p->u.str = make_tabled(p->u.str);
469 break;
470
471 case T_CLOSURE:
472 cleanup_closure(p, context);
473 break;
474 }
475 } /* for */
476 } /* cleanup_vector() */
477
478 /*-------------------------------------------------------------------------*/
479 static Bool
cleanup_single_object(object_t * obj,cleanup_t * context)480 cleanup_single_object (object_t * obj, cleanup_t * context)
481
482 /* Cleanup object <ob> using context <context>.
483 *
484 * If the object is on the swap, it will be swapped in for the time
485 * of the function.
486 *
487 * Return FALSE if the objects was present in memory, and TRUE if it
488 * had to be swapped in.
489 *
490 * The function checks all variables of this object for references
491 * to destructed objects and removes them. Also, untabled strings
492 * are made tabled.
493 */
494
495 {
496 int was_swapped = 0;
497
498 /* Swap in the object if necessary */
499 if ((obj->flags & O_SWAPPED)
500 && (was_swapped = load_ob_from_swap(obj)) < 0)
501 {
502 errorf("(%s:%d) Out of memory swapping in %s\n", __FILE__, __LINE__
503 , get_txt(obj->name));
504 return MY_FALSE;
505 }
506
507
508 /* If the object's program blueprint is destructed, remove that
509 * reference.
510 */
511
512 if (obj->prog->blueprint
513 && (obj->prog->blueprint->flags & O_DESTRUCTED)
514 )
515 {
516 free_object(obj->prog->blueprint, "cleanup object");
517 obj->prog->blueprint = NULL;
518 remove_prog_swap(obj->prog, MY_TRUE);
519 }
520
521 /* Clean up all the variables */
522 cleanup_vector(obj->variables, obj->prog->num_variables, context);
523
524 /* Clean up */
525 if (was_swapped)
526 {
527 swap(obj, was_swapped);
528 }
529
530 return was_swapped != 0;
531 } /* cleanup_single_object() */
532
533 /*-------------------------------------------------------------------------*/
534 static void
cleanup_structures(cleanup_t * context)535 cleanup_structures (cleanup_t * context)
536
537 /* Cleanup the value holding structures of the driver, using context
538 * <context>.
539 *
540 * The structures are:
541 * - driver hooks
542 * - wizlist extra entries
543 */
544
545 {
546 /* Cleanup the wizlist */
547 {
548 wiz_list_t * wiz;
549
550 for (wiz = all_wiz; wiz != NULL; wiz = wiz->next)
551 cleanup_vector(&wiz->extra, 1, context);
552
553 cleanup_vector(&default_wizlist_entry.extra, 1, context);
554 }
555
556 /* Cleanup the driver hooks.
557 * We have to be careful here to not free the lambda-closure hooks even
558 * if they are bound to destructed objects.
559 */
560 {
561 int i;
562
563 for (i = 0; i < NUM_DRIVER_HOOKS; i++)
564 {
565 if (driver_hook[i].type == T_CLOSURE
566 && ( driver_hook[i].x.closure_type == CLOSURE_LAMBDA
567 || driver_hook[i].x.closure_type == CLOSURE_BOUND_LAMBDA
568 )
569 )
570 {
571 if (destructed_object_ref(&driver_hook[i]))
572 {
573 lambda_t * l = driver_hook[i].u.lambda;
574
575 free_object(l->ob, "cleanup_structures");
576 l->ob = ref_object(master_ob, "cleanup_structures");
577 }
578 }
579 else
580 cleanup_vector(&driver_hook[i], 1, context);
581 }
582 }
583 } /* cleanup_structures() */
584
585 /*-------------------------------------------------------------------------*/
586 static void
cleanup_compact_mappings(cleanup_t * context)587 cleanup_compact_mappings (cleanup_t * context)
588
589 /* Compact all mappings listed in the <context>.
590 * This must be the very last action in the cleanup process.
591 */
592
593 {
594 mapping_t * m;
595
596 for (m = context->mlist; m != NULL; m = context->mlist)
597 {
598 context->mlist = m->next;
599 if (m->ref > 1)
600 compact_mapping(m, context->mcompact);
601 free_mapping(m); /* Might deallocate it fully */
602 }
603 } /* cleanup_compact_mappings() */
604
605 #endif /* NEW_CLEANUP */
606
607 /*-------------------------------------------------------------------------*/
608 void
cleanup_object(object_t * obj)609 cleanup_object (object_t * obj)
610
611 /* Cleanup object <ob>, but don't force the mapping compaction.
612 *
613 * If the object is on the swap, it will be swapped in for the time
614 * of the function.
615 *
616 * The function checks all variables of this object for references
617 * to destructed objects and removes them. Also, untabled strings
618 * are made tabled. The time for the next cleanup is set to
619 * a time in the interval [0.9*time_to_cleanup .. 1.1 * time_to_cleanup]
620 * from now (if time_to_cleanup is 0, DEFAULT_CLEANUP_TIME is assumed).
621 *
622 * This function is called by the backend.
623 */
624
625 {
626 #ifndef NEW_CLEANUP
627 return;
628 #else
629 cleanup_t * context = NULL;
630 #ifdef LOG_NEW_CLEANUP
631 struct timeval t_begin, t_end;
632 #endif /* LOG_NEW_CLEANUP */
633 Bool didSwap = MY_FALSE;
634 unsigned long numValues = 0;
635
636 #ifdef LOG_NEW_CLEANUP
637 if (gettimeofday(&t_begin, NULL))
638 {
639 t_begin.tv_sec = t_begin.tv_usec = 0;
640 }
641 #endif /* LOG_NEW_CLEANUP */
642
643 context = cleanup_new(MY_FALSE);
644 if (context != NULL)
645 {
646 didSwap = cleanup_single_object(obj, context);
647 cleanup_compact_mappings(context);
648 numValues = context->numValues;
649 cleanup_free(context);
650 }
651 obj->time_cleanup = current_time + (9*time_to_data_cleanup)/10
652 + random_number((2*time_to_data_cleanup)/10);
653
654 #ifdef LOG_NEW_CLEANUP
655 if (t_begin.tv_sec == 0
656 || gettimeofday(&t_end, NULL))
657 {
658 debug_message("%s Data-Clean: %6lu values: /%s %s\n"
659 , time_stamp(), numValues, get_txt(obj->name)
660 , didSwap ? "(swapped)" : "");
661 printf("%s Data-Clean: %6lu values: /%s %s\n"
662 , time_stamp(), numValues, get_txt(obj->name)
663 , didSwap ? "(swapped)" : "");
664 }
665 else
666 {
667 t_end.tv_sec -= t_begin.tv_sec;
668 t_end.tv_usec -= t_begin.tv_usec;
669 if (t_end.tv_usec < 0)
670 {
671 t_end.tv_sec--;
672 t_end.tv_usec += 1000000;
673 }
674
675 debug_message("%s Data-Clean: %3ld.%06ld s, %6lu values: /%s%s\n"
676 , time_stamp()
677 , (long)t_end.tv_sec, (long)t_end.tv_usec
678 , numValues
679 , get_txt(obj->name)
680 , didSwap ? " (swapped)" : ""
681 );
682 printf("%s Data-Clean: %3ld.%06ld s, %6lu values: /%s%s\n"
683 , time_stamp()
684 , (long)t_end.tv_sec, (long)t_end.tv_usec
685 , numValues
686 , get_txt(obj->name)
687 , didSwap ? " (swapped)" : ""
688 );
689 }
690 #endif /* LOG_NEW_CLEANUP */
691
692 #endif /* NEW_CLEANUP */
693 } /* cleanup_object() */
694
695 /*-------------------------------------------------------------------------*/
696 void
cleanup_driver_structures(void)697 cleanup_driver_structures (void)
698
699 /* Cleanup the fixed driver structures if it is time.
700 *
701 * The time for the next cleanup is set to a time in the interval
702 * [0.9*time_to_cleanup .. 1.1 * time_to_cleanup] from now (if time_to_cleanup
703 * is 0, DEFAULT_CLEANUP_TIME is assumed).
704 *
705 * This function is called by the backend.
706 */
707
708 {
709 #ifndef NEW_CLEANUP
710 return;
711 #else
712 cleanup_t * context = NULL;
713 #ifdef LOG_NEW_CLEANUP
714 struct timeval t_begin, t_end;
715 #endif /* LOG_NEW_CLEANUP */
716 unsigned long numValues = 0;
717
718 static mp_int time_cleanup = 0;
719 /* Time of the next regular cleanup. */
720
721 /* Is it time for the cleanup yet? */
722 if (time_cleanup != 0 && time_cleanup >= current_time)
723 return;
724
725 time_cleanup = current_time + (9*time_to_data_cleanup)/10
726 + random_number((2*time_to_data_cleanup)/10);
727
728 #ifdef LOG_NEW_CLEANUP
729 if (gettimeofday(&t_begin, NULL))
730 {
731 t_begin.tv_sec = t_begin.tv_usec = 0;
732 }
733 #endif /* LOG_NEW_CLEANUP */
734
735 context = cleanup_new(MY_FALSE);
736 if (context != NULL)
737 {
738 cleanup_structures(context);
739 cleanup_compact_mappings(context);
740 numValues = context->numValues;
741 cleanup_free(context);
742 }
743
744 #ifdef LOG_NEW_CLEANUP
745 if (t_begin.tv_sec == 0
746 || gettimeofday(&t_end, NULL))
747 {
748 debug_message("%s Data-Clean: %6lu values: Fixed structures\n"
749 , time_stamp(), numValues);
750 printf("%s Data-Clean: %6lu values: Fixed structures\n"
751 , time_stamp(), numValues);
752 }
753 else
754 {
755 t_end.tv_sec -= t_begin.tv_sec;
756 t_end.tv_usec -= t_begin.tv_usec;
757 if (t_end.tv_usec < 0)
758 {
759 t_end.tv_sec--;
760 t_end.tv_usec += 1000000;
761 }
762
763 debug_message("%s Data-Clean: %3ld.%06ld s, %6lu values: Fixed structures\n"
764 , time_stamp()
765 , (long)t_end.tv_sec, (long)t_end.tv_usec
766 , numValues
767 );
768 printf("%s Data-Clean: %3ld.%06ld s, %6lu values: Fixed structures\n"
769 , time_stamp()
770 , (long)t_end.tv_sec, (long)t_end.tv_usec
771 , numValues
772 );
773 }
774 #endif /* LOG_NEW_CLEANUP */
775
776 #endif /* NEW_CLEANUP */
777 } /* cleanup_driver_structures() */
778
779 /*-------------------------------------------------------------------------*/
780 void
cleanup_all_objects(void)781 cleanup_all_objects (void)
782
783 /* Cleanup all objects in the game, and force the mapping compaction.
784 * This function is called by the garbage-collector right at the start,
785 * and also by the backend.
786 */
787
788 {
789 #ifndef NEW_CLEANUP
790 return;
791 #else
792 cleanup_t * context = NULL;
793 #ifdef LOG_NEW_CLEANUP_ALL
794 struct timeval t_begin, t_end;
795 #endif /* LOG_NEW_CLEANUP_ALL */
796 long numObjects = 0;
797 unsigned long numValues = 0;
798
799 #ifdef LOG_NEW_CLEANUP_ALL
800 if (gettimeofday(&t_begin, NULL))
801 {
802 t_begin.tv_sec = t_begin.tv_usec = 0;
803 }
804 debug_message("%s Data-Clean: All Objects\n"
805 , time_stamp()
806 );
807 printf("%s Data-Clean: All Objects\n"
808 , time_stamp()
809 );
810 #endif /* LOG_NEW_CLEANUP_ALL */
811
812 context = cleanup_new(MY_TRUE);
813 if (context != NULL)
814 {
815 object_t * ob;
816 for (ob = obj_list; ob; ob = ob->next_all)
817 {
818 /* If the object is swapped for the cleanup, throw away
819 * the pointertable afterwards as the memory locations
820 * are no longer unique.
821 */
822 if ( cleanup_single_object(ob, context)
823 && !cleanup_reset(context))
824 {
825 cleanup_free(context);
826 return;
827 }
828 numObjects++;
829 }
830 cleanup_structures(context);
831 cleanup_compact_mappings(context);
832 numValues = context->numValues;
833 cleanup_free(context);
834 }
835
836 #ifdef LOG_NEW_CLEANUP_ALL
837 if (t_begin.tv_sec == 0
838 || gettimeofday(&t_end, NULL))
839 {
840 debug_message("%s Data-Cleaned %ld objects: %lu values.\n", time_stamp(), numObjects, numValues);
841 printf("%s Data-Cleaned %ld objects: %lu values.\n", time_stamp(), numObjects, numValues);
842 }
843 else
844 {
845 t_end.tv_sec -= t_begin.tv_sec;
846 t_end.tv_usec -= t_begin.tv_usec;
847 if (t_end.tv_usec < 0)
848 {
849 t_end.tv_sec--;
850 t_end.tv_usec += 1000000;
851 }
852
853 debug_message("%s Data-Cleaned %ld objects in %ld.%06ld s, %6lu values.\n"
854 , time_stamp(), numObjects
855 , (long)t_end.tv_sec, (long)t_end.tv_usec
856 , numValues
857 );
858 printf("%s Data-Cleaned %ld objects in %ld.%06ld s, %6lu values.\n"
859 , time_stamp(), numObjects
860 , (long)t_end.tv_sec, (long)t_end.tv_usec
861 , numValues
862 );
863 }
864 #endif /* LOG_NEW_CLEANUP_ALL */
865
866 #endif /* NEW_CLEANUP */
867 } /* cleanup_all_objects() */
868
869 /*=========================================================================*/
870
871 /* The real collector - only if the allocator allows it.
872 */
873
874 #if defined(GC_SUPPORT)
875
876 #if defined(CHECK_OBJECT_GC_REF) && defined(DUMP_GC_REFS)
877 # error Must define either CHECK_OBJECT_GC_REF or DUMP_GC_REFS.
878 # undef DUMP_GC_REFS
879 #endif
880
881 #define CLEAR_REF(p) x_clear_ref(p)
882 /* Clear the memory block marker for <p>
883 */
884
885 #ifdef CHECK_OBJECT_GC_REF
gc_mark_ref(void * p,const char * file,int line)886 unsigned long gc_mark_ref(void * p, const char * file, int line)
887 {
888 if (is_object_allocation(p))
889 {
890 dprintf3(gout, "DEBUG: Object %x referenced as something else from %s:%d\n"
891 , (p_int)p, (p_int)file, (p_int)line);
892 }
893 if (is_program_allocation(p))
894 {
895 dprintf3(gout, "DEBUG: Program %x referenced as something else from %s:%d\n"
896 , (p_int)p, (p_int)file, (p_int)line);
897 }
898 return x_mark_ref(p);
899 }
900
901 #define MARK_REF(p) gc_mark_ref(p, __FILE__, __LINE__)
902 #define MARK_PLAIN_REF(p) x_mark_ref(p)
903
904 #else
905 #define MARK_REF(p) x_mark_ref(p)
906 /* Set the memory block marker for <p>
907 */
908 #define MARK_PLAIN_REF(p) MARK_REF(p)
909 #endif
910
911 #define TEST_REF(p) x_test_ref(p)
912 /* Check the memory block marker for <p>, return TRUE if _not_ set.
913 */
914
915 #define CHECK_REF(p) ( TEST_REF(p) && ( MARK_REF(p),MY_TRUE ) )
916 /* Check the memory block marker for <p> and set it if necessary.
917 * Return TRUE if the marker was not set, FALSE else.
918 */
919
920 #define MSTRING_REFS(str) ((str)->info.ref)
921 /* Return the refcount of mstring <str>
922 */
923
924 /* Forward declarations */
925
926 static void clear_map_ref_filter (svalue_t *, svalue_t *, void *);
927 static void clear_ref_in_closure (lambda_t *l, ph_int type);
928 static void gc_count_ref_in_closure (svalue_t *csvp);
929 static void gc_MARK_MSTRING_REF (string_t * str);
930
931 #define count_ref_in_closure(p) \
932 GC_REF_DUMP(svalue_t*, p, "Count ref in closure", gc_count_ref_in_closure)
933
934 #define MARK_MSTRING_REF(str) \
935 GC_REF_DUMP(string_t*, str, "Mark string", gc_MARK_MSTRING_REF)
936
937 /*-------------------------------------------------------------------------*/
938
939 #if defined(MALLOC_TRACE)
940
941 #define WRITES(d, s) writes(d, s)
942
943 /*-------------------------------------------------------------------------*/
944 static INLINE void
write_malloc_trace(void * p)945 write_malloc_trace (void * p)
946
947 /* Dump the allocation information for <p>, if any.
948 */
949
950 {
951 WRITES(gout, ((char **)(p))[-2]);
952 WRITES(gout, " ");
953 writed(gout, (int)((p_uint *)(p))[-1]);
954 WRITES(gout, "\n");
955 } /* write_malloc_trace() */
956
957 #else
958
959 #define write_malloc_trace(p)
960 #define WRITES(d, s)
961
962 #endif /* MALLOC_TRACE */
963
964 /*-------------------------------------------------------------------------*/
965 void
clear_memory_reference(void * p)966 clear_memory_reference (void *p)
967
968 /* Clear the memory block marker for block <p>.
969 */
970
971 {
972 CLEAR_REF(p);
973 } /* clear_memory_reference() */
974
975 /*-------------------------------------------------------------------------*/
976 Bool
test_memory_reference(void * p)977 test_memory_reference (void *p)
978
979 /* Test if the memory block <p> is marked as referenced.
980 * Return TRUE if it is NOT referenced, and FALSE it it is.
981 */
982
983 {
984 return TEST_REF(p);
985 } /* test_memory_reference() */
986
987 /*-------------------------------------------------------------------------*/
988 static INLINE void
gc_note_ref(void * p,const char * file,int line)989 gc_note_ref (void *p
990 #ifdef CHECK_OBJECT_GC_REF
991 , const char * file, int line
992 #endif
993 )
994
995 /* Note the reference to memory block <p>.
996 *
997 * It is no use to write a diagnostic on the second or higher reference
998 * to the memory block, as this can happen when an object is swapped in,
999 * marked, swapped out, and the next swapped-in object reuses the memory block
1000 * released from the one before.
1001 */
1002
1003 {
1004 if (TEST_REF(p))
1005 {
1006 #ifdef CHECK_OBJECT_GC_REF
1007 gc_mark_ref(p, file, line);
1008 #else
1009 MARK_REF(p);
1010 #endif
1011 return;
1012 }
1013 } /* gc_note_ref() */
1014
1015 #ifdef CHECK_OBJECT_GC_REF
gc_note_malloced_block_ref(void * p,const char * file,int line)1016 void gc_note_malloced_block_ref (void *p, const char * file, int line) { gc_note_ref(p, file, line); }
1017 #define note_ref(p) gc_note_ref(p, __FILE__, __LINE__)
1018 #define passed_note_ref(p) gc_note_ref(p, file, line)
1019 #else
gc_note_malloced_block_ref(void * p)1020 void gc_note_malloced_block_ref (void *p) { gc_note_ref(p); }
1021
1022 #define note_ref(p) GC_REF_DUMP(void*, p, "Note ref", gc_note_ref)
1023 #define passed_note_ref(p) note_ref(p)
1024 #endif
1025
1026 /*-------------------------------------------------------------------------*/
1027 void
clear_string_ref(string_t * p)1028 clear_string_ref (string_t *p)
1029
1030 /* Clear the references in string <p>
1031 */
1032
1033 {
1034 p->info.ref = 0;
1035 } /* clear_string_ref() */
1036
1037 /*-------------------------------------------------------------------------*/
1038 void
clear_program_ref(program_t * p,Bool clear_ref)1039 clear_program_ref (program_t *p, Bool clear_ref)
1040
1041 /* Clear the refcounts of all inherited programs and other associated
1042 * data of of <p> .
1043 * If <clear_ref> is TRUE, the refcount of <p> itself is cleared, too.
1044 */
1045
1046 {
1047 int i;
1048
1049 if (clear_ref)
1050 {
1051 p->ref = 0;
1052 }
1053
1054 if (p->name)
1055 clear_string_ref(p->name);
1056
1057 /* Variables */
1058 for (i = p->num_variables; --i >= 0;)
1059 {
1060 clear_fulltype_ref(&p->variables[i].type);
1061 }
1062
1063 /* Non-inherited functions */
1064
1065 for (i = p->num_functions; --i >= 0; )
1066 {
1067 if ( !(p->functions[i] & NAME_INHERITED) )
1068 {
1069 vartype_t vt;
1070
1071 memcpy(
1072 &vt,
1073 FUNCTION_TYPEP(p->program + (p->functions[i] & FUNSTART_MASK)),
1074 sizeof vt
1075 );
1076 clear_vartype_ref(&vt);
1077 }
1078 }
1079
1080 #ifdef USE_STRUCTS
1081 /* struct definitions */
1082 for (i = 0; i <p->num_structs; i++)
1083 {
1084 clear_struct_type_ref(p->struct_defs[i].type);
1085 }
1086 #endif /* USE_STRUCTS */
1087
1088 for (i = 0; i < p->num_inherited; i++)
1089 {
1090 /* Inherited programs are never swapped. Only programs with blueprints
1091 * are swapped, and a blueprint and one inheritance makes two refs.
1092 */
1093 program_t *p2;
1094
1095 p2 = p->inherit[i].prog;
1096 if (p2->ref)
1097 {
1098 clear_program_ref(p2, MY_TRUE);
1099 }
1100 }
1101 } /* clear_program_ref() */
1102
1103 /*-------------------------------------------------------------------------*/
1104 void
clear_object_ref(object_t * p)1105 clear_object_ref (object_t *p)
1106
1107 /* If <p> is a destructed object, its refcounts are cleared.
1108 * If <p> is a live object, its refcounts are assumed to be cleared
1109 * by the GC main method.
1110 */
1111
1112 {
1113 if ((p->flags & O_DESTRUCTED) && p->ref)
1114 {
1115 #if defined(CHECK_OBJECT_REF) && defined(DEBUG)
1116 p->extra_ref = p->ref;
1117 #endif
1118 p->ref = 0;
1119 clear_string_ref(p->name);
1120 if (p->prog->blueprint
1121 && (p->prog->blueprint->flags & O_DESTRUCTED)
1122 && p->prog->blueprint->ref
1123 )
1124 {
1125 #if defined(CHECK_OBJECT_REF) && defined(DEBUG)
1126 p->prog->blueprint->extra_ref = p->prog->blueprint->ref;
1127 #endif
1128 p->prog->blueprint->ref = 0;
1129 }
1130 clear_program_ref(p->prog, MY_TRUE);
1131 }
1132 } /* clear_object_ref() */
1133
1134 /*-------------------------------------------------------------------------*/
1135 void
gc_mark_program_ref(program_t * p)1136 gc_mark_program_ref (program_t *p)
1137
1138 /* Set the marker of program <p> and of all data referenced by <p>.
1139 */
1140
1141 {
1142 #ifdef CHECK_OBJECT_GC_REF
1143 if (TEST_REF(p) && ( MARK_PLAIN_REF(p),MY_TRUE ) )
1144 #else
1145 if (CHECK_REF(p)) /* ...then mark referenced data */
1146 #endif
1147 {
1148 int i;
1149
1150 unsigned char *program = p->program;
1151 uint32 *functions = p->functions;
1152 string_t **strings;
1153 variable_t *variables;
1154
1155 if (p->ref++)
1156 {
1157 dump_malloc_trace(1, p);
1158 fatal("First reference to program %p '%s', but ref count %ld != 0\n"
1159 , p, p->name ? get_txt(p->name) : "<null>", (long)p->ref - 1
1160 );
1161 }
1162
1163 MARK_MSTRING_REF(p->name);
1164
1165 /* Mark the blueprint object, if any */
1166 if (p->blueprint)
1167 {
1168 if (p->blueprint->flags & O_DESTRUCTED)
1169 {
1170 reference_destructed_object(p->blueprint);
1171 p->blueprint = NULL;
1172 remove_prog_swap(p, MY_TRUE);
1173 }
1174 else
1175 {
1176 p->blueprint->ref++;
1177 /* No note_ref() necessary: the blueprint is in
1178 * the global object list
1179 */
1180 }
1181 }
1182
1183 if (p->line_numbers)
1184 note_ref(p->line_numbers);
1185
1186 /* Non-inherited functions */
1187
1188 for (i = p->num_functions; --i >= 0; )
1189 {
1190 if ( !(functions[i] & NAME_INHERITED) )
1191 {
1192 string_t *name;
1193 vartype_t vt;
1194
1195 memcpy(
1196 &name,
1197 FUNCTION_NAMEP(program + (functions[i] & FUNSTART_MASK)),
1198 sizeof name
1199 );
1200 MARK_MSTRING_REF(name);
1201
1202 memcpy(
1203 &vt,
1204 FUNCTION_TYPEP(program + (functions[i] & FUNSTART_MASK)),
1205 sizeof vt
1206 );
1207 count_vartype_ref(&vt);
1208 }
1209 }
1210
1211 /* String literals */
1212
1213 strings = p->strings;
1214 for (i = p->num_strings; --i >= 0; )
1215 {
1216 string_t *str = *strings++;
1217 MARK_MSTRING_REF(str);
1218 }
1219
1220 /* Variable names */
1221
1222 variables = p->variables;
1223 for (i = p->num_variables; --i >= 0; variables++)
1224 {
1225 MARK_MSTRING_REF(variables->name);
1226 count_fulltype_ref(&variables->type);
1227 }
1228
1229 /* Inherited programs */
1230
1231 for (i=0; i< p->num_inherited; i++)
1232 mark_program_ref(p->inherit[i].prog);
1233
1234 #ifdef USE_STRUCTS
1235 /* struct definitions */
1236 for (i = 0; i < p->num_structs; i++)
1237 {
1238 count_struct_type_ref(p->struct_defs[i].type);
1239 }
1240 #endif /* USE_STRUCTS */
1241
1242 /* Included files */
1243
1244 for (i=0; i< p->num_includes; i++)
1245 {
1246 string_t *str;
1247 str = p->includes[i].name; MARK_MSTRING_REF(str);
1248 str = p->includes[i].filename; MARK_MSTRING_REF(str);
1249 }
1250 }
1251 else
1252 {
1253 if (!p->ref++)
1254 {
1255 dump_malloc_trace(1, p);
1256 fatal("Program block %p '%s' referenced as something else\n"
1257 , p, p->name ? get_txt(p->name) : "<null>");
1258 }
1259 }
1260 } /* gc_mark_program_ref() */
1261
1262 /*-------------------------------------------------------------------------*/
1263 static void
mark_object_ref(object_t * ob)1264 mark_object_ref (object_t *ob)
1265
1266 /* Mark the object <ob> as referenced and increase its refcount.
1267 * This method should be called only for destructed objects and
1268 * from the GC main loop for the initial count of live objects.
1269 */
1270
1271 {
1272 MARK_PLAIN_REF(ob); ob->ref++;
1273 if (ob->prog) mark_program_ref(ob->prog);
1274 if (ob->name) MARK_MSTRING_REF(ob->name);
1275 if (ob->load_name) MARK_MSTRING_REF(ob->load_name);
1276 } /* mark_object_ref() */
1277
1278 /*-------------------------------------------------------------------------*/
1279 void
gc_reference_destructed_object(object_t * ob)1280 gc_reference_destructed_object (object_t *ob)
1281
1282 /* Note the reference to a destructed object <ob>. The referee has to
1283 * replace its reference by a svalue.number 0 since all these objects
1284 * will be freed later.
1285 */
1286
1287 {
1288 if (TEST_REF(ob))
1289 {
1290 if (ob->ref)
1291 {
1292 dump_malloc_trace(1, ob);
1293 fatal("First reference to destructed object %p '%s', "
1294 "but ref count %ld != 0\n"
1295 , ob, ob->name ? get_txt(ob->name) : "<null>", (long)ob->ref
1296 );
1297 }
1298
1299 /* Destructed objects are not swapped */
1300 ob->next_all = gc_obj_list_destructed;
1301 gc_obj_list_destructed = ob;
1302 mark_object_ref(ob);
1303 }
1304 else
1305 {
1306 if (!ob->ref)
1307 {
1308 write_malloc_trace(ob);
1309 dump_malloc_trace(1, ob);
1310 fatal("Destructed object %p '%s' referenced as something else\n"
1311 , ob, ob->name ? get_txt(ob->name) : "<null>");
1312 }
1313 }
1314 } /* gc_reference_destructed_object() */
1315
1316 /*-------------------------------------------------------------------------*/
1317 static void
gc_MARK_MSTRING_REF(string_t * str)1318 gc_MARK_MSTRING_REF (string_t * str)
1319
1320 /* Increment the refcount of mstring <str>. How it works:
1321 * If MSTRING_REFS() is 0, the refcount either overflowed or it is
1322 * the first visit to the block. If it's the first visit, CHECK_REF
1323 * will return TRUE, otherwise we have an overflow and the MSTRING_REFS--
1324 * will undo the ++ from earlier.
1325 */
1326
1327 {
1328 if (CHECK_REF(str))
1329 {
1330 /* First visit to this block */
1331 MSTRING_REFS(str)++;
1332 }
1333 else if (MSTRING_REFS(str))
1334 {
1335 /* Not the first visit, and refcounts didn't overrun either */
1336 MSTRING_REFS(str)++;
1337 if (!MSTRING_REFS(str))
1338 {
1339 /* Refcount overflow */
1340 dprintf2(gout, "DEBUG: mark string: %x '%s' refcount reaches max!\n"
1341 , (p_int)str, (p_int)str->txt);
1342 }
1343 }
1344 } /* gc_MARK_MSTRING_REF(str) */
1345
1346 /*-------------------------------------------------------------------------*/
1347 void
gc_count_ref_from_string(string_t * p)1348 gc_count_ref_from_string (string_t *p)
1349
1350 /* Count the reference to mstring <p>.
1351 */
1352
1353 {
1354 gc_MARK_MSTRING_REF(p);
1355 } /* gc_count_ref_from_string() */
1356
1357 /*-------------------------------------------------------------------------*/
1358 static void
clear_map_ref_filter(svalue_t * key,svalue_t * data,void * extra)1359 clear_map_ref_filter (svalue_t *key, svalue_t *data, void *extra)
1360
1361 /* Auxiliary function to clear the refs in a mapping.
1362 * It is called with the <key> and <data> vector, the latter of
1363 * width (p_int)<extra>
1364 */
1365 {
1366 clear_ref_in_vector(key, 1);
1367 clear_ref_in_vector(data, (size_t)extra);
1368 } /* clear_map_ref_filter() */
1369
1370 /*-------------------------------------------------------------------------*/
1371 void
clear_ref_in_vector(svalue_t * svp,size_t num)1372 clear_ref_in_vector (svalue_t *svp, size_t num)
1373
1374 /* Clear the refs of the <num> elements of vector <svp>.
1375 */
1376
1377 {
1378 svalue_t *p;
1379
1380 if (!svp) /* e.g. when called for obj->variables */
1381 return;
1382
1383 for (p = svp; p < svp+num; p++)
1384 {
1385 switch(p->type)
1386 {
1387 case T_OBJECT:
1388 /* this might be a destructed object, which has it's ref not
1389 * cleared by the obj_list because it is no longer a member
1390 * Alas, swapped objects must not have prog->ref cleared.
1391 */
1392 clear_object_ref(p->u.ob);
1393 continue;
1394
1395 case T_STRING:
1396 case T_SYMBOL:
1397 clear_string_ref(p->u.str);
1398 break;
1399
1400 case T_POINTER:
1401 case T_QUOTED_ARRAY:
1402 if (!p->u.vec->ref)
1403 continue;
1404 p->u.vec->ref = 0;
1405 clear_ref_in_vector(&p->u.vec->item[0], VEC_SIZE(p->u.vec));
1406 continue;
1407
1408 #ifdef USE_STRUCTS
1409 case T_STRUCT:
1410 clear_struct_ref(p->u.strct);
1411 continue;
1412 #endif /* USE_STRUCTS */
1413
1414 case T_MAPPING:
1415 if (p->u.map->ref)
1416 {
1417 mapping_t *m;
1418 p_int num_values;
1419
1420 #ifdef DEBUG
1421 /* The initial cleanup phase should take care of compacting
1422 * all dirty mappings, however just in case one slips
1423 * through...
1424 */
1425 if (p->u.map->hash != NULL)
1426 dprintf1(gcollect_outfd
1427 , "Mapping %x still has a hash part.\n"
1428 , (p_int)p->u.map);
1429 #endif
1430 m = p->u.map;
1431 m->ref = 0;
1432 num_values = m->num_values;
1433 walk_mapping(m, clear_map_ref_filter, (char *)num_values );
1434 }
1435 continue;
1436
1437 case T_CLOSURE:
1438 if (CLOSURE_MALLOCED(p->x.closure_type))
1439 {
1440 lambda_t *l;
1441
1442 l = p->u.lambda;
1443 if (l->ref)
1444 {
1445 l->ref = 0;
1446 clear_ref_in_closure(l, p->x.closure_type);
1447 }
1448 }
1449 else
1450 clear_object_ref(p->u.ob);
1451 continue;
1452 }
1453 }
1454 } /* clear_ref_in_vector() */
1455
1456 /*-------------------------------------------------------------------------*/
1457 void
gc_count_ref_in_vector(svalue_t * svp,size_t num,const char * file,int line)1458 gc_count_ref_in_vector (svalue_t *svp, size_t num
1459 #ifdef CHECK_OBJECT_GC_REF
1460 , const char * file, int line
1461 #endif
1462 )
1463
1464 /* Count the references the <num> elements of vector <p>.
1465 */
1466
1467 {
1468 svalue_t *p;
1469
1470 if (!svp) /* e.g. when called for obj->variables */
1471 return;
1472
1473 for (p = svp; p < svp+num; p++) {
1474 switch(p->type)
1475 {
1476 case T_OBJECT:
1477 {
1478 object_t *ob;
1479
1480 ob = p->u.ob;
1481 if (ob->flags & O_DESTRUCTED)
1482 {
1483 put_number(p, 0);
1484 reference_destructed_object(ob);
1485 }
1486 else
1487 {
1488 ob->ref++;
1489 }
1490 continue;
1491 }
1492
1493 case T_POINTER:
1494 case T_QUOTED_ARRAY:
1495 /* Don't use CHECK_REF on the null vector */
1496 if (p->u.vec != &null_vector && CHECK_REF(p->u.vec))
1497 {
1498 count_array_size(p->u.vec);
1499 #ifdef CHECK_OBJECT_GC_REF
1500 gc_count_ref_in_vector(&p->u.vec->item[0], VEC_SIZE(p->u.vec), file, line);
1501 #else
1502 count_ref_in_vector(&p->u.vec->item[0], VEC_SIZE(p->u.vec));
1503 #endif
1504 }
1505 p->u.vec->ref++;
1506 continue;
1507
1508 #ifdef USE_STRUCTS
1509 case T_STRUCT:
1510 count_struct_ref(p->u.strct);
1511 continue;
1512 #endif /* USE_STRUCTS */
1513
1514 case T_MAPPING:
1515 if (CHECK_REF(p->u.map))
1516 {
1517 mapping_t *m;
1518
1519 m = p->u.map;
1520 count_ref_in_mapping(m);
1521 count_mapping_size(m);
1522 }
1523 p->u.map->ref++;
1524 continue;
1525
1526 case T_STRING:
1527 MARK_MSTRING_REF(p->u.str);
1528 continue;
1529
1530 case T_CLOSURE:
1531 if (CLOSURE_MALLOCED(p->x.closure_type))
1532 {
1533 if (p->u.lambda->ref++ <= 0)
1534 {
1535 count_ref_in_closure(p);
1536 }
1537 }
1538 else
1539 {
1540 object_t *ob;
1541
1542 ob = p->u.ob;
1543 if (ob->flags & O_DESTRUCTED)
1544 {
1545 put_number(p, 0);
1546 reference_destructed_object(ob);
1547 }
1548 else
1549 {
1550 ob->ref++;
1551 }
1552 }
1553 continue;
1554
1555 case T_SYMBOL:
1556 MARK_MSTRING_REF(p->u.str);
1557 continue;
1558 }
1559 } /* for */
1560 } /* gc_count_ref_in_vector() */
1561
1562 /*-------------------------------------------------------------------------*/
1563 static void
mark_unreferenced_string(string_t * string)1564 mark_unreferenced_string (string_t *string)
1565
1566 /* If the shared string <string> stored in the memory block <start> is
1567 * not referenced, it is deallocated.
1568 */
1569
1570 {
1571 if (TEST_REF(string))
1572 {
1573 dprintf2(gout,
1574 "tabled string %x '%s' was left unreferenced, freeing now.\n",
1575 (p_int) string, (p_int)string->txt
1576 );
1577
1578 MARK_REF(string);
1579 MSTRING_REFS(string) = 0;
1580 }
1581 } /* mark_unreferenced_string() */
1582
1583 /*-------------------------------------------------------------------------*/
1584 static void
gc_note_action_ref(action_t * p)1585 gc_note_action_ref (action_t *p)
1586
1587 /* Mark the strings of function and verb of all sentences in list <p>.
1588 */
1589
1590 {
1591 do {
1592 if (p->function)
1593 MARK_MSTRING_REF(p->function);
1594 if (p->verb)
1595 MARK_MSTRING_REF(p->verb);
1596 note_ref(p);
1597 } while ( NULL != (p = (action_t *)p->sent.next) );
1598 }
1599
1600 #define note_action_ref(p) \
1601 GC_REF_DUMP(action_t*, p, "Note action ref", gc_note_action_ref)
1602
1603 /*-------------------------------------------------------------------------*/
1604 static void
gc_count_ref_in_closure(svalue_t * csvp)1605 gc_count_ref_in_closure (svalue_t *csvp)
1606
1607 /* Count the reference to closure <csvp> and all referenced data.
1608 * Closures using a destructed object are stored in the stale_ lists
1609 * for later removal (and .ref is set to -1).
1610 */
1611
1612 {
1613 lambda_t *l = csvp->u.lambda;
1614 ph_int type = csvp->x.closure_type;
1615
1616 if (!l->ref)
1617 {
1618 /* This closure was bound to a destructed object, and has been
1619 * encountered before.
1620 */
1621 l->ref--; /* Undo ref increment that was done by the caller */
1622 if (type == CLOSURE_BOUND_LAMBDA)
1623 {
1624 csvp->x.closure_type = CLOSURE_UNBOUND_LAMBDA;
1625 (csvp->u.lambda = l->function.lambda)->ref++;
1626 }
1627 else
1628 {
1629 put_number(csvp, 0);
1630 }
1631 return;
1632 }
1633
1634 /* If the closure is bound, make sure that the object it is
1635 * bound to really exists.
1636 */
1637
1638 if (type != CLOSURE_UNBOUND_LAMBDA)
1639 {
1640 object_t *ob;
1641
1642 ob = l->ob;
1643 if (ob->flags & O_DESTRUCTED
1644 || ( type == CLOSURE_LFUN
1645 && l->function.lfun.ob->flags & O_DESTRUCTED) )
1646 {
1647 l->ref = -1;
1648 if (type == CLOSURE_LAMBDA)
1649 {
1650 l->ob = (object_t *)stale_lambda_closures;
1651 stale_lambda_closures = l;
1652 }
1653 else
1654 {
1655 l->ob = (object_t *)stale_misc_closures;
1656 stale_misc_closures = l;
1657 if (type == CLOSURE_LFUN)
1658 {
1659 if (l->function.lfun.ob->flags & O_DESTRUCTED)
1660 {
1661 reference_destructed_object(l->function.lfun.ob);
1662 }
1663 }
1664 }
1665
1666 if (ob->flags & O_DESTRUCTED)
1667 {
1668 reference_destructed_object(ob);
1669 }
1670
1671 if (type == CLOSURE_BOUND_LAMBDA)
1672 {
1673 csvp->x.closure_type = CLOSURE_UNBOUND_LAMBDA;
1674 csvp->u.lambda = l->function.lambda;
1675 }
1676 else
1677 {
1678 put_number(csvp, 0);
1679 }
1680 }
1681 else
1682 {
1683 /* Object exists: count reference */
1684
1685 ob->ref++;
1686 if (type == CLOSURE_LFUN)
1687 {
1688 l->function.lfun.ob->ref++;
1689 if(l->function.lfun.inhProg)
1690 mark_program_ref(l->function.lfun.inhProg);
1691 }
1692 }
1693 }
1694
1695 /* Count the references in the code of the closure */
1696
1697 if (l->prog_ob)
1698 {
1699 if (l->prog_ob->flags & O_DESTRUCTED)
1700 {
1701 reference_destructed_object(l->prog_ob);
1702 l->prog_ob = NULL;
1703 l->prog_pc = 0;
1704 }
1705 else
1706 {
1707 /* Object exists: count reference */
1708 l->prog_ob->ref++;
1709 }
1710 }
1711
1712 if (CLOSURE_HAS_CODE(type))
1713 {
1714 mp_int num_values;
1715 svalue_t *svp;
1716
1717 svp = (svalue_t *)l;
1718 if ( (num_values = EXTRACT_UCHAR(l->function.code)) == 0xff)
1719 num_values = svp[-0x100].u.number;
1720 svp -= num_values;
1721 note_ref(svp);
1722 count_ref_in_vector(svp, (size_t)num_values);
1723 }
1724 else
1725 {
1726 note_ref(l);
1727 if (type == CLOSURE_BOUND_LAMBDA)
1728 {
1729 lambda_t *l2 = l->function.lambda;
1730
1731 if (!l2->ref++) {
1732 svalue_t sv;
1733
1734 sv.type = T_CLOSURE;
1735 sv.x.closure_type = CLOSURE_UNBOUND_LAMBDA;
1736 sv.u.lambda = l2;
1737 count_ref_in_closure(&sv);
1738 }
1739 }
1740 #ifdef USE_NEW_INLINES
1741 if (type == CLOSURE_LFUN && l->function.lfun.context_size != 0)
1742 {
1743 unsigned short size = l->function.lfun.context_size;
1744 l->function.lfun.context_size = 0; /* Prevent recursion */
1745 count_ref_in_vector(l->context, size);
1746 l->function.lfun.context_size = size;
1747 }
1748 #endif /* USE_NEW_INLINES */
1749 }
1750 } /* count_ref_in_closure() */
1751
1752 /*-------------------------------------------------------------------------*/
1753 static void
clear_ref_in_closure(lambda_t * l,ph_int type)1754 clear_ref_in_closure (lambda_t *l, ph_int type)
1755
1756 /* Clear the references in closure <l> which is of type <type>.
1757 */
1758
1759 {
1760 if (l->prog_ob)
1761 clear_object_ref(l->prog_ob);
1762
1763 if (CLOSURE_HAS_CODE(type))
1764 {
1765 mp_int num_values;
1766 svalue_t *svp;
1767
1768 svp = (svalue_t *)l;
1769 if ( (num_values = EXTRACT_UCHAR(l->function.code)) == 0xff)
1770 num_values = svp[-0x100].u.number;
1771 svp -= num_values;
1772 clear_ref_in_vector(svp, (size_t)num_values);
1773 }
1774 else if (type == CLOSURE_BOUND_LAMBDA)
1775 {
1776 lambda_t *l2 = l->function.lambda;
1777
1778 if (l2->ref) {
1779 l2->ref = 0;
1780 clear_ref_in_closure(l2, CLOSURE_UNBOUND_LAMBDA);
1781 }
1782 }
1783
1784 if (type != CLOSURE_UNBOUND_LAMBDA)
1785 clear_object_ref(l->ob);
1786
1787 if (type == CLOSURE_LFUN)
1788 {
1789 clear_object_ref(l->function.lfun.ob);
1790 if (l->function.lfun.inhProg)
1791 clear_program_ref(l->function.lfun.inhProg, MY_TRUE);
1792 }
1793
1794 #ifdef USE_NEW_INLINES
1795 if (type == CLOSURE_LFUN && l->function.lfun.context_size != 0)
1796 {
1797 unsigned short size = l->function.lfun.context_size;
1798 l->function.lfun.context_size = 0; /* Prevent recursion */
1799 clear_ref_in_vector(l->context, size);
1800 l->function.lfun.context_size = size;
1801 }
1802 #endif /* USE_NEW_INLINES */
1803 } /* clear_ref_in_closure() */
1804
1805 /*-------------------------------------------------------------------------*/
1806 void
restore_default_gc_log(void)1807 restore_default_gc_log (void)
1808
1809 /* If gcollect_outfd was redirected to some other file, that file is
1810 * closed and the default log file is restored.
1811 */
1812
1813 {
1814 if (gcollect_outfd != default_gcollect_outfd)
1815 {
1816 if (gcollect_outfd != 1 && gcollect_outfd != 2)
1817 close(gcollect_outfd);
1818 gcollect_outfd = default_gcollect_outfd;
1819 }
1820 } /* restore_default_gc_log() */
1821
1822 /*-------------------------------------------------------------------------*/
1823 void
new_default_gc_log(int fd)1824 new_default_gc_log (int fd)
1825
1826 /* Redirect the default and the current log file to file <fd>. If the
1827 * current log file is identical to the default log file, it is
1828 * redirected, too.
1829 */
1830
1831 {
1832 if (default_gcollect_outfd != fd)
1833 {
1834 restore_default_gc_log();
1835
1836 if (default_gcollect_outfd != 1 && default_gcollect_outfd != 2)
1837 close(default_gcollect_outfd);
1838 default_gcollect_outfd = gcollect_outfd = fd;
1839 }
1840 } /* new_default_gc_log() */
1841
1842 /*-------------------------------------------------------------------------*/
1843 void
garbage_collection(void)1844 garbage_collection(void)
1845
1846 /* The Mark-Sweep garbage collector.
1847 *
1848 * Free all possible memory, then loop through every object and variable
1849 * in the game, check the reference counts and deallocate unused memory.
1850 * This takes time and should not be used lightheartedly.
1851 *
1852 * The function must be called outside of LPC evaluations.
1853 */
1854
1855 {
1856 object_t *ob, *next_ob;
1857 lambda_t *l, *next_l;
1858 int i;
1859 long dobj_count;
1860
1861 if (gcollect_outfd != 1 && gcollect_outfd != 2)
1862 {
1863 dprintf1(gcollect_outfd, "\n%s --- Garbage Collection ---\n"
1864 , (long)time_stamp());
1865 }
1866
1867 /* --- Pass 0: dispose of some unnecessary stuff ---
1868 */
1869
1870 dobj_count = tot_alloc_object;
1871
1872 malloc_privilege = MALLOC_MASTER;
1873 RESET_LIMITS;
1874 CLEAR_EVAL_COST;
1875 out_of_memory = MY_FALSE;
1876 assert_master_ob_loaded();
1877 malloc_privilege = MALLOC_SYSTEM;
1878
1879 /* Recover as much memory from temporaries as possible.
1880 * However, don't call mb_release() yet as the swap buffer
1881 * is still needed.
1882 */
1883 if (obj_list_replace)
1884 replace_programs();
1885 handle_newly_destructed_objects();
1886 free_save_object_buffers();
1887 free_interpreter_temporaries();
1888 free_action_temporaries();
1889 #ifdef USE_PGSQL
1890 pg_purge_connections();
1891 #endif /* USE_PGSQL */
1892 remove_stale_player_data();
1893 remove_stale_call_outs();
1894 free_defines();
1895 free_all_local_names();
1896 remove_unknown_identifier();
1897 check_wizlist_for_destr();
1898 cleanup_all_objects();
1899 if (current_error_trace)
1900 {
1901 free_array(current_error_trace);
1902 current_error_trace = NULL;
1903 }
1904 if (uncaught_error_trace)
1905 {
1906 free_array(uncaught_error_trace);
1907 uncaught_error_trace = NULL;
1908 }
1909
1910 remove_destructed_objects(MY_TRUE); /* After reducing all object references! */
1911
1912 if (dobj_count != tot_alloc_object)
1913 {
1914 dprintf2(gcollect_outfd, "%s GC pass 1: Freed %d objects.\n"
1915 , (long)time_stamp(), dobj_count - tot_alloc_object);
1916 }
1917
1918 #ifdef CHECK_OBJECT_REF
1919 while (newly_destructed_obj_shadows != NULL)
1920 {
1921 object_shadow_t *sh = newly_destructed_obj_shadows;
1922 newly_destructed_obj_shadows = sh->next;
1923 xfree(sh);
1924 }
1925 while (destructed_obj_shadows != NULL)
1926 {
1927 object_shadow_t *sh = destructed_obj_shadows;
1928 destructed_obj_shadows = sh->next;
1929 xfree(sh);
1930 }
1931 #endif /* CHECK_OBJECT_REF */
1932
1933
1934 /* --- Pass 1: clear the 'referenced' flag in all malloced blocks ---
1935 */
1936 mem_clear_ref_flags();
1937
1938 /* --- Pass 2: clear the ref counts ---
1939 */
1940
1941 gc_status = gcClearRefs;
1942 if (d_flag > 3)
1943 {
1944 debug_message("%s start of garbage_collection\n", time_stamp());
1945 }
1946
1947 clear_array_size();
1948 clear_mapping_size();
1949
1950 /* Process the list of all objects */
1951
1952 for (ob = obj_list; ob; ob = ob->next_all) {
1953 int was_swapped;
1954 Bool clear_prog_ref;
1955
1956 if (d_flag > 4)
1957 {
1958 debug_message("%s clearing refs for object '%s'\n"
1959 , time_stamp(), get_txt(ob->name));
1960 }
1961 was_swapped = 0;
1962 #if defined(CHECK_OBJECT_REF) && defined(DEBUG)
1963 ob->extra_ref = ob->ref;
1964 #endif
1965 if (ob->flags & O_SWAPPED
1966 && (was_swapped = load_ob_from_swap(ob)) & 1)
1967 {
1968 /* don't clear the program ref count. It is 1 */
1969 clear_prog_ref = MY_FALSE;
1970 }
1971 else
1972 {
1973 /* Take special care of inherited programs, the associated
1974 * objects might be destructed.
1975 */
1976 clear_prog_ref = MY_TRUE;
1977 }
1978 if (was_swapped < 0)
1979 fatal("Totally out of MEMORY in GC: (swapping in '%s')\n"
1980 , get_txt(ob->name));
1981
1982 clear_program_ref(ob->prog, clear_prog_ref);
1983
1984 ob->ref = 0;
1985 clear_string_ref(ob->name);
1986 clear_ref_in_vector(ob->variables, ob->prog->num_variables);
1987 if (was_swapped)
1988 {
1989 swap(ob, was_swapped);
1990 }
1991 }
1992 if (d_flag > 3)
1993 {
1994 debug_message("%s ref counts referenced by obj_list cleared\n"
1995 , time_stamp());
1996 }
1997
1998 /* Process the interactives */
1999
2000 for(i = 0 ; i < MAX_PLAYERS; i++)
2001 {
2002 input_t * it;
2003
2004 if (all_players[i] == NULL)
2005 continue;
2006
2007 for ( it = all_players[i]->input_handler; it != NULL; it = it->next)
2008 {
2009 clear_memory_reference(it);
2010 clear_input_refs(it);
2011 }
2012
2013 #ifdef USE_TLS
2014 if (all_players[i]->tls_cb != NULL)
2015 {
2016 clear_memory_reference(all_players[i]->tls_cb);
2017 clear_ref_in_callback(all_players[i]->tls_cb);
2018 }
2019 #endif
2020 clear_ref_in_vector(&all_players[i]->prompt, 1);
2021
2022 /* snoop_by and modify_command are known to be NULL or non-destructed
2023 * objects.
2024 */
2025 }
2026
2027 /* Process the driver hooks */
2028
2029 clear_ref_in_vector(driver_hook, NUM_DRIVER_HOOKS);
2030
2031 /* Let the modules process their data */
2032
2033 mstring_clear_refs();
2034 clear_ref_from_wiz_list();
2035 clear_ref_from_call_outs();
2036 clear_ref_from_efuns();
2037 #if defined(USE_PARSE_COMMAND)
2038 clear_parse_refs();
2039 #endif
2040 clear_simul_efun_refs();
2041 clear_interpreter_refs();
2042 clear_comm_refs();
2043 clear_rxcache_refs();
2044 #ifdef USE_STRUCTS
2045 clear_tabled_struct_refs();
2046 #endif
2047 #ifdef USE_PGSQL
2048 pg_clear_refs();
2049 #endif /* USE_PGSQL */
2050
2051 mb_clear_refs();
2052 /* As this call also covers the swap buffer, it MUST come after
2053 * processing (and potentially swapping) the objects.
2054 */
2055
2056 null_vector.ref = 0;
2057
2058 /* Finally, walk the list of destructed objects and clear all references
2059 * in them.
2060 */
2061 for (ob = destructed_objs; ob; ob = ob->next_all)
2062 {
2063 if (d_flag > 4)
2064 {
2065 debug_message("%s clearing refs for destructed object '%s'\n"
2066 , time_stamp(), get_txt(ob->name));
2067 }
2068
2069 if (ob->name)
2070 clear_string_ref(ob->name);
2071 if (ob->load_name)
2072 clear_string_ref(ob->load_name);
2073 ob->prog->ref = 0;
2074 clear_program_ref(ob->prog, MY_TRUE);
2075 ob->ref = 0;
2076 }
2077
2078
2079 /* --- Pass 3: Compute the ref counts, and set the 'referenced' flag where
2080 * appropriate ---
2081 */
2082
2083 gc_status = gcCountRefs;
2084
2085 gc_obj_list_destructed = NULL;
2086 stale_lambda_closures = NULL;
2087 stale_misc_closures = NULL;
2088 stale_mappings = NULL;
2089
2090
2091 /* Handle the known destructed objects first, as later calls to
2092 * reference_destructed_object() will clobber the list.
2093 */
2094 for (ob = destructed_objs; ob; )
2095 {
2096 object_t *next = ob->next_all;
2097
2098 dprintf1(gcollect_outfd
2099 , "Freeing destructed object '%s'\n"
2100 , (p_int)get_txt(ob->name)
2101 );
2102 reference_destructed_object(ob); /* Clobbers .next_all */
2103
2104 ob = next;
2105 }
2106
2107 num_destructed = 0;
2108 destructed_objs = NULL;
2109
2110
2111 /* Process the list of all objects.
2112 */
2113 for (ob = obj_list; ob; ob = ob->next_all)
2114 {
2115 int was_swapped;
2116
2117 was_swapped = 0;
2118 if (ob->flags & O_SWAPPED)
2119 {
2120 was_swapped = load_ob_from_swap(ob);
2121 if (was_swapped & 1)
2122 {
2123 #ifdef DUMP_GC_REFS
2124 dprintf1(gcollect_outfd, "Clear ref of swapped-in program %x\n", (long)ob->prog);
2125 #endif
2126 CLEAR_REF(ob->prog);
2127 ob->prog->ref = 0;
2128 }
2129 }
2130
2131 mark_object_ref(ob);
2132
2133 if (ob->prog->num_variables)
2134 {
2135 note_ref(ob->variables);
2136 }
2137
2138 count_ref_in_vector(ob->variables, ob->prog->num_variables);
2139
2140 if (ob->sent)
2141 {
2142 sentence_t *sent;
2143
2144 sent = ob->sent;
2145 if (ob->flags & O_SHADOW)
2146 {
2147 note_ref(sent);
2148
2149 /* If there is a ->ip, it will be processed as
2150 * part of the player object handling below.
2151 */
2152 sent = sent->next;
2153 }
2154 if (sent)
2155 note_action_ref((action_t *)sent);
2156 }
2157
2158 if (was_swapped)
2159 {
2160 swap(ob, was_swapped);
2161 }
2162 }
2163
2164 if (d_flag > 3)
2165 {
2166 debug_message("%s obj_list evaluated\n", time_stamp());
2167 }
2168
2169 /* Process the interactives. */
2170
2171 for(i = 0 ; i < MAX_PLAYERS; i++)
2172 {
2173 input_t * it;
2174
2175 if (all_players[i] == NULL)
2176 continue;
2177
2178 note_ref(all_players[i]);
2179
2180 if (all_players[i]->write_first)
2181 {
2182 struct write_buffer_s *tmp = all_players[i]->write_first;
2183
2184 do
2185 {
2186 note_ref(tmp);
2187 tmp = tmp->next;
2188 } while (tmp != NULL);
2189 }
2190 #ifdef USE_MCCP
2191 if (all_players[i]->out_compress != NULL)
2192 note_ref(all_players[i]->out_compress);
2193 if (all_players[i]->out_compress_buf != NULL)
2194 note_ref(all_players[i]->out_compress_buf);
2195 #endif /* USE_MCCP */
2196
2197 /* There are no destructed interactives, or interactives
2198 * referencing destructed objects.
2199 */
2200
2201 all_players[i]->ob->ref++;
2202 if ( NULL != (ob = all_players[i]->snoop_by) )
2203 {
2204 if (!O_IS_INTERACTIVE(ob))
2205 {
2206 ob->ref++;
2207 }
2208 } /* end of snoop-processing */
2209
2210 for ( it = all_players[i]->input_handler; it != NULL; it = it->next)
2211 {
2212 note_ref(it);
2213 count_input_refs(it);
2214 } /* end of input_to processing */
2215
2216 #ifdef USE_TLS
2217 if (all_players[i]->tls_cb != NULL)
2218 {
2219 note_ref(all_players[i]->tls_cb);
2220 count_ref_in_callback(all_players[i]->tls_cb);
2221 }
2222 #endif
2223
2224 if ( NULL != (ob = all_players[i]->modify_command) )
2225 {
2226 ob->ref++;
2227 }
2228
2229 count_ref_in_vector(&all_players[i]->prompt, 1);
2230
2231 if (all_players[i]->trace_prefix)
2232 {
2233 count_ref_from_string(all_players[i]->trace_prefix);
2234 }
2235 }
2236
2237 /* Let the modules process their data */
2238
2239 count_ref_from_wiz_list();
2240 count_ref_from_call_outs();
2241 count_ref_from_efuns();
2242
2243 if (master_ob)
2244 master_ob->ref++;
2245 else
2246 fatal("No master object\n");
2247
2248 MARK_MSTRING_REF(master_name_str);
2249 count_lex_refs();
2250 count_compiler_refs();
2251 count_simul_efun_refs();
2252 #if defined(SUPPLY_PARSE_COMMAND)
2253 count_old_parse_refs();
2254 #endif
2255 mstring_note_refs();
2256 note_otable_ref();
2257 count_comm_refs();
2258 count_interpreter_refs();
2259 count_heart_beat_refs();
2260 count_rxcache_refs();
2261 #ifdef USE_PGSQL
2262 pg_count_refs();
2263 #endif /* USE_PGSQL */
2264
2265 mb_note_refs();
2266
2267 if (reserved_user_area)
2268 note_ref(reserved_user_area);
2269 if (reserved_master_area)
2270 note_ref(reserved_master_area);
2271 if (reserved_system_area)
2272 note_ref(reserved_system_area);
2273
2274 note_ref(mud_lib);
2275 null_vector.ref++;
2276
2277 /* Process the driver hooks */
2278
2279 count_ref_in_vector(driver_hook, NUM_DRIVER_HOOKS);
2280
2281 gc_status = gcInactive;
2282
2283 /* --- Pass 4: remove unreferenced strings and struct types ---
2284 */
2285
2286 #ifdef USE_STRUCTS
2287 remove_unreferenced_structs();
2288 #endif
2289 mstring_walk_table(mark_unreferenced_string);
2290 mstring_gc_table();
2291
2292 /* --- Pass 5: Release all destructed objects ---
2293 *
2294 * It is vital that all information freed here is already known
2295 * as referenced, so we won't free it a second time in pass 6.
2296 */
2297
2298 dobj_count = 0;
2299 for (ob = gc_obj_list_destructed; ob; ob = next_ob)
2300 {
2301 next_ob = ob->next_all;
2302 free_object(ob, "garbage collection");
2303 dobj_count++;
2304 }
2305
2306 for (l = stale_lambda_closures; l; )
2307 {
2308 svalue_t sv;
2309
2310 next_l = (lambda_t *)l->ob;
2311 l->ref = 1;
2312 sv.type = T_CLOSURE;
2313 sv.x.closure_type = CLOSURE_UNBOUND_LAMBDA;
2314 sv.u.lambda = l;
2315 l = (lambda_t *)l->ob;
2316 free_closure(&sv);
2317 }
2318
2319 for (l = stale_misc_closures; l; l = next_l)
2320 {
2321 next_l = (lambda_t *)l->ob;
2322 xfree((char *)l);
2323 }
2324
2325 clean_stale_mappings();
2326
2327 /* --- Pass 6: Release all unused memory ---
2328 */
2329
2330 mem_free_unrefed_memory();
2331 reallocate_reserved_areas();
2332 if (!reserved_user_area)
2333 {
2334 svalue_t *res = NULL;
2335 if (reserved_system_area)
2336 {
2337 RESET_LIMITS;
2338 CLEAR_EVAL_COST;
2339 malloc_privilege = MALLOC_MASTER;
2340 res = callback_master(STR_QUOTA_DEMON, 0);
2341 }
2342 /* Once: remove_uids(res && (res->type != T_NUMBER || res->u.number) );
2343 * but that function was never implemented.
2344 */
2345 }
2346
2347 /* Release the memory from the buffers. Eventually it will be
2348 * allocated again, but for now the point is to reduce the amount
2349 * of allocated memory.
2350 */
2351 mb_release();
2352
2353 /* Allow the memory manager to do some consolidation */
2354 mem_consolidate(MY_TRUE);
2355
2356 /* Finally, try to reclaim the reserved areas */
2357
2358 reallocate_reserved_areas();
2359
2360 time_last_gc = time(NULL);
2361 dprintf2(gcollect_outfd, "%s GC freed %d destructed objects.\n"
2362 , (long)time_stamp(), dobj_count);
2363 #if defined(CHECK_OBJECT_REF) && defined(DEBUG)
2364 for (ob = obj_list; ob; ob = ob->next_all) {
2365 if (ob->extra_ref != ob->ref
2366 && strchr(get_txt(ob->name), '#') == NULL
2367 )
2368 {
2369 dprintf4(2, "DEBUG: GC object %x '%s': refs %d, extra_refs %d\n"
2370 , (p_int)ob, (p_int)get_txt(ob->name), (p_int)ob->ref
2371 , (p_int)ob->extra_ref);
2372 }
2373 }
2374 #endif
2375
2376 /* If the GC log was redirected, close that file and set the
2377 * logging back to the default file.
2378 */
2379 restore_default_gc_log();
2380 } /* garbage_collection() */
2381
2382
2383 #if defined(MALLOC_TRACE)
2384
2385 /* Some functions to print the tracing data from the memory blocks.
2386 * The show_ functions are called from xmalloc directly.
2387 */
2388
2389 #ifdef USE_STRUCTS
2390 static void show_struct(int d, void *block, int depth);
2391 #endif /* USE_STRUCTS */
2392
2393 /*-------------------------------------------------------------------------*/
2394 static void
show_string(int d,char * block,int depth UNUSED)2395 show_string (int d, char *block, int depth UNUSED)
2396
2397 /* Print the string from memory <block> on filedescriptor <d>.
2398 */
2399
2400 {
2401 #ifdef __MWERKS__
2402 # pragma unused(depth)
2403 #endif
2404 size_t len;
2405
2406 if (block == NULL)
2407 {
2408 WRITES(d, "<null>");
2409 }
2410 else
2411 {
2412 WRITES(d, "\"");
2413 if ((len = strlen(block)) < 70)
2414 {
2415 write(d, block, len);
2416 WRITES(d, "\"");
2417 }
2418 else
2419 {
2420 write(d, block, 50);
2421 WRITES(d, "\" (truncated, length ");writed(d, len);WRITES(d, ")");
2422 }
2423 }
2424 } /* show_string() */
2425
2426 /*-------------------------------------------------------------------------*/
2427 static void
show_mstring_data(int d,void * block,int depth UNUSED)2428 show_mstring_data (int d, void *block, int depth UNUSED)
2429
2430 /* Print the stringdata from memory <block> on filedescriptor <d>.
2431 */
2432
2433 {
2434 #ifdef __MWERKS__
2435 # pragma unused(depth)
2436 #endif
2437 string_t *str;
2438
2439 str = (string_t *)block;
2440 WRITES(d, "(");
2441 writed(d, (p_uint)str->size);
2442 WRITES(d, ")\"");
2443 if (str->size < 50)
2444 {
2445 write(d, block, str->size);
2446 WRITES(d, "\"");
2447 }
2448 else
2449 {
2450 write(d, block, 50);
2451 WRITES(d, "\" (truncated)");
2452 }
2453 } /* show_mstring_data() */
2454
2455 /*-------------------------------------------------------------------------*/
2456 static void
show_mstring(int d,void * block,int depth)2457 show_mstring (int d, void *block, int depth)
2458
2459 /* Print the mstring from memory <block> on filedescriptor <d>.
2460 */
2461
2462 {
2463 if (block == NULL)
2464 {
2465 WRITES(d, "<null>");
2466 }
2467 else
2468 {
2469 string_t *str;
2470
2471 str = (string_t *)block;
2472 if (str->info.tabled)
2473 {
2474 WRITES(d, "Tabled string: ");
2475 show_mstring_data(d, str, depth);
2476 }
2477 else
2478 {
2479 WRITES(d, "Untabled string: ");
2480 show_mstring_data(d, str, depth);
2481 }
2482 /* TODO: This is how it should be
2483 * TODO:: show_mstring_data(d, str->str, depth);
2484 * TODO:: alas it crashes the driver when destructed leaked objects
2485 * TODO:: are found 'cause their name is no langer value (though
2486 * TODO:: the reason for that is yet unknown). See 3.3.168 mails/bugs.
2487 */
2488 }
2489 } /* show_mstring() */
2490
2491 /*-------------------------------------------------------------------------*/
2492 static void
show_object(int d,void * block,int depth)2493 show_object (int d, void *block, int depth)
2494
2495 /* Print the data about object <block> on filedescriptor <d>.
2496 */
2497
2498 {
2499 object_t *ob;
2500
2501 ob = (object_t *)block;
2502 if (depth) {
2503 object_t *o;
2504
2505 for (o = obj_list; o && o != ob; o = o->next_all) NOOP;
2506 if (!o || o->flags & O_DESTRUCTED) {
2507 WRITES(d, "Destructed object in block 0x");
2508 write_x(d, (p_uint)((unsigned *)block - xalloc_overhead()));
2509 WRITES(d, "\n");
2510 return;
2511 }
2512 }
2513 WRITES(d, "Object: ");
2514 if (ob->flags & O_DESTRUCTED)
2515 WRITES(d, "(destructed) ");
2516 show_mstring(d, ob->name, 0);
2517 WRITES(d, " from ");
2518 show_mstring(d, ob->load_name, 0);
2519 WRITES(d, ", uid: ");
2520 show_string(d, ob->user->name ? get_txt(ob->user->name) : "0", 0);
2521 WRITES(d, "\n");
2522 } /* show_object() */
2523
2524 /*-------------------------------------------------------------------------*/
2525 static void
show_cl_literal(int d,void * block,int depth UNUSED)2526 show_cl_literal (int d, void *block, int depth UNUSED)
2527
2528 /* Print the data about literal closure <block> on filedescriptor <d>.
2529 */
2530
2531 {
2532 #ifdef __MWERKS__
2533 # pragma unused(depth)
2534 #endif
2535 lambda_t *l;
2536 object_t *obj;
2537
2538 l = (lambda_t *)block;
2539
2540 WRITES(d, "Closure literal: Object ");
2541
2542 obj = l->ob;
2543 if (obj)
2544 {
2545 if (obj->name)
2546 show_mstring(d, obj->name, 0);
2547 else
2548 WRITES(d, "(no name)");
2549 if (obj->flags & O_DESTRUCTED)
2550 WRITES(d, " (destructed)");
2551 }
2552 else
2553 WRITES(d, "<null>");
2554
2555 WRITES(d, ", index ");
2556 writed(d, l->function.var_index);
2557 WRITES(d, ", ref ");
2558 writed(d, l->ref);
2559 WRITES(d, "\n");
2560 } /* show_cl_literal() */
2561
2562 /*-------------------------------------------------------------------------*/
2563 static void
show_array(int d,void * block,int depth)2564 show_array(int d, void *block, int depth)
2565
2566 /* Print the array at recursion <depth> from memory <block> on
2567 * filedescriptor <d>. Recursive printing stops at <depth> == 2.
2568 */
2569
2570 {
2571 vector_t *a;
2572 mp_int i, j;
2573 svalue_t *svp;
2574 wiz_list_t *user = NULL;
2575 mp_int a_size;
2576
2577 a = (vector_t *)block;
2578
2579 /* Can't use VEC_SIZE() here, as the memory block may have been
2580 * partly overwritten by the malloc pointers already.
2581 */
2582 a_size = (mp_int)( xalloced_size(a)
2583 - ( xalloc_overhead() +
2584 ( sizeof(vector_t) - sizeof(svalue_t) )
2585 )
2586
2587 ) / (sizeof(svalue_t));
2588
2589 if (depth && a != &null_vector)
2590 {
2591 int freed;
2592 wiz_list_t *wl;
2593
2594 wl = NULL;
2595 freed = is_freed(block, sizeof(vector_t) );
2596 if (!freed)
2597 {
2598 user = a->user;
2599 wl = all_wiz;
2600 if (user)
2601 for ( ; wl && wl != user; wl = wl->next) NOOP;
2602 }
2603 if (freed || !wl || a_size <= 0 || a_size > MAX_ARRAY_SIZE
2604 || xalloced_size((char *)a) - xalloc_overhead() !=
2605 sizeof(vector_t) + sizeof(svalue_t) * (a_size - 1) )
2606 {
2607 WRITES(d, "Array in freed block 0x");
2608 write_x(d, (p_uint)((unsigned *)block - xalloc_overhead()));
2609 WRITES(d, "\n");
2610 return;
2611 }
2612 }
2613 else
2614 {
2615 user = a->user;
2616 }
2617
2618 WRITES(d, "Array ");
2619 write_x(d, (p_int)a);
2620 WRITES(d, " size ");
2621 writed(d, (p_uint)a_size);
2622 WRITES(d, ", uid: ");
2623 show_string(d, user ? (user->name ? get_txt(user->name) : "<null>")
2624 :"0", 0);
2625 WRITES(d, "\n");
2626 if (depth > 2)
2627 return;
2628
2629 i = 32 >> depth;
2630 if (i > a_size)
2631 i = a_size;
2632
2633 for (svp = a->item; --i >= 0; svp++)
2634 {
2635 for (j = depth + 1; --j >= 0;) WRITES(d, " ");
2636 switch(svp->type)
2637 {
2638 case T_POINTER:
2639 show_array(d, (char *)svp->u.vec, depth+1);
2640 break;
2641
2642 #ifdef USE_STRUCTS
2643 case T_STRUCT:
2644 show_struct(d, (char *)svp->u.strct, depth+1);
2645 break;
2646 #endif /* USE_STRUCTS */
2647
2648 case T_NUMBER:
2649 writed(d, (p_uint)svp->u.number);
2650 WRITES(d, "\n");
2651 break;
2652
2653 case T_STRING:
2654 if (is_freed(svp->u.str, 1) )
2655 {
2656 WRITES(d, "String in freed block 0x");
2657 write_x(d, (p_uint)((unsigned *)block - xalloc_overhead()));
2658 WRITES(d, "\n");
2659 break;
2660 }
2661 WRITES(d, "String: ");
2662 show_mstring(d, svp->u.str, 0);
2663 WRITES(d, "\n");
2664 break;
2665
2666 case T_CLOSURE:
2667 if (svp->x.closure_type == CLOSURE_LFUN
2668 || svp->x.closure_type == CLOSURE_IDENTIFIER)
2669 show_cl_literal(d, (char *)svp->u.lambda, depth);
2670 else
2671 {
2672 WRITES(d, "Closure type ");
2673 writed(d, svp->x.closure_type);
2674 WRITES(d, "\n");
2675 }
2676 break;
2677
2678 case T_OBJECT:
2679 show_object(d, (char *)svp->u.ob, 1);
2680 break;
2681
2682 default:
2683 WRITES(d, "Svalue type ");writed(d, svp->type);WRITES(d, "\n");
2684 break;
2685 }
2686 }
2687 } /* show_array() */
2688
2689 #ifdef USE_STRUCTS
2690 /*-------------------------------------------------------------------------*/
2691 static void
show_struct(int d,void * block,int depth)2692 show_struct(int d, void *block, int depth)
2693
2694 /* Print the struct at recursion <depth> from memory <block> on
2695 * filedescriptor <d>. Recursive printing stops at <depth> == 2.
2696 */
2697
2698 {
2699 struct_t *a;
2700 mp_int i, j;
2701 svalue_t *svp;
2702 wiz_list_t *user;
2703 mp_int a_size;
2704
2705 user = NULL;
2706
2707 a = (struct_t *)block;
2708
2709 /* Can't use struct_size() here, as the memory block may have been
2710 * partly overwritten by the smalloc pointers already.
2711 */
2712 a_size = (mp_int)( xalloced_size(a)
2713 - ( xalloc_overhead() +
2714 ( sizeof(struct_t) - sizeof(svalue_t) ) / SIZEOF_CHAR_P
2715 )
2716
2717 ) / (sizeof(svalue_t)/SIZEOF_CHAR_P);
2718
2719 if (depth)
2720 {
2721 int freed;
2722 wiz_list_t *wl;
2723
2724 wl = NULL;
2725 freed = is_freed(block, sizeof(vector_t) );
2726 if (!freed)
2727 {
2728 user = a->user;
2729 wl = all_wiz;
2730 if (user)
2731 for ( ; wl && wl != user; wl = wl->next) NOOP;
2732 }
2733 if (freed || !wl || a_size <= 0
2734 || (xalloced_size((char *)a) - xalloc_overhead()) << 2 !=
2735 sizeof(struct_t) + sizeof(svalue_t) * (a_size - 1) )
2736 {
2737 WRITES(d, "struct in freed block 0x");
2738 write_x(d, (p_uint)((unsigned *)block - xalloc_overhead()));
2739 WRITES(d, "\n");
2740 return;
2741 }
2742 }
2743 else
2744 {
2745 user = a->user;
2746 }
2747
2748 WRITES(d, "struct ");
2749 write_x(d, (p_int)a);
2750 WRITES(d, " size ");writed(d, (p_uint)a_size);
2751 WRITES(d, ", uid: ");
2752 show_string(d, user ? (user->name ? get_txt(user->name) : "<null>")
2753 : "0", 0);
2754 WRITES(d, "\n");
2755 if (depth > 2)
2756 return;
2757
2758 i = 32 >> depth;
2759 if (i > a_size)
2760 i = a_size;
2761
2762 for (svp = a->member; --i >= 0; svp++)
2763 {
2764 for (j = depth + 1; --j >= 0;) WRITES(d, " ");
2765 switch(svp->type)
2766 {
2767 case T_POINTER:
2768 show_array(d, (char *)svp->u.vec, depth+1);
2769 break;
2770
2771 case T_STRUCT:
2772 show_struct(d, (char *)svp->u.strct, depth+1);
2773 break;
2774
2775 case T_NUMBER:
2776 writed(d, (p_uint)svp->u.number);
2777 WRITES(d, "\n");
2778 break;
2779
2780 case T_STRING:
2781 if (is_freed(svp->u.str, 1) )
2782 {
2783 WRITES(d, "String in freed block 0x");
2784 write_x(d, (p_uint)((unsigned *)block - xalloc_overhead()));
2785 WRITES(d, "\n");
2786 break;
2787 }
2788 WRITES(d, "String: ");
2789 show_mstring(d, svp->u.str, 0);
2790 WRITES(d, "\n");
2791 break;
2792
2793 case T_CLOSURE:
2794 if (svp->x.closure_type == CLOSURE_IDENTIFIER)
2795 show_cl_literal(d, (char *)svp->u.lambda, depth);
2796 else
2797 {
2798 WRITES(d, "Closure type ");
2799 writed(d, svp->x.closure_type);
2800 WRITES(d, "\n");
2801 }
2802 break;
2803
2804 case T_OBJECT:
2805 show_object(d, (char *)svp->u.ob, 1);
2806 break;
2807
2808 default:
2809 WRITES(d, "Svalue type ");writed(d, svp->type);WRITES(d, "\n");
2810 break;
2811 }
2812 }
2813 } /* show_struct() */
2814 #endif /* USE_STRUCTS */
2815
2816 /*-------------------------------------------------------------------------*/
2817 void
setup_print_block_dispatcher(void)2818 setup_print_block_dispatcher (void)
2819
2820 /* Setup the tracing data dispatcher in xmalloc with the show_ functions
2821 * above. Remember that the data dispatcher works by storing the file
2822 * and line information of sample allocations. We just have to make sure
2823 * to cover all possible allocation locations (with the string module and
2824 * its pervasive inlining this is not easy).
2825 *
2826 * This is here because I like to avoid xmalloc calling closures, and
2827 * gcollect.c is already notorious for including almost every header file
2828 * anyway.
2829 */
2830
2831 {
2832 svalue_t tmp_closure;
2833 vector_t *a, *b;
2834
2835 assert_master_ob_loaded();
2836
2837 #if 0
2838 /* Since the strings store the location of the call to the function
2839 * which in turn called the string module function, the print
2840 * block dispatcher won't be able to recognize them.
2841 */
2842 store_print_block_dispatch_info(STR_EMPTY, show_mstring);
2843 store_print_block_dispatch_info(STR_EMPTY->str, show_mstring_data);
2844 str = mstring_alloc_string(1);
2845 store_print_block_dispatch_info(str, show_mstring);
2846 store_print_block_dispatch_info(str->str, show_mstring_data);
2847 mstring_free(str);
2848 str = mstring_new_string("\t");
2849 store_print_block_dispatch_info(str, show_mstring);
2850 store_print_block_dispatch_info(str->str, show_mstring_data);
2851 str = mstring_table_inplace(str);
2852 store_print_block_dispatch_info(str->link, show_mstring);
2853 mstring_free(str);
2854 #endif
2855
2856 a = allocate_array(1);
2857 store_print_block_dispatch_info((char *)a, show_array);
2858 b = slice_array(a, 0, 0);
2859 store_print_block_dispatch_info((char *)b, show_array);
2860 free_array(a);
2861 free_array(b);
2862 store_print_block_dispatch_info((char *)master_ob, show_object);
2863 #ifdef CHECK_OBJECT_GC_REF
2864 note_object_allocation_info((char*)master_ob);
2865 note_program_allocation_info((char*)(master_ob->prog));
2866 #endif
2867
2868 tmp_closure.type = T_CLOSURE;
2869 tmp_closure.x.closure_type = CLOSURE_EFUN + F_ALLOCATE;
2870 tmp_closure.u.ob = master_ob;
2871 push_number(inter_sp, 1);
2872 call_lambda(&tmp_closure, 1);
2873 store_print_block_dispatch_info(inter_sp->u.vec, show_array);
2874 free_svalue(inter_sp--);
2875
2876 current_object = master_ob;
2877 #ifdef USE_NEW_INLINES
2878 closure_literal(&tmp_closure, 0, 0, 0);
2879 #else
2880 closure_literal(&tmp_closure, 0, 0);
2881 #endif /* USE_NEW_INLINES */
2882 store_print_block_dispatch_info(tmp_closure.u.lambda, show_cl_literal);
2883 free_svalue(&tmp_closure);
2884 }
2885 #endif /* MALLOC_TRACE */
2886
2887 #endif /* GC_SUPPORT */
2888
2889 /*=========================================================================*/
2890
2891 /* Default functions when the allocator doesn't support GC.
2892 */
2893
2894 #if !defined(GC_SUPPORT)
2895
2896 void
garbage_collection(void)2897 garbage_collection (void)
2898
2899 /* Free as much memory as possible and try to reallocate the
2900 * reserved areas - that's all we can do.
2901 */
2902
2903 {
2904 assert_master_ob_loaded();
2905 handle_newly_destructed_objects();
2906 free_save_object_buffers();
2907 free_interpreter_temporaries();
2908 free_action_temporaries();
2909 #ifdef USE_PGSQL
2910 pg_purge_connections();
2911 #endif /* USE_PGSQL */
2912 remove_stale_player_data();
2913 remove_stale_call_outs();
2914 mb_release();
2915 free_defines();
2916 free_all_local_names();
2917 remove_unknown_identifier();
2918 check_wizlist_for_destr();
2919 cleanup_all_objects();
2920 if (current_error_trace)
2921 {
2922 free_array(current_error_trace);
2923 current_error_trace = NULL;
2924 }
2925 if (uncaught_error_trace)
2926 {
2927 free_array(uncaught_error_trace);
2928 uncaught_error_trace = NULL;
2929 }
2930 remove_destructed_objects(MY_TRUE);
2931
2932 reallocate_reserved_areas();
2933 time_last_gc = time(NULL);
2934 }
2935 #endif /* GC_SUPPORT */
2936
2937
2938 #if !defined(MALLOC_TRACE) || !defined(GC_SUPPORT)
2939
setup_print_block_dispatcher(void)2940 void setup_print_block_dispatcher (void) { NOOP }
2941
2942 #endif
2943
2944 /***************************************************************************/
2945
2946