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 without_interrupts ();
59 static void unwind_frame_discard_internal ();
60 static void unwind_frame_run_internal ();
61 static void add_unwind_protect_internal ();
62 static void remove_unwind_protect_internal ();
63 static void run_unwind_protects_internal ();
64 static void clear_unwind_protects_internal ();
65 static void restore_variable ();
66 static void discard_saved_var ();
68 static UNWIND_ELT
*unwind_protect_list
= (UNWIND_ELT
*)NULL
;
70 extern int interrupt_immediately
;
72 /* Run a function without interrupts. This relies on the fact that the
73 FUNCTION cannot change the value of interrupt_immediately. (I.e., does
76 without_interrupts (function
, arg1
, arg2
)
80 int old_interrupt_immediately
;
82 old_interrupt_immediately
= interrupt_immediately
;
83 interrupt_immediately
= 0;
85 (*function
)(arg1
, arg2
);
87 interrupt_immediately
= old_interrupt_immediately
;
90 /* Start the beginning of a region. */
92 begin_unwind_frame (tag
)
95 add_unwind_protect ((Function
*)NULL
, tag
);
98 /* Discard the unwind protects back to TAG. */
100 discard_unwind_frame (tag
)
103 if (unwind_protect_list
)
104 without_interrupts (unwind_frame_discard_internal
, tag
, (char *)NULL
);
107 /* Run the unwind protects back to TAG. */
109 run_unwind_frame (tag
)
112 if (unwind_protect_list
)
113 without_interrupts (unwind_frame_run_internal
, tag
, (char *)NULL
);
116 /* Add the function CLEANUP with ARG to the list of unwindable things. */
118 add_unwind_protect (cleanup
, arg
)
122 without_interrupts (add_unwind_protect_internal
, (char *)cleanup
, arg
);
125 /* Remove the top unwind protect from the list. */
127 remove_unwind_protect ()
129 if (unwind_protect_list
)
131 (remove_unwind_protect_internal
, (char *)NULL
, (char *)NULL
);
134 /* Run the list of cleanup functions in unwind_protect_list. */
136 run_unwind_protects ()
138 if (unwind_protect_list
)
140 (run_unwind_protects_internal
, (char *)NULL
, (char *)NULL
);
143 /* Erase the unwind-protect list. If flags is 1, free the elements. */
145 clear_unwind_protect_list (flags
)
148 if (unwind_protect_list
)
150 (clear_unwind_protects_internal
, (char *)flags
, (char *)NULL
);
153 /* **************************************************************** */
155 /* The Actual Functions */
157 /* **************************************************************** */
160 add_unwind_protect_internal (cleanup
, arg
)
166 elt
= (UNWIND_ELT
*)xmalloc (sizeof (UNWIND_ELT
));
167 elt
->cleanup
= cleanup
;
169 elt
->next
= unwind_protect_list
;
170 unwind_protect_list
= elt
;
174 remove_unwind_protect_internal (ignore1
, ignore2
)
175 char *ignore1
, *ignore2
;
179 elt
= unwind_protect_list
;
182 unwind_protect_list
= unwind_protect_list
->next
;
183 if (elt
->cleanup
&& elt
->cleanup
== (Function
*)restore_variable
)
184 discard_saved_var ((SAVED_VAR
*)elt
->arg
);
190 run_unwind_protects_internal (ignore1
, ignore2
)
191 char *ignore1
, *ignore2
;
193 UNWIND_ELT
*t
, *elt
= unwind_protect_list
;
197 /* This function can be run at strange times, like when unwinding
198 the entire world of unwind protects. Thus, we may come across
199 an element which is simply a label for a catch frame. Don't call
200 the non-existant function. */
202 (*(elt
->cleanup
)) (elt
->arg
);
208 unwind_protect_list
= elt
;
212 clear_unwind_protects_internal (flag
, ignore
)
215 int free_elts
= (int)flag
;
218 if (free_elts
!= 0 && unwind_protect_list
)
220 while (unwind_protect_list
)
221 remove_unwind_protect_internal ((char *)NULL
, (char *)NULL
);
223 unwind_protect_list
= (UNWIND_ELT
*)NULL
;
227 unwind_frame_discard_internal (tag
, ignore
)
232 while (elt
= unwind_protect_list
)
234 unwind_protect_list
= unwind_protect_list
->next
;
235 if (elt
->cleanup
== 0 && (STREQ (elt
->arg
, tag
)))
240 else if (elt
->cleanup
&& elt
->cleanup
== (Function
*)restore_variable
)
242 discard_saved_var ((SAVED_VAR
*)elt
->arg
);
251 unwind_frame_run_internal (tag
, ignore
)
256 while (elt
= unwind_protect_list
)
258 unwind_protect_list
= elt
->next
;
260 /* If tag, then compare. */
263 if (STREQ (elt
->arg
, tag
))
273 (*(elt
->cleanup
)) (elt
->arg
);
280 discard_saved_var (sv
)
283 if (sv
->size
!= sizeof (int))
284 free (sv
->desired_setting
);
288 /* Restore the value of a variable, based on the contents of SV. If
289 sv->size is greater than sizeof (int), sv->desired_setting points to
290 a block of memory SIZE bytes long holding the value, rather than the
291 value itself. This block of memory is copied back into the variable. */
293 restore_variable (sv
)
296 if (sv
->size
!= sizeof (int))
298 FASTCOPY ((char *)sv
->desired_setting
, (char *)sv
->variable
, sv
->size
);
299 free (sv
->desired_setting
);
302 *(sv
->variable
) = (int)sv
->desired_setting
;
307 /* Save the value of a variable so it will be restored when unwind-protects
308 are run. VAR is a pointer to the variable. VALUE is the value to be
309 saved. SIZE is the size in bytes of VALUE. If SIZE is bigger than what
310 can be saved in an int, memory will be allocated and the value saved
311 into that using bcopy (). */
313 unwind_protect_var (var
, value
, size
)
318 SAVED_VAR
*s
= (SAVED_VAR
*)xmalloc (sizeof (SAVED_VAR
));
321 if (size
!= sizeof (int))
323 s
->desired_setting
= (char *)xmalloc (size
);
324 FASTCOPY (value
, (char *)s
->desired_setting
, size
);
327 s
->desired_setting
= value
;
329 add_unwind_protect ((Function
*)restore_variable
, (char *)s
);