Mercurial > hg > xemacs-beta
diff src/print.c @ 5014:c2e0c3af5fe3
cleanups to debug-print, try harder to make it work during GC
-------------------- ChangeLog entries follow: --------------------
src/ChangeLog addition:
2010-02-08 Ben Wing <ben@xemacs.org>
* emacs.c:
* emacs.c (assert_failed):
Fix comments about when inhibit_non_essential_printing_operations
is set and how used. Increment/decrement in assert_failed rather
than just setting/resetting to avoid hosing things in case we're
called when the value is already non-zero. Similarly increment/
decrement in_assert_failed.
* gc.c (gc_prepare):
* gc.c (gc_finish):
Increment/decrement inhibit_non_essential_printing_operations
rather than setting/resetting.
* print.c:
* print.c (debug_out):
* print.c (write_string_to_alternate_debugging_output):
* print.c (restore_inhibit_non_essential_conversion_operations):
* print.c (debug_print_exit):
* print.c (debug_print_enter):
* print.c (debug_prin1):
* print.c (debug_p4):
* print.c (ext_print_begin):
* print.c (ext_print_end):
* print.c (external_debug_print):
* print.c (debug_p3):
* print.c (debug_backtrace):
* print.c (debug_short_backtrace):
* print.c (vars_of_print):
Lots of cleanup. Fix debug_out() so it binds
inhibit_non_essential_printing_operations around it to ensure no
conversion. Remove many other places that set the same var since
the lower-level functions now all do it. A few other places, add
inhibit_non_essential_printing_operations bindings.Extract the
code out that sets up and resets lots of bindings in debug_prin1()
so that debug_backtrace() can use it, and rewrite it to use the
new STORE_VOID_IN_LISP() rather than having to have a single
static opaque structure holding all the bindings (and not handling
reentrancy). Fix raw `char' to be `CIbyte' in the declaration of
`alternate_do_string'.
* signal.c (check_what_happened):
Fix bug: Don't try to check for QUIT when
inhibit_non_essential_printing_operations or we may screw things
up if QUIT happens during debug printing.
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Mon, 08 Feb 2010 07:00:24 -0600 |
parents | ae48681c47fa |
children | b5df3737028a |
line wrap: on
line diff
--- a/src/print.c Mon Feb 08 06:42:16 2010 -0600 +++ b/src/print.c Mon Feb 08 07:00:24 2010 -0600 @@ -137,7 +137,8 @@ Lisp_Object Vinhibit_quit; }; -static Lisp_Object debug_prin1_bindings; +static int begin_inhibit_non_essential_conversion_operations (void); + int stdout_needs_newline; @@ -362,10 +363,12 @@ void debug_out (const CIbyte *fmt, ...) { + int depth = begin_inhibit_non_essential_conversion_operations (); va_list args; va_start (args, fmt); write_string_to_external_output_va (fmt, args, EXT_PRINT_ALL); va_end (args); + unbind_to (depth); } DOESNT_RETURN @@ -2142,8 +2145,8 @@ if (alternate_do_pointer + extlen >= alternate_do_size) { alternate_do_size = - max(alternate_do_size * 2, alternate_do_pointer + extlen + 1); - XREALLOC_ARRAY (alternate_do_string, char, alternate_do_size); + max (alternate_do_size * 2, alternate_do_pointer + extlen + 1); + XREALLOC_ARRAY (alternate_do_string, CIbyte, alternate_do_size); } memcpy (alternate_do_string + alternate_do_pointer, extptr, extlen); alternate_do_pointer += extlen; @@ -2260,18 +2263,38 @@ return Qnil; } +static Lisp_Object +restore_inhibit_non_essential_conversion_operations (Lisp_Object obj) +{ + inhibit_non_essential_conversion_operations = XINT (obj); + return Qnil; +} + +/* Bind the value of inhibit_non_essential_conversion_operations to 1 + in a way that involves no consing. */ +static int +begin_inhibit_non_essential_conversion_operations (void) +{ + int depth = + record_unwind_protect + (restore_inhibit_non_essential_conversion_operations, + make_int (inhibit_non_essential_conversion_operations)); + inhibit_non_essential_conversion_operations = 1; + return depth; +} + static int debug_print_length = 50; static int debug_print_level = 15; static int debug_print_readably = -1; /* Restore values temporarily bound by debug_prin1. We use this approach to - avoid consing in debug_prin1. That is verboten, since debug_prin1 can be + avoid consing in debug_prin1. That is verboten, since debug_print can be called by cons debugging code. */ static Lisp_Object -debug_prin1_exit (Lisp_Object UNUSED (ignored)) +debug_print_exit (Lisp_Object val) { - struct debug_bindings *bindings = - (struct debug_bindings *) XOPAQUE (debug_prin1_bindings)->data; + struct debug_bindings *bindings = + (struct debug_bindings *) GET_VOID_FROM_LISP (val); inhibit_non_essential_conversion_operations = bindings->inhibit_non_essential_conversion_operations; print_depth = bindings->print_depth; @@ -2285,20 +2308,18 @@ return Qnil; } -/* Print an object, `prin1'-style, to various possible debugging outputs. - Make sure it's completely unbuffered so that, in the event of a crash - somewhere, we see as much as possible that happened before it. - */ -static void -debug_prin1 (Lisp_Object debug_print_obj, int flags) +/* Save values and bind them to new values suitable for debug output. We + try very hard to avoid any Lisp allocation (i.e. consing) during the + operation of debug printing, since we might be calling it from inside GC + or other sensitive places. This means we have to be a bit careful with + record_unwind_protect to not create any temporary Lisp objects. */ + +static int +debug_print_enter (struct debug_bindings *bindings) { - /* This function can GC */ - /* by doing this, we trick various things that are non-essential but might cause crashes into not getting executed. */ int specdepth; - struct debug_bindings *bindings = - (struct debug_bindings *) XOPAQUE (debug_prin1_bindings)->data; bindings->inhibit_non_essential_conversion_operations = inhibit_non_essential_conversion_operations; @@ -2310,7 +2331,8 @@ bindings->Vprint_length = Vprint_length; bindings->Vprint_level = Vprint_level; bindings->Vinhibit_quit = Vinhibit_quit; - specdepth = record_unwind_protect (debug_prin1_exit, Qnil); + specdepth = record_unwind_protect (debug_print_exit, + STORE_VOID_IN_LISP (bindings)); inhibit_non_essential_conversion_operations = 1; print_depth = 0; @@ -2324,6 +2346,20 @@ Vprint_level = make_int (debug_print_level); Vinhibit_quit = Qt; + return specdepth; +} + +/* Print an object, `prin1'-style, to various possible debugging outputs. + Make sure it's completely unbuffered so that, in the event of a crash + somewhere, we see as much as possible that happened before it. + */ +static void +debug_prin1 (Lisp_Object debug_print_obj, int flags) +{ + /* This function cannot GC, since GC is forbidden */ + struct debug_bindings bindings; + int specdepth = debug_print_enter (&bindings); + if ((flags & EXT_PRINT_STDOUT) || (flags & EXT_PRINT_STDERR)) print_internal (debug_print_obj, Qexternal_debugging_output, 1); if (flags & EXT_PRINT_ALTERNATE) @@ -2342,7 +2378,6 @@ void debug_p4 (Lisp_Object obj) { - inhibit_non_essential_conversion_operations = 1; if (STRINGP (obj)) debug_out ("\"%s\"", XSTRING_DATA (obj)); else if (CONSP (obj)) @@ -2416,42 +2451,41 @@ ((struct old_lcrecord_header *) header)->uid)); #endif /* not NEW_GC */ } - - inhibit_non_essential_conversion_operations = 0; } -static void +static int ext_print_begin (int dest) { + int depth = begin_inhibit_non_essential_conversion_operations (); if (dest & EXT_PRINT_ALTERNATE) alternate_do_pointer = 0; if (dest & (EXT_PRINT_STDERR | EXT_PRINT_STDOUT)) stdout_clear_before_next_output = 1; + return depth; } static void -ext_print_end (int dest) +ext_print_end (int dest, int depth) { if (dest & (EXT_PRINT_MSWINDOWS | EXT_PRINT_STDERR | EXT_PRINT_STDOUT)) external_out (dest & (EXT_PRINT_MSWINDOWS | EXT_PRINT_STDERR | EXT_PRINT_STDOUT), "\n"); + unbind_to (depth); } static void external_debug_print (Lisp_Object object, int dest) { - ext_print_begin (dest); + int depth = ext_print_begin (dest); debug_prin1 (object, dest); - ext_print_end (dest); + ext_print_end (dest, depth); } void debug_p3 (Lisp_Object obj) { debug_p4 (obj); - inhibit_non_essential_conversion_operations = 1; debug_out ("\n"); - inhibit_non_essential_conversion_operations = 0; } void @@ -2483,22 +2517,9 @@ void debug_backtrace (void) { - /* This function can GC */ - - /* by doing this, we trick various things that are non-essential - but might cause crashes into not getting executed. */ - int specdepth = - internal_bind_int (&inhibit_non_essential_conversion_operations, 1); - - internal_bind_int (&print_depth, 0); - internal_bind_int (&print_readably, 0); - internal_bind_int (&print_unbuffered, print_unbuffered + 1); - if (debug_print_length > 0) - internal_bind_lisp_object (&Vprint_length, make_int (debug_print_length)); - if (debug_print_level > 0) - internal_bind_lisp_object (&Vprint_level, make_int (debug_print_level)); - /* #### Do we need this? It was in the old code. */ - internal_bind_lisp_object (&Vinhibit_quit, Vinhibit_quit); + /* This function cannot GC, since GC is forbidden */ + struct debug_bindings bindings; + int specdepth = debug_print_enter (&bindings); Fbacktrace (Qexternal_debugging_output, Qt); stderr_out ("\n"); @@ -2519,6 +2540,7 @@ { int first = 1; struct backtrace *bt = backtrace_list; + debug_out (" ["); while (length > 0 && bt) { @@ -2698,10 +2720,9 @@ */ ); Vprint_message_label = Qprint; - debug_prin1_bindings = - make_opaque (OPAQUE_UNINIT, sizeof (struct debug_bindings)); - staticpro (&debug_prin1_bindings); - + /* The exact size doesn't matter since we realloc when necessary. + Use CIbyte instead of Ibyte so that debuggers show the associated + string automatically. */ alternate_do_size = 5000; - alternate_do_string = xnew_array(char, 5000); + alternate_do_string = xnew_array (CIbyte, 5000); }