diff options
Diffstat (limited to 'unwind_prot.c')
-rw-r--r-- | unwind_prot.c | 196 |
1 files changed, 91 insertions, 105 deletions
diff --git a/unwind_prot.c b/unwind_prot.c index 628845c..13dfc78 100644 --- a/unwind_prot.c +++ b/unwind_prot.c @@ -33,37 +33,54 @@ Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ # include <unistd.h> #endif +#if STDC_HEADERS +# include <stddef.h> +#endif + +#ifndef offsetof +# define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif + #include "command.h" #include "general.h" #include "unwind_prot.h" #include "quit.h" #include "sig.h" -/* If CLEANUP is null, then ARG contains a tag to throw back to. */ -typedef struct _uwp { - struct _uwp *next; - Function *cleanup; - char *arg; -} UNWIND_ELT; - -/* Structure describing a saved variable and the value to restore it to. - If a cleanup function is set to restore_variable, the `arg' pointer - points to this. */ +/* Structure describing a saved variable and the value to restore it to. */ typedef struct { - int *variable; - char *desired_setting; + char *variable; int size; + char desired_setting[1]; /* actual size is `size' */ } SAVED_VAR; -static void without_interrupts (); -static void unwind_frame_discard_internal (); -static void unwind_frame_run_internal (); -static void add_unwind_protect_internal (); -static void remove_unwind_protect_internal (); -static void run_unwind_protects_internal (); -static void clear_unwind_protects_internal (); -static void restore_variable (); -static void discard_saved_var (); +/* If HEAD.CLEANUP is null, then ARG.V contains a tag to throw back to. + If HEAD.CLEANUP is restore_variable, then SV.V contains the saved + variable. Otherwise, call HEAD.CLEANUP (ARG.V) to clean up. */ +typedef union uwp { + struct uwp_head { + union uwp *next; + Function *cleanup; + } head; + struct { + struct uwp_head uwp_head; + char *v; + } arg; + struct { + struct uwp_head uwp_head; + SAVED_VAR v; + } sv; +} UNWIND_ELT; + +static void without_interrupts __P((VFunction *, char *, char *)); +static void unwind_frame_discard_internal __P((char *, char *)); +static void unwind_frame_run_internal __P((char *, char *)); +static void add_unwind_protect_internal __P((Function *, char *)); +static void remove_unwind_protect_internal __P((char *, char *)); +static void run_unwind_protects_internal __P((char *, char *)); +static void clear_unwind_protects_internal __P((char *, char *)); +static inline void restore_variable __P((SAVED_VAR *)); +static void unwind_protect_mem_internal __P((char *, char *)); static UNWIND_ELT *unwind_protect_list = (UNWIND_ELT *)NULL; @@ -145,9 +162,14 @@ void clear_unwind_protect_list (flags) int flags; { + char *flag; + if (unwind_protect_list) - without_interrupts - (clear_unwind_protects_internal, (char *)flags, (char *)NULL); + { + flag = flags ? "" : (char *)NULL; + without_interrupts + (clear_unwind_protects_internal, flag, (char *)NULL); + } } /* **************************************************************** */ @@ -164,9 +186,9 @@ add_unwind_protect_internal (cleanup, arg) UNWIND_ELT *elt; elt = (UNWIND_ELT *)xmalloc (sizeof (UNWIND_ELT)); - elt->cleanup = cleanup; - elt->arg = arg; - elt->next = unwind_protect_list; + elt->head.next = unwind_protect_list; + elt->head.cleanup = cleanup; + elt->arg.v = arg; unwind_protect_list = elt; } @@ -179,9 +201,7 @@ remove_unwind_protect_internal (ignore1, ignore2) elt = unwind_protect_list; if (elt) { - unwind_protect_list = unwind_protect_list->next; - if (elt->cleanup && elt->cleanup == (Function *)restore_variable) - discard_saved_var ((SAVED_VAR *)elt->arg); + unwind_protect_list = unwind_protect_list->head.next; free (elt); } } @@ -190,32 +210,14 @@ static void run_unwind_protects_internal (ignore1, ignore2) char *ignore1, *ignore2; { - UNWIND_ELT *t, *elt = unwind_protect_list; - - while (elt) - { - /* This function can be run at strange times, like when unwinding - the entire world of unwind protects. Thus, we may come across - an element which is simply a label for a catch frame. Don't call - the non-existant function. */ - if (elt->cleanup) - (*(elt->cleanup)) (elt->arg); - - t = elt; - elt = elt->next; - free (t); - } - unwind_protect_list = elt; + unwind_frame_run_internal ((char *) NULL, (char *) NULL); } static void clear_unwind_protects_internal (flag, ignore) char *flag, *ignore; { - int free_elts = (int)flag; - UNWIND_ELT *elt; - - if (free_elts != 0 && unwind_protect_list) + if (flag) { while (unwind_protect_list) remove_unwind_protect_internal ((char *)NULL, (char *)NULL); @@ -231,22 +233,27 @@ unwind_frame_discard_internal (tag, ignore) while (elt = unwind_protect_list) { - unwind_protect_list = unwind_protect_list->next; - if (elt->cleanup == 0 && (STREQ (elt->arg, tag))) + unwind_protect_list = unwind_protect_list->head.next; + if (elt->head.cleanup == 0 && (STREQ (elt->arg.v, tag))) { free (elt); break; } - else if (elt->cleanup && elt->cleanup == (Function *)restore_variable) - { - discard_saved_var ((SAVED_VAR *)elt->arg); - free (elt); - } else free (elt); } } +/* Restore the value of a variable, based on the contents of SV. + sv->desired_setting is a block of memory SIZE bytes long holding the + value itself. This block of memory is copied back into the variable. */ +static inline void +restore_variable (sv) + SAVED_VAR *sv; +{ + FASTCOPY (sv->desired_setting, sv->variable, sv->size); +} + static void unwind_frame_run_internal (tag, ignore) char *tag, *ignore; @@ -255,76 +262,55 @@ unwind_frame_run_internal (tag, ignore) while (elt = unwind_protect_list) { - unwind_protect_list = elt->next; + unwind_protect_list = elt->head.next; /* If tag, then compare. */ - if (!elt->cleanup) + if (!elt->head.cleanup) { - if (STREQ (elt->arg, tag)) + if (tag && STREQ (elt->arg.v, tag)) { free (elt); break; } - free (elt); - continue; } else { - (*(elt->cleanup)) (elt->arg); - free (elt); + if (elt->head.cleanup == (Function *) restore_variable) + restore_variable (&elt->sv.v); + else + (*(elt->head.cleanup)) (elt->arg.v); } - } -} -static void -discard_saved_var (sv) - SAVED_VAR *sv; -{ - if (sv->size != sizeof (int)) - free (sv->desired_setting); - free (sv); + free (elt); + } } -/* Restore the value of a variable, based on the contents of SV. If - sv->size is greater than sizeof (int), sv->desired_setting points to - a block of memory SIZE bytes long holding the value, rather than the - value itself. This block of memory is copied back into the variable. */ static void -restore_variable (sv) - SAVED_VAR *sv; +unwind_protect_mem_internal (var, psize) + char *var; + char *psize; { - if (sv->size != sizeof (int)) - { - FASTCOPY ((char *)sv->desired_setting, (char *)sv->variable, sv->size); - free (sv->desired_setting); - } - else - *(sv->variable) = (int)sv->desired_setting; + int size, allocated; + UNWIND_ELT *elt; - free (sv); + size = *(int *) psize; + allocated = size + offsetof (UNWIND_ELT, sv.v.desired_setting[0]); + elt = (UNWIND_ELT *)xmalloc (allocated); + elt->head.next = unwind_protect_list; + elt->head.cleanup = (Function *) restore_variable; + elt->sv.v.variable = var; + elt->sv.v.size = size; + FASTCOPY (var, elt->sv.v.desired_setting, size); + unwind_protect_list = elt; } /* Save the value of a variable so it will be restored when unwind-protects - are run. VAR is a pointer to the variable. VALUE is the value to be - saved. SIZE is the size in bytes of VALUE. If SIZE is bigger than what - can be saved in an int, memory will be allocated and the value saved - into that using bcopy (). */ + are run. VAR is a pointer to the variable. SIZE is the size in + bytes of VAR. */ void -unwind_protect_var (var, value, size) - int *var; - char *value; +unwind_protect_mem (var, size) + char *var; int size; { - SAVED_VAR *s = (SAVED_VAR *)xmalloc (sizeof (SAVED_VAR)); - - s->variable = var; - if (size != sizeof (int)) - { - s->desired_setting = (char *)xmalloc (size); - FASTCOPY (value, (char *)s->desired_setting, size); - } - else - s->desired_setting = value; - s->size = size; - add_unwind_protect ((Function *)restore_variable, (char *)s); + without_interrupts (unwind_protect_mem_internal, var, (char *) &size); } |