From 782a8e2e7c69c3d98bd69bcfdbb65ded520576f4 Mon Sep 17 00:00:00 2001 From: Tim Janik Date: Fri, 29 Dec 2000 02:16:51 +0000 Subject: [PATCH] got rid of outdated dmalloc support. provide g_try_malloc() and Thu Dec 28 10:21:46 2000 Tim Janik * gmem.[hc]: got rid of outdated dmalloc support. provide g_try_malloc() and g_try_realloc() which _may_ fail and return NULL. nuked g_mem_check(), provided GMemVTable for memory function virtualization, alterable at program startup with g_mem_set_vtable(). provided glib_mem_profiler_table and g_mem_profile() to support limited profiling information out of the box (uses mprotect() for free()ed areas on linux). provide globally visible G_MEM_ALIGN. buncha cleanups. * docs/macros.txt: file to get a clue about the various configuration macros. * docs/debugging.txt: explain debugging traps. * configure.in: got rid of --enable-mem-check and --enable-mem-profile, define GLIB_SIZEOF_VOID_P and GLIB_SIZEOF_LONG. check malloc prototypes and define SANE_MALLOC_PROTOS is we can use them. * gutils.c, gscanner.c: fix up compatibility warnings, use g_message(). Thu Dec 28 11:36:44 2000 Tim Janik * gbsearcharray.c (upper_power2): disable G_BSEARCH_ALIGN_POWER2 fucntionality if DISABLE_MEM_POOLS is defined. * gtype.c: honour DISABLE_MEM_POOLS. * gsignal.c (g_signal_init): flag signal key bsearch array with G_BSEARCH_ALIGN_POWER2 to avoid excessive growth time. honour DISABLE_MEM_POOLS. * gparam.h: added G_PARAM_READWRITE alias for (G_PARAM_READABLE | G_PARAM_WRITABLE). --- ChangeLog | 24 + ChangeLog.pre-2-0 | 24 + ChangeLog.pre-2-10 | 24 + ChangeLog.pre-2-12 | 24 + ChangeLog.pre-2-2 | 24 + ChangeLog.pre-2-4 | 24 + ChangeLog.pre-2-6 | 24 + ChangeLog.pre-2-8 | 24 + acconfig.h | 1 + configure.in | 73 +- docs/debugging.txt | 28 + docs/macros.txt | 79 ++ docs/reference/glib/tmpl/date.sgml | 118 --- docs/reference/glib/tmpl/glib-unused.sgml | 161 +++- docs/reference/glib/tmpl/modules.sgml | 9 - docs/reference/glib/tmpl/random_numbers.sgml | 38 +- glib/gbsearcharray.c | 4 + glib/gmem.c | 957 +++++++++++-------- glib/gmem.h | 128 +-- glib/gscanner.c | 5 +- glib/gutils.c | 8 +- gmem.c | 957 +++++++++++-------- gmem.h | 128 +-- gobject/ChangeLog | 14 + gobject/gbsearcharray.c | 4 + gobject/gobject.c | 49 +- gobject/gparam.h | 1 + gobject/gsignal.c | 28 +- gobject/gtype.c | 8 +- gscanner.c | 5 +- gutils.c | 8 +- 31 files changed, 1845 insertions(+), 1158 deletions(-) create mode 100644 docs/debugging.txt create mode 100644 docs/macros.txt diff --git a/ChangeLog b/ChangeLog index 94195f140..5a5332673 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +Thu Dec 28 10:21:46 2000 Tim Janik + + * gmem.[hc]: got rid of outdated dmalloc support. provide g_try_malloc() + and g_try_realloc() which _may_ fail and return NULL. + nuked g_mem_check(), provided GMemVTable for memory function + virtualization, alterable at program startup with g_mem_set_vtable(). + provided glib_mem_profiler_table and g_mem_profile() to support limited + profiling information out of the box (uses mprotect() for free()ed areas + on linux). + provide globally visible G_MEM_ALIGN. + buncha cleanups. + + * docs/macros.txt: file to get a clue about the various configuration + macros. + + * docs/debugging.txt: explain debugging traps. + + * configure.in: got rid of --enable-mem-check and --enable-mem-profile, + define GLIB_SIZEOF_VOID_P and GLIB_SIZEOF_LONG. check malloc prototypes + and define SANE_MALLOC_PROTOS is we can use them. + + + * gutils.c, gscanner.c: fix up compatibility warnings, use g_message(). + 2000-12-27 Tor Lillqvist * README.win32: Update. diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index 94195f140..5a5332673 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,27 @@ +Thu Dec 28 10:21:46 2000 Tim Janik + + * gmem.[hc]: got rid of outdated dmalloc support. provide g_try_malloc() + and g_try_realloc() which _may_ fail and return NULL. + nuked g_mem_check(), provided GMemVTable for memory function + virtualization, alterable at program startup with g_mem_set_vtable(). + provided glib_mem_profiler_table and g_mem_profile() to support limited + profiling information out of the box (uses mprotect() for free()ed areas + on linux). + provide globally visible G_MEM_ALIGN. + buncha cleanups. + + * docs/macros.txt: file to get a clue about the various configuration + macros. + + * docs/debugging.txt: explain debugging traps. + + * configure.in: got rid of --enable-mem-check and --enable-mem-profile, + define GLIB_SIZEOF_VOID_P and GLIB_SIZEOF_LONG. check malloc prototypes + and define SANE_MALLOC_PROTOS is we can use them. + + + * gutils.c, gscanner.c: fix up compatibility warnings, use g_message(). + 2000-12-27 Tor Lillqvist * README.win32: Update. diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 94195f140..5a5332673 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,27 @@ +Thu Dec 28 10:21:46 2000 Tim Janik + + * gmem.[hc]: got rid of outdated dmalloc support. provide g_try_malloc() + and g_try_realloc() which _may_ fail and return NULL. + nuked g_mem_check(), provided GMemVTable for memory function + virtualization, alterable at program startup with g_mem_set_vtable(). + provided glib_mem_profiler_table and g_mem_profile() to support limited + profiling information out of the box (uses mprotect() for free()ed areas + on linux). + provide globally visible G_MEM_ALIGN. + buncha cleanups. + + * docs/macros.txt: file to get a clue about the various configuration + macros. + + * docs/debugging.txt: explain debugging traps. + + * configure.in: got rid of --enable-mem-check and --enable-mem-profile, + define GLIB_SIZEOF_VOID_P and GLIB_SIZEOF_LONG. check malloc prototypes + and define SANE_MALLOC_PROTOS is we can use them. + + + * gutils.c, gscanner.c: fix up compatibility warnings, use g_message(). + 2000-12-27 Tor Lillqvist * README.win32: Update. diff --git a/ChangeLog.pre-2-12 b/ChangeLog.pre-2-12 index 94195f140..5a5332673 100644 --- a/ChangeLog.pre-2-12 +++ b/ChangeLog.pre-2-12 @@ -1,3 +1,27 @@ +Thu Dec 28 10:21:46 2000 Tim Janik + + * gmem.[hc]: got rid of outdated dmalloc support. provide g_try_malloc() + and g_try_realloc() which _may_ fail and return NULL. + nuked g_mem_check(), provided GMemVTable for memory function + virtualization, alterable at program startup with g_mem_set_vtable(). + provided glib_mem_profiler_table and g_mem_profile() to support limited + profiling information out of the box (uses mprotect() for free()ed areas + on linux). + provide globally visible G_MEM_ALIGN. + buncha cleanups. + + * docs/macros.txt: file to get a clue about the various configuration + macros. + + * docs/debugging.txt: explain debugging traps. + + * configure.in: got rid of --enable-mem-check and --enable-mem-profile, + define GLIB_SIZEOF_VOID_P and GLIB_SIZEOF_LONG. check malloc prototypes + and define SANE_MALLOC_PROTOS is we can use them. + + + * gutils.c, gscanner.c: fix up compatibility warnings, use g_message(). + 2000-12-27 Tor Lillqvist * README.win32: Update. diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index 94195f140..5a5332673 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,27 @@ +Thu Dec 28 10:21:46 2000 Tim Janik + + * gmem.[hc]: got rid of outdated dmalloc support. provide g_try_malloc() + and g_try_realloc() which _may_ fail and return NULL. + nuked g_mem_check(), provided GMemVTable for memory function + virtualization, alterable at program startup with g_mem_set_vtable(). + provided glib_mem_profiler_table and g_mem_profile() to support limited + profiling information out of the box (uses mprotect() for free()ed areas + on linux). + provide globally visible G_MEM_ALIGN. + buncha cleanups. + + * docs/macros.txt: file to get a clue about the various configuration + macros. + + * docs/debugging.txt: explain debugging traps. + + * configure.in: got rid of --enable-mem-check and --enable-mem-profile, + define GLIB_SIZEOF_VOID_P and GLIB_SIZEOF_LONG. check malloc prototypes + and define SANE_MALLOC_PROTOS is we can use them. + + + * gutils.c, gscanner.c: fix up compatibility warnings, use g_message(). + 2000-12-27 Tor Lillqvist * README.win32: Update. diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 94195f140..5a5332673 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,27 @@ +Thu Dec 28 10:21:46 2000 Tim Janik + + * gmem.[hc]: got rid of outdated dmalloc support. provide g_try_malloc() + and g_try_realloc() which _may_ fail and return NULL. + nuked g_mem_check(), provided GMemVTable for memory function + virtualization, alterable at program startup with g_mem_set_vtable(). + provided glib_mem_profiler_table and g_mem_profile() to support limited + profiling information out of the box (uses mprotect() for free()ed areas + on linux). + provide globally visible G_MEM_ALIGN. + buncha cleanups. + + * docs/macros.txt: file to get a clue about the various configuration + macros. + + * docs/debugging.txt: explain debugging traps. + + * configure.in: got rid of --enable-mem-check and --enable-mem-profile, + define GLIB_SIZEOF_VOID_P and GLIB_SIZEOF_LONG. check malloc prototypes + and define SANE_MALLOC_PROTOS is we can use them. + + + * gutils.c, gscanner.c: fix up compatibility warnings, use g_message(). + 2000-12-27 Tor Lillqvist * README.win32: Update. diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 94195f140..5a5332673 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,27 @@ +Thu Dec 28 10:21:46 2000 Tim Janik + + * gmem.[hc]: got rid of outdated dmalloc support. provide g_try_malloc() + and g_try_realloc() which _may_ fail and return NULL. + nuked g_mem_check(), provided GMemVTable for memory function + virtualization, alterable at program startup with g_mem_set_vtable(). + provided glib_mem_profiler_table and g_mem_profile() to support limited + profiling information out of the box (uses mprotect() for free()ed areas + on linux). + provide globally visible G_MEM_ALIGN. + buncha cleanups. + + * docs/macros.txt: file to get a clue about the various configuration + macros. + + * docs/debugging.txt: explain debugging traps. + + * configure.in: got rid of --enable-mem-check and --enable-mem-profile, + define GLIB_SIZEOF_VOID_P and GLIB_SIZEOF_LONG. check malloc prototypes + and define SANE_MALLOC_PROTOS is we can use them. + + + * gutils.c, gscanner.c: fix up compatibility warnings, use g_message(). + 2000-12-27 Tor Lillqvist * README.win32: Update. diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 94195f140..5a5332673 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,27 @@ +Thu Dec 28 10:21:46 2000 Tim Janik + + * gmem.[hc]: got rid of outdated dmalloc support. provide g_try_malloc() + and g_try_realloc() which _may_ fail and return NULL. + nuked g_mem_check(), provided GMemVTable for memory function + virtualization, alterable at program startup with g_mem_set_vtable(). + provided glib_mem_profiler_table and g_mem_profile() to support limited + profiling information out of the box (uses mprotect() for free()ed areas + on linux). + provide globally visible G_MEM_ALIGN. + buncha cleanups. + + * docs/macros.txt: file to get a clue about the various configuration + macros. + + * docs/debugging.txt: explain debugging traps. + + * configure.in: got rid of --enable-mem-check and --enable-mem-profile, + define GLIB_SIZEOF_VOID_P and GLIB_SIZEOF_LONG. check malloc prototypes + and define SANE_MALLOC_PROTOS is we can use them. + + + * gutils.c, gscanner.c: fix up compatibility warnings, use g_message(). + 2000-12-27 Tor Lillqvist * README.win32: Update. diff --git a/acconfig.h b/acconfig.h index c923979ac..c048af23c 100644 --- a/acconfig.h +++ b/acconfig.h @@ -44,3 +44,4 @@ ignoring punctuation (such as underscores). */ #undef USE_LIBICONV +#undef SANE_MALLOC_PROTOS diff --git a/configure.in b/configure.in index b0174ee68..afe2fe285 100644 --- a/configure.in +++ b/configure.in @@ -102,8 +102,6 @@ esac[]dnl dnl declare --enable-* args and collect ac_help strings AC_ARG_ENABLE(debug, [ --enable-debug=[no/minimum/yes] turn on debugging [default=$debug_default]],,enable_debug=$debug_default) AC_ARG_ENABLE(msg-prefix, [ --enable-msg-prefix turn on program name and PID prefixing of messages and warnings],,enable_msg_prefix=no) -AC_ARG_ENABLE(mem_check, [ --enable-mem-check turn on malloc/free sanity checking [default=no]],,enable_mem_check=no) -AC_ARG_ENABLE(mem_profile, [ --enable-mem-profile turn on malloc profiling atexit [default=no]],,enable_mem_profile=no) AC_ARG_ENABLE(gc_friendly, [ --enable-gc-friendly turn on garbage collector friendliness [default=no]],,enable_gc_friendly=no) AC_ARG_ENABLE(mem_pools, [ --disable-mem-pools disable all glib memory pools],,disable_mem_pools=no) AC_ARG_ENABLE(ansi, [ --enable-ansi turn on strict ansi [default=no]], @@ -116,23 +114,17 @@ if test "x$enable_threads" != "xyes"; then enable_threads=no fi -AC_MSG_CHECKING(whether to enable memory checking) -if test "x$enable_mem_check" = "xyes"; then - AC_DEFINE(ENABLE_MEM_CHECK, 1, [Whether to enable memory checking]) - AC_SUBST(ENABLE_MEM_CHECK) - AC_MSG_RESULT(yes) +if test "x$enable_debug" = "xyes"; then + test "$cflags_set" = set || CFLAGS="$CFLAGS -g" + GLIB_DEBUG_FLAGS="-DG_ENABLE_DEBUG" else - AC_MSG_RESULT(no) + if test "x$enable_debug" = "xno"; then + GLIB_DEBUG_FLAGS="-DG_DISABLE_ASSERT -DG_DISABLE_CHECKS" + fi fi -AC_MSG_CHECKING(whether to enable memory profiling) -if test "x$enable_mem_profile" = "xyes"; then - AC_DEFINE(ENABLE_MEM_PROFILE, 1, [Whether to enable memory profiling]) - AC_SUBST(ENABLE_MEM_PROFILE) - AC_MSG_RESULT(yes) -else - AC_MSG_RESULT(no) -fi +AC_DEFINE_UNQUOTED(G_COMPILED_WITH_DEBUGGING, "${enable_debug}", + [Whether glib was compiled with debugging enabled]) AC_MSG_CHECKING(whether to enable garbage collector friendliness) if test "x$enable_gc_friendly" = "xyes"; then @@ -152,19 +144,6 @@ else AC_MSG_RESULT(yes) fi - -if test "x$enable_debug" = "xyes"; then - test "$cflags_set" = set || CFLAGS="$CFLAGS -g" - GLIB_DEBUG_FLAGS="-DG_ENABLE_DEBUG" -else - if test "x$enable_debug" = "xno"; then - GLIB_DEBUG_FLAGS="-DG_DISABLE_ASSERT -DG_DISABLE_CHECKS" - fi -fi - -AC_DEFINE_UNQUOTED(G_COMPILED_WITH_DEBUGGING, "${enable_debug}", - [Whether glib was compiled with debugging enabled]) - if test "x$enable_msg_prefix" = "xyes"; then AC_DEFINE_UNQUOTED(G_ENABLE_MSG_PREFIX, 1, [Enable prefixing of error messages with program names]) @@ -290,6 +269,33 @@ dnl long doubles were not used, and a portability problem dnl AC_C_LONG_DOUBLE AC_C_CONST +dnl ok, here we try to check whether the systems prototypes for +dnl malloc and friends actually match the prototypes provided +dnl by gmem.h (keep in sync). i currently only know how to check +dnl this reliably with gcc (-Werror), improvements for other +dnl compilers are apprechiated. +SANE_MALLOC_PROTOS=no +AC_MSG_CHECKING([if malloc() and friends prototypes are gmem.h compatible]) +glib_save_CFLAGS=$CFLAGS +if test "x$GCC" = "xyes"; then + CFLAGS="$CFLAGS -Werror" + AC_TRY_COMPILE([#include ], [ + void* (*my_calloc_p) (size_t, size_t) = calloc; + void* (*my_malloc_p) (size_t) = malloc; + void (*my_free_p) (void*) = free; + void* (*my_realloc_p) (void*, size_t) = realloc; + my_calloc_p = 0; + my_malloc_p = 0; + my_free_p = 0; + my_realloc_p = 0; + ], + AC_DEFINE(SANE_MALLOC_PROTOS) + SANE_MALLOC_PROTOS=yes) +fi +AC_MSG_RESULT($SANE_MALLOC_PROTOS) +CFLAGS=$glib_save_CFLAGS + + dnl AC_C_INLINE is useless to us since it bails out too early, we need to dnl truely know which ones of `inline', `__inline' and `__inline__' are dnl actually supported. @@ -1374,6 +1380,13 @@ _______EOF fi fi + cat >>$outfile <<_______EOF + +#define GLIB_SIZEOF_VOID_P $glib_void_p +#define GLIB_SIZEOF_LONG $glib_long + +_______EOF + case x$glib_size_t in x2) echo "typedef gint16 gssize;" >> $outfile echo "typedef guint16 gsize;" >> $outfile @@ -1625,6 +1638,8 @@ $ac_cv_sizeof_long_long) ;; esac glib_size_t=$glib_cv_sizeof_size_t +glib_void_p=$ac_cv_sizeof_long +glib_long=$ac_cv_sizeof_void_p gintbits=`expr $ac_cv_sizeof_int \* 8` glongbits=`expr $ac_cv_sizeof_long \* 8` diff --git a/docs/debugging.txt b/docs/debugging.txt new file mode 100644 index 000000000..6f3bca1cc --- /dev/null +++ b/docs/debugging.txt @@ -0,0 +1,28 @@ + + +G_BREAKPOINT () traps for the debugger +====================================== + +Some code portions contain trap variables that can be set during +debugging time if G_ENABLE_DEBUG has been defined upon compilation +(use the --enable-debug=yes option to configure for this, macros.txt +covers more details). +Such traps lead to immediate code halts to examine the current +program state and backtrace. +Currently, the following trap variables exist: + +static volatile gulong glib_trap_free_size; +static volatile gulong glib_trap_realloc_size; +static volatile gulong glib_trap_malloc_size; + If set to a size > 0, g_free(), g_realloc() and g_malloc() + respectively, will be intercepted if the size matches the + size of the corresponding memory block to free/reallocate/allocate. + This will only work with g_mem_set_vtable (glib_mem_profiler_table) + upon startup though, because memory profiling is required to match + on the memory block sizes. +static volatile GObject *glib_trap_object_ref; + If set to a valid object pointer, ref/unref will be intercepted + with G_BREAKPOINT (); + + +2000/12/28 Tim Janik diff --git a/docs/macros.txt b/docs/macros.txt new file mode 100644 index 000000000..b9f1fca89 --- /dev/null +++ b/docs/macros.txt @@ -0,0 +1,79 @@ + + +GLib's configure options and corresponding macros +================================================= + +--enable-debug=no + -DG_DISABLE_ASSERT -DG_DISABLE_CHECKS +--enable-debug=minimum [default for stable branches] + none +--enable-debug=yes [default for development branches] + -DG_ENABLE_DEBUG -g +--enable-gc-friendly=yes + #define ENABLE_GC_FRIENDLY 1 +--disable-mem-pools=yes + #define DISABLE_MEM_POOLS 1 + +Besides these, there are some local feature specific options, but my main +focus here is to concentrate on macros that affect overall GLib behaviour +and/or third party code. + + +Notes on GLib's internal and global macros +========================================== + + +ENABLE_GC_FRIENDLY + Newly allocated memory that isn't directly initialized, as well + as memory being freed should be reset to 0. The point here is to + allow memory checkers and similar programs that use bohem GC alike + algorithms to produce more accurate results. +DISABLE_MEM_POOLS + Many small chunks of memory are often allocated via collective pools + in GLib and are cached after release to speed up reallocations. + For sparse memory systems this behaviour is often inferior, so + memory pools can be disabled to avoid excessive caching and force + atomic maintenance of chunks through the g_malloc/g_free. + Code currently affected by this macro: + - GList, GSList, GNode allocations + - GMemChunks become basically non-effective + - GSignal disables all caching (potentially very slow) + - GType doesn't honour the GTypeInfo n_preallocs field anymore + - the GBSearchArray flag G_BSEARCH_ALIGN_POWER2 becomes non-functional +G_DISABLE_ASSERT + The g_assert() and g_assert_not_reached() become non-functional + with this define. The motivation is to speed up end-user apps by + avoiding expensive checks. + This macro can affect third-party code. --enable-debug=no will only + disable the assertion macros for GLib itself, but third-party code + that passes -DG_DISABLE_ASSERT to the compiler upon its own build + will end up with the non-functional variants after including glib.h + as well. + NOTE: Code inside the assertion macros should not have side effects + that affect the operation of the program. +G_DISABLE_CHECKS + This macro is similar to G_DISABLE_ASSERT, it affects third-party + code as mentioned above and the NOTE about G_DISABLE_ASSERT applies + too. The macros that become non-functional here are + g_return_if_fail(), g_return_val_if_fail(), g_return_if_reached() and + g_return_val_if_reached(). + Additionally the glib_mem_profiler_table and g_mem_profile() from + gmem.h become non-functional if this macro is supplied. + This macro also switches off certain checks in the GSignal code. +G_ENABLE_DEBUG + Quite a bit of additional debugging code is compiled into GLib for this + macro, and since it is a globally visible define, third-party code may + be affected by it similar to G_DISABLE_ASSERT. + The additional code executed/compiled for this macro currently involve: + - extra validity checks for GDate + - memory profiling traps in gmem.c (consult debugging.txt for details) + - BREAKPOINT abortion for fatal log levels in gmessage.c instead of + plain abort() to allow debuggers trapping and overriding them + - added verbosity of gscanner.c to catch deprecated code paths + - added verbosity of gutils.c to catch deprecated code paths + - object ref/unref traps (consult debugging.txt) and object bookkeeping + in gobject.c + - extra validity checks in gsignal.c + + +2000/12/28 Tim Janik diff --git a/docs/reference/glib/tmpl/date.sgml b/docs/reference/glib/tmpl/date.sgml index 60f27af09..4f35e5227 100644 --- a/docs/reference/glib/tmpl/date.sgml +++ b/docs/reference/glib/tmpl/date.sgml @@ -422,74 +422,6 @@ dates must be valid. greater than zero if @lhs is greater than @rhs - - -Return the day of the month; the #GDate must be valid. - - -@date: Date to extract the day of the month from -@Returns: Day of the month - - - - -Accessor for the month of the year. Date must be valid. - - -@date: Date to get the month from -@Returns: A #GDateMonth - - - - -Accessor; returns the year of a #GDate. The date must be valid. - - -@date: Date -@Returns: Year in which the date falls - - - - -Accessor, returns the Julian day or "serial number" of the #GDate. The -Julian day is simply the number of days since January 1, Year 1; i.e., -January 1, Year 1 is Julian day 1; January 2, Year 1 is Julian day 2, -etc. Date must be valid. - - -@date: Date to extract the Julian day from -@Returns: Julian day - - - - -Returns the day of the week for a #GDate. The date must be valid. - - -@date: Date -@Returns: Day of the week as a #GDateWeekday - - - - -Return the day of the year, where Jan 1 is the first day of the -year. Date must be valid. - - -@date: Date to extract day of year from -@Returns: Day of the year - - - - -Return the number of days in a month, taking leap years into account. - - -@month: Month -@year: Year -@Returns: Number of days in @month during the year @year. - - Returns TRUE if the date is on the first of a month. Date must be valid. @@ -517,56 +449,6 @@ Returns TRUE if the year is a leap year @Returns: Boolean, if the year is a leap year - - -Return the week of the year, where weeks are understood to start on -Monday. If the date is before the first Monday of the year, return -0. Date must be valid. - - -@date: Date to use -@Returns: Week of the year - - - - -Return the number of weeks in the year, where weeks are taken to start -on Monday. Will be 52 or 53. Date must be valid. (Years always have 52 -7-day periods, plus 1 or 2 extra days depending on whether it's a leap -year. This function is basically telling you how many Mondays are in -the year, i.e. there are 53 Mondays if one of the extra days happens -to be a Monday.) - - -@year: Year -@Returns: Number of Mondays in the year - - - - -Week of the year during which this date falls, if weeks are understood -to being on Sunday. Date must be valid. Can return 0 if the day is -before the first Sunday of the year. - - -@date: Date -@Returns: Week number - - - - -Return the number of weeks in the year, where weeks are taken to start -on Sunday. Will be 52 or 53. Date must be valid. (Years always have 52 -7-day periods, plus 1 or 2 extra days depending on whether it's a leap -year. This function is basically telling you how many Sundays are in -the year, i.e. there are 53 Sundays if one of the extra days happens -to be a Sunday.) - - -@year: Year to count weeks in -@Returns: Number of weeks - - Generate a printed representation of the date, in a locale-specific diff --git a/docs/reference/glib/tmpl/glib-unused.sgml b/docs/reference/glib/tmpl/glib-unused.sgml index f22b1e7aa..877be2d3c 100644 --- a/docs/reference/glib/tmpl/glib-unused.sgml +++ b/docs/reference/glib/tmpl/glib-unused.sgml @@ -1,3 +1,11 @@ + + +Return the day of the month; the #GDate must be valid. + + +@date: Date to extract the day of the month from +@Returns: Day of the month + @@ -24,6 +32,19 @@ @callback_data: @callback_funcs: + + +Return the number of weeks in the year, where weeks are taken to start +on Sunday. Will be 52 or 53. Date must be valid. (Years always have 52 +7-day periods, plus 1 or 2 extra days depending on whether it's a leap +year. This function is basically telling you how many Sundays are in +the year, i.e. there are 53 Sundays if one of the extra days happens +to be a Sunday.) + + +@year: Year to count weeks in +@Returns: Number of weeks + @@ -55,6 +76,26 @@ @source: @can_recurse: + + +Return the number of days in a month, taking leap years into account. + + +@month: Month +@year: Year +@Returns: Number of days in @month during the year @year. + + + +Accessor, returns the Julian day or "serial number" of the #GDate. The +Julian day is simply the number of days since January 1, Year 1; i.e., +January 1, Year 1 is Julian day 1; January 2, Year 1 is Julian day 2, +etc. Date must be valid. + + +@date: Date to extract the Julian day from +@Returns: Julian day + @@ -192,6 +233,16 @@ See #G_PRIORITY_DEFAULT, #G_PRIORITY_DEFAULT_IDLE, #G_PRIORITY_HIGH, @struct_size: @Returns: + + +Return the week of the year, where weeks are understood to start on +Monday. If the date is before the first Monday of the year, return +0. Date must be valid. + + +@date: Date to use +@Returns: Week of the year + @@ -225,6 +276,14 @@ type of source. @source: @Returns: + + +Accessor; returns the year of a #GDate. The date must be valid. + + +@date: Date +@Returns: Year in which the date falls + @@ -233,6 +292,14 @@ type of source. @tmpl: @Returns: + + +Accessor for the month of the year. Date must be valid. + + +@date: Date to get the month from +@Returns: A #GDateMonth + @@ -255,14 +322,6 @@ type of source. - - - - - -@source: -@timeval: - @@ -272,6 +331,14 @@ type of source. @s2: @Returns: + + + + + +@source: +@timeval: + @@ -309,6 +376,14 @@ type of source. @array: @compare_func: + + +Expands to the proper shared library suffix for the current platform +without the leading dot. For the most Unices and Linux this is "so", +for some HPUX versions this is "sl" and for Windows this is "dll". + + + @@ -387,6 +462,15 @@ type of source. @source: @fd: + + +Return the day of the year, where Jan 1 is the first day of the +year. Date must be valid. + + +@date: Date to extract day of year from +@Returns: Day of the year + @@ -446,6 +530,16 @@ type of source. @priority: @Returns: + + +Week of the year during which this date falls, if weeks are understood +to being on Sunday. Date must be valid. Can return 0 if the day is +before the first Sunday of the year. + + +@date: Date +@Returns: Week number + @@ -473,6 +567,19 @@ type of source. @user_data: @Returns: + + +Return the number of weeks in the year, where weeks are taken to start +on Monday. Will be 52 or 53. Date must be valid. (Years always have 52 +7-day periods, plus 1 or 2 extra days depending on whether it's a leap +year. This function is basically telling you how many Mondays are in +the year, i.e. there are 53 Mondays if one of the extra days happens +to be a Monday.) + + +@year: Year +@Returns: Number of Mondays in the year + @@ -496,6 +603,15 @@ type of source. + + +Return a random #gboolean from @rand. This corresponds to a unbiased +coin toss. + + +@rand: a #GRand. +@Returns: a random #gboolean. + @@ -540,13 +656,6 @@ Removes a file descriptor from the list being polled. - - -Turns the argument into a string literal by using the '#' stringizing operator. - - -@x: text to convert to a literal string. - @@ -554,6 +663,13 @@ Turns the argument into a string literal by using the '#' stringizing operator. @Returns: + + +Turns the argument into a string literal by using the '#' stringizing operator. + + +@x: text to convert to a literal string. + @@ -576,6 +692,14 @@ Turns the argument into a string literal by using the '#' stringizing operator. @loop: + + +Returns the day of the week for a #GDate. The date must be valid. + + +@date: Date +@Returns: Day of the week as a #GDateWeekday + @@ -611,6 +735,13 @@ There are no flags right now @G_MARKUP_DO_NOT_USE_THIS_UNSUPPORTED_FLAG: + + +Return a random #gboolean. This corresponds to a unbiased coin toss. + + +@Returns: a random #gboolean. + diff --git a/docs/reference/glib/tmpl/modules.sgml b/docs/reference/glib/tmpl/modules.sgml index 0719be68d..8e5b3498b 100644 --- a/docs/reference/glib/tmpl/modules.sgml +++ b/docs/reference/glib/tmpl/modules.sgml @@ -195,15 +195,6 @@ It is passed the #GModule structure. @module: the module about to be unloaded. - - -Expands to the proper shared library suffix for the current platform -without the leading dot. For the most Unices and Linux this is "so", -for some HPUX versions this is "sl" and for Windows this is "dll". - - - - Used to declare functions exported by modules. diff --git a/docs/reference/glib/tmpl/random_numbers.sgml b/docs/reference/glib/tmpl/random_numbers.sgml index 4282c5243..aa91b93b0 100644 --- a/docs/reference/glib/tmpl/random_numbers.sgml +++ b/docs/reference/glib/tmpl/random_numbers.sgml @@ -70,16 +70,6 @@ accessed through the g_rand_* functions. @seed: - - -Return a random #gboolean from @rand. This corresponds to a unbiased -coin toss. - - -@rand: a #GRand. -@Returns: a random #gboolean. - - @@ -91,9 +81,12 @@ coin toss. @rand: +@min: +@max: +@Returns: + @begin: @end: -@Returns: @@ -107,9 +100,12 @@ coin toss. @rand: +@min: +@max: +@Returns: + @begin: @end: -@Returns: @@ -118,14 +114,6 @@ coin toss. @seed: - - -Return a random #gboolean. This corresponds to a unbiased coin toss. - - -@Returns: a random #gboolean. - - @@ -135,9 +123,12 @@ Return a random #gboolean. This corresponds to a unbiased coin toss. +@min: +@max: +@Returns: + @begin: @end: -@Returns: @@ -149,8 +140,11 @@ Return a random #gboolean. This corresponds to a unbiased coin toss. +@min: +@max: +@Returns: + @begin: @end: -@Returns: diff --git a/glib/gbsearcharray.c b/glib/gbsearcharray.c index 199115300..dbba47c9b 100644 --- a/glib/gbsearcharray.c +++ b/glib/gbsearcharray.c @@ -27,7 +27,11 @@ static inline guint upper_power2 (guint number) { +#ifdef DISABLE_MEM_POOLS + return number; +#else /* !DISABLE_MEM_POOLS */ return number ? 1 << g_bit_storage (number - 1) : 0; +#endif /* !DISABLE_MEM_POOLS */ } static inline gpointer diff --git a/glib/gmem.c b/glib/gmem.c index 73e01a993..b0909a0dc 100644 --- a/glib/gmem.c +++ b/glib/gmem.c @@ -36,50 +36,533 @@ #include #include "glib.h" -/* #define ENABLE_MEM_PROFILE */ -/* #define ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS */ -/* #define ENABLE_MEM_CHECK */ -#define MEM_PROFILE_TABLE_SIZE 8192 -/* - * This library can check for some attempts to do illegal things to - * memory (ENABLE_MEM_CHECK), and can do profiling - * (ENABLE_MEM_PROFILE). Both features are implemented by storing - * words before the start of the memory chunk. - * - * The first, at offset -2*SIZEOF_LONG, is used only if - * ENABLE_MEM_CHECK is set, and stores 0 after the memory has been - * allocated and 1 when it has been freed. The second, at offset - * -SIZEOF_LONG, is used if either flag is set and stores the size of - * the block. - * - * The MEM_CHECK flag is checked when memory is realloc'd and free'd, - * and it can be explicitly checked before using a block by calling - * g_mem_check(). +/* notes on macros: + * having DISABLE_MEM_POOLS defined, disables mem_chunks alltogether, their + * allocations are performed through ordinary g_malloc/g_free. + * having G_DISABLE_CHECKS defined disables use of glib_mem_profiler_table and + * g_mem_profile(). + * REALLOC_0_WORKS is defined if g_realloc (NULL, x) works. + * SANE_MALLOC_PROTOS is defined if the systems malloc() and friends functions + * match the corresponding GLib prototypes, keep configure.in and gmem.h in sync here. + * if ENABLE_GC_FRIENDLY is defined, freed memory should be 0-wiped. */ -#if defined(ENABLE_MEM_PROFILE) && defined(ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS) -#define ENTER_MEM_CHUNK_ROUTINE() \ - g_private_set (allocating_for_mem_chunk, \ - g_private_get (allocating_for_mem_chunk) + 1) -#define LEAVE_MEM_CHUNK_ROUTINE() \ - g_private_set (allocating_for_mem_chunk, \ - g_private_get (allocating_for_mem_chunk) - 1) -#else -#define ENTER_MEM_CHUNK_ROUTINE() -#define LEAVE_MEM_CHUNK_ROUTINE() -#endif - +#define MEM_PROFILE_TABLE_SIZE 4096 #define MEM_AREA_SIZE 4L -#if SIZEOF_VOID_P > SIZEOF_LONG -#define MEM_ALIGN SIZEOF_VOID_P -#else -#define MEM_ALIGN SIZEOF_LONG -#endif +#ifdef G_DISABLE_CHECKS +# define ENTER_MEM_CHUNK_ROUTINE() +# define LEAVE_MEM_CHUNK_ROUTINE() +# define IN_MEM_CHUNK_ROUTINE() FALSE +#else /* !G_DISABLE_CHECKS */ +static GPrivate* mem_chunk_recursion = NULL; +# define MEM_CHUNK_ROUTINE_COUNT() GPOINTER_TO_UINT (g_private_get (mem_chunk_recursion)) +# define ENTER_MEM_CHUNK_ROUTINE() g_private_set (mem_chunk_recursion, GUINT_TO_POINTER (MEM_CHUNK_ROUTINE_COUNT () + 1)) +# define LEAVE_MEM_CHUNK_ROUTINE() g_private_set (mem_chunk_recursion, GUINT_TO_POINTER (MEM_CHUNK_ROUTINE_COUNT () - 1)) +#endif /* !G_DISABLE_CHECKS */ + +#ifndef REALLOC_0_WORKS +static gpointer +standard_realloc (gpointer mem, + gsize n_bytes) +{ + if (!mem) + return malloc (n_bytes); + else + return realloc (mem, n_bytes); +} +#endif /* !REALLOC_0_WORKS */ + +#ifdef SANE_MALLOC_PROTOS +# define standard_malloc malloc +# ifdef REALLOC_0_WORKS +# define standard_realloc realloc +# endif /* REALLOC_0_WORKS */ +# define standard_free free +# define standard_calloc calloc +# define standard_try_malloc malloc +# define standard_try_realloc realloc +#else /* !SANE_MALLOC_PROTOS */ +static gpointer +standard_malloc (gsize n_bytes) +{ + return malloc (n_bytes); +} +# ifdef REALLOC_0_WORKS +static gpointer +standard_realloc (gpointer mem, + gsize n_bytes) +{ + return realloc (mem, n_bytes); +} +# endif /* REALLOC_0_WORKS */ +static void +standard_free (gpointer mem) +{ + return free (mem); +} +static gpointer +standard_calloc (gsize n_blocks, + gsize n_bytes) +{ + return calloc (n_blocks, n_bytes); +} +#define standard_try_malloc standard_malloc +#define standard_try_realloc standard_realloc +#endif /* !SANE_MALLOC_PROTOS */ +/* --- variables --- */ +static GMemVTable glib_mem_vtable = { + standard_malloc, + standard_realloc, + standard_free, + standard_calloc, + standard_try_malloc, + standard_try_realloc, +}; + + +/* --- functions --- */ +gpointer +g_malloc (gulong n_bytes) +{ + if (n_bytes) + { + gpointer mem; + + mem = glib_mem_vtable.malloc (n_bytes); + if (mem) + return mem; + + g_error ("%s: failed to allocate %lu bytes", G_STRLOC, n_bytes); + } + + return NULL; +} + +gpointer +g_malloc0 (gulong n_bytes) +{ + if (n_bytes) + { + gpointer mem; + + mem = glib_mem_vtable.calloc (1, n_bytes); + if (mem) + return mem; + + g_error ("%s: failed to allocate %lu bytes", G_STRLOC, n_bytes); + } + + return NULL; +} + +gpointer +g_realloc (gpointer mem, + gulong n_bytes) +{ + if (n_bytes) + { + mem = glib_mem_vtable.realloc (mem, n_bytes); + if (mem) + return mem; + + g_error ("%s: failed to allocate %lu bytes", G_STRLOC, n_bytes); + } + + if (mem) + glib_mem_vtable.free (mem); + + return NULL; +} + +void +g_free (gpointer mem) +{ + if (mem) + glib_mem_vtable.free (mem); +} + +gpointer +g_try_malloc (gulong n_bytes) +{ + if (n_bytes) + return glib_mem_vtable.try_malloc (n_bytes); + else + return NULL; +} + +gpointer +g_try_realloc (gpointer mem, + gulong n_bytes) +{ + if (n_bytes) + return glib_mem_vtable.try_realloc (mem, n_bytes); + + if (mem) + glib_mem_vtable.free (mem); + + return NULL; +} + +static gpointer +fallback_calloc (gsize n_blocks, + gsize n_block_bytes) +{ + gsize l = n_blocks * n_block_bytes; + gpointer mem = glib_mem_vtable.malloc (l); + + if (mem) + memset (mem, 0, l); + + return mem; +} + +void +g_mem_set_vtable (GMemVTable *vtable) +{ + gboolean vtable_set = FALSE; + + if (!vtable_set) + { + vtable_set |= TRUE; + if (vtable->malloc && vtable->realloc && vtable->free) + { + glib_mem_vtable.malloc = vtable->malloc; + glib_mem_vtable.realloc = vtable->realloc; + glib_mem_vtable.free = vtable->free; + glib_mem_vtable.calloc = vtable->calloc ? vtable->calloc : fallback_calloc; + glib_mem_vtable.try_malloc = vtable->try_malloc ? vtable->try_malloc : glib_mem_vtable.malloc; + glib_mem_vtable.try_realloc = vtable->try_realloc ? vtable->try_realloc : glib_mem_vtable.realloc; + } + else + g_warning (G_STRLOC ": memory allocation vtable lacks one of malloc(), realloc() or free()"); + } + else + g_warning (G_STRLOC ": memory allocation vtable can only be set once at startup"); +} + + +/* --- memory profiling and checking --- */ +#ifdef G_DISABLE_CHECKS +GMemVTable *glib_mem_profiler_table = &glib_mem_vtable; +void +g_mem_profile (void) +{ +} +#else /* !G_DISABLE_CHECKS */ +typedef enum { + PROFILER_FREE = 0, + PROFILER_ALLOC = 1, + PROFILER_RELOC = 2, + PROFILER_ZINIT = 4 +} ProfilerJob; +static guint *profile_data = NULL; +static gulong profile_allocs = 0; +static gulong profile_mc_allocs = 0; +static gulong profile_zinit = 0; +static gulong profile_frees = 0; +static gulong profile_mc_frees = 0; +G_LOCK_DEFINE_STATIC (g_profile_mutex); +#ifdef G_ENABLE_DEBUG +static volatile gulong glib_trap_free_size = 0; +static volatile gulong glib_trap_realloc_size = 0; +static volatile gulong glib_trap_malloc_size = 0; +#endif /* G_ENABLE_DEBUG */ + +#define PROFILE_TABLE(f1,f2,f3) ( ( ((f3) << 2) | ((f2) << 1) | (f1) ) * (MEM_PROFILE_TABLE_SIZE + 1)) + +static void +profiler_log (ProfilerJob job, + gulong n_bytes, + gboolean success) +{ + G_LOCK (g_profile_mutex); + if (!profile_data) + { + profile_data = standard_malloc ((MEM_PROFILE_TABLE_SIZE + 1) * 8 * sizeof (profile_data[0])); + if (!profile_data) /* memory system kiddin' me, eh? */ + { + G_UNLOCK (g_profile_mutex); + return; + } + } + + if (MEM_CHUNK_ROUTINE_COUNT () == 0) + { + if (n_bytes < MEM_PROFILE_TABLE_SIZE) + profile_data[n_bytes + PROFILE_TABLE ((job & PROFILER_ALLOC) != 0, + (job & PROFILER_RELOC) != 0, + success != 0)] += 1; + else + profile_data[MEM_PROFILE_TABLE_SIZE + PROFILE_TABLE ((job & PROFILER_ALLOC) != 0, + (job & PROFILER_RELOC) != 0, + success != 0)] += 1; + if (success) + { + if (job & PROFILER_ALLOC) + { + profile_allocs += n_bytes; + if (job & PROFILER_ZINIT) + profile_zinit += n_bytes; + } + else + profile_frees += n_bytes; + } + } + else if (success) + { + if (job & PROFILER_ALLOC) + profile_mc_allocs += n_bytes; + else + profile_mc_frees += n_bytes; + } + G_UNLOCK (g_profile_mutex); +} + +static void +profile_print_locked (guint *local_data, + gboolean success) +{ + gboolean need_header = TRUE; + guint i; + + for (i = 0; i <= MEM_PROFILE_TABLE_SIZE; i++) + { + glong t_malloc = local_data[i + PROFILE_TABLE (1, 0, success)]; + glong t_realloc = local_data[i + PROFILE_TABLE (1, 1, success)]; + glong t_free = local_data[i + PROFILE_TABLE (0, 0, success)]; + glong t_refree = local_data[i + PROFILE_TABLE (0, 1, success)]; + + if (!t_malloc && !t_realloc && !t_free && !t_refree) + continue; + else if (need_header) + { + need_header = FALSE; + g_print (" blocks of | allocated | freed | allocated | freed | n_bytes \n"); + g_print (" n_bytes | n_times by | n_times by | n_times by | n_times by | remaining \n"); + g_print (" | malloc() | free() | realloc() | realloc() | \n"); + g_print ("===========|============|============|============|============|===========\n"); + } + if (i < MEM_PROFILE_TABLE_SIZE) + g_print ("%10u | %10ld | %10ld | %10ld | %10ld |%+11ld\n", + i, t_malloc, t_free, t_realloc, t_refree, + (t_malloc - t_free + t_realloc - t_refree) * i); + else if (i >= MEM_PROFILE_TABLE_SIZE) + g_print (" >%6u | %10ld | %10ld | %10ld | %10ld | ***\n", + i, t_malloc, t_free, t_realloc, t_refree); + } + if (need_header) + g_print (" --- none ---\n"); +} + +void +g_mem_profile (void) +{ + guint local_data[(MEM_PROFILE_TABLE_SIZE + 1) * 8 * sizeof (profile_data[0])]; + gulong local_allocs = profile_allocs; + gulong local_zinit = profile_zinit; + gulong local_frees = profile_frees; + gulong local_mc_allocs = profile_mc_allocs; + gulong local_mc_frees = profile_mc_frees; + + G_LOCK (g_profile_mutex); + + if (!profile_data) + { + G_UNLOCK (g_profile_mutex); + return; + } + + memcpy (local_data, profile_data, (MEM_PROFILE_TABLE_SIZE + 1) * 8 * sizeof (profile_data[0])); + + g_print ("GLib Memory statistics (successful operations):\n"); + profile_print_locked (local_data, TRUE); + g_print ("GLib Memory statistics (failing operations):\n"); + profile_print_locked (local_data, FALSE); + g_print ("Total bytes: allocated=%lu, zero-initialized=%lu (%.2f%%), freed=%lu (%.2f%%), remaining=%lu\n", + local_allocs, + local_zinit, + ((gdouble) local_zinit) / local_allocs * 100.0, + local_frees, + ((gdouble) local_frees) / local_allocs * 100.0, + local_allocs - local_frees); + g_print ("MemChunk bytes: allocated=%lu, freed=%lu (%.2f%%), remaining=%lu\n", + local_mc_allocs, + local_mc_frees, + ((gdouble) local_mc_frees) / local_mc_allocs * 100.0, + local_mc_allocs - local_mc_frees); + G_UNLOCK (g_profile_mutex); +} + +static gpointer +profiler_try_malloc (gsize n_bytes) +{ + gulong *p; + +#ifdef G_ENABLE_DEBUG + if (glib_trap_malloc_size == n_bytes) + G_BREAKPOINT (); +#endif /* G_ENABLE_DEBUG */ + + p = standard_malloc (sizeof (gulong) * 2 + n_bytes); + + if (p) + { + p[0] = 0; /* free count */ + p[1] = n_bytes; /* length */ + profiler_log (PROFILER_ALLOC, n_bytes, TRUE); + p += 2; + } + else + profiler_log (PROFILER_ALLOC, n_bytes, FALSE); + + return p; +} + +static gpointer +profiler_malloc (gsize n_bytes) +{ + gpointer mem = profiler_try_malloc (n_bytes); + + if (!mem) + g_mem_profile (); + + return mem; +} + +static gpointer +profiler_calloc (gsize n_blocks, + gsize n_block_bytes) +{ + gsize l = n_blocks * n_block_bytes; + gulong *p; + +#ifdef G_ENABLE_DEBUG + if (glib_trap_malloc_size == l) + G_BREAKPOINT (); +#endif /* G_ENABLE_DEBUG */ + + p = standard_calloc (1, sizeof (gulong) * 2 + l); + + if (p) + { + p[0] = 0; /* free count */ + p[1] = l; /* length */ + profiler_log (PROFILER_ALLOC | PROFILER_ZINIT, l, TRUE); + p += 2; + } + else + { + profiler_log (PROFILER_ALLOC | PROFILER_ZINIT, l, FALSE); + g_mem_profile (); + } + + return p; +} + +static void +profiler_free (gpointer mem) +{ + gulong *p = mem; + + p -= 2; + if (p[0]) /* free count */ + { + g_warning ("free(%p): memory has been freed %lu times already", p + 2, p[0]); + profiler_log (PROFILER_FREE, + p[1], /* length */ + FALSE); + } + else + { +#ifdef G_ENABLE_DEBUG + if (glib_trap_free_size == p[1]) + G_BREAKPOINT (); +#endif /* G_ENABLE_DEBUG */ + + profiler_log (PROFILER_FREE, + p[1], /* length */ + TRUE); + memset (p + 2, 0xaa, p[1]); + + /* for all those that miss standard_free (p); in this place, yes, + * we do leak all memory when profiling, and that is intentional + * to catch double frees. patch submissions are futile. + */ + } + p[0] += 1; +} + +static gpointer +profiler_try_realloc (gpointer mem, + gsize n_bytes) +{ + gulong *p = mem; + + p -= 2; + +#ifdef G_ENABLE_DEBUG + if (glib_trap_realloc_size == n_bytes) + G_BREAKPOINT (); +#endif /* G_ENABLE_DEBUG */ + + if (mem && p[0]) /* free count */ + { + g_warning ("realloc(%p, %u): memory has been freed %lu times already", p + 2, n_bytes, p[0]); + profiler_log (PROFILER_ALLOC | PROFILER_RELOC, n_bytes, FALSE); + + return NULL; + } + else + { + p = standard_realloc (mem ? p : NULL, sizeof (gulong) * 2 + n_bytes); + + if (p) + { + if (mem) + profiler_log (PROFILER_FREE | PROFILER_RELOC, p[1], TRUE); + p[0] = 0; + p[1] = n_bytes; + profiler_log (PROFILER_ALLOC | PROFILER_RELOC, p[1], TRUE); + p += 2; + } + else + profiler_log (PROFILER_ALLOC | PROFILER_RELOC, n_bytes, FALSE); + + return p; + } +} + +static gpointer +profiler_realloc (gpointer mem, + gsize n_bytes) +{ + mem = profiler_try_realloc (mem, n_bytes); + + if (!mem) + g_mem_profile (); + + return mem; +} + +static GMemVTable profiler_table = { + profiler_malloc, + profiler_realloc, + profiler_free, + profiler_calloc, + profiler_try_malloc, + profiler_try_realloc, +}; +GMemVTable *glib_mem_profiler_table = &profiler_table; + +#endif /* !G_DISABLE_CHECKS */ + + +/* --- MemChunks --- */ typedef struct _GFreeAtom GFreeAtom; typedef struct _GMemArea GMemArea; typedef struct _GRealMemChunk GRealMemChunk; @@ -132,337 +615,12 @@ static gint g_mem_chunk_area_compare (GMemArea *a, static gint g_mem_chunk_area_search (GMemArea *a, gchar *addr); - /* here we can't use StaticMutexes, as they depend upon a working - * g_malloc, the same holds true for StaticPrivate */ -static GMutex* mem_chunks_lock = NULL; + * g_malloc, the same holds true for StaticPrivate + */ +static GMutex *mem_chunks_lock = NULL; static GRealMemChunk *mem_chunks = NULL; -#endif -#ifdef ENABLE_MEM_PROFILE -static GMutex* mem_profile_lock; -static gulong allocations[MEM_PROFILE_TABLE_SIZE] = { 0 }; -static gulong allocated_mem = 0; -static gulong freed_mem = 0; -static GPrivate* allocating_for_mem_chunk = NULL; -#define IS_IN_MEM_CHUNK_ROUTINE() \ - GPOINTER_TO_UINT (g_private_get (allocating_for_mem_chunk)) -#endif /* ENABLE_MEM_PROFILE */ - - -#ifndef USE_DMALLOC - -gpointer -g_malloc (gulong size) -{ - gpointer p; - - -#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK) - gulong *t; -#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ - - - if (size == 0) - return NULL; - - -#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK) - size += SIZEOF_LONG; -#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ - -#ifdef ENABLE_MEM_CHECK - size += SIZEOF_LONG; -#endif /* ENABLE_MEM_CHECK */ - - - p = (gpointer) malloc (size); - if (!p) - g_error ("could not allocate %ld bytes", size); - - -#ifdef ENABLE_MEM_CHECK - size -= SIZEOF_LONG; - - t = p; - p = ((guchar*) p + SIZEOF_LONG); - *t = 0; -#endif /* ENABLE_MEM_CHECK */ - -#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK) - size -= SIZEOF_LONG; - - t = p; - p = ((guchar*) p + SIZEOF_LONG); - *t = size; - -#ifdef ENABLE_MEM_PROFILE - g_mutex_lock (mem_profile_lock); -# ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS - if(!IS_IN_MEM_CHUNK_ROUTINE()) { -# endif - if (size <= MEM_PROFILE_TABLE_SIZE - 1) - allocations[size-1] += 1; - else - allocations[MEM_PROFILE_TABLE_SIZE - 1] += 1; - allocated_mem += size; -# ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS - } -# endif - g_mutex_unlock (mem_profile_lock); -#endif /* ENABLE_MEM_PROFILE */ -#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ - - - return p; -} - -gpointer -g_malloc0 (gulong size) -{ - gpointer p; - - -#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK) - gulong *t; -#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ - - - if (size == 0) - return NULL; - - -#if defined (ENABLE_MEM_PROFILE) || defined (ENABLE_MEM_CHECK) - size += SIZEOF_LONG; -#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ - -#ifdef ENABLE_MEM_CHECK - size += SIZEOF_LONG; -#endif /* ENABLE_MEM_CHECK */ - - - p = (gpointer) calloc (size, 1); - if (!p) - g_error ("could not allocate %ld bytes", size); - - -#ifdef ENABLE_MEM_CHECK - size -= SIZEOF_LONG; - - t = p; - p = ((guchar*) p + SIZEOF_LONG); - *t = 0; -#endif /* ENABLE_MEM_CHECK */ - -#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK) - size -= SIZEOF_LONG; - - t = p; - p = ((guchar*) p + SIZEOF_LONG); - *t = size; - -# ifdef ENABLE_MEM_PROFILE - g_mutex_lock (mem_profile_lock); -# ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS - if(!IS_IN_MEM_CHUNK_ROUTINE()) { -# endif - if (size <= (MEM_PROFILE_TABLE_SIZE - 1)) - allocations[size-1] += 1; - else - allocations[MEM_PROFILE_TABLE_SIZE - 1] += 1; - allocated_mem += size; -# ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS - } -# endif - g_mutex_unlock (mem_profile_lock); -# endif /* ENABLE_MEM_PROFILE */ -#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ - - - return p; -} - -gpointer -g_realloc (gpointer mem, - gulong size) -{ - gpointer p; - -#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK) - gulong *t; -#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ - - - if (size == 0) - { - g_free (mem); - - return NULL; - } - - -#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK) - size += SIZEOF_LONG; -#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ - -#ifdef ENABLE_MEM_CHECK - size += SIZEOF_LONG; -#endif /* ENABLE_MEM_CHECK */ - - - if (!mem) - { -#ifdef REALLOC_0_WORKS - p = (gpointer) realloc (NULL, size); -#else /* !REALLOC_0_WORKS */ - p = (gpointer) malloc (size); -#endif /* !REALLOC_0_WORKS */ - } - else - { -#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK) - t = (gulong*) ((guchar*) mem - SIZEOF_LONG); -#ifdef ENABLE_MEM_PROFILE - g_mutex_lock (mem_profile_lock); - freed_mem += *t; - g_mutex_unlock (mem_profile_lock); -#endif /* ENABLE_MEM_PROFILE */ - mem = t; -#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ - -#ifdef ENABLE_MEM_CHECK - t = (gulong*) ((guchar*) mem - SIZEOF_LONG); - if (*t >= 1) - g_warning ("trying to realloc freed memory\n"); - mem = t; -#endif /* ENABLE_MEM_CHECK */ - - p = (gpointer) realloc (mem, size); - } - - if (!p) - g_error ("could not reallocate %lu bytes", (gulong) size); - - -#ifdef ENABLE_MEM_CHECK - size -= SIZEOF_LONG; - - t = p; - p = ((guchar*) p + SIZEOF_LONG); - *t = 0; -#endif /* ENABLE_MEM_CHECK */ - -#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK) - size -= SIZEOF_LONG; - - t = p; - p = ((guchar*) p + SIZEOF_LONG); - *t = size; - -#ifdef ENABLE_MEM_PROFILE - g_mutex_lock (mem_profile_lock); -#ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS - if(!IS_IN_MEM_CHUNK_ROUTINE()) { -#endif - if (size <= (MEM_PROFILE_TABLE_SIZE - 1)) - allocations[size-1] += 1; - else - allocations[MEM_PROFILE_TABLE_SIZE - 1] += 1; - allocated_mem += size; -#ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS - } -#endif - g_mutex_unlock (mem_profile_lock); -#endif /* ENABLE_MEM_PROFILE */ -#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ - - - return p; -} - -void -g_free (gpointer mem) -{ - if (mem) - { -#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK) - gulong *t; - gulong size; -#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ - -#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK) - t = (gulong*) ((guchar*) mem - SIZEOF_LONG); - size = *t; -#ifdef ENABLE_MEM_PROFILE - g_mutex_lock (mem_profile_lock); - freed_mem += size; - g_mutex_unlock (mem_profile_lock); -#endif /* ENABLE_MEM_PROFILE */ - mem = t; -#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ - -#ifdef ENABLE_MEM_CHECK - t = (gulong*) ((guchar*) mem - SIZEOF_LONG); - if (*t >= 1) - g_warning ("freeing previously freed (%lu times) memory\n", *t); - *t += 1; - mem = t; - - memset ((guchar*) mem + 2 * SIZEOF_LONG, 0, size); -#else /* ENABLE_MEM_CHECK */ - free (mem); -#endif /* ENABLE_MEM_CHECK */ - } -} - -#endif /* ! USE_DMALLOC */ - - -void -g_mem_profile (void) -{ -#ifdef ENABLE_MEM_PROFILE - gint i; - gulong local_allocations[MEM_PROFILE_TABLE_SIZE]; - gulong local_allocated_mem; - gulong local_freed_mem; - - g_mutex_lock (mem_profile_lock); - for (i = 0; i < MEM_PROFILE_TABLE_SIZE; i++) - local_allocations[i] = allocations[i]; - local_allocated_mem = allocated_mem; - local_freed_mem = freed_mem; - g_mutex_unlock (mem_profile_lock); - - for (i = 0; i < (MEM_PROFILE_TABLE_SIZE - 1); i++) - if (local_allocations[i] > 0) - g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, - "%lu allocations of %d bytes", local_allocations[i], i + 1); - - if (local_allocations[MEM_PROFILE_TABLE_SIZE - 1] > 0) - g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, - "%lu allocations of greater than %d bytes", - local_allocations[MEM_PROFILE_TABLE_SIZE - 1], MEM_PROFILE_TABLE_SIZE - 1); - g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes allocated", local_allocated_mem); - g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes freed", local_freed_mem); - g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes in use", local_allocated_mem - local_freed_mem); -#endif /* ENABLE_MEM_PROFILE */ -} - -void -g_mem_check (gpointer mem) -{ -#ifdef ENABLE_MEM_CHECK - gulong *t; - - t = (gulong*) ((guchar*) mem - SIZEOF_LONG - SIZEOF_LONG); - - if (*t >= 1) - g_warning ("mem: 0x%08lx has been freed %lu times\n", (gulong) mem, *t); -#endif /* ENABLE_MEM_CHECK */ -} - -#ifndef DISABLE_MEM_POOLS GMemChunk* g_mem_chunk_new (gchar *name, gint atom_size, @@ -475,7 +633,7 @@ g_mem_chunk_new (gchar *name, g_return_val_if_fail (atom_size > 0, NULL); g_return_val_if_fail (area_size >= atom_size, NULL); - ENTER_MEM_CHUNK_ROUTINE(); + ENTER_MEM_CHUNK_ROUTINE (); area_size = (area_size + atom_size - 1) / atom_size; area_size *= atom_size; @@ -495,8 +653,8 @@ g_mem_chunk_new (gchar *name, if (mem_chunk->type == G_ALLOC_AND_FREE) mem_chunk->mem_tree = g_tree_new ((GCompareFunc) g_mem_chunk_area_compare); - if (mem_chunk->atom_size % MEM_ALIGN) - mem_chunk->atom_size += MEM_ALIGN - (mem_chunk->atom_size % MEM_ALIGN); + if (mem_chunk->atom_size % G_MEM_ALIGN) + mem_chunk->atom_size += G_MEM_ALIGN - (mem_chunk->atom_size % G_MEM_ALIGN); rarea_size = area_size + sizeof (GMemArea) - MEM_AREA_SIZE; rarea_size = g_mem_chunk_compute_size (rarea_size, atom_size + sizeof (GMemArea) - MEM_AREA_SIZE); @@ -510,7 +668,7 @@ g_mem_chunk_new (gchar *name, mem_chunks = mem_chunk; g_mutex_unlock (mem_chunks_lock); - LEAVE_MEM_CHUNK_ROUTINE(); + LEAVE_MEM_CHUNK_ROUTINE (); return ((GMemChunk*) mem_chunk); } @@ -524,7 +682,7 @@ g_mem_chunk_destroy (GMemChunk *mem_chunk) g_return_if_fail (mem_chunk != NULL); - ENTER_MEM_CHUNK_ROUTINE(); + ENTER_MEM_CHUNK_ROUTINE (); rmem_chunk = (GRealMemChunk*) mem_chunk; @@ -551,7 +709,7 @@ g_mem_chunk_destroy (GMemChunk *mem_chunk) g_free (rmem_chunk); - LEAVE_MEM_CHUNK_ROUTINE(); + LEAVE_MEM_CHUNK_ROUTINE (); } gpointer @@ -561,7 +719,7 @@ g_mem_chunk_alloc (GMemChunk *mem_chunk) GMemArea *temp_area; gpointer mem; - ENTER_MEM_CHUNK_ROUTINE(); + ENTER_MEM_CHUNK_ROUTINE (); g_return_val_if_fail (mem_chunk != NULL, NULL); @@ -688,7 +846,7 @@ g_mem_chunk_alloc (GMemChunk *mem_chunk) outa_here: - LEAVE_MEM_CHUNK_ROUTINE(); + LEAVE_MEM_CHUNK_ROUTINE (); return mem; } @@ -720,7 +878,7 @@ g_mem_chunk_free (GMemChunk *mem_chunk, g_return_if_fail (mem_chunk != NULL); g_return_if_fail (mem != NULL); - ENTER_MEM_CHUNK_ROUTINE(); + ENTER_MEM_CHUNK_ROUTINE (); rmem_chunk = (GRealMemChunk*) mem_chunk; @@ -751,7 +909,7 @@ g_mem_chunk_free (GMemChunk *mem_chunk, } } - LEAVE_MEM_CHUNK_ROUTINE(); + LEAVE_MEM_CHUNK_ROUTINE (); } /* This doesn't free the free_area if there is one */ @@ -766,6 +924,8 @@ g_mem_chunk_clean (GMemChunk *mem_chunk) g_return_if_fail (mem_chunk != NULL); + ENTER_MEM_CHUNK_ROUTINE (); + rmem_chunk = (GRealMemChunk*) mem_chunk; if (rmem_chunk->type == G_ALLOC_AND_FREE) @@ -819,6 +979,7 @@ g_mem_chunk_clean (GMemChunk *mem_chunk) } } } + LEAVE_MEM_CHUNK_ROUTINE (); } void @@ -830,6 +991,8 @@ g_mem_chunk_reset (GMemChunk *mem_chunk) g_return_if_fail (mem_chunk != NULL); + ENTER_MEM_CHUNK_ROUTINE (); + rmem_chunk = (GRealMemChunk*) mem_chunk; mem_areas = rmem_chunk->mem_areas; @@ -849,6 +1012,8 @@ g_mem_chunk_reset (GMemChunk *mem_chunk) if (rmem_chunk->mem_tree) g_tree_destroy (rmem_chunk->mem_tree); rmem_chunk->mem_tree = g_tree_new ((GCompareFunc) g_mem_chunk_area_compare); + + LEAVE_MEM_CHUNK_ROUTINE (); } void @@ -869,7 +1034,7 @@ g_mem_chunk_print (GMemChunk *mem_chunk) mem += rmem_chunk->area_size - mem_areas->free; mem_areas = mem_areas->next; } - + g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%s: %ld bytes using %d mem areas", rmem_chunk->name, mem, rmem_chunk->num_mem_areas); @@ -919,7 +1084,6 @@ g_blow_chunks (void) } } - static gulong g_mem_chunk_compute_size (gulong size, gulong min_size) @@ -963,10 +1127,10 @@ g_mem_chunk_area_search (GMemArea *a, } return -1; } + #else /* DISABLE_MEM_POOLS */ -typedef struct -{ +typedef struct { guint alloc_size; /* the size of an atom */ } GMinimalMemChunk; @@ -1023,33 +1187,15 @@ g_mem_chunk_free (GMemChunk *mem_chunk, g_free (mem); } -void -g_mem_chunk_clean (GMemChunk *mem_chunk) -{ -} +void g_mem_chunk_clean (GMemChunk *mem_chunk) {} +void g_mem_chunk_reset (GMemChunk *mem_chunk) {} +void g_mem_chunk_print (GMemChunk *mem_chunk) {} +void g_mem_chunk_info (void) {} +void g_blow_chunks (void) {} -void -g_mem_chunk_reset (GMemChunk *mem_chunk) -{ -} - -void -g_mem_chunk_print (GMemChunk *mem_chunk) -{ -} - -void -g_mem_chunk_info (void) -{ -} - -void -g_blow_chunks (void) -{ -} - #endif /* DISABLE_MEM_POOLS */ + /* generic allocators */ struct _GAllocator /* from gmem.c */ @@ -1100,10 +1246,9 @@ void g_mem_init (void) { #ifndef DISABLE_MEM_POOLS - mem_chunks_lock = g_mutex_new(); + mem_chunks_lock = g_mutex_new (); #endif -#if ENABLE_MEM_PROFILE - mem_profile_lock = g_mutex_new(); - allocating_for_mem_chunk = g_private_new(NULL); +#ifndef G_DISABLE_CHECKS + mem_chunk_recursion = g_private_new (NULL); #endif } diff --git a/glib/gmem.h b/glib/gmem.h index 72e7b2877..2ba1344fc 100644 --- a/glib/gmem.h +++ b/glib/gmem.h @@ -29,35 +29,70 @@ #include -/* optionally feature DMALLOC memory allocation debugger - */ -#ifdef USE_DMALLOC -#include "dmalloc.h" -#endif - G_BEGIN_DECLS -typedef struct _GAllocator GAllocator; -typedef struct _GMemChunk GMemChunk; +typedef struct _GAllocator GAllocator; +typedef struct _GMemChunk GMemChunk; +typedef struct _GMemVTable GMemVTable; -/* Provide macros for easily allocating memory. The macros - * will cast the allocated memory to the specified type - * in order to avoid compiler warnings. (Makes the code neater). + +#if GLIB_SIZEOF_VOID_P > GLIB_SIZEOF_LONG +# define G_MEM_ALIGN GLIB_SIZEOF_VOID_P +#else /* GLIB_SIZEOF_VOID_P <= GLIB_SIZEOF_LONG */ +# define G_MEM_ALIGN GLIB_SIZEOF_LONG +#endif /* GLIB_SIZEOF_VOID_P <= GLIB_SIZEOF_LONG */ + + +/* Memory allocation functions */ +gpointer g_malloc (gulong n_bytes); +gpointer g_malloc0 (gulong n_bytes); +gpointer g_realloc (gpointer mem, + gulong n_bytes); +void g_free (gpointer mem); +gpointer g_try_malloc (gulong n_bytes); +gpointer g_try_realloc (gpointer mem, + gulong n_bytes); -#ifdef __DMALLOC_H__ -# define g_new(type, count) (ALLOC (type, count)) -# define g_new0(type, count) (CALLOC (type, count)) -# define g_renew(type, mem, count) (REALLOC (mem, type, count)) -#else /* __DMALLOC_H__ */ -# define g_new(type, count) \ - ((type *) g_malloc ((unsigned) sizeof (type) * (count))) -# define g_new0(type, count) \ - ((type *) g_malloc0 ((unsigned) sizeof (type) * (count))) -# define g_renew(type, mem, count) \ - ((type *) g_realloc (mem, (unsigned) sizeof (type) * (count))) -#endif /* __DMALLOC_H__ */ +/* Convenience memory allocators + */ +#define g_new(struct_type, n_structs) \ + ((struct_type *) g_malloc (((gsize) sizeof (struct_type)) * ((gsize) (n_structs)))) +#define g_new0(struct_type, n_structs) \ + ((struct_type *) g_malloc0 (((gsize) sizeof (struct_type)) * ((gsize) (n_structs)))) +#define g_renew(struct_type, mem, n_structs) \ + ((struct_type *) g_realloc ((mem), ((gsize) sizeof (struct_type)) * ((gsize) (n_structs)))) + + +/* Memory allocation virtualization for debugging purposes + * g_mem_set_vtable() has to be the very first GLib function called + * if being used + */ +struct _GMemVTable +{ + gpointer (*malloc) (gsize n_bytes); + gpointer (*realloc) (gpointer mem, + gsize n_bytes); + void (*free) (gpointer mem); + /* optional */ + gpointer (*calloc) (gsize n_blocks, + gsize n_block_bytes); + gpointer (*try_malloc) (gsize n_bytes); + gpointer (*try_realloc) (gpointer mem, + gsize n_bytes); +}; +void g_mem_set_vtable (GMemVTable *vtable); + + +/* Memory profiler and checker, has to be enabled via g_mem_set_vtable() + */ +extern GMemVTable *glib_mem_profiler_table; +void g_mem_profile (void); + + +/* Memchunk convenience functions + */ #define g_mem_chunk_create(type, pre_alloc, alloc_type) ( \ g_mem_chunk_new (#type " mem chunks (" #pre_alloc ")", \ sizeof (type), \ @@ -74,37 +109,6 @@ typedef struct _GMemChunk GMemChunk; g_mem_chunk_free ((mem_chunk), (mem)); \ } G_STMT_END -/* Memory allocation and debugging - */ -#ifdef USE_DMALLOC - -#define g_malloc(size) ((gpointer) MALLOC (size)) -#define g_malloc0(size) ((gpointer) CALLOC (char, size)) -#define g_realloc(mem,size) ((gpointer) REALLOC (mem, char, size)) -#define g_free(mem) FREE (mem) - -#else /* !USE_DMALLOC */ - -gpointer g_malloc (gulong size); -gpointer g_malloc0 (gulong size); -gpointer g_realloc (gpointer mem, - gulong size); -void g_free (gpointer mem); - -#endif /* !USE_DMALLOC */ - -void g_mem_profile (void); -void g_mem_check (gpointer mem); - -/* Generic allocators - */ -GAllocator* g_allocator_new (const gchar *name, - guint n_preallocs); -void g_allocator_free (GAllocator *allocator); - -#define G_ALLOCATOR_LIST (1) -#define G_ALLOCATOR_SLIST (2) -#define G_ALLOCATOR_NODE (3) /* "g_mem_chunk_new" creates a new memory chunk. * Memory chunks are used to allocate pieces of memory which are @@ -150,9 +154,21 @@ void g_mem_chunk_info (void); * much better name than "g_mem_chunk_clean_all" or something * similar. */ -void g_blow_chunks (void); +void g_blow_chunks (void); + + +/* Generic allocators + */ +GAllocator* g_allocator_new (const gchar *name, + guint n_preallocs); +void g_allocator_free (GAllocator *allocator); + +/* internal */ +#define G_ALLOCATOR_LIST (1) +#define G_ALLOCATOR_SLIST (2) +#define G_ALLOCATOR_NODE (3) + G_END_DECLS #endif /* __G_MEM_H__ */ - diff --git a/glib/gscanner.c b/glib/gscanner.c index 3291a8c64..02e801c73 100644 --- a/glib/gscanner.c +++ b/glib/gscanner.c @@ -570,8 +570,8 @@ g_scanner_freeze_symbol_table (GScanner *scanner) if (first_call) { - g_warning("g_scanner_freeze_symbol_table and " - "g_scanner_thaw_symbol_table are deprecated."); + g_message ("g_scanner_freeze_symbol_table() and " + "g_scanner_thaw_symbol_table() are deprecated."); first_call = FALSE; } #endif /* G_ENABLE_DEBUG */ @@ -580,6 +580,7 @@ g_scanner_freeze_symbol_table (GScanner *scanner) void g_scanner_thaw_symbol_table (GScanner *scanner) { + g_scanner_freeze_symbol_table (scanner); } GTokenType diff --git a/glib/gutils.c b/glib/gutils.c index 41fdb7ad7..3001ec71b 100644 --- a/glib/gutils.c +++ b/glib/gutils.c @@ -383,9 +383,9 @@ g_basename (const gchar *file_name) if (first_call) { - g_warning("g_basename is deprecated. Use g_path_get_basename instead."); - g_warning("Watch out! You have to g_free the string returned by " - "g_path_get_basename."); + g_message ("g_basename is deprecated. Use g_path_get_basename instead. " + "Beware that the string returned by g_path_get_basename() has " + " to be g_free()ed."); first_call = FALSE; } #endif /* G_ENABLE_DEBUG */ @@ -512,7 +512,7 @@ g_dirname (const gchar *file_name) if (first_call) { - g_warning("g_dirname is deprecated. Use g_path_get_dirname instead."); + g_message ("g_dirname() is deprecated. Use g_path_get_dirname() instead."); first_call = FALSE; } #endif /* G_ENABLE_DEBUG */ diff --git a/gmem.c b/gmem.c index 73e01a993..b0909a0dc 100644 --- a/gmem.c +++ b/gmem.c @@ -36,50 +36,533 @@ #include #include "glib.h" -/* #define ENABLE_MEM_PROFILE */ -/* #define ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS */ -/* #define ENABLE_MEM_CHECK */ -#define MEM_PROFILE_TABLE_SIZE 8192 -/* - * This library can check for some attempts to do illegal things to - * memory (ENABLE_MEM_CHECK), and can do profiling - * (ENABLE_MEM_PROFILE). Both features are implemented by storing - * words before the start of the memory chunk. - * - * The first, at offset -2*SIZEOF_LONG, is used only if - * ENABLE_MEM_CHECK is set, and stores 0 after the memory has been - * allocated and 1 when it has been freed. The second, at offset - * -SIZEOF_LONG, is used if either flag is set and stores the size of - * the block. - * - * The MEM_CHECK flag is checked when memory is realloc'd and free'd, - * and it can be explicitly checked before using a block by calling - * g_mem_check(). +/* notes on macros: + * having DISABLE_MEM_POOLS defined, disables mem_chunks alltogether, their + * allocations are performed through ordinary g_malloc/g_free. + * having G_DISABLE_CHECKS defined disables use of glib_mem_profiler_table and + * g_mem_profile(). + * REALLOC_0_WORKS is defined if g_realloc (NULL, x) works. + * SANE_MALLOC_PROTOS is defined if the systems malloc() and friends functions + * match the corresponding GLib prototypes, keep configure.in and gmem.h in sync here. + * if ENABLE_GC_FRIENDLY is defined, freed memory should be 0-wiped. */ -#if defined(ENABLE_MEM_PROFILE) && defined(ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS) -#define ENTER_MEM_CHUNK_ROUTINE() \ - g_private_set (allocating_for_mem_chunk, \ - g_private_get (allocating_for_mem_chunk) + 1) -#define LEAVE_MEM_CHUNK_ROUTINE() \ - g_private_set (allocating_for_mem_chunk, \ - g_private_get (allocating_for_mem_chunk) - 1) -#else -#define ENTER_MEM_CHUNK_ROUTINE() -#define LEAVE_MEM_CHUNK_ROUTINE() -#endif - +#define MEM_PROFILE_TABLE_SIZE 4096 #define MEM_AREA_SIZE 4L -#if SIZEOF_VOID_P > SIZEOF_LONG -#define MEM_ALIGN SIZEOF_VOID_P -#else -#define MEM_ALIGN SIZEOF_LONG -#endif +#ifdef G_DISABLE_CHECKS +# define ENTER_MEM_CHUNK_ROUTINE() +# define LEAVE_MEM_CHUNK_ROUTINE() +# define IN_MEM_CHUNK_ROUTINE() FALSE +#else /* !G_DISABLE_CHECKS */ +static GPrivate* mem_chunk_recursion = NULL; +# define MEM_CHUNK_ROUTINE_COUNT() GPOINTER_TO_UINT (g_private_get (mem_chunk_recursion)) +# define ENTER_MEM_CHUNK_ROUTINE() g_private_set (mem_chunk_recursion, GUINT_TO_POINTER (MEM_CHUNK_ROUTINE_COUNT () + 1)) +# define LEAVE_MEM_CHUNK_ROUTINE() g_private_set (mem_chunk_recursion, GUINT_TO_POINTER (MEM_CHUNK_ROUTINE_COUNT () - 1)) +#endif /* !G_DISABLE_CHECKS */ + +#ifndef REALLOC_0_WORKS +static gpointer +standard_realloc (gpointer mem, + gsize n_bytes) +{ + if (!mem) + return malloc (n_bytes); + else + return realloc (mem, n_bytes); +} +#endif /* !REALLOC_0_WORKS */ + +#ifdef SANE_MALLOC_PROTOS +# define standard_malloc malloc +# ifdef REALLOC_0_WORKS +# define standard_realloc realloc +# endif /* REALLOC_0_WORKS */ +# define standard_free free +# define standard_calloc calloc +# define standard_try_malloc malloc +# define standard_try_realloc realloc +#else /* !SANE_MALLOC_PROTOS */ +static gpointer +standard_malloc (gsize n_bytes) +{ + return malloc (n_bytes); +} +# ifdef REALLOC_0_WORKS +static gpointer +standard_realloc (gpointer mem, + gsize n_bytes) +{ + return realloc (mem, n_bytes); +} +# endif /* REALLOC_0_WORKS */ +static void +standard_free (gpointer mem) +{ + return free (mem); +} +static gpointer +standard_calloc (gsize n_blocks, + gsize n_bytes) +{ + return calloc (n_blocks, n_bytes); +} +#define standard_try_malloc standard_malloc +#define standard_try_realloc standard_realloc +#endif /* !SANE_MALLOC_PROTOS */ +/* --- variables --- */ +static GMemVTable glib_mem_vtable = { + standard_malloc, + standard_realloc, + standard_free, + standard_calloc, + standard_try_malloc, + standard_try_realloc, +}; + + +/* --- functions --- */ +gpointer +g_malloc (gulong n_bytes) +{ + if (n_bytes) + { + gpointer mem; + + mem = glib_mem_vtable.malloc (n_bytes); + if (mem) + return mem; + + g_error ("%s: failed to allocate %lu bytes", G_STRLOC, n_bytes); + } + + return NULL; +} + +gpointer +g_malloc0 (gulong n_bytes) +{ + if (n_bytes) + { + gpointer mem; + + mem = glib_mem_vtable.calloc (1, n_bytes); + if (mem) + return mem; + + g_error ("%s: failed to allocate %lu bytes", G_STRLOC, n_bytes); + } + + return NULL; +} + +gpointer +g_realloc (gpointer mem, + gulong n_bytes) +{ + if (n_bytes) + { + mem = glib_mem_vtable.realloc (mem, n_bytes); + if (mem) + return mem; + + g_error ("%s: failed to allocate %lu bytes", G_STRLOC, n_bytes); + } + + if (mem) + glib_mem_vtable.free (mem); + + return NULL; +} + +void +g_free (gpointer mem) +{ + if (mem) + glib_mem_vtable.free (mem); +} + +gpointer +g_try_malloc (gulong n_bytes) +{ + if (n_bytes) + return glib_mem_vtable.try_malloc (n_bytes); + else + return NULL; +} + +gpointer +g_try_realloc (gpointer mem, + gulong n_bytes) +{ + if (n_bytes) + return glib_mem_vtable.try_realloc (mem, n_bytes); + + if (mem) + glib_mem_vtable.free (mem); + + return NULL; +} + +static gpointer +fallback_calloc (gsize n_blocks, + gsize n_block_bytes) +{ + gsize l = n_blocks * n_block_bytes; + gpointer mem = glib_mem_vtable.malloc (l); + + if (mem) + memset (mem, 0, l); + + return mem; +} + +void +g_mem_set_vtable (GMemVTable *vtable) +{ + gboolean vtable_set = FALSE; + + if (!vtable_set) + { + vtable_set |= TRUE; + if (vtable->malloc && vtable->realloc && vtable->free) + { + glib_mem_vtable.malloc = vtable->malloc; + glib_mem_vtable.realloc = vtable->realloc; + glib_mem_vtable.free = vtable->free; + glib_mem_vtable.calloc = vtable->calloc ? vtable->calloc : fallback_calloc; + glib_mem_vtable.try_malloc = vtable->try_malloc ? vtable->try_malloc : glib_mem_vtable.malloc; + glib_mem_vtable.try_realloc = vtable->try_realloc ? vtable->try_realloc : glib_mem_vtable.realloc; + } + else + g_warning (G_STRLOC ": memory allocation vtable lacks one of malloc(), realloc() or free()"); + } + else + g_warning (G_STRLOC ": memory allocation vtable can only be set once at startup"); +} + + +/* --- memory profiling and checking --- */ +#ifdef G_DISABLE_CHECKS +GMemVTable *glib_mem_profiler_table = &glib_mem_vtable; +void +g_mem_profile (void) +{ +} +#else /* !G_DISABLE_CHECKS */ +typedef enum { + PROFILER_FREE = 0, + PROFILER_ALLOC = 1, + PROFILER_RELOC = 2, + PROFILER_ZINIT = 4 +} ProfilerJob; +static guint *profile_data = NULL; +static gulong profile_allocs = 0; +static gulong profile_mc_allocs = 0; +static gulong profile_zinit = 0; +static gulong profile_frees = 0; +static gulong profile_mc_frees = 0; +G_LOCK_DEFINE_STATIC (g_profile_mutex); +#ifdef G_ENABLE_DEBUG +static volatile gulong glib_trap_free_size = 0; +static volatile gulong glib_trap_realloc_size = 0; +static volatile gulong glib_trap_malloc_size = 0; +#endif /* G_ENABLE_DEBUG */ + +#define PROFILE_TABLE(f1,f2,f3) ( ( ((f3) << 2) | ((f2) << 1) | (f1) ) * (MEM_PROFILE_TABLE_SIZE + 1)) + +static void +profiler_log (ProfilerJob job, + gulong n_bytes, + gboolean success) +{ + G_LOCK (g_profile_mutex); + if (!profile_data) + { + profile_data = standard_malloc ((MEM_PROFILE_TABLE_SIZE + 1) * 8 * sizeof (profile_data[0])); + if (!profile_data) /* memory system kiddin' me, eh? */ + { + G_UNLOCK (g_profile_mutex); + return; + } + } + + if (MEM_CHUNK_ROUTINE_COUNT () == 0) + { + if (n_bytes < MEM_PROFILE_TABLE_SIZE) + profile_data[n_bytes + PROFILE_TABLE ((job & PROFILER_ALLOC) != 0, + (job & PROFILER_RELOC) != 0, + success != 0)] += 1; + else + profile_data[MEM_PROFILE_TABLE_SIZE + PROFILE_TABLE ((job & PROFILER_ALLOC) != 0, + (job & PROFILER_RELOC) != 0, + success != 0)] += 1; + if (success) + { + if (job & PROFILER_ALLOC) + { + profile_allocs += n_bytes; + if (job & PROFILER_ZINIT) + profile_zinit += n_bytes; + } + else + profile_frees += n_bytes; + } + } + else if (success) + { + if (job & PROFILER_ALLOC) + profile_mc_allocs += n_bytes; + else + profile_mc_frees += n_bytes; + } + G_UNLOCK (g_profile_mutex); +} + +static void +profile_print_locked (guint *local_data, + gboolean success) +{ + gboolean need_header = TRUE; + guint i; + + for (i = 0; i <= MEM_PROFILE_TABLE_SIZE; i++) + { + glong t_malloc = local_data[i + PROFILE_TABLE (1, 0, success)]; + glong t_realloc = local_data[i + PROFILE_TABLE (1, 1, success)]; + glong t_free = local_data[i + PROFILE_TABLE (0, 0, success)]; + glong t_refree = local_data[i + PROFILE_TABLE (0, 1, success)]; + + if (!t_malloc && !t_realloc && !t_free && !t_refree) + continue; + else if (need_header) + { + need_header = FALSE; + g_print (" blocks of | allocated | freed | allocated | freed | n_bytes \n"); + g_print (" n_bytes | n_times by | n_times by | n_times by | n_times by | remaining \n"); + g_print (" | malloc() | free() | realloc() | realloc() | \n"); + g_print ("===========|============|============|============|============|===========\n"); + } + if (i < MEM_PROFILE_TABLE_SIZE) + g_print ("%10u | %10ld | %10ld | %10ld | %10ld |%+11ld\n", + i, t_malloc, t_free, t_realloc, t_refree, + (t_malloc - t_free + t_realloc - t_refree) * i); + else if (i >= MEM_PROFILE_TABLE_SIZE) + g_print (" >%6u | %10ld | %10ld | %10ld | %10ld | ***\n", + i, t_malloc, t_free, t_realloc, t_refree); + } + if (need_header) + g_print (" --- none ---\n"); +} + +void +g_mem_profile (void) +{ + guint local_data[(MEM_PROFILE_TABLE_SIZE + 1) * 8 * sizeof (profile_data[0])]; + gulong local_allocs = profile_allocs; + gulong local_zinit = profile_zinit; + gulong local_frees = profile_frees; + gulong local_mc_allocs = profile_mc_allocs; + gulong local_mc_frees = profile_mc_frees; + + G_LOCK (g_profile_mutex); + + if (!profile_data) + { + G_UNLOCK (g_profile_mutex); + return; + } + + memcpy (local_data, profile_data, (MEM_PROFILE_TABLE_SIZE + 1) * 8 * sizeof (profile_data[0])); + + g_print ("GLib Memory statistics (successful operations):\n"); + profile_print_locked (local_data, TRUE); + g_print ("GLib Memory statistics (failing operations):\n"); + profile_print_locked (local_data, FALSE); + g_print ("Total bytes: allocated=%lu, zero-initialized=%lu (%.2f%%), freed=%lu (%.2f%%), remaining=%lu\n", + local_allocs, + local_zinit, + ((gdouble) local_zinit) / local_allocs * 100.0, + local_frees, + ((gdouble) local_frees) / local_allocs * 100.0, + local_allocs - local_frees); + g_print ("MemChunk bytes: allocated=%lu, freed=%lu (%.2f%%), remaining=%lu\n", + local_mc_allocs, + local_mc_frees, + ((gdouble) local_mc_frees) / local_mc_allocs * 100.0, + local_mc_allocs - local_mc_frees); + G_UNLOCK (g_profile_mutex); +} + +static gpointer +profiler_try_malloc (gsize n_bytes) +{ + gulong *p; + +#ifdef G_ENABLE_DEBUG + if (glib_trap_malloc_size == n_bytes) + G_BREAKPOINT (); +#endif /* G_ENABLE_DEBUG */ + + p = standard_malloc (sizeof (gulong) * 2 + n_bytes); + + if (p) + { + p[0] = 0; /* free count */ + p[1] = n_bytes; /* length */ + profiler_log (PROFILER_ALLOC, n_bytes, TRUE); + p += 2; + } + else + profiler_log (PROFILER_ALLOC, n_bytes, FALSE); + + return p; +} + +static gpointer +profiler_malloc (gsize n_bytes) +{ + gpointer mem = profiler_try_malloc (n_bytes); + + if (!mem) + g_mem_profile (); + + return mem; +} + +static gpointer +profiler_calloc (gsize n_blocks, + gsize n_block_bytes) +{ + gsize l = n_blocks * n_block_bytes; + gulong *p; + +#ifdef G_ENABLE_DEBUG + if (glib_trap_malloc_size == l) + G_BREAKPOINT (); +#endif /* G_ENABLE_DEBUG */ + + p = standard_calloc (1, sizeof (gulong) * 2 + l); + + if (p) + { + p[0] = 0; /* free count */ + p[1] = l; /* length */ + profiler_log (PROFILER_ALLOC | PROFILER_ZINIT, l, TRUE); + p += 2; + } + else + { + profiler_log (PROFILER_ALLOC | PROFILER_ZINIT, l, FALSE); + g_mem_profile (); + } + + return p; +} + +static void +profiler_free (gpointer mem) +{ + gulong *p = mem; + + p -= 2; + if (p[0]) /* free count */ + { + g_warning ("free(%p): memory has been freed %lu times already", p + 2, p[0]); + profiler_log (PROFILER_FREE, + p[1], /* length */ + FALSE); + } + else + { +#ifdef G_ENABLE_DEBUG + if (glib_trap_free_size == p[1]) + G_BREAKPOINT (); +#endif /* G_ENABLE_DEBUG */ + + profiler_log (PROFILER_FREE, + p[1], /* length */ + TRUE); + memset (p + 2, 0xaa, p[1]); + + /* for all those that miss standard_free (p); in this place, yes, + * we do leak all memory when profiling, and that is intentional + * to catch double frees. patch submissions are futile. + */ + } + p[0] += 1; +} + +static gpointer +profiler_try_realloc (gpointer mem, + gsize n_bytes) +{ + gulong *p = mem; + + p -= 2; + +#ifdef G_ENABLE_DEBUG + if (glib_trap_realloc_size == n_bytes) + G_BREAKPOINT (); +#endif /* G_ENABLE_DEBUG */ + + if (mem && p[0]) /* free count */ + { + g_warning ("realloc(%p, %u): memory has been freed %lu times already", p + 2, n_bytes, p[0]); + profiler_log (PROFILER_ALLOC | PROFILER_RELOC, n_bytes, FALSE); + + return NULL; + } + else + { + p = standard_realloc (mem ? p : NULL, sizeof (gulong) * 2 + n_bytes); + + if (p) + { + if (mem) + profiler_log (PROFILER_FREE | PROFILER_RELOC, p[1], TRUE); + p[0] = 0; + p[1] = n_bytes; + profiler_log (PROFILER_ALLOC | PROFILER_RELOC, p[1], TRUE); + p += 2; + } + else + profiler_log (PROFILER_ALLOC | PROFILER_RELOC, n_bytes, FALSE); + + return p; + } +} + +static gpointer +profiler_realloc (gpointer mem, + gsize n_bytes) +{ + mem = profiler_try_realloc (mem, n_bytes); + + if (!mem) + g_mem_profile (); + + return mem; +} + +static GMemVTable profiler_table = { + profiler_malloc, + profiler_realloc, + profiler_free, + profiler_calloc, + profiler_try_malloc, + profiler_try_realloc, +}; +GMemVTable *glib_mem_profiler_table = &profiler_table; + +#endif /* !G_DISABLE_CHECKS */ + + +/* --- MemChunks --- */ typedef struct _GFreeAtom GFreeAtom; typedef struct _GMemArea GMemArea; typedef struct _GRealMemChunk GRealMemChunk; @@ -132,337 +615,12 @@ static gint g_mem_chunk_area_compare (GMemArea *a, static gint g_mem_chunk_area_search (GMemArea *a, gchar *addr); - /* here we can't use StaticMutexes, as they depend upon a working - * g_malloc, the same holds true for StaticPrivate */ -static GMutex* mem_chunks_lock = NULL; + * g_malloc, the same holds true for StaticPrivate + */ +static GMutex *mem_chunks_lock = NULL; static GRealMemChunk *mem_chunks = NULL; -#endif -#ifdef ENABLE_MEM_PROFILE -static GMutex* mem_profile_lock; -static gulong allocations[MEM_PROFILE_TABLE_SIZE] = { 0 }; -static gulong allocated_mem = 0; -static gulong freed_mem = 0; -static GPrivate* allocating_for_mem_chunk = NULL; -#define IS_IN_MEM_CHUNK_ROUTINE() \ - GPOINTER_TO_UINT (g_private_get (allocating_for_mem_chunk)) -#endif /* ENABLE_MEM_PROFILE */ - - -#ifndef USE_DMALLOC - -gpointer -g_malloc (gulong size) -{ - gpointer p; - - -#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK) - gulong *t; -#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ - - - if (size == 0) - return NULL; - - -#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK) - size += SIZEOF_LONG; -#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ - -#ifdef ENABLE_MEM_CHECK - size += SIZEOF_LONG; -#endif /* ENABLE_MEM_CHECK */ - - - p = (gpointer) malloc (size); - if (!p) - g_error ("could not allocate %ld bytes", size); - - -#ifdef ENABLE_MEM_CHECK - size -= SIZEOF_LONG; - - t = p; - p = ((guchar*) p + SIZEOF_LONG); - *t = 0; -#endif /* ENABLE_MEM_CHECK */ - -#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK) - size -= SIZEOF_LONG; - - t = p; - p = ((guchar*) p + SIZEOF_LONG); - *t = size; - -#ifdef ENABLE_MEM_PROFILE - g_mutex_lock (mem_profile_lock); -# ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS - if(!IS_IN_MEM_CHUNK_ROUTINE()) { -# endif - if (size <= MEM_PROFILE_TABLE_SIZE - 1) - allocations[size-1] += 1; - else - allocations[MEM_PROFILE_TABLE_SIZE - 1] += 1; - allocated_mem += size; -# ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS - } -# endif - g_mutex_unlock (mem_profile_lock); -#endif /* ENABLE_MEM_PROFILE */ -#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ - - - return p; -} - -gpointer -g_malloc0 (gulong size) -{ - gpointer p; - - -#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK) - gulong *t; -#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ - - - if (size == 0) - return NULL; - - -#if defined (ENABLE_MEM_PROFILE) || defined (ENABLE_MEM_CHECK) - size += SIZEOF_LONG; -#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ - -#ifdef ENABLE_MEM_CHECK - size += SIZEOF_LONG; -#endif /* ENABLE_MEM_CHECK */ - - - p = (gpointer) calloc (size, 1); - if (!p) - g_error ("could not allocate %ld bytes", size); - - -#ifdef ENABLE_MEM_CHECK - size -= SIZEOF_LONG; - - t = p; - p = ((guchar*) p + SIZEOF_LONG); - *t = 0; -#endif /* ENABLE_MEM_CHECK */ - -#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK) - size -= SIZEOF_LONG; - - t = p; - p = ((guchar*) p + SIZEOF_LONG); - *t = size; - -# ifdef ENABLE_MEM_PROFILE - g_mutex_lock (mem_profile_lock); -# ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS - if(!IS_IN_MEM_CHUNK_ROUTINE()) { -# endif - if (size <= (MEM_PROFILE_TABLE_SIZE - 1)) - allocations[size-1] += 1; - else - allocations[MEM_PROFILE_TABLE_SIZE - 1] += 1; - allocated_mem += size; -# ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS - } -# endif - g_mutex_unlock (mem_profile_lock); -# endif /* ENABLE_MEM_PROFILE */ -#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ - - - return p; -} - -gpointer -g_realloc (gpointer mem, - gulong size) -{ - gpointer p; - -#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK) - gulong *t; -#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ - - - if (size == 0) - { - g_free (mem); - - return NULL; - } - - -#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK) - size += SIZEOF_LONG; -#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ - -#ifdef ENABLE_MEM_CHECK - size += SIZEOF_LONG; -#endif /* ENABLE_MEM_CHECK */ - - - if (!mem) - { -#ifdef REALLOC_0_WORKS - p = (gpointer) realloc (NULL, size); -#else /* !REALLOC_0_WORKS */ - p = (gpointer) malloc (size); -#endif /* !REALLOC_0_WORKS */ - } - else - { -#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK) - t = (gulong*) ((guchar*) mem - SIZEOF_LONG); -#ifdef ENABLE_MEM_PROFILE - g_mutex_lock (mem_profile_lock); - freed_mem += *t; - g_mutex_unlock (mem_profile_lock); -#endif /* ENABLE_MEM_PROFILE */ - mem = t; -#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ - -#ifdef ENABLE_MEM_CHECK - t = (gulong*) ((guchar*) mem - SIZEOF_LONG); - if (*t >= 1) - g_warning ("trying to realloc freed memory\n"); - mem = t; -#endif /* ENABLE_MEM_CHECK */ - - p = (gpointer) realloc (mem, size); - } - - if (!p) - g_error ("could not reallocate %lu bytes", (gulong) size); - - -#ifdef ENABLE_MEM_CHECK - size -= SIZEOF_LONG; - - t = p; - p = ((guchar*) p + SIZEOF_LONG); - *t = 0; -#endif /* ENABLE_MEM_CHECK */ - -#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK) - size -= SIZEOF_LONG; - - t = p; - p = ((guchar*) p + SIZEOF_LONG); - *t = size; - -#ifdef ENABLE_MEM_PROFILE - g_mutex_lock (mem_profile_lock); -#ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS - if(!IS_IN_MEM_CHUNK_ROUTINE()) { -#endif - if (size <= (MEM_PROFILE_TABLE_SIZE - 1)) - allocations[size-1] += 1; - else - allocations[MEM_PROFILE_TABLE_SIZE - 1] += 1; - allocated_mem += size; -#ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS - } -#endif - g_mutex_unlock (mem_profile_lock); -#endif /* ENABLE_MEM_PROFILE */ -#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ - - - return p; -} - -void -g_free (gpointer mem) -{ - if (mem) - { -#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK) - gulong *t; - gulong size; -#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ - -#if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK) - t = (gulong*) ((guchar*) mem - SIZEOF_LONG); - size = *t; -#ifdef ENABLE_MEM_PROFILE - g_mutex_lock (mem_profile_lock); - freed_mem += size; - g_mutex_unlock (mem_profile_lock); -#endif /* ENABLE_MEM_PROFILE */ - mem = t; -#endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */ - -#ifdef ENABLE_MEM_CHECK - t = (gulong*) ((guchar*) mem - SIZEOF_LONG); - if (*t >= 1) - g_warning ("freeing previously freed (%lu times) memory\n", *t); - *t += 1; - mem = t; - - memset ((guchar*) mem + 2 * SIZEOF_LONG, 0, size); -#else /* ENABLE_MEM_CHECK */ - free (mem); -#endif /* ENABLE_MEM_CHECK */ - } -} - -#endif /* ! USE_DMALLOC */ - - -void -g_mem_profile (void) -{ -#ifdef ENABLE_MEM_PROFILE - gint i; - gulong local_allocations[MEM_PROFILE_TABLE_SIZE]; - gulong local_allocated_mem; - gulong local_freed_mem; - - g_mutex_lock (mem_profile_lock); - for (i = 0; i < MEM_PROFILE_TABLE_SIZE; i++) - local_allocations[i] = allocations[i]; - local_allocated_mem = allocated_mem; - local_freed_mem = freed_mem; - g_mutex_unlock (mem_profile_lock); - - for (i = 0; i < (MEM_PROFILE_TABLE_SIZE - 1); i++) - if (local_allocations[i] > 0) - g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, - "%lu allocations of %d bytes", local_allocations[i], i + 1); - - if (local_allocations[MEM_PROFILE_TABLE_SIZE - 1] > 0) - g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, - "%lu allocations of greater than %d bytes", - local_allocations[MEM_PROFILE_TABLE_SIZE - 1], MEM_PROFILE_TABLE_SIZE - 1); - g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes allocated", local_allocated_mem); - g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes freed", local_freed_mem); - g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes in use", local_allocated_mem - local_freed_mem); -#endif /* ENABLE_MEM_PROFILE */ -} - -void -g_mem_check (gpointer mem) -{ -#ifdef ENABLE_MEM_CHECK - gulong *t; - - t = (gulong*) ((guchar*) mem - SIZEOF_LONG - SIZEOF_LONG); - - if (*t >= 1) - g_warning ("mem: 0x%08lx has been freed %lu times\n", (gulong) mem, *t); -#endif /* ENABLE_MEM_CHECK */ -} - -#ifndef DISABLE_MEM_POOLS GMemChunk* g_mem_chunk_new (gchar *name, gint atom_size, @@ -475,7 +633,7 @@ g_mem_chunk_new (gchar *name, g_return_val_if_fail (atom_size > 0, NULL); g_return_val_if_fail (area_size >= atom_size, NULL); - ENTER_MEM_CHUNK_ROUTINE(); + ENTER_MEM_CHUNK_ROUTINE (); area_size = (area_size + atom_size - 1) / atom_size; area_size *= atom_size; @@ -495,8 +653,8 @@ g_mem_chunk_new (gchar *name, if (mem_chunk->type == G_ALLOC_AND_FREE) mem_chunk->mem_tree = g_tree_new ((GCompareFunc) g_mem_chunk_area_compare); - if (mem_chunk->atom_size % MEM_ALIGN) - mem_chunk->atom_size += MEM_ALIGN - (mem_chunk->atom_size % MEM_ALIGN); + if (mem_chunk->atom_size % G_MEM_ALIGN) + mem_chunk->atom_size += G_MEM_ALIGN - (mem_chunk->atom_size % G_MEM_ALIGN); rarea_size = area_size + sizeof (GMemArea) - MEM_AREA_SIZE; rarea_size = g_mem_chunk_compute_size (rarea_size, atom_size + sizeof (GMemArea) - MEM_AREA_SIZE); @@ -510,7 +668,7 @@ g_mem_chunk_new (gchar *name, mem_chunks = mem_chunk; g_mutex_unlock (mem_chunks_lock); - LEAVE_MEM_CHUNK_ROUTINE(); + LEAVE_MEM_CHUNK_ROUTINE (); return ((GMemChunk*) mem_chunk); } @@ -524,7 +682,7 @@ g_mem_chunk_destroy (GMemChunk *mem_chunk) g_return_if_fail (mem_chunk != NULL); - ENTER_MEM_CHUNK_ROUTINE(); + ENTER_MEM_CHUNK_ROUTINE (); rmem_chunk = (GRealMemChunk*) mem_chunk; @@ -551,7 +709,7 @@ g_mem_chunk_destroy (GMemChunk *mem_chunk) g_free (rmem_chunk); - LEAVE_MEM_CHUNK_ROUTINE(); + LEAVE_MEM_CHUNK_ROUTINE (); } gpointer @@ -561,7 +719,7 @@ g_mem_chunk_alloc (GMemChunk *mem_chunk) GMemArea *temp_area; gpointer mem; - ENTER_MEM_CHUNK_ROUTINE(); + ENTER_MEM_CHUNK_ROUTINE (); g_return_val_if_fail (mem_chunk != NULL, NULL); @@ -688,7 +846,7 @@ g_mem_chunk_alloc (GMemChunk *mem_chunk) outa_here: - LEAVE_MEM_CHUNK_ROUTINE(); + LEAVE_MEM_CHUNK_ROUTINE (); return mem; } @@ -720,7 +878,7 @@ g_mem_chunk_free (GMemChunk *mem_chunk, g_return_if_fail (mem_chunk != NULL); g_return_if_fail (mem != NULL); - ENTER_MEM_CHUNK_ROUTINE(); + ENTER_MEM_CHUNK_ROUTINE (); rmem_chunk = (GRealMemChunk*) mem_chunk; @@ -751,7 +909,7 @@ g_mem_chunk_free (GMemChunk *mem_chunk, } } - LEAVE_MEM_CHUNK_ROUTINE(); + LEAVE_MEM_CHUNK_ROUTINE (); } /* This doesn't free the free_area if there is one */ @@ -766,6 +924,8 @@ g_mem_chunk_clean (GMemChunk *mem_chunk) g_return_if_fail (mem_chunk != NULL); + ENTER_MEM_CHUNK_ROUTINE (); + rmem_chunk = (GRealMemChunk*) mem_chunk; if (rmem_chunk->type == G_ALLOC_AND_FREE) @@ -819,6 +979,7 @@ g_mem_chunk_clean (GMemChunk *mem_chunk) } } } + LEAVE_MEM_CHUNK_ROUTINE (); } void @@ -830,6 +991,8 @@ g_mem_chunk_reset (GMemChunk *mem_chunk) g_return_if_fail (mem_chunk != NULL); + ENTER_MEM_CHUNK_ROUTINE (); + rmem_chunk = (GRealMemChunk*) mem_chunk; mem_areas = rmem_chunk->mem_areas; @@ -849,6 +1012,8 @@ g_mem_chunk_reset (GMemChunk *mem_chunk) if (rmem_chunk->mem_tree) g_tree_destroy (rmem_chunk->mem_tree); rmem_chunk->mem_tree = g_tree_new ((GCompareFunc) g_mem_chunk_area_compare); + + LEAVE_MEM_CHUNK_ROUTINE (); } void @@ -869,7 +1034,7 @@ g_mem_chunk_print (GMemChunk *mem_chunk) mem += rmem_chunk->area_size - mem_areas->free; mem_areas = mem_areas->next; } - + g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%s: %ld bytes using %d mem areas", rmem_chunk->name, mem, rmem_chunk->num_mem_areas); @@ -919,7 +1084,6 @@ g_blow_chunks (void) } } - static gulong g_mem_chunk_compute_size (gulong size, gulong min_size) @@ -963,10 +1127,10 @@ g_mem_chunk_area_search (GMemArea *a, } return -1; } + #else /* DISABLE_MEM_POOLS */ -typedef struct -{ +typedef struct { guint alloc_size; /* the size of an atom */ } GMinimalMemChunk; @@ -1023,33 +1187,15 @@ g_mem_chunk_free (GMemChunk *mem_chunk, g_free (mem); } -void -g_mem_chunk_clean (GMemChunk *mem_chunk) -{ -} +void g_mem_chunk_clean (GMemChunk *mem_chunk) {} +void g_mem_chunk_reset (GMemChunk *mem_chunk) {} +void g_mem_chunk_print (GMemChunk *mem_chunk) {} +void g_mem_chunk_info (void) {} +void g_blow_chunks (void) {} -void -g_mem_chunk_reset (GMemChunk *mem_chunk) -{ -} - -void -g_mem_chunk_print (GMemChunk *mem_chunk) -{ -} - -void -g_mem_chunk_info (void) -{ -} - -void -g_blow_chunks (void) -{ -} - #endif /* DISABLE_MEM_POOLS */ + /* generic allocators */ struct _GAllocator /* from gmem.c */ @@ -1100,10 +1246,9 @@ void g_mem_init (void) { #ifndef DISABLE_MEM_POOLS - mem_chunks_lock = g_mutex_new(); + mem_chunks_lock = g_mutex_new (); #endif -#if ENABLE_MEM_PROFILE - mem_profile_lock = g_mutex_new(); - allocating_for_mem_chunk = g_private_new(NULL); +#ifndef G_DISABLE_CHECKS + mem_chunk_recursion = g_private_new (NULL); #endif } diff --git a/gmem.h b/gmem.h index 72e7b2877..2ba1344fc 100644 --- a/gmem.h +++ b/gmem.h @@ -29,35 +29,70 @@ #include -/* optionally feature DMALLOC memory allocation debugger - */ -#ifdef USE_DMALLOC -#include "dmalloc.h" -#endif - G_BEGIN_DECLS -typedef struct _GAllocator GAllocator; -typedef struct _GMemChunk GMemChunk; +typedef struct _GAllocator GAllocator; +typedef struct _GMemChunk GMemChunk; +typedef struct _GMemVTable GMemVTable; -/* Provide macros for easily allocating memory. The macros - * will cast the allocated memory to the specified type - * in order to avoid compiler warnings. (Makes the code neater). + +#if GLIB_SIZEOF_VOID_P > GLIB_SIZEOF_LONG +# define G_MEM_ALIGN GLIB_SIZEOF_VOID_P +#else /* GLIB_SIZEOF_VOID_P <= GLIB_SIZEOF_LONG */ +# define G_MEM_ALIGN GLIB_SIZEOF_LONG +#endif /* GLIB_SIZEOF_VOID_P <= GLIB_SIZEOF_LONG */ + + +/* Memory allocation functions */ +gpointer g_malloc (gulong n_bytes); +gpointer g_malloc0 (gulong n_bytes); +gpointer g_realloc (gpointer mem, + gulong n_bytes); +void g_free (gpointer mem); +gpointer g_try_malloc (gulong n_bytes); +gpointer g_try_realloc (gpointer mem, + gulong n_bytes); -#ifdef __DMALLOC_H__ -# define g_new(type, count) (ALLOC (type, count)) -# define g_new0(type, count) (CALLOC (type, count)) -# define g_renew(type, mem, count) (REALLOC (mem, type, count)) -#else /* __DMALLOC_H__ */ -# define g_new(type, count) \ - ((type *) g_malloc ((unsigned) sizeof (type) * (count))) -# define g_new0(type, count) \ - ((type *) g_malloc0 ((unsigned) sizeof (type) * (count))) -# define g_renew(type, mem, count) \ - ((type *) g_realloc (mem, (unsigned) sizeof (type) * (count))) -#endif /* __DMALLOC_H__ */ +/* Convenience memory allocators + */ +#define g_new(struct_type, n_structs) \ + ((struct_type *) g_malloc (((gsize) sizeof (struct_type)) * ((gsize) (n_structs)))) +#define g_new0(struct_type, n_structs) \ + ((struct_type *) g_malloc0 (((gsize) sizeof (struct_type)) * ((gsize) (n_structs)))) +#define g_renew(struct_type, mem, n_structs) \ + ((struct_type *) g_realloc ((mem), ((gsize) sizeof (struct_type)) * ((gsize) (n_structs)))) + + +/* Memory allocation virtualization for debugging purposes + * g_mem_set_vtable() has to be the very first GLib function called + * if being used + */ +struct _GMemVTable +{ + gpointer (*malloc) (gsize n_bytes); + gpointer (*realloc) (gpointer mem, + gsize n_bytes); + void (*free) (gpointer mem); + /* optional */ + gpointer (*calloc) (gsize n_blocks, + gsize n_block_bytes); + gpointer (*try_malloc) (gsize n_bytes); + gpointer (*try_realloc) (gpointer mem, + gsize n_bytes); +}; +void g_mem_set_vtable (GMemVTable *vtable); + + +/* Memory profiler and checker, has to be enabled via g_mem_set_vtable() + */ +extern GMemVTable *glib_mem_profiler_table; +void g_mem_profile (void); + + +/* Memchunk convenience functions + */ #define g_mem_chunk_create(type, pre_alloc, alloc_type) ( \ g_mem_chunk_new (#type " mem chunks (" #pre_alloc ")", \ sizeof (type), \ @@ -74,37 +109,6 @@ typedef struct _GMemChunk GMemChunk; g_mem_chunk_free ((mem_chunk), (mem)); \ } G_STMT_END -/* Memory allocation and debugging - */ -#ifdef USE_DMALLOC - -#define g_malloc(size) ((gpointer) MALLOC (size)) -#define g_malloc0(size) ((gpointer) CALLOC (char, size)) -#define g_realloc(mem,size) ((gpointer) REALLOC (mem, char, size)) -#define g_free(mem) FREE (mem) - -#else /* !USE_DMALLOC */ - -gpointer g_malloc (gulong size); -gpointer g_malloc0 (gulong size); -gpointer g_realloc (gpointer mem, - gulong size); -void g_free (gpointer mem); - -#endif /* !USE_DMALLOC */ - -void g_mem_profile (void); -void g_mem_check (gpointer mem); - -/* Generic allocators - */ -GAllocator* g_allocator_new (const gchar *name, - guint n_preallocs); -void g_allocator_free (GAllocator *allocator); - -#define G_ALLOCATOR_LIST (1) -#define G_ALLOCATOR_SLIST (2) -#define G_ALLOCATOR_NODE (3) /* "g_mem_chunk_new" creates a new memory chunk. * Memory chunks are used to allocate pieces of memory which are @@ -150,9 +154,21 @@ void g_mem_chunk_info (void); * much better name than "g_mem_chunk_clean_all" or something * similar. */ -void g_blow_chunks (void); +void g_blow_chunks (void); + + +/* Generic allocators + */ +GAllocator* g_allocator_new (const gchar *name, + guint n_preallocs); +void g_allocator_free (GAllocator *allocator); + +/* internal */ +#define G_ALLOCATOR_LIST (1) +#define G_ALLOCATOR_SLIST (2) +#define G_ALLOCATOR_NODE (3) + G_END_DECLS #endif /* __G_MEM_H__ */ - diff --git a/gobject/ChangeLog b/gobject/ChangeLog index 4dc481a0c..7be5398e1 100644 --- a/gobject/ChangeLog +++ b/gobject/ChangeLog @@ -1,3 +1,17 @@ +Thu Dec 28 11:36:44 2000 Tim Janik + + * gbsearcharray.c (upper_power2): disable G_BSEARCH_ALIGN_POWER2 + fucntionality if DISABLE_MEM_POOLS is defined. + + * gtype.c: honour DISABLE_MEM_POOLS. + + * gsignal.c (g_signal_init): flag signal key bsearch array with + G_BSEARCH_ALIGN_POWER2 to avoid excessive growth time. honour + DISABLE_MEM_POOLS. + + * gparam.h: added G_PARAM_READWRITE alias for (G_PARAM_READABLE | + G_PARAM_WRITABLE). + 2000-12-15 Tor Lillqvist * gobject.def: Update. diff --git a/gobject/gbsearcharray.c b/gobject/gbsearcharray.c index 199115300..dbba47c9b 100644 --- a/gobject/gbsearcharray.c +++ b/gobject/gbsearcharray.c @@ -27,7 +27,11 @@ static inline guint upper_power2 (guint number) { +#ifdef DISABLE_MEM_POOLS + return number; +#else /* !DISABLE_MEM_POOLS */ return number ? 1 << g_bit_storage (number - 1) : 0; +#endif /* !DISABLE_MEM_POOLS */ } static inline gpointer diff --git a/gobject/gobject.c b/gobject/gobject.c index 6a8bc0b5c..d273552d5 100644 --- a/gobject/gobject.c +++ b/gobject/gobject.c @@ -27,7 +27,6 @@ #define PREALLOC_CPARAMS (8) -#define DEBUG_OBJECTS /* --- macros --- */ @@ -126,22 +125,21 @@ struct _NotifyQueue /* --- variables --- */ -static GQuark quark_notify_queue = 0; -static GQuark quark_property_id = 0; -static GQuark quark_closure_array = 0; -static GParamSpecPool *pspec_pool = NULL; -static gulong gobject_signals[LAST_SIGNAL] = { 0, }; +static GQuark quark_notify_queue = 0; +static GQuark quark_property_id = 0; +static GQuark quark_closure_array = 0; +static GParamSpecPool *pspec_pool = NULL; +static gulong gobject_signals[LAST_SIGNAL] = { 0, }; /* --- functions --- */ -#ifdef DEBUG_OBJECTS - +#ifdef G_ENABLE_DEBUG /* We need an actual method for handling debug keys in GLib. * For now, we'll simply use, as a method * 'extern gboolean glib_debug_objects' */ +static volatile GObject *glib_trap_object_ref = NULL; gboolean glib_debug_objects = FALSE; - static guint debug_objects_count = 0; static GHashTable *debug_objects_ht = NULL; static void @@ -168,7 +166,7 @@ debug_objects_atexit (void) } } } -#endif /* DEBUG_OBJECTS */ +#endif /* G_ENABLE_DEBUG */ void g_object_type_init (void) /* sync with gtype.c */ @@ -210,9 +208,9 @@ g_object_type_init (void) /* sync with gtype.c */ type = g_type_register_fundamental (G_TYPE_OBJECT, "GObject", &info, &finfo, 0); g_assert (type == G_TYPE_OBJECT); -#ifdef DEBUG_OBJECTS +#ifdef G_ENABLE_DEBUG g_atexit (debug_objects_atexit); -#endif /* DEBUG_OBJECTS */ +#endif /* G_ENABLE_DEBUG */ } static void @@ -433,7 +431,7 @@ g_object_init (GObject *object) /* freeze object's notification queue, g_object_new_valist() takes care of that */ object_freeze_notifies (object); -#ifdef DEBUG_OBJECTS +#ifdef G_ENABLE_DEBUG if (glib_debug_objects) { if (!debug_objects_ht) @@ -441,7 +439,7 @@ g_object_init (GObject *object) debug_objects_count++; g_hash_table_insert (debug_objects_ht, object, object); } -#endif /* DEBUG_OBJECTS */ +#endif /* G_ENABLE_DEBUG */ } static void @@ -512,15 +510,20 @@ g_object_last_unref (GObject *object) if (object->ref_count == 1) /* may have been re-referenced meanwhile */ G_OBJECT_GET_CLASS (object)->shutdown (object); +#ifdef G_ENABLE_DEBUG + if (glib_trap_object_ref == object) + G_BREAKPOINT (); +#endif /* G_ENABLE_DEBUG */ + object->ref_count -= 1; if (object->ref_count == 0) /* may have been re-referenced meanwhile */ { G_OBJECT_GET_CLASS (object)->finalize (object); -#ifdef DEBUG_OBJECTS +#ifdef G_ENABLE_DEBUG if (glib_debug_objects && debug_objects_ht) g_assert (g_hash_table_lookup (debug_objects_ht, object) == NULL); -#endif /* DEBUG_OBJECTS */ +#endif /* G_ENABLE_DEBUG */ g_type_free_instance ((GTypeInstance*) object); } } @@ -540,7 +543,7 @@ g_object_finalize (GObject *object) g_signal_handlers_destroy (object); g_datalist_clear (&object->qdata); -#ifdef DEBUG_OBJECTS +#ifdef G_ENABLE_DEBUG if (glib_debug_objects) { g_assert (g_hash_table_lookup (debug_objects_ht, object) == object); @@ -548,7 +551,7 @@ g_object_finalize (GObject *object) g_hash_table_remove (debug_objects_ht, object); debug_objects_count--; } -#endif /* DEBUG_OBJECTS */ +#endif /* G_ENABLE_DEBUG */ } static inline void @@ -1224,6 +1227,11 @@ g_object_ref (gpointer _object) g_return_val_if_fail (G_IS_OBJECT (object), NULL); g_return_val_if_fail (object->ref_count > 0, NULL); +#ifdef G_ENABLE_DEBUG + if (glib_trap_object_ref == object) + G_BREAKPOINT (); +#endif /* G_ENABLE_DEBUG */ + object->ref_count += 1; return object; @@ -1237,6 +1245,11 @@ g_object_unref (gpointer _object) g_return_if_fail (G_IS_OBJECT (object)); g_return_if_fail (object->ref_count > 0); +#ifdef G_ENABLE_DEBUG + if (glib_trap_object_ref == object) + G_BREAKPOINT (); +#endif /* G_ENABLE_DEBUG */ + if (object->ref_count > 1) object->ref_count -= 1; else diff --git a/gobject/gparam.h b/gobject/gparam.h index 9ead986ef..bf8a16cc8 100644 --- a/gobject/gparam.h +++ b/gobject/gparam.h @@ -53,6 +53,7 @@ typedef enum /* bits in the range 0xffffff00 are reserved for 3rd party usage */ #define G_PARAM_USER_MASK (0xffffff00) } GParamFlags; +#define G_PARAM_READWRITE (G_PARAM_READABLE | G_PARAM_WRITABLE) /* --- typedefs & structures --- */ diff --git a/gobject/gsignal.c b/gobject/gsignal.c index af69cc909..16f464bf5 100644 --- a/gobject/gsignal.c +++ b/gobject/gsignal.c @@ -33,15 +33,14 @@ #define HANDLER_PRE_ALLOC (48) #define EMISSION_PRE_ALLOC (16) -#define TIGHT_MEMORY (1) - #define REPORT_BUG "please report occourance circumstances to gtk-devel-list@gnome.org" /* --- generic allocation --- */ -/* we can special case allocations generically by replacing +/* we special case allocations generically by replacing * these functions with more speed/memory aware variants */ +#ifndef DISABLE_MEM_POOLS static inline gpointer g_generic_node_alloc (GTrashStack **trash_stack_p, guint sizeof_node, @@ -71,6 +70,21 @@ g_generic_node_free (GTrashStack **trash_stack_p, { g_trash_stack_push (trash_stack_p, node); } +#else /* !DISABLE_MEM_POOLS */ +static inline gpointer +g_generic_node_alloc (GTrashStack **trash_stack_p, + guint sizeof_node, + guint nodes_pre_alloc) +{ + return g_malloc (sizeof_node); +} +static inline void +g_generic_node_free (GTrashStack **trash_stack_p, + gpointer node) +{ + g_free (node); +} +#endif /* !DISABLE_MEM_POOLS */ /* --- typedefs --- */ @@ -640,7 +654,7 @@ g_signal_init (void) /* sync with gtype.c */ /* setup signal key array */ g_signal_key_bsa.cmp_func = signal_key_cmp; g_signal_key_bsa.sizeof_node = sizeof (SignalKey); - g_signal_key_bsa.flags = 0; /* alloc-only */ + g_signal_key_bsa.flags = G_BSEARCH_ALIGN_POWER2; /* alloc-only */ /* setup handler list binary searchable array hash table (in german, that'd be one word ;) */ g_handler_list_bsa_ht = g_hash_table_new (g_direct_hash, NULL); @@ -1066,7 +1080,7 @@ signal_destroy_R (SignalNode *signal_node) signal_node->c_marshaller = NULL; signal_node->emission_hooks = NULL; -#ifndef G_DISABLE_CHECKS +#ifdef G_ENABLE_DEBUG /* check current emissions */ { Emission *emission; @@ -1539,7 +1553,7 @@ g_signal_emitv (const GValue *instance_and_params, G_UNLOCK (g_signal_mutex); return; } -#ifndef G_DISABLE_CHECKS +#ifdef G_ENABLE_DEBUG if (detail && !(node->flags & G_SIGNAL_DETAILED)) { g_warning ("%s: signal id `%u' does not support detail (%u)", G_STRLOC, signal_id, detail); @@ -1582,7 +1596,7 @@ g_signal_emitv (const GValue *instance_and_params, } else return_value = NULL; -#endif /* !G_DISABLE_CHECKS */ +#endif /* G_ENABLE_DEBUG */ signal_emit_R (node, detail, instance, return_value, instance_and_params); G_UNLOCK (g_signal_mutex); diff --git a/gobject/gtype.c b/gobject/gtype.c index 6f9aed300..6aba911f9 100644 --- a/gobject/gtype.c +++ b/gobject/gtype.c @@ -21,7 +21,6 @@ #include "gtypeplugin.h" #include -#undef FIXME_DISABLE_PREALLOCATIONS /* NOTE: some functions (some internal variants and exported ones) * invalidate data portions of the TypeNodes. if external functions/callbacks @@ -753,10 +752,11 @@ type_data_make (TypeNode *node, data->instance.class_data = info->class_data; data->instance.class = NULL; data->instance.instance_size = info->instance_size; - data->instance.n_preallocs = MIN (info->n_preallocs, 1024); -#ifdef FIXME_DISABLE_PREALLOCATIONS +#ifdef DISABLE_MEM_POOLS data->instance.n_preallocs = 0; -#endif +#else /* !DISABLE_MEM_POOLS */ + data->instance.n_preallocs = MIN (info->n_preallocs, 1024); +#endif /* !DISABLE_MEM_POOLS */ data->instance.instance_init = info->instance_init; data->instance.mem_chunk = NULL; } diff --git a/gscanner.c b/gscanner.c index 3291a8c64..02e801c73 100644 --- a/gscanner.c +++ b/gscanner.c @@ -570,8 +570,8 @@ g_scanner_freeze_symbol_table (GScanner *scanner) if (first_call) { - g_warning("g_scanner_freeze_symbol_table and " - "g_scanner_thaw_symbol_table are deprecated."); + g_message ("g_scanner_freeze_symbol_table() and " + "g_scanner_thaw_symbol_table() are deprecated."); first_call = FALSE; } #endif /* G_ENABLE_DEBUG */ @@ -580,6 +580,7 @@ g_scanner_freeze_symbol_table (GScanner *scanner) void g_scanner_thaw_symbol_table (GScanner *scanner) { + g_scanner_freeze_symbol_table (scanner); } GTokenType diff --git a/gutils.c b/gutils.c index 41fdb7ad7..3001ec71b 100644 --- a/gutils.c +++ b/gutils.c @@ -383,9 +383,9 @@ g_basename (const gchar *file_name) if (first_call) { - g_warning("g_basename is deprecated. Use g_path_get_basename instead."); - g_warning("Watch out! You have to g_free the string returned by " - "g_path_get_basename."); + g_message ("g_basename is deprecated. Use g_path_get_basename instead. " + "Beware that the string returned by g_path_get_basename() has " + " to be g_free()ed."); first_call = FALSE; } #endif /* G_ENABLE_DEBUG */ @@ -512,7 +512,7 @@ g_dirname (const gchar *file_name) if (first_call) { - g_warning("g_dirname is deprecated. Use g_path_get_dirname instead."); + g_message ("g_dirname() is deprecated. Use g_path_get_dirname() instead."); first_call = FALSE; } #endif /* G_ENABLE_DEBUG */