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