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