e576bb2002-10-11Martin Nilsson /* || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. */
aedfb12002-10-09Martin Nilsson 
db3e131997-02-06Fredrik Hübinette (Hubbe) #include "global.h"
5267b71995-08-09Fredrik Hübinette (Hubbe) #include "module.h"
bb55f81997-03-16Fredrik Hübinette (Hubbe) #include "pike_macros.h"
b2d3e42000-12-01Fredrik Hübinette (Hubbe) #include "pike_error.h"
db3e131997-02-06Fredrik Hübinette (Hubbe) #include "builtin_functions.h" #include "main.h" #include "svalue.h" #include "interpret.h" #include "stralloc.h" #include "object.h" #include "mapping.h"
992e662000-07-06Fredrik Hübinette (Hubbe) #include "program_id.h"
37b0222002-01-31Marcus Comstedt #include "lex.h"
6c46a72004-12-29Henrik Grubbström (Grubba) #include "pike_security.h"
a6b1142004-12-29Henrik Grubbström (Grubba) #include "cpp.h" #include "backend.h" #include "threads.h" #include "operators.h" #include "signal_handler.h" #include "dynamic_load.h"
faf7fb2004-12-29Henrik Grubbström (Grubba) #include "gc.h" #include "multiset.h" #include "pike_types.h" #include "constants.h"
22c0842005-03-28Martin Nilsson #include "bignum.h" #include "module_support.h"
5267b71995-08-09Fredrik Hübinette (Hubbe) 
db3e131997-02-06Fredrik Hübinette (Hubbe) #include "modules/modlist_headers.h"
9eab532006-02-27Martin Stjernholm #ifndef PRE_PIKE
f173082001-02-01Fredrik Hübinette (Hubbe) #include "post_modules/modlist_headers.h"
9eab532006-02-27Martin Stjernholm #endif
5267b71995-08-09Fredrik Hübinette (Hubbe) 
48073c2003-02-05Henrik Grubbström (Grubba) /* Define this to trace the initialization and cleanup of static modules. */ /* #define TRACE_MODULE */
59f8eb2007-05-18Henrik Grubbström (Grubba) #ifdef PIKE_EXTRA_DEBUG #define TRACE_MAIN #define TRACE_MODULE #endif
48073c2003-02-05Henrik Grubbström (Grubba) #if defined(TRACE_MAIN) || defined(TRACE_MODULE) #define TRACE(X) fprintf X #else /* !TRACE_MAIN */ #define TRACE(X) #endif /* TRACE_MAIN */
24ddc71998-03-28Henrik Grubbström (Grubba) 
6c46a72004-12-29Henrik Grubbström (Grubba) static void init_builtin_modules(void) { void init_iterators(void);
2c660c2005-12-31Martin Nilsson #ifdef WITH_FACETS
6c46a72004-12-29Henrik Grubbström (Grubba)  void init_facetgroup(void);
2c660c2005-12-31Martin Nilsson #endif
6c46a72004-12-29Henrik Grubbström (Grubba) 
d18ea62010-07-19Martin Stjernholm #ifdef DEBUG_MALLOC /* Make some statically allocated structs known to dmalloc. These * will still show up in the DO_PIKE_CLEANUP leak report if they * leak, in spite of dmalloc_accept_leak. */ dmalloc_register (&empty_array, sizeof (empty_array), DMALLOC_LOCATION()); dmalloc_accept_leak (&empty_array); dmalloc_register (&weak_empty_array, sizeof (weak_empty_array), DMALLOC_LOCATION()); dmalloc_accept_leak (&weak_empty_array); #endif
e6e4432007-05-18Henrik Grubbström (Grubba)  TRACE((stderr, "Init cpp...\n"));
6c46a72004-12-29Henrik Grubbström (Grubba)  init_cpp();
e6e4432007-05-18Henrik Grubbström (Grubba)  TRACE((stderr, "Init backend...\n"));
6c46a72004-12-29Henrik Grubbström (Grubba)  init_backend();
e6e4432007-05-18Henrik Grubbström (Grubba)  TRACE((stderr, "Init iterators...\n"));
6c46a72004-12-29Henrik Grubbström (Grubba)  init_iterators();
e6e4432007-05-18Henrik Grubbström (Grubba)  TRACE((stderr, "Init searching...\n"));
6c46a72004-12-29Henrik Grubbström (Grubba)  init_pike_searching();
e6e4432007-05-18Henrik Grubbström (Grubba)  TRACE((stderr, "Init error handling...\n"));
6c46a72004-12-29Henrik Grubbström (Grubba)  init_error();
e6e4432007-05-18Henrik Grubbström (Grubba)  TRACE((stderr, "Init security system...\n"));
6c46a72004-12-29Henrik Grubbström (Grubba)  init_pike_security();
e6e4432007-05-18Henrik Grubbström (Grubba)  TRACE((stderr, "Init threads...\n"));
6c46a72004-12-29Henrik Grubbström (Grubba)  th_init();
e6e4432007-05-18Henrik Grubbström (Grubba)  TRACE((stderr, "Init operators...\n"));
6c46a72004-12-29Henrik Grubbström (Grubba)  init_operators();
e6e4432007-05-18Henrik Grubbström (Grubba)  TRACE((stderr, "Init builtin...\n"));
6c46a72004-12-29Henrik Grubbström (Grubba)  init_builtin();
e6e4432007-05-18Henrik Grubbström (Grubba)  TRACE((stderr, "Init efuns...\n"));
6c46a72004-12-29Henrik Grubbström (Grubba)  init_builtin_efuns();
e6e4432007-05-18Henrik Grubbström (Grubba)  TRACE((stderr, "Init signal handling...\n"));
6c46a72004-12-29Henrik Grubbström (Grubba)  init_signals();
e6e4432007-05-18Henrik Grubbström (Grubba)  TRACE((stderr, "Init dynamic loading...\n"));
6c46a72004-12-29Henrik Grubbström (Grubba)  init_dynamic_load();
2c660c2005-12-31Martin Nilsson #ifdef WITH_FACETS
e6e4432007-05-18Henrik Grubbström (Grubba)  TRACE((stderr, "Init facets...\n"));
6c46a72004-12-29Henrik Grubbström (Grubba)  init_facetgroup();
2c660c2005-12-31Martin Nilsson #endif
ec1d702013-05-27Martin Nilsson  TRACE((stderr, "Init sprintf...\n")); init_sprintf();
6c46a72004-12-29Henrik Grubbström (Grubba) } static void exit_builtin_modules(void) { #ifdef DO_PIKE_CLEANUP void exit_iterators(void);
2c660c2005-12-31Martin Nilsson #ifdef WITH_FACETS
6c46a72004-12-29Henrik Grubbström (Grubba)  void exit_facetgroup(void);
2c660c2005-12-31Martin Nilsson #endif
6c46a72004-12-29Henrik Grubbström (Grubba)  /* Clear various global references. */
ec1d702013-05-27Martin Nilsson  exit_sprintf();
6c46a72004-12-29Henrik Grubbström (Grubba) #ifdef AUTO_BIGNUM exit_auto_bignum(); #endif exit_pike_searching(); exit_object(); exit_signals();
4664532010-05-31Henrik Grubbström (Grubba)  exit_builtin_efuns();
6c46a72004-12-29Henrik Grubbström (Grubba)  exit_builtin(); exit_cpp(); cleanup_interpret(); exit_builtin_constants(); cleanup_module_support(); exit_operators(); exit_iterators();
2c660c2005-12-31Martin Nilsson #ifdef WITH_FACETS
6c46a72004-12-29Henrik Grubbström (Grubba)  exit_facetgroup();
2c660c2005-12-31Martin Nilsson #endif
6c46a72004-12-29Henrik Grubbström (Grubba)  cleanup_program(); cleanup_compiler(); cleanup_error(); exit_backend(); cleanup_gc(); cleanup_pike_types();
09a5732008-08-05Martin Stjernholm #ifdef PIKE_THREADS
6c46a72004-12-29Henrik Grubbström (Grubba)  /* This zaps Pike_interpreter.thread_state among other things, so * THREADS_ALLOW/DISALLOW are NOPs beyond this point. */ th_cleanup();
09a5732008-08-05Martin Stjernholm #endif
c1f4762008-11-02Henrik Grubbström (Grubba)  free_all_pike_list_node_blocks();
6c46a72004-12-29Henrik Grubbström (Grubba)  exit_pike_security(); free_svalue(& throw_value);
1ab4ac2008-01-26Martin Stjernholm  mark_free_svalue (&throw_value);
6c46a72004-12-29Henrik Grubbström (Grubba)  do_gc(NULL, 1); if (exit_with_cleanup) { int leak_found = 0;
09a5732008-08-05Martin Stjernholm #ifdef PIKE_THREADS
f8a04f2008-08-05Martin Stjernholm  if(count_pike_threads())
6c46a72004-12-29Henrik Grubbström (Grubba)  {
4aa6b52008-08-05Martin Stjernholm  fprintf(stderr,"Cleanup-on-exit aborted " "because %d thread(s) still are running.\n", count_pike_threads());
6c46a72004-12-29Henrik Grubbström (Grubba)  exit_with_cleanup = 0; return; } #endif #ifdef DEBUG_MALLOC search_all_memheaders_for_references(); #endif /* The use of markers below only works after a gc run where it
b245af2008-06-23Martin Stjernholm  * hasn't freed anything. Since we've destructed all live objects * in exit_modules, nothing should be left after the run above, so * only one more run is necessary. */
6c46a72004-12-29Henrik Grubbström (Grubba)  gc_keep_markers = 1; do_gc (NULL, 1);
b733792006-07-04Martin Stjernholm #define STATIC_ARRAYS &empty_array, &weak_empty_array,
6c46a72004-12-29Henrik Grubbström (Grubba) 
cd9dfa2008-03-29Martin Stjernholm #define REPORT_LINKED_LIST_LEAKS(TYPE, START, STATICS, T_TYPE, NAME, \ PRINT_EXTRA) do { \
6c46a72004-12-29Henrik Grubbström (Grubba)  struct TYPE *x; \ for (x = START; x; x = x->next) { \ struct marker *m = find_marker (x); \ if (!m) { \ DO_IF_DEBUG ( \ fprintf (stderr, "Didn't find gc marker as expected for:\n"); \ describe_something (x, T_TYPE, 2, 2, 0, NULL); \ ); \ } \ else { \ int is_static = 0; \
59f8eb2007-05-18Henrik Grubbström (Grubba)  /*static const*/ struct TYPE *statics[] = {STATICS NULL}; \
6c46a72004-12-29Henrik Grubbström (Grubba)  ptrdiff_t i; /* Use signed type to avoid warnings from gcc. */ \
b733792006-07-04Martin Stjernholm  for (i = 0; i < (ptrdiff_t) (NELEM (statics) - 1); i++) \
6c46a72004-12-29Henrik Grubbström (Grubba)  if (x == statics[i]) \ is_static = 1; \
97a7332008-03-30Martin Stjernholm  /* Note: m->xrefs is always zero here since the mark pass \ * isn't run in gc_destruct_everything mode. */ \
6c46a72004-12-29Henrik Grubbström (Grubba)  if (x->refs != m->refs + is_static) { \ if (!leak_found) { \ fputs ("Leak(s) found at exit:\n", stderr); \ leak_found = 1; \ } \
97a7332008-03-30Martin Stjernholm  fprintf (stderr, NAME " at %p got %d unaccounted refs " \ "(and %d accounted): ", \ x, x->refs - (m->refs + is_static), \ m->refs + is_static); \
cd9dfa2008-03-29Martin Stjernholm  safe_print_short_svalue (stderr, (union anything *) &x, T_TYPE); \ {PRINT_EXTRA;} \
97a7332008-03-30Martin Stjernholm  fputc ('\n', stderr); \ /* describe (x); */ \
cd9dfa2008-03-29Martin Stjernholm  DO_IF_DMALLOC ( \ debug_malloc_dump_references (x, 2, 1, 0); \ fputc ('\n', stderr); \ ); \
97a7332008-03-30Martin Stjernholm  DO_IF_DEBUG (m->flags |= GC_CLEANUP_LEAKED); \
6c46a72004-12-29Henrik Grubbström (Grubba)  } \ } \ } \ } while (0)
cd9dfa2008-03-29Martin Stjernholm  REPORT_LINKED_LIST_LEAKS (array, first_array, STATIC_ARRAYS, T_ARRAY, "Array", {}); REPORT_LINKED_LIST_LEAKS (multiset, first_multiset, NOTHING, T_MULTISET, "Multiset", {}); REPORT_LINKED_LIST_LEAKS (mapping, first_mapping, NOTHING, T_MAPPING, "Mapping", {}); REPORT_LINKED_LIST_LEAKS ( program, first_program, NOTHING, T_PROGRAM, "Program", { /* This kind of info is rarely useful - the output from * print_short_svalue is usually enough to identify the program, and * the dmalloc ref dump shows where it has been used. DO_IF_DEBUG( struct program *p = (struct program *)x;
97a7332008-03-30Martin Stjernholm  fputc ('\n', stderr);
cd9dfa2008-03-29Martin Stjernholm  if (p->parent) { fprintf(stderr, " Parent is: %p\n", p->parent); dump_program_tables(p->parent, 6); } fprintf(stderr, " Symbol tables:\n"); dump_program_tables(p, 4); ); */ } ); REPORT_LINKED_LIST_LEAKS ( object, first_object, NOTHING, T_OBJECT, "Object", {
97a7332008-03-30Martin Stjernholm  if (!x->prog) { fputs (" (destructed)", stderr); DO_IF_DEBUG ({ struct program *p = id_to_program (x->program_id); if (p) { fputs ("\n Program for destructed object: ", stderr); safe_print_short_svalue (stderr, (union anything *) &p, T_PROGRAM); } else fprintf (stderr, "\n Program for destructed object gone too, " "its id was: %d", x->program_id); }); }
cd9dfa2008-03-29Martin Stjernholm  });
6c46a72004-12-29Henrik Grubbström (Grubba) 
59f8eb2007-05-18Henrik Grubbström (Grubba)  { size_t index; for (index = 0; index < pike_type_hash_size; index++) {
97a7332008-03-30Martin Stjernholm  REPORT_LINKED_LIST_LEAKS(pike_type, pike_type_hash[index], NOTHING, PIKE_T_TYPE, "Type", {});
59f8eb2007-05-18Henrik Grubbström (Grubba)  } }
6c46a72004-12-29Henrik Grubbström (Grubba) #undef REPORT_LINKED_LIST_LEAKS /* Just remove the extra external refs reported above and do * another gc so that we don't report the blocks again in the low * level dmalloc reports. */
97a7332008-03-30Martin Stjernholm #ifdef PIKE_DEBUG /* If we stumble on the real refs whose refcounts we're zapping, * we should try to handle it gracefully, and log all frees. */ gc_external_refs_zapped = 1; #endif
3fd1ea2008-06-02Martin Stjernholm #ifdef VALGRIND_DO_LEAK_CHECK /* Let valgrind print a leak report before we free the leaked * blocks. Ideally we should only free the svalues inside them * below and make the report afterwards. */ VALGRIND_DO_LEAK_CHECK; #endif
6c46a72004-12-29Henrik Grubbström (Grubba)  #define ZAP_LINKED_LIST_LEAKS(TYPE, START, STATICS) do { \ struct TYPE *x, *next; \ for (x = START; x; x = next) { \ struct marker *m = find_marker (x); \ next = x->next; \ if (m) { \ int is_static = 0; \
b733792006-07-04Martin Stjernholm  static const struct TYPE *statics[] = {STATICS NULL}; \
6c46a72004-12-29Henrik Grubbström (Grubba)  ptrdiff_t i; /* Use signed type to avoid warnings from gcc. */ \ INT32 refs; \
b733792006-07-04Martin Stjernholm  for (i = 0; i < (ptrdiff_t) (NELEM (statics) - 1); i++) \
6c46a72004-12-29Henrik Grubbström (Grubba)  if (x == statics[i]) \ is_static = 1; \ refs = x->refs; \ while (refs > m->refs + is_static) { \ PIKE_CONCAT(free_, TYPE) (x); \ refs--; \ } \ } \ } \ } while (0) ZAP_LINKED_LIST_LEAKS (array, first_array, STATIC_ARRAYS);
b733792006-07-04Martin Stjernholm  ZAP_LINKED_LIST_LEAKS (multiset, first_multiset, NOTHING); ZAP_LINKED_LIST_LEAKS (mapping, first_mapping, NOTHING); ZAP_LINKED_LIST_LEAKS (program, first_program, NOTHING); ZAP_LINKED_LIST_LEAKS (object, first_object, NOTHING);
6c46a72004-12-29Henrik Grubbström (Grubba) 
97a7332008-03-30Martin Stjernholm  { size_t index; for (index = 0; index < pike_type_hash_size; index++) { ZAP_LINKED_LIST_LEAKS(pike_type, pike_type_hash[index], NOTHING); } }
6c46a72004-12-29Henrik Grubbström (Grubba) 
97a7332008-03-30Martin Stjernholm #undef ZAP_LINKED_LIST_LEAKS
6c46a72004-12-29Henrik Grubbström (Grubba)  do_gc (NULL, 1); gc_keep_markers = 0; exit_gc(); } destruct_objects_to_destruct_cb(); /* Now there are no arrays/objects/programs/anything left. */ really_clean_up_interpret(); cleanup_callbacks(); free_all_callable_blocks(); exit_destroy_called_mark_hash(); cleanup_pike_type_table(); cleanup_shared_string_table(); free_dynamic_load(); first_mapping=0; free_all_mapping_blocks(); first_object=0; free_all_object_blocks(); first_program=0; free_all_program_blocks(); exit_multiset();
b24c9e2008-06-29Martin Nilsson #endif /* DO_PIKE_CLEANUP */
6c46a72004-12-29Henrik Grubbström (Grubba) }
db3e131997-02-06Fredrik Hübinette (Hubbe) typedef void (*modfun)(void);
5267b71995-08-09Fredrik Hübinette (Hubbe) 
db3e131997-02-06Fredrik Hübinette (Hubbe) struct static_module
5267b71995-08-09Fredrik Hübinette (Hubbe) {
db3e131997-02-06Fredrik Hübinette (Hubbe)  char *name; modfun init; modfun exit; };
5267b71995-08-09Fredrik Hübinette (Hubbe) 
5a59872004-09-19Martin Nilsson static const struct static_module module_list[] = {
6c46a72004-12-29Henrik Grubbström (Grubba)  { "Builtin", init_builtin_modules, exit_builtin_modules }
db3e131997-02-06Fredrik Hübinette (Hubbe) #include "modules/modlist.h"
9eab532006-02-27Martin Stjernholm #ifndef PRE_PIKE
f173082001-02-01Fredrik Hübinette (Hubbe) #include "post_modules/modlist.h"
9eab532006-02-27Martin Stjernholm #endif
db3e131997-02-06Fredrik Hübinette (Hubbe) }; void init_modules(void)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
1cb5d52004-04-14Henrik Grubbström (Grubba)  struct program *p = NULL;
766bc82004-10-16Marcus Agehall  volatile unsigned int e;
37b0222002-01-31Marcus Comstedt 
e021fe2008-04-14Henrik Grubbström (Grubba)  enter_compiler(NULL, 1);
c712e71998-04-23Fredrik Hübinette (Hubbe)  start_new_program();
992e662000-07-06Fredrik Hübinette (Hubbe)  Pike_compiler->new_program->id=PROG___BUILTIN_ID;
db3e131997-02-06Fredrik Hübinette (Hubbe) 
5267b71995-08-09Fredrik Hübinette (Hubbe)  for(e=0;e<NELEM(module_list);e++) {
37b0222002-01-31Marcus Comstedt  JMP_BUF recovery;
1cb5d52004-04-14Henrik Grubbström (Grubba)  if (!p) { start_new_program();
75876b2004-04-14Henrik Grubbström (Grubba)  p = Pike_compiler->new_program;
1cb5d52004-04-14Henrik Grubbström (Grubba)  }
37b0222002-01-31Marcus Comstedt  if(SETJMP(recovery)) {
1cb5d52004-04-14Henrik Grubbström (Grubba)  /* FIXME: We could loop here until we find p. */
37b0222002-01-31Marcus Comstedt  free_program(end_program());
1cb5d52004-04-14Henrik Grubbström (Grubba)  p = NULL;
37b0222002-01-31Marcus Comstedt  call_handle_error(); } else {
48073c2003-02-05Henrik Grubbström (Grubba)  TRACE((stderr, "Initializing static module #%d: \"%s\"...\n", e, module_list[e].name));
37b0222002-01-31Marcus Comstedt  module_list[e].init();
0bd1472004-04-15Henrik Grubbström (Grubba)  if ( #if 0 Pike_compiler->new_program->num_identifier_references #else /* !0 */ 1 #endif /* 0 */ ) {
1cb5d52004-04-14Henrik Grubbström (Grubba)  debug_end_class(module_list[e].name,strlen(module_list[e].name),0); p = NULL; } else { /* No identifier references -- Disabled module. */ }
37b0222002-01-31Marcus Comstedt  } UNSETJMP(recovery);
5267b71995-08-09Fredrik Hübinette (Hubbe)  }
1cb5d52004-04-14Henrik Grubbström (Grubba)  if (p) free_program(end_program());
c712e71998-04-23Fredrik Hübinette (Hubbe)  push_text("_static_modules"); push_object(low_clone(p=end_program())); f_add_constant(2); free_program(p);
e021fe2008-04-14Henrik Grubbström (Grubba)  exit_compiler();
5267b71995-08-09Fredrik Hübinette (Hubbe) }
db3e131997-02-06Fredrik Hübinette (Hubbe) void exit_modules(void)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
37b0222002-01-31Marcus Comstedt  JMP_BUF recovery;
766bc82004-10-16Marcus Agehall  volatile int e;
00538d2003-03-26Martin Nilsson 
bd18892005-01-01Henrik Grubbström (Grubba) #ifdef DO_PIKE_CLEANUP size_t count; if (exit_with_cleanup) {
09a5732008-08-05Martin Stjernholm  /* Kill the threads and destruct all remaining objects while we * have a proper execution environment. The downside is that the * leak report below will always report destructed objects. We use * the gc in a special mode for this to get a reasonably sane * destruct order. */ #ifdef PIKE_THREADS cleanup_all_other_threads(); #endif
bd18892005-01-01Henrik Grubbström (Grubba)  gc_destruct_everything = 1; count = do_gc (NULL, 1); while (count) { size_t new_count = do_gc (NULL, 1); if (new_count >= count) { fprintf (stderr, "Some destroy function is creating new objects " "during final cleanup - can't exit cleanly.\n"); break; } count = new_count; }
14a89b2007-05-13Martin Stjernholm #ifdef PIKE_DEBUG if (!count) { struct object *o; for (o = first_object; o; o = o->next)
5c4fc12007-05-13Martin Stjernholm  if (gc_object_is_live (o))
14a89b2007-05-13Martin Stjernholm  gc_fatal (o, 0, "Object missed in gc_destruct_everything mode.\n"); for (o = objects_to_destruct; o; o = o->next)
5c4fc12007-05-13Martin Stjernholm  if (gc_object_is_live (o))
14a89b2007-05-13Martin Stjernholm  gc_fatal (o, 0, "Object missed in gc_destruct_everything mode" " (is on objects_to_destruct list).\n"); }
b24c9e2008-06-29Martin Nilsson #endif /* PIKE_DEBUG */
bd18892005-01-01Henrik Grubbström (Grubba)  gc_destruct_everything = 0;
ac9b152006-01-25Martin Stjernholm  exit_cleanup_in_progress = 1; /* Warn about object creation from now on. */
bd18892005-01-01Henrik Grubbström (Grubba)  } /* Unload dynamic modules before static ones. */ exit_dynamic_load();
b24c9e2008-06-29Martin Nilsson #endif /* DO_PIKE_CLEANUP */
00538d2003-03-26Martin Nilsson 
db3e131997-02-06Fredrik Hübinette (Hubbe)  for(e=NELEM(module_list)-1;e>=0;e--)
37b0222002-01-31Marcus Comstedt  { if(SETJMP(recovery)) call_handle_error();
48073c2003-02-05Henrik Grubbström (Grubba)  else { TRACE((stderr, "Exiting static module #%d: \"%s\"...\n", e, module_list[e].name));
37b0222002-01-31Marcus Comstedt  module_list[e].exit();
48073c2003-02-05Henrik Grubbström (Grubba)  }
37b0222002-01-31Marcus Comstedt  UNSETJMP(recovery); }
5267b71995-08-09Fredrik Hübinette (Hubbe) }