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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
22 /* **************************************************************** */
24 /* Unwind Protection Scheme for Bash */
26 /* **************************************************************** */
29 #include "bashtypes.h"
30 #if defined (HAVE_UNISTD_H)
36 #include "unwind_prot.h"
40 /* If CLEANUP is null, then ARG contains a tag to throw back to. */
48 unwind_frame_discard_internal (), unwind_frame_run_internal (),
49 add_unwind_protect_internal (), remove_unwind_protect_internal (),
50 run_unwind_protects_internal (), without_interrupts ();
52 static UNWIND_ELT
*unwind_protect_list
= (UNWIND_ELT
*)NULL
;
54 extern int interrupt_immediately
;
56 /* Run a function without interrupts. This relies on the fact that the
57 FUNCTION cannot change the value of interrupt_immediately. (I.e., does
60 without_interrupts (function
, arg1
, arg2
)
64 int old_interrupt_immediately
;
66 old_interrupt_immediately
= interrupt_immediately
;
67 interrupt_immediately
= 0;
69 (*function
)(arg1
, arg2
);
71 interrupt_immediately
= old_interrupt_immediately
;
74 /* Start the beginning of a region. */
76 begin_unwind_frame (tag
)
79 add_unwind_protect ((Function
*)NULL
, tag
);
82 /* Discard the unwind protects back to TAG. */
84 discard_unwind_frame (tag
)
87 if (unwind_protect_list
)
88 without_interrupts (unwind_frame_discard_internal
, tag
, (char *)NULL
);
91 /* Run the unwind protects back to TAG. */
93 run_unwind_frame (tag
)
96 if (unwind_protect_list
)
97 without_interrupts (unwind_frame_run_internal
, tag
, (char *)NULL
);
100 /* Add the function CLEANUP with ARG to the list of unwindable things. */
102 add_unwind_protect (cleanup
, arg
)
106 without_interrupts (add_unwind_protect_internal
, (char *)cleanup
, arg
);
109 /* Remove the top unwind protect from the list. */
111 remove_unwind_protect ()
113 if (unwind_protect_list
)
115 (remove_unwind_protect_internal
, (char *)NULL
, (char *)NULL
);
118 /* Run the list of cleanup functions in unwind_protect_list. */
120 run_unwind_protects ()
122 if (unwind_protect_list
)
124 (run_unwind_protects_internal
, (char *)NULL
, (char *)NULL
);
127 /* **************************************************************** */
129 /* The Actual Functions */
131 /* **************************************************************** */
134 add_unwind_protect_internal (cleanup
, arg
)
140 elt
= (UNWIND_ELT
*)xmalloc (sizeof (UNWIND_ELT
));
141 elt
->cleanup
= cleanup
;
143 elt
->next
= unwind_protect_list
;
144 unwind_protect_list
= elt
;
148 remove_unwind_protect_internal ()
150 UNWIND_ELT
*elt
= unwind_protect_list
;
154 unwind_protect_list
= unwind_protect_list
->next
;
160 run_unwind_protects_internal ()
162 UNWIND_ELT
*t
, *elt
= unwind_protect_list
;
166 /* This function can be run at strange times, like when unwinding
167 the entire world of unwind protects. Thus, we may come across
168 an element which is simply a label for a catch frame. Don't call
169 the non-existant function. */
171 (*(elt
->cleanup
)) (elt
->arg
);
177 unwind_protect_list
= elt
;
181 unwind_frame_discard_internal (tag
)
186 while (elt
= unwind_protect_list
)
188 unwind_protect_list
= unwind_protect_list
->next
;
189 if (!elt
->cleanup
&& (STREQ (elt
->arg
, tag
)))
200 unwind_frame_run_internal (tag
)
205 while (elt
= unwind_protect_list
)
207 unwind_protect_list
= elt
->next
;
209 /* If tag, then compare. */
212 if (STREQ (elt
->arg
, tag
))
222 (*(elt
->cleanup
)) (elt
->arg
);
228 /* Structure describing a saved variable and the value to restore it to. */
231 char *desired_setting
;
235 /* Restore the value of a variable, based on the contents of SV. If
236 sv->size is greater than sizeof (int), sv->desired_setting points to
237 a block of memory SIZE bytes long holding the value, rather than the
238 value itself. This block of memory is copied back into the variable. */
240 restore_variable (sv
)
243 if (sv
->size
!= sizeof (int))
245 bcopy ((char *)sv
->desired_setting
, (char *)sv
->variable
, sv
->size
);
246 free (sv
->desired_setting
);
249 *(sv
->variable
) = (int)sv
->desired_setting
;
254 /* Save the value of a variable so it will be restored when unwind-protects
255 are run. VAR is a pointer to the variable. VALUE is the value to be
256 saved. SIZE is the size in bytes of VALUE. If SIZE is bigger than what
257 can be saved in an int, memory will be allocated and the value saved
258 into that using bcopy (). */
260 unwind_protect_var (var
, value
, size
)
265 SAVED_VAR
*s
= (SAVED_VAR
*)xmalloc (sizeof (SAVED_VAR
));
268 if (size
!= sizeof (int))
270 s
->desired_setting
= (char *)xmalloc (size
);
271 bcopy (value
, (char *)s
->desired_setting
, size
);
274 s
->desired_setting
= value
;
276 add_unwind_protect ((Function
*)restore_variable
, (char *)s
);