This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[rfa] catch_exceptions()


Hello,

Following up on my last e-mail, here is a tested patch that adds 
catch_exceptions() to top.c

If this is approved, I think I'll add catch_errors() to the ARI (under 
warnings).

	Andrew
2001-08-13  Andrew Cagney  <ac131313@redhat.com>

	* defs.h (enum return_reason): Renumber so that all values are
	negative.
	(RETURN_MASK): Negate reason.
	(catch_exception_ftype): Declare.
	(catch_exceptions): Declare.
	* top.c (catcher): New function, based on catch_errors.  Add in
	parameter func_uiout and out parameters func_val, func_caught and
	func_cleanup.  Change type of func to catch_exceptions_ftype.
	Save/restore uiout.
	(struct catch_errors_args): Define.
	(do_catch_errors): New function.
	(catch_errors): Rewrite, use do_catch_errors and catcher.
	(catch_exceptions): New function, use catcher.

Index: defs.h
===================================================================
RCS file: /cvs/src/src/gdb/defs.h,v
retrieving revision 1.62
diff -p -r1.62 defs.h
*** defs.h	2001/08/02 20:57:19	1.62
--- defs.h	2001/08/15 17:49:33
*************** extern NORETURN void internal_error (con
*** 1084,1104 ****
  
  extern NORETURN void nomem (long) ATTR_NORETURN;
  
! /* Reasons for calling return_to_top_level.  Note: enum value 0 is
!    reserved for internal use as the return value from an initial
!    setjmp().  */
  
  enum return_reason
    {
      /* User interrupt.  */
!     RETURN_QUIT = 1,
      /* Any other error.  */
      RETURN_ERROR
    };
  
  #define	ALL_CLEANUPS	((struct cleanup *)0)
  
! #define RETURN_MASK(reason)	(1 << (int)(reason))
  #define RETURN_MASK_QUIT	RETURN_MASK (RETURN_QUIT)
  #define RETURN_MASK_ERROR	RETURN_MASK (RETURN_ERROR)
  #define RETURN_MASK_ALL		(RETURN_MASK_QUIT | RETURN_MASK_ERROR)
--- 1084,1106 ----
  
  extern NORETURN void nomem (long) ATTR_NORETURN;
  
! /* Reasons for calling return_to_top_level.  NOTE: all reason values
!    must be less than zero.  enum value 0 is reserved for internal use
!    as the return value from an initial setjmp().  The functioin
!    catch_exceptions() reserves values >= 0 as legal results from its
!    wrapped function.  */
  
  enum return_reason
    {
      /* User interrupt.  */
!     RETURN_QUIT = -2,
      /* Any other error.  */
      RETURN_ERROR
    };
  
  #define	ALL_CLEANUPS	((struct cleanup *)0)
  
! #define RETURN_MASK(reason)	(1 << (int)(-reason))
  #define RETURN_MASK_QUIT	RETURN_MASK (RETURN_QUIT)
  #define RETURN_MASK_ERROR	RETURN_MASK (RETURN_ERROR)
  #define RETURN_MASK_ALL		(RETURN_MASK_QUIT | RETURN_MASK_ERROR)
*************** typedef int return_mask;
*** 1106,1117 ****
  
  extern NORETURN void return_to_top_level (enum return_reason) ATTR_NORETURN;
  
  /* If CATCH_ERRORS_FTYPE throws an error, catch_errors() returns zero
     otherwize the result from CATCH_ERRORS_FTYPE is returned. It is
     probably useful for CATCH_ERRORS_FTYPE to always return a non-zero
     value. It's unfortunate that, catch_errors() does not return an
     indication of the exact exception that it caught - quit_flag might
!    help. */
  
  typedef int (catch_errors_ftype) (PTR);
  extern int catch_errors (catch_errors_ftype *, PTR, char *, return_mask);
--- 1108,1148 ----
  
  extern NORETURN void return_to_top_level (enum return_reason) ATTR_NORETURN;
  
+ /* Call FUNC(UIOUT, FUNC_ARGS) but wrapped within an exception
+    handler.  If an exception (enum return_reason) is thrown using
+    return_to_top_level() than all cleanups installed since
+    catch_exceptions() was entered are invoked, the (-ve) exception
+    value is then returned by catch_exceptions.  If FUNC() returns
+    normally (with a postive or zero return value) then that value is
+    returned by catch_exceptions().  It is an internal_error() for
+    FUNC() to return a negative value.
+ 
+    For the period of the FUNC() call: UIOUT is installed as the output
+    builder; ERRSTRING is installed as the error/quit message; and a
+    new cleanup_chain is established.  The old values are restored
+    before catch_exceptions() returns.
+ 
+    FIXME; cagney/2001-08-13: The need to override the global UIOUT
+    builder variable should just go away.
+ 
+    This function superseeds catch_errors().
+ 
+    This function uses SETJMP() and LONGJUMP().  */
+ 
+ struct ui_out;
+ typedef int (catch_exceptions_ftype) (struct ui_out *ui_out, void *args);
+ extern int catch_exceptions (struct ui_out *uiout,
+ 			     catch_exceptions_ftype *func, void *func_args,
+ 			     char *errstring, return_mask mask);
+ 
  /* If CATCH_ERRORS_FTYPE throws an error, catch_errors() returns zero
     otherwize the result from CATCH_ERRORS_FTYPE is returned. It is
     probably useful for CATCH_ERRORS_FTYPE to always return a non-zero
     value. It's unfortunate that, catch_errors() does not return an
     indication of the exact exception that it caught - quit_flag might
!    help.
! 
!    This function is superseeded by catch_exceptions().  */
  
  typedef int (catch_errors_ftype) (PTR);
  extern int catch_errors (catch_errors_ftype *, PTR, char *, return_mask);
Index: top.c
===================================================================
RCS file: /cvs/src/src/gdb/top.c,v
retrieving revision 1.42
diff -p -r1.42 top.c
*** top.c	2001/08/01 18:39:23	1.42
--- top.c	2001/08/15 17:49:40
***************
*** 41,46 ****
--- 41,47 ----
  #include "version.h"
  #include "serial.h"
  #include "doublest.h"
+ #include "gdb_assert.h"
  
  /* readline include files */
  #include <readline/readline.h>
*************** return_to_top_level (enum return_reason 
*** 347,356 ****
    (NORETURN void) SIGLONGJMP (*catch_return, (int) reason);
  }
  
! /* Call FUNC with arg ARGS, catching any errors.  If there is no
!    error, return the value returned by FUNC.  If there is an error,
!    print ERRSTRING, print the specific error message, then return
!    zero.
  
     Must not be called with immediate_quit in effect (bad things might
     happen, say we got a signal in the middle of a memcpy to quit_return).
--- 348,358 ----
    (NORETURN void) SIGLONGJMP (*catch_return, (int) reason);
  }
  
! /* Call FUNC() with args FUNC_UIOUT and FUNC_ARGS, catching any
!    errors.  Set FUNC_CAUGHT to an ``enum return_reason'' if the
!    function is aborted (using return_to_top_level() or zero if the
!    function returns normally.  Set FUNC_VAL to the value returned by
!    the function or 0 if the function was aborted.
  
     Must not be called with immediate_quit in effect (bad things might
     happen, say we got a signal in the middle of a memcpy to quit_return).
*************** return_to_top_level (enum return_reason 
*** 378,398 ****
     be consolidated into a single file instead of being distributed
     between utils.c and top.c? */
  
! int
! catch_errors (catch_errors_ftype *func, void * args, char *errstring,
! 	      return_mask mask)
  {
    SIGJMP_BUF *saved_catch;
    SIGJMP_BUF catch;
-   int val;
    struct cleanup *saved_cleanup_chain;
    char *saved_error_pre_print;
    char *saved_quit_pre_print;
  
    /* Return value from SIGSETJMP(): enum return_reason if error or
       quit caught, 0 otherwise. */
    int caught;
  
    /* Override error/quit messages during FUNC. */
  
    saved_error_pre_print = error_pre_print;
--- 380,409 ----
     be consolidated into a single file instead of being distributed
     between utils.c and top.c? */
  
! static void
! catcher (catch_exceptions_ftype *func,
! 	 struct ui_out *func_uiout,
! 	 void *func_args,
! 	 int *func_val,
! 	 enum return_reason *func_caught,
! 	 char *errstring,
! 	 return_mask mask)
  {
    SIGJMP_BUF *saved_catch;
    SIGJMP_BUF catch;
    struct cleanup *saved_cleanup_chain;
    char *saved_error_pre_print;
    char *saved_quit_pre_print;
+   struct ui_out *saved_uiout;
  
    /* Return value from SIGSETJMP(): enum return_reason if error or
       quit caught, 0 otherwise. */
    int caught;
  
+   /* Return value from FUNC(): Hopefully non-zero. Explicitly set to
+      zero if an error quit was caught.  */
+   int val;
+ 
    /* Override error/quit messages during FUNC. */
  
    saved_error_pre_print = error_pre_print;
*************** catch_errors (catch_errors_ftype *func, 
*** 403,408 ****
--- 414,424 ----
    if (mask & RETURN_MASK_QUIT)
      quit_pre_print = errstring;
  
+   /* Override the global ``struct ui_out'' builder.  */
+ 
+   saved_uiout = uiout;
+   uiout = func_uiout;
+ 
    /* Prevent error/quit during FUNC from calling cleanups established
       prior to here. */
  
*************** catch_errors (catch_errors_ftype *func, 
*** 414,420 ****
    catch_return = &catch;
    caught = SIGSETJMP (catch);
    if (!caught)
!     val = (*func) (args);
    else
      val = 0;
    catch_return = saved_catch;
--- 430,436 ----
    catch_return = &catch;
    caught = SIGSETJMP (catch);
    if (!caught)
!     val = (*func) (func_uiout, func_args);
    else
      val = 0;
    catch_return = saved_catch;
*************** catch_errors (catch_errors_ftype *func, 
*** 426,472 ****
       do_cleanups call (to cover the problem) or an assertion check to
       detect bad FUNCs code. */
  
!   /* Restore the cleanup chain and error/quit messages to their
!      original states. */
  
    restore_cleanups (saved_cleanup_chain);
  
    if (mask & RETURN_MASK_QUIT)
      quit_pre_print = saved_quit_pre_print;
    if (mask & RETURN_MASK_ERROR)
      error_pre_print = saved_error_pre_print;
- 
-   /* Return normally if no error/quit event occurred. */
  
!   if (!caught)
!     return val;
  
!   /* If the caller didn't request that the event be caught, relay the
       event to the next containing catch_errors(). */
  
!   if (!(mask & RETURN_MASK (caught)))
!     return_to_top_level (caught);
! 
!   /* Tell the caller that an event was caught.
! 
!      FIXME: nsd/2000-02-22: When MASK is RETURN_MASK_ALL, the caller
!      can't tell what type of event occurred.
  
!      A possible fix is to add a new interface, catch_event(), that
!      returns enum return_reason after catching an error or a quit.
  
!      When returning normally, i.e. without catching an error or a
!      quit, catch_event() could return RETURN_NORMAL, which would be
!      added to enum return_reason.  FUNC would return information
!      exclusively via ARGS.
  
!      Alternatively, normal catch_event() could return FUNC's return
!      value.  The caller would need to be aware of potential overlap
!      with enum return_reason, which could be publicly restricted to
!      negative values to simplify return value processing in FUNC and
!      in the caller. */
  
!   return 0;
  }
  
  struct captured_command_args
--- 442,519 ----
       do_cleanups call (to cover the problem) or an assertion check to
       detect bad FUNCs code. */
  
!   /* Restore the cleanup chain, the error/quit messages, and the uiout
!      builder, to their original states. */
  
    restore_cleanups (saved_cleanup_chain);
  
+   uiout = saved_uiout;
+ 
    if (mask & RETURN_MASK_QUIT)
      quit_pre_print = saved_quit_pre_print;
    if (mask & RETURN_MASK_ERROR)
      error_pre_print = saved_error_pre_print;
  
!   /* Return normally if no error/quit event occurred or this catcher
!      can handle this exception.  The caller analyses the func return
!      values.  */
! 
!   if (!caught || (mask & RETURN_MASK (caught)))
!     {
!       *func_val = val;
!       *func_caught = caught;
!       return;
!     }
  
!   /* The caller didn't request that the event be caught, relay the
       event to the next containing catch_errors(). */
  
!   return_to_top_level (caught);
! }
  
! int
! catch_exceptions (struct ui_out *uiout,
! 		  catch_exceptions_ftype *func,
! 		  void *func_args,
! 		  char *errstring,
! 		  return_mask mask)
! {
!   int val;
!   enum return_reason caught;
!   catcher (func, uiout, func_args, &val, &caught, errstring, mask);
!   gdb_assert (val >= 0);
!   gdb_assert (caught <= 0);
!   if (caught < 0)
!     return caught;
!   return val;
! }
  
! struct catch_errors_args
! {
!   catch_errors_ftype *func;
!   void *func_args;
! };
  
! int
! do_catch_errors (struct ui_out *uiout, void *data)
! {
!   struct catch_errors_args *args = data;
!   return args->func (args->func_args);
! }
  
! int
! catch_errors (catch_errors_ftype *func, void *func_args, char *errstring,
! 	      return_mask mask)
! {
!   int val;
!   enum return_reason caught;
!   struct catch_errors_args args;
!   args.func = func;
!   args.func_args = func_args;
!   catcher (do_catch_errors, uiout, &args, &val, &caught, errstring, mask);
!   if (caught != 0)
!     return 0;
!   return val;
  }
  
  struct captured_command_args

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]