source: vendor/bash/3.1-p17/unwind_prot.c

Last change on this file was 3231, checked in by bird, 18 years ago

eol style.

  • Property svn:eol-style set to native
File size: 7.8 KB
Line 
1/* I can't stand it anymore! Please can't we just write the
2 whole Unix system in lisp or something? */
3
4/* Copyright (C) 1987-2002 Free Software Foundation, Inc.
5
6This file is part of GNU Bash, the Bourne Again SHell.
7
8Bash is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
10Software Foundation; either version 2, or (at your option) any later
11version.
12
13Bash is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16for more details.
17
18You should have received a copy of the GNU General Public License along
19with Bash; see the file COPYING. If not, write to the Free Software
20Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
21
22/* **************************************************************** */
23/* */
24/* Unwind Protection Scheme for Bash */
25/* */
26/* **************************************************************** */
27#include "config.h"
28
29#include "bashtypes.h"
30#include "bashansi.h"
31
32#if defined (HAVE_UNISTD_H)
33# include <unistd.h>
34#endif
35
36#if STDC_HEADERS
37# include <stddef.h>
38#endif
39
40#ifndef offsetof
41# define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
42#endif
43
44#include "command.h"
45#include "general.h"
46#include "unwind_prot.h"
47#include "quit.h"
48#include "sig.h"
49
50/* Structure describing a saved variable and the value to restore it to. */
51typedef struct {
52 char *variable;
53 int size;
54 char desired_setting[1]; /* actual size is `size' */
55} SAVED_VAR;
56
57/* If HEAD.CLEANUP is null, then ARG.V contains a tag to throw back to.
58 If HEAD.CLEANUP is restore_variable, then SV.V contains the saved
59 variable. Otherwise, call HEAD.CLEANUP (ARG.V) to clean up. */
60typedef union uwp {
61 struct uwp_head {
62 union uwp *next;
63 Function *cleanup;
64 } head;
65 struct {
66 struct uwp_head uwp_head;
67 char *v;
68 } arg;
69 struct {
70 struct uwp_head uwp_head;
71 SAVED_VAR v;
72 } sv;
73} UNWIND_ELT;
74
75
76extern int interrupt_immediately;
77
78static void without_interrupts __P((VFunction *, char *, char *));
79static void unwind_frame_discard_internal __P((char *, char *));
80static void unwind_frame_run_internal __P((char *, char *));
81static void add_unwind_protect_internal __P((Function *, char *));
82static void remove_unwind_protect_internal __P((char *, char *));
83static void run_unwind_protects_internal __P((char *, char *));
84static void clear_unwind_protects_internal __P((char *, char *));
85static inline void restore_variable __P((SAVED_VAR *));
86static void unwind_protect_mem_internal __P((char *, char *));
87
88static UNWIND_ELT *unwind_protect_list = (UNWIND_ELT *)NULL;
89
90#define uwpalloc(elt) (elt) = (UNWIND_ELT *)xmalloc (sizeof (UNWIND_ELT))
91#define uwpfree(elt) free(elt)
92
93/* Run a function without interrupts. This relies on the fact that the
94 FUNCTION cannot change the value of interrupt_immediately. (I.e., does
95 not call QUIT (). */
96static void
97without_interrupts (function, arg1, arg2)
98 VFunction *function;
99 char *arg1, *arg2;
100{
101 int old_interrupt_immediately;
102
103 old_interrupt_immediately = interrupt_immediately;
104 interrupt_immediately = 0;
105
106 (*function)(arg1, arg2);
107
108 interrupt_immediately = old_interrupt_immediately;
109}
110
111/* Start the beginning of a region. */
112void
113begin_unwind_frame (tag)
114 char *tag;
115{
116 add_unwind_protect ((Function *)NULL, tag);
117}
118
119/* Discard the unwind protects back to TAG. */
120void
121discard_unwind_frame (tag)
122 char *tag;
123{
124 if (unwind_protect_list)
125 without_interrupts (unwind_frame_discard_internal, tag, (char *)NULL);
126}
127
128/* Run the unwind protects back to TAG. */
129void
130run_unwind_frame (tag)
131 char *tag;
132{
133 if (unwind_protect_list)
134 without_interrupts (unwind_frame_run_internal, tag, (char *)NULL);
135}
136
137/* Add the function CLEANUP with ARG to the list of unwindable things. */
138void
139add_unwind_protect (cleanup, arg)
140 Function *cleanup;
141 char *arg;
142{
143 without_interrupts (add_unwind_protect_internal, (char *)cleanup, arg);
144}
145
146/* Remove the top unwind protect from the list. */
147void
148remove_unwind_protect ()
149{
150 if (unwind_protect_list)
151 without_interrupts
152 (remove_unwind_protect_internal, (char *)NULL, (char *)NULL);
153}
154
155/* Run the list of cleanup functions in unwind_protect_list. */
156void
157run_unwind_protects ()
158{
159 if (unwind_protect_list)
160 without_interrupts
161 (run_unwind_protects_internal, (char *)NULL, (char *)NULL);
162}
163
164/* Erase the unwind-protect list. If flags is 1, free the elements. */
165void
166clear_unwind_protect_list (flags)
167 int flags;
168{
169 char *flag;
170
171 if (unwind_protect_list)
172 {
173 flag = flags ? "" : (char *)NULL;
174 without_interrupts
175 (clear_unwind_protects_internal, flag, (char *)NULL);
176 }
177}
178
179/* **************************************************************** */
180/* */
181/* The Actual Functions */
182/* */
183/* **************************************************************** */
184
185static void
186add_unwind_protect_internal (cleanup, arg)
187 Function *cleanup;
188 char *arg;
189{
190 UNWIND_ELT *elt;
191
192 uwpalloc (elt);
193 elt->head.next = unwind_protect_list;
194 elt->head.cleanup = cleanup;
195 elt->arg.v = arg;
196 unwind_protect_list = elt;
197}
198
199static void
200remove_unwind_protect_internal (ignore1, ignore2)
201 char *ignore1, *ignore2;
202{
203 UNWIND_ELT *elt;
204
205 elt = unwind_protect_list;
206 if (elt)
207 {
208 unwind_protect_list = unwind_protect_list->head.next;
209 uwpfree (elt);
210 }
211}
212
213static void
214run_unwind_protects_internal (ignore1, ignore2)
215 char *ignore1, *ignore2;
216{
217 unwind_frame_run_internal ((char *) NULL, (char *) NULL);
218}
219
220static void
221clear_unwind_protects_internal (flag, ignore)
222 char *flag, *ignore;
223{
224 if (flag)
225 {
226 while (unwind_protect_list)
227 remove_unwind_protect_internal ((char *)NULL, (char *)NULL);
228 }
229 unwind_protect_list = (UNWIND_ELT *)NULL;
230}
231
232static void
233unwind_frame_discard_internal (tag, ignore)
234 char *tag, *ignore;
235{
236 UNWIND_ELT *elt;
237
238 while (elt = unwind_protect_list)
239 {
240 unwind_protect_list = unwind_protect_list->head.next;
241 if (elt->head.cleanup == 0 && (STREQ (elt->arg.v, tag)))
242 {
243 uwpfree (elt);
244 break;
245 }
246 else
247 uwpfree (elt);
248 }
249}
250
251/* Restore the value of a variable, based on the contents of SV.
252 sv->desired_setting is a block of memory SIZE bytes long holding the
253 value itself. This block of memory is copied back into the variable. */
254static inline void
255restore_variable (sv)
256 SAVED_VAR *sv;
257{
258 FASTCOPY (sv->desired_setting, sv->variable, sv->size);
259}
260
261static void
262unwind_frame_run_internal (tag, ignore)
263 char *tag, *ignore;
264{
265 UNWIND_ELT *elt;
266
267 while (elt = unwind_protect_list)
268 {
269 unwind_protect_list = elt->head.next;
270
271 /* If tag, then compare. */
272 if (!elt->head.cleanup)
273 {
274 if (tag && STREQ (elt->arg.v, tag))
275 {
276 uwpfree (elt);
277 break;
278 }
279 }
280 else
281 {
282 if (elt->head.cleanup == (Function *) restore_variable)
283 restore_variable (&elt->sv.v);
284 else
285 (*(elt->head.cleanup)) (elt->arg.v);
286 }
287
288 uwpfree (elt);
289 }
290}
291
292static void
293unwind_protect_mem_internal (var, psize)
294 char *var;
295 char *psize;
296{
297 int size, allocated;
298 UNWIND_ELT *elt;
299
300 size = *(int *) psize;
301 allocated = size + offsetof (UNWIND_ELT, sv.v.desired_setting[0]);
302 elt = (UNWIND_ELT *)xmalloc (allocated);
303 elt->head.next = unwind_protect_list;
304 elt->head.cleanup = (Function *) restore_variable;
305 elt->sv.v.variable = var;
306 elt->sv.v.size = size;
307 FASTCOPY (var, elt->sv.v.desired_setting, size);
308 unwind_protect_list = elt;
309}
310
311/* Save the value of a variable so it will be restored when unwind-protects
312 are run. VAR is a pointer to the variable. SIZE is the size in
313 bytes of VAR. */
314void
315unwind_protect_mem (var, size)
316 char *var;
317 int size;
318{
319 without_interrupts (unwind_protect_mem_internal, var, (char *) &size);
320}
Note: See TracBrowser for help on using the repository browser.