00001
00002
00003
00004
00005
00006
00007
00008 #ifndef GC_H
00009 #define GC_H
00010
00011 #include "global.h"
00012 #include "callback.h"
00013 #include "queue.h"
00014 #include "threads.h"
00015 #include "interpret.h"
00016 #include "pike_rusage.h"
00017
00018
00019
00020 extern int gc_enabled;
00021
00022
00023
00024
00025 extern double gc_garbage_ratio_low;
00026
00027
00028
00029
00030 extern double gc_time_ratio;
00031
00032
00033
00034
00035 extern double gc_garbage_ratio_high;
00036
00037
00038
00039
00040
00041 extern double gc_average_slowness;
00042
00043
00044
00045
00046 #define GC_MIN_ALLOC_THRESHOLD 1000
00047
00048
00049
00050
00051 #define GC_MAX_ALLOC_THRESHOLD (ALLOC_COUNT_TYPE_MAX - 10000000)
00052
00053
00054
00055
00056
00057
00058
00059
00060 #ifdef INT64
00061 #define ALLOC_COUNT_TYPE INT64
00062 #define ALLOC_COUNT_TYPE_MAX MAX_INT64
00063 #define PRINT_ALLOC_COUNT_TYPE "%"PRINTINT64"d"
00064 #else
00065 #define ALLOC_COUNT_TYPE unsigned long
00066 #define ALLOC_COUNT_TYPE_MAX ULONG_MAX
00067 #define PRINT_ALLOC_COUNT_TYPE "%lu"
00068 #endif
00069
00070 extern INT32 num_objects;
00071 extern ALLOC_COUNT_TYPE num_allocs, alloc_threshold;
00072 PMOD_EXPORT extern int Pike_in_gc;
00073 extern int gc_generation;
00074 extern int gc_trace, gc_debug;
00075 extern cpu_time_t auto_gc_time;
00076
00077 extern struct callback *gc_evaluator_callback;
00078 #ifdef PIKE_DEBUG
00079 extern void *gc_svalue_location;
00080 #endif
00081
00082 #ifdef DO_PIKE_CLEANUP
00083 extern int gc_destruct_everything;
00084 extern int gc_keep_markers;
00085 #else
00086 #define gc_destruct_everything 0
00087 #define gc_keep_markers 0
00088 #endif
00089
00090 #define ADD_GC_CALLBACK() do { if(!gc_evaluator_callback) gc_evaluator_callback=add_to_callback(&evaluator_callbacks,(callback_func)do_gc,0,0); }while(0)
00091
00092 #define LOW_GC_ALLOC(OBJ) do { \
00093 extern int d_flag; \
00094 num_objects++; \
00095 num_allocs++; \
00096 DO_IF_DEBUG( \
00097 if(d_flag) CHECK_INTERPRETER_LOCK(); \
00098 if(Pike_in_gc > GC_PASS_PREPARE && Pike_in_gc < GC_PASS_FREE) \
00099 Pike_fatal("Allocating new objects within gc is not allowed!\n"); \
00100 ) \
00101 if (Pike_in_gc) remove_marker(OBJ); \
00102 } while (0)
00103
00104 #ifdef ALWAYS_GC
00105 #define GC_ALLOC(OBJ) do{ \
00106 LOW_GC_ALLOC(OBJ); \
00107 ADD_GC_CALLBACK(); \
00108 } while(0)
00109 #else
00110 #define GC_ALLOC(OBJ) do{ \
00111 LOW_GC_ALLOC(OBJ); \
00112 if(num_allocs >= alloc_threshold) \
00113 ADD_GC_CALLBACK(); \
00114 } while(0)
00115 #endif
00116
00117 #ifdef PIKE_DEBUG
00118
00119
00120
00121 #define GC_FREE_SIMPLE_BLOCK(PTR) do { \
00122 extern int d_flag; \
00123 if(d_flag) CHECK_INTERPRETER_LOCK(); \
00124 if (Pike_in_gc == GC_PASS_CHECK) \
00125 Pike_fatal("No free is allowed in this gc pass.\n"); \
00126 else \
00127 remove_marker(PTR); \
00128 } while (0)
00129
00130
00131
00132 #define GC_FREE_BLOCK(PTR) do { \
00133 extern int d_flag; \
00134 if(d_flag) CHECK_INTERPRETER_LOCK(); \
00135 if (Pike_in_gc > GC_PASS_PREPARE && Pike_in_gc < GC_PASS_FREE) \
00136 Pike_fatal("Freeing objects within gc is not allowed.\n"); \
00137 } while (0)
00138
00139 #else
00140 #define GC_FREE_SIMPLE_BLOCK(PTR) do {} while (0)
00141 #define GC_FREE_BLOCK(PTR) do {} while (0)
00142 #endif
00143
00144 #define GC_FREE(PTR) do { \
00145 GC_FREE_BLOCK(PTR); \
00146 DO_IF_DEBUG( \
00147 if(num_objects < 1) \
00148 Pike_fatal("Panic!! less than zero objects!\n"); \
00149 ); \
00150 num_objects-- ; \
00151 }while(0)
00152
00153 struct gc_pop_frame;
00154
00155 struct marker
00156 {
00157 struct marker *next;
00158 struct gc_pop_frame *frame;
00159 void *data;
00160 INT32 refs;
00161
00162
00163 INT32 weak_refs;
00164
00165
00166
00167
00168
00169 #ifdef PIKE_DEBUG
00170 INT32 xrefs;
00171
00172 INT32 saved_refs;
00173
00174
00175 unsigned INT32 flags;
00176 #else
00177 unsigned INT16 flags;
00178 #endif
00179 };
00180
00181 #define GC_MARKED 0x0001
00182
00183
00184 #define GC_NOT_REFERENCED 0x0002
00185
00186
00187
00188 #define GC_CYCLE_CHECKED 0x0004
00189
00190 #define GC_LIVE 0x0008
00191
00192
00193
00194 #define GC_LIVE_OBJ 0x0010
00195
00196 #define GC_LIVE_RECURSE 0x0020
00197
00198 #define GC_GOT_DEAD_REF 0x0040
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209 #define GC_FREE_VISITED 0x0080
00210
00211
00212
00213 #define GC_USER_1 0x0100
00214 #define GC_USER_2 0x0200
00215
00216
00217
00218 #define GC_PRETOUCHED 0x4000
00219
00220 #define GC_MIDDLETOUCHED 0x8000
00221
00222
00223 #ifdef PIKE_DEBUG
00224 #define GC_IS_REFERENCED 0x00040000
00225
00226 #define GC_XREFERENCED 0x00080000
00227
00228
00229 #define GC_DO_FREE 0x00100000
00230
00231 #define GC_GOT_EXTRA_REF 0x00200000
00232
00233 #define GC_WEAK_FREED 0x00400000
00234
00235
00236 #define GC_CHECKED_AS_WEAK 0x00800000
00237
00238 #define GC_WATCHED 0x01000000
00239
00240 #define GC_CLEANUP_FREED 0x02000000
00241
00242
00243 #endif
00244
00245 #ifdef PIKE_DEBUG
00246 #define get_marker debug_get_marker
00247 #define find_marker debug_find_marker
00248 #endif
00249
00250 #include "block_alloc_h.h"
00251 PTR_HASH_ALLOC_FIXED_FILL_PAGES(marker, n/a);
00252
00253 #ifdef PIKE_DEBUG
00254 #undef get_marker
00255 #define get_marker(X) ((struct marker *) debug_malloc_pass(debug_get_marker(X)))
00256 #undef find_marker
00257 #define find_marker(X) ((struct marker *) debug_malloc_pass(debug_find_marker(X)))
00258 #endif
00259
00260 extern size_t gc_ext_weak_refs;
00261
00262 typedef void gc_cycle_check_cb (void *data, int weak);
00263
00264
00265 struct gc_frame;
00266 struct callback *debug_add_gc_callback(callback_func call,
00267 void *arg,
00268 callback_func free_func);
00269 void dump_gc_info(void);
00270 int attempt_to_identify(void *something, void **inblock);
00271 void describe_location(void *real_memblock,
00272 int real_type,
00273 void *location,
00274 int indent,
00275 int depth,
00276 int flags);
00277 void debug_gc_fatal(void *a, int flags, const char *fmt, ...);
00278 void low_describe_something(void *a,
00279 int t,
00280 int indent,
00281 int depth,
00282 int flags,
00283 void *inblock);
00284 void describe_something(void *a, int t, int indent, int depth, int flags, void *inblock);
00285 PMOD_EXPORT void describe(void *x);
00286 void debug_describe_svalue(struct svalue *s);
00287 void gc_watch(void *a);
00288 void debug_gc_touch(void *a);
00289 PMOD_EXPORT int real_gc_check(void *a);
00290 int real_gc_check_weak(void *a);
00291 void exit_gc(void);
00292 void locate_references(void *a);
00293 void debug_gc_add_extra_ref(void *a);
00294 void debug_gc_free_extra_ref(void *a);
00295 int debug_gc_is_referenced(void *a);
00296 int gc_mark_external (void *a, const char *place);
00297 void debug_really_free_gc_frame(struct gc_frame *l);
00298 int gc_do_weak_free(void *a);
00299 void gc_delayed_free(void *a, int type);
00300 void debug_gc_mark_enqueue(queue_call call, void *data);
00301 int gc_mark(void *a);
00302 PMOD_EXPORT void gc_cycle_enqueue(gc_cycle_check_cb *checkfn, void *data, int weak);
00303 void gc_cycle_run_queue(void);
00304 int gc_cycle_push(void *x, struct marker *m, int weak);
00305 void do_gc_recurse_svalues(struct svalue *s, int num);
00306 void do_gc_recurse_short_svalue(union anything *u, int type);
00307 int gc_do_free(void *a);
00308 size_t do_gc(void *ignored, int explicit_call);
00309 void f__gc_status(INT32 args);
00310 void cleanup_gc(void);
00311
00312 #if defined (PIKE_DEBUG) && defined (DEBUG_MALLOC)
00313 #define DMALLOC_TOUCH_MARKER(X, EXPR) (get_marker(X), (EXPR))
00314 #else
00315 #define DMALLOC_TOUCH_MARKER(X, EXPR) (EXPR)
00316 #endif
00317
00318 #define gc_check(VP) \
00319 DMALLOC_TOUCH_MARKER(VP, real_gc_check(debug_malloc_pass(VP)))
00320 #define gc_check_weak(VP) \
00321 DMALLOC_TOUCH_MARKER(VP, real_gc_check_weak(debug_malloc_pass(VP)))
00322
00323 #ifdef GC_MARK_DEBUG
00324
00325 void gc_mark_enqueue (queue_call fn, void *data);
00326 void gc_mark_run_queue();
00327 void gc_mark_discard_queue();
00328
00329 #else
00330
00331 extern struct pike_queue gc_mark_queue;
00332 #define gc_mark_enqueue(FN, DATA) enqueue (&gc_mark_queue, (FN), (DATA))
00333 #define gc_mark_run_queue() run_queue (&gc_mark_queue)
00334 #define gc_mark_discard_queue() discard_queue (&gc_mark_queue)
00335
00336 #endif
00337
00338 #if defined (PIKE_DEBUG) || defined (GC_MARK_DEBUG)
00339
00340 extern void *gc_found_in;
00341 extern int gc_found_in_type;
00342 extern const char *gc_found_place;
00343
00344 #define GC_ENTER(THING, TYPE) \
00345 do { \
00346 void *orig_gc_found_in = gc_found_in; \
00347 int orig_gc_found_in_type = gc_found_in_type; \
00348 gc_found_in = (THING); \
00349 gc_found_in_type = (TYPE); \
00350 do
00351
00352 #define GC_LEAVE \
00353 while (0); \
00354 gc_found_in = orig_gc_found_in; \
00355 gc_found_in_type = orig_gc_found_in_type; \
00356 } while (0)
00357
00358 static INLINE int debug_gc_check (void *a, const char *place)
00359 {
00360 int res;
00361 const char *orig_gc_found_place = gc_found_place;
00362 gc_found_place = place;
00363 res = gc_check (a);
00364 gc_found_place = orig_gc_found_place;
00365 return res;
00366 }
00367
00368 static INLINE int debug_gc_check_weak (void *a, const char *place)
00369 {
00370 int res;
00371 const char *orig_gc_found_place = gc_found_place;
00372 gc_found_place = place;
00373 res = gc_check_weak (a);
00374 gc_found_place = orig_gc_found_place;
00375 return res;
00376 }
00377
00378 #define debug_gc_check_svalues(S, NUM, PLACE) \
00379 do { \
00380 const char *orig_gc_found_place = gc_found_place; \
00381 gc_found_place = (PLACE); \
00382 gc_check_svalues ((S), (NUM)); \
00383 gc_found_place = orig_gc_found_place; \
00384 } while (0)
00385
00386 #define debug_gc_check_weak_svalues(S, NUM, PLACE) \
00387 do { \
00388 const char *orig_gc_found_place = gc_found_place; \
00389 gc_found_place = (PLACE); \
00390 gc_check_weak_svalues ((S), (NUM)); \
00391 gc_found_place = orig_gc_found_place; \
00392 } while (0)
00393
00394 #else
00395
00396 #define GC_ENTER(THING, TYPE) do
00397 #define GC_LEAVE while (0)
00398 #define debug_gc_check(X, PLACE) gc_check (X)
00399 #define debug_gc_check_weak(X, PLACE) gc_check_weak (X)
00400 #define debug_gc_check_svalues(S, NUM, PLACE) gc_check_svalues ((S), (NUM))
00401 #define debug_gc_check_weak_svalues(S, NUM, PLACE) gc_check_weak_svalues ((S), (NUM))
00402
00403 #endif
00404
00405 #define gc_fatal \
00406 fprintf(stderr, "%s:%d: GC fatal:\n", __FILE__, __LINE__), debug_gc_fatal
00407
00408 #ifdef PIKE_DEBUG
00409
00410 #define gc_checked_as_weak(X) do { \
00411 get_marker(X)->flags |= GC_CHECKED_AS_WEAK; \
00412 } while (0)
00413 #define gc_assert_checked_as_weak(X) do { \
00414 if (!(find_marker(X)->flags & GC_CHECKED_AS_WEAK)) \
00415 Pike_fatal("A thing was checked as nonweak but " \
00416 "marked or cycle checked as weak.\n"); \
00417 } while (0)
00418 #define gc_assert_checked_as_nonweak(X) do { \
00419 if (find_marker(X)->flags & GC_CHECKED_AS_WEAK) \
00420 Pike_fatal("A thing was checked as weak but " \
00421 "marked or cycle checked as nonweak.\n"); \
00422 } while (0)
00423
00424 #else
00425
00426 #define gc_checked_as_weak(X) do {} while (0)
00427 #define gc_assert_checked_as_weak(X) do {} while (0)
00428 #define gc_assert_checked_as_nonweak(X) do {} while (0)
00429
00430 #endif
00431
00432 #define gc_recurse_svalues(S,N) \
00433 (Pike_in_gc == GC_PASS_CYCLE ? \
00434 gc_cycle_check_svalues((S), (N)) : gc_mark_svalues((S), (N)))
00435 #define gc_recurse_short_svalue(U,T) \
00436 (Pike_in_gc == GC_PASS_CYCLE ? \
00437 gc_cycle_check_short_svalue((U), (T)) : gc_mark_short_svalue((U), (T)))
00438 #define gc_recurse_weak_svalues(S,N) \
00439 (Pike_in_gc == GC_PASS_CYCLE ? \
00440 gc_cycle_check_weak_svalues((S), (N)) : gc_mark_weak_svalues((S), (N)))
00441 #define gc_recurse_weak_short_svalue(U,T) \
00442 (Pike_in_gc == GC_PASS_CYCLE ? \
00443 gc_cycle_check_weak_short_svalue((U), (T)) : gc_mark_weak_short_svalue((U), (T)))
00444
00445 #define GC_RECURSE_THING(V, T) \
00446 (DMALLOC_TOUCH_MARKER(V, Pike_in_gc == GC_PASS_CYCLE) ? \
00447 PIKE_CONCAT(gc_cycle_check_, T)(V, 0) : \
00448 PIKE_CONCAT3(gc_mark_, T, _as_referenced)(V))
00449 #define gc_recurse_array(V) GC_RECURSE_THING((V), array)
00450 #define gc_recurse_mapping(V) GC_RECURSE_THING((V), mapping)
00451 #define gc_recurse_multiset(V) GC_RECURSE_THING((V), multiset)
00452 #define gc_recurse_object(V) GC_RECURSE_THING((V), object)
00453 #define gc_recurse_program(V) GC_RECURSE_THING((V), program)
00454
00455 #ifdef PIKE_DEBUG
00456 #define gc_is_referenced(X) \
00457 DMALLOC_TOUCH_MARKER(X, debug_gc_is_referenced(debug_malloc_pass(X)))
00458 #else
00459 #define gc_is_referenced(X) !(get_marker(X)->flags & GC_NOT_REFERENCED)
00460 #endif
00461
00462 #define add_gc_callback(X,Y,Z) \
00463 dmalloc_touch(struct callback *,debug_add_gc_callback((X),(Y),(Z)))
00464
00465 #ifndef PIKE_DEBUG
00466 #define gc_add_extra_ref(X) (++*(INT32 *)(X))
00467 #define gc_free_extra_ref(X)
00468 #else
00469 #define gc_add_extra_ref(X) debug_gc_add_extra_ref(debug_malloc_pass(X))
00470 #define gc_free_extra_ref(X) debug_gc_free_extra_ref(debug_malloc_pass(X))
00471 #endif
00472
00473 #define GC_PASS_PREPARE 50
00474 #define GC_PASS_PRETOUCH 90
00475 #define GC_PASS_CHECK 100
00476 #define GC_PASS_MARK 200
00477 #define GC_PASS_CYCLE 250
00478 #define GC_PASS_ZAP_WEAK 260
00479 #define GC_PASS_MIDDLETOUCH 270
00480 #define GC_PASS_FREE 300
00481 #define GC_PASS_KILL 400
00482 #define GC_PASS_DESTRUCT 500
00483 #define GC_PASS_POSTTOUCH 510
00484
00485 #define GC_PASS_LOCATE -1
00486 #define GC_PASS_DISABLED -2
00487
00488 #ifdef PIKE_DEBUG
00489 extern int gc_in_cycle_check;
00490 #endif
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506 #define GC_CYCLE_ENTER(X, TYPE, WEAK) do { \
00507 void *_thing_ = (X); \
00508 struct marker *_m_ = get_marker(_thing_); \
00509 if (!(_m_->flags & GC_MARKED)) { \
00510 DO_IF_DEBUG( \
00511 if (gc_in_cycle_check) \
00512 Pike_fatal("Recursing immediately in gc cycle check.\n"); \
00513 gc_in_cycle_check = 1; \
00514 ); \
00515 if (gc_cycle_push(_thing_, _m_, (WEAK))) {
00516
00517 #define GC_CYCLE_ENTER_OBJECT(X, WEAK) do { \
00518 struct object *_thing_ = (X); \
00519 struct marker *_m_ = get_marker(_thing_); \
00520 if (!(_m_->flags & GC_MARKED)) { \
00521 if (_thing_->prog && FIND_LFUN(_thing_->prog, LFUN_DESTROY) != -1) \
00522 _m_->flags |= GC_LIVE|GC_LIVE_OBJ; \
00523 DO_IF_DEBUG( \
00524 if (gc_in_cycle_check) \
00525 Pike_fatal("Recursing immediately in gc cycle check.\n"); \
00526 gc_in_cycle_check = 1; \
00527 ); \
00528 if (gc_cycle_push(_thing_, _m_, (WEAK))) {
00529
00530 #define GC_CYCLE_LEAVE \
00531 } \
00532 DO_IF_DEBUG(gc_in_cycle_check = 0); \
00533 } \
00534 } while (0)
00535
00536 #endif