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.
5c4fc12007-05-13Martin Stjernholm || $Id: module.c,v 1.43 2007/05/13 15:43:07 mast Exp $
e576bb2002-10-11Martin Nilsson */
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 */ #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)  init_cpp(); init_backend(); init_iterators(); init_pike_searching(); init_error(); init_pike_security(); th_init(); init_operators(); init_builtin(); init_builtin_efuns(); init_signals(); init_dynamic_load();
2c660c2005-12-31Martin Nilsson #ifdef WITH_FACETS
6c46a72004-12-29Henrik Grubbström (Grubba)  init_facetgroup();
2c660c2005-12-31Martin Nilsson #endif
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. */ #ifdef AUTO_BIGNUM exit_auto_bignum(); #endif exit_pike_searching(); exit_object(); exit_signals(); 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(); /* This zaps Pike_interpreter.thread_state among other things, so * THREADS_ALLOW/DISALLOW are NOPs beyond this point. */ th_cleanup(); #ifdef SHARED_NODES free(node_hash.table); #endif /* SHARED_NODES */ exit_pike_security(); free_svalue(& throw_value); throw_value.type=T_INT; do_gc(NULL, 1); if (exit_with_cleanup) { int leak_found = 0; #ifdef _REENTRANT if(count_pike_threads()>1) { fprintf(stderr,"Byte counting aborted, because all threads have not exited properly.\n"); 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 * hasn't freed anything. Since we've destructed all objects in * exit_main, nothing should be left after the run above, so only * one more run is necessary. */ 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)  #define REPORT_LINKED_LIST_LEAKS(TYPE, START, STATICS, T_TYPE, NAME) do { \ 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; \
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. */ \
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; \ if (x->refs != m->refs + is_static) { \ if (!leak_found) { \ fputs ("Leak(s) found at exit:\n", stderr); \ leak_found = 1; \ } \ fprintf (stderr, NAME " got %d unaccounted references: ", \ x->refs - (m->refs + is_static)); \ print_short_svalue (stderr, (union anything *) &x, T_TYPE); \ fputc ('\n', stderr); \
fec15e2007-04-25Martin Stjernholm  DO_IF_DMALLOC (debug_malloc_dump_references (x, 2, 1, 0)); \
6c46a72004-12-29Henrik Grubbström (Grubba)  } \ } \ } \ } while (0) REPORT_LINKED_LIST_LEAKS (array, first_array, STATIC_ARRAYS, T_ARRAY, "Array");
b733792006-07-04Martin Stjernholm  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"); REPORT_LINKED_LIST_LEAKS (object, first_object, NOTHING, T_OBJECT, "Object");
fec15e2007-04-25Martin Stjernholm  report_all_type_leaks();
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. */ #if 1 /* It can be a good idea to disable this to leave the blocks * around to be reported by an external memchecker like valgrind. * Ideally we should only free the svalues inside these things but * leave the blocks themselves. */ #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) { \ DO_IF_DEBUG (m->flags |= GC_CLEANUP_FREED); \ 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);
fec15e2007-04-25Martin Stjernholm  free_all_leaked_types();
6c46a72004-12-29Henrik Grubbström (Grubba)  #undef ZAP_LINKED_LIST_LEAKS #ifdef PIKE_DEBUG /* If we stumble on the real refs whose refcounts we've zapped * above we should try to handle it gracefully. */ gc_external_refs_zapped = 1; #endif #endif 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(); #endif }
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  struct lex save_lex; save_lex = lex; lex.current_line=1; lex.current_file=make_shared_string("-");
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);
37b0222002-01-31Marcus Comstedt  free_string(lex.current_file); lex = save_lex;
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) { /* 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. */ 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"); } #endif
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(); #endif
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) }