1 /* I can't stand it anymore! Please can't we just write the
2 whole Unix system in lisp or something? */
4 /* Copyright (C) 1987,1989 Free Software Foundation, Inc.
6 This file is part of GNU Bash, the Bourne Again SHell.
8 Bash is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
13 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 You should have received a copy of the GNU General Public License along
19 with Bash; see the file COPYING. If not, write to the Free Software
20 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
22 /* **************************************************************** */
24 /* Unwind Protection Scheme for Bash */
26 /* **************************************************************** */
29 #include "bashtypes.h"
32 #if defined (HAVE_UNISTD_H)
38 #include "unwind_prot.h"
42 /* If CLEANUP is null, then ARG contains a tag to throw back to. */
49 /* Structure describing a saved variable and the value to restore it to.
50 If a cleanup function is set to restore_variable, the `arg' pointer
54 char *desired_setting;
58 static void unwind_frame_discard_internal (), unwind_frame_run_internal ();
59 static void add_unwind_protect_internal (), remove_unwind_protect_internal ();
60 static void run_unwind_protects_internal (), without_interrupts ();
62 static void restore_variable ();
63 static void discard_saved_var ();
65 static UNWIND_ELT *unwind_protect_list = (UNWIND_ELT *)NULL;
67 extern int interrupt_immediately;
69 /* Run a function without interrupts. This relies on the fact that the
70 FUNCTION cannot change the value of interrupt_immediately. (I.e., does
73 without_interrupts (function, arg1, arg2)
77 int old_interrupt_immediately;
79 old_interrupt_immediately = interrupt_immediately;
80 interrupt_immediately = 0;
82 (*function)(arg1, arg2);
84 interrupt_immediately = old_interrupt_immediately;
87 /* Start the beginning of a region. */
89 begin_unwind_frame (tag)
92 add_unwind_protect ((Function *)NULL, tag);
95 /* Discard the unwind protects back to TAG. */
97 discard_unwind_frame (tag)
100 if (unwind_protect_list)
101 without_interrupts (unwind_frame_discard_internal, tag, (char *)NULL);
104 /* Run the unwind protects back to TAG. */
106 run_unwind_frame (tag)
109 if (unwind_protect_list)
110 without_interrupts (unwind_frame_run_internal, tag, (char *)NULL);
113 /* Add the function CLEANUP with ARG to the list of unwindable things. */
115 add_unwind_protect (cleanup, arg)
119 without_interrupts (add_unwind_protect_internal, (char *)cleanup, arg);
122 /* Remove the top unwind protect from the list. */
124 remove_unwind_protect ()
126 if (unwind_protect_list)
128 (remove_unwind_protect_internal, (char *)NULL, (char *)NULL);
131 /* Run the list of cleanup functions in unwind_protect_list. */
133 run_unwind_protects ()
135 if (unwind_protect_list)
137 (run_unwind_protects_internal, (char *)NULL, (char *)NULL);
140 /* **************************************************************** */
142 /* The Actual Functions */
144 /* **************************************************************** */
147 add_unwind_protect_internal (cleanup, arg)
153 elt = (UNWIND_ELT *)xmalloc (sizeof (UNWIND_ELT));
154 elt->cleanup = cleanup;
156 elt->next = unwind_protect_list;
157 unwind_protect_list = elt;
161 remove_unwind_protect_internal ()
165 elt = unwind_protect_list;
168 unwind_protect_list = unwind_protect_list->next;
169 if (elt->cleanup && elt->cleanup == (Function *)restore_variable)
170 discard_saved_var ((SAVED_VAR *)elt->arg);
176 run_unwind_protects_internal ()
178 UNWIND_ELT *t, *elt = unwind_protect_list;
182 /* This function can be run at strange times, like when unwinding
183 the entire world of unwind protects. Thus, we may come across
184 an element which is simply a label for a catch frame. Don't call
185 the non-existant function. */
187 (*(elt->cleanup)) (elt->arg);
193 unwind_protect_list = elt;
197 unwind_frame_discard_internal (tag)
202 while (elt = unwind_protect_list)
204 unwind_protect_list = unwind_protect_list->next;
205 if (elt->cleanup == 0 && (STREQ (elt->arg, tag)))
210 else if (elt->cleanup && elt->cleanup == (Function *)restore_variable)
212 discard_saved_var ((SAVED_VAR *)elt->arg);
221 unwind_frame_run_internal (tag)
226 while (elt = unwind_protect_list)
228 unwind_protect_list = elt->next;
230 /* If tag, then compare. */
233 if (STREQ (elt->arg, tag))
243 (*(elt->cleanup)) (elt->arg);
250 discard_saved_var (sv)
253 if (sv->size != sizeof (int))
254 free (sv->desired_setting);
258 /* Restore the value of a variable, based on the contents of SV. If
259 sv->size is greater than sizeof (int), sv->desired_setting points to
260 a block of memory SIZE bytes long holding the value, rather than the
261 value itself. This block of memory is copied back into the variable. */
263 restore_variable (sv)
266 if (sv->size != sizeof (int))
268 FASTCOPY ((char *)sv->desired_setting, (char *)sv->variable, sv->size);
269 free (sv->desired_setting);
272 *(sv->variable) = (int)sv->desired_setting;
277 /* Save the value of a variable so it will be restored when unwind-protects
278 are run. VAR is a pointer to the variable. VALUE is the value to be
279 saved. SIZE is the size in bytes of VALUE. If SIZE is bigger than what
280 can be saved in an int, memory will be allocated and the value saved
281 into that using bcopy (). */
283 unwind_protect_var (var, value, size)
288 SAVED_VAR *s = (SAVED_VAR *)xmalloc (sizeof (SAVED_VAR));
291 if (size != sizeof (int))
293 /* There is a problem here when VALUE is 0. This tries to copy the
294 first SIZE bytes starting at memory location 0 into
295 s->desired_setting. There is no guarantee that these bytes are
296 0, or make a valid null pointer. We can try to bzero the space,
297 or just save it as 0 (or (void *)0). If we do the latter, make
298 sure restore_variable is changed to understand it. */
299 s->desired_setting = (char *)xmalloc (size);
301 bzero ((char *)s->desired_setting, size);
303 FASTCOPY (value, (char *)s->desired_setting, size);
306 s->desired_setting = value;
308 add_unwind_protect ((Function *)restore_variable, (char *)s);