]> git.ipfire.org Git - thirdparty/bash.git/blame - unwind_prot.c
Bash-5.0 patch 4: the wait builtin without arguments only waits for known children...
[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 */
a0c0a00f 52#include "ocache.h"
726f6388 53
f73dda09 54/* Structure describing a saved variable and the value to restore it to. */
d166f048 55typedef struct {
f73dda09 56 char *variable;
d166f048 57 int size;
f73dda09 58 char desired_setting[1]; /* actual size is `size' */
d166f048
JA
59} SAVED_VAR;
60
f73dda09
JA
61/* If HEAD.CLEANUP is null, then ARG.V contains a tag to throw back to.
62 If HEAD.CLEANUP is restore_variable, then SV.V contains the saved
63 variable. Otherwise, call HEAD.CLEANUP (ARG.V) to clean up. */
64typedef union uwp {
65 struct uwp_head {
66 union uwp *next;
67 Function *cleanup;
68 } head;
69 struct {
70 struct uwp_head uwp_head;
71 char *v;
72 } arg;
73 struct {
74 struct uwp_head uwp_head;
75 SAVED_VAR v;
76 } sv;
77} UNWIND_ELT;
78
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
a0c0a00f
CR
91/* Allocating from a cache of unwind-protect elements */
92#define UWCACHESIZE 128
93
94sh_obj_cache_t uwcache = {0, 0, 0};
95
96#if 0
7117c2d2
JA
97#define uwpalloc(elt) (elt) = (UNWIND_ELT *)xmalloc (sizeof (UNWIND_ELT))
98#define uwpfree(elt) free(elt)
a0c0a00f
CR
99#else
100#define uwpalloc(elt) ocache_alloc (uwcache, UNWIND_ELT, elt)
101#define uwpfree(elt) ocache_free (uwcache, UNWIND_ELT, elt)
102#endif
103
104void
105uwp_init ()
106{
107 ocache_create (uwcache, UNWIND_ELT, UWCACHESIZE);
108}
726f6388
JA
109
110/* Run a function without interrupts. This relies on the fact that the
111 FUNCTION cannot change the value of interrupt_immediately. (I.e., does
112 not call QUIT (). */
113static void
114without_interrupts (function, arg1, arg2)
115 VFunction *function;
116 char *arg1, *arg2;
117{
118 int old_interrupt_immediately;
119
120 old_interrupt_immediately = interrupt_immediately;
121 interrupt_immediately = 0;
122
123 (*function)(arg1, arg2);
124
125 interrupt_immediately = old_interrupt_immediately;
126}
127
128/* Start the beginning of a region. */
129void
130begin_unwind_frame (tag)
131 char *tag;
132{
133 add_unwind_protect ((Function *)NULL, tag);
134}
135
136/* Discard the unwind protects back to TAG. */
137void
138discard_unwind_frame (tag)
139 char *tag;
140{
141 if (unwind_protect_list)
142 without_interrupts (unwind_frame_discard_internal, tag, (char *)NULL);
143}
144
145/* Run the unwind protects back to TAG. */
146void
147run_unwind_frame (tag)
148 char *tag;
149{
150 if (unwind_protect_list)
151 without_interrupts (unwind_frame_run_internal, tag, (char *)NULL);
152}
153
154/* Add the function CLEANUP with ARG to the list of unwindable things. */
155void
156add_unwind_protect (cleanup, arg)
157 Function *cleanup;
158 char *arg;
159{
160 without_interrupts (add_unwind_protect_internal, (char *)cleanup, arg);
161}
162
163/* Remove the top unwind protect from the list. */
164void
165remove_unwind_protect ()
166{
167 if (unwind_protect_list)
168 without_interrupts
169 (remove_unwind_protect_internal, (char *)NULL, (char *)NULL);
170}
171
172/* Run the list of cleanup functions in unwind_protect_list. */
173void
174run_unwind_protects ()
175{
176 if (unwind_protect_list)
177 without_interrupts
178 (run_unwind_protects_internal, (char *)NULL, (char *)NULL);
179}
180
28ef6c31
JA
181/* Erase the unwind-protect list. If flags is 1, free the elements. */
182void
183clear_unwind_protect_list (flags)
184 int flags;
185{
f73dda09
JA
186 char *flag;
187
28ef6c31 188 if (unwind_protect_list)
f73dda09
JA
189 {
190 flag = flags ? "" : (char *)NULL;
191 without_interrupts
192 (clear_unwind_protects_internal, flag, (char *)NULL);
193 }
28ef6c31
JA
194}
195
3185942a
JA
196int
197have_unwind_protects ()
198{
199 return (unwind_protect_list != 0);
200}
201
a0c0a00f
CR
202int
203unwind_protect_tag_on_stack (tag)
204 const char *tag;
205{
206 UNWIND_ELT *elt;
207
208 elt = unwind_protect_list;
209 while (elt)
210 {
211 if (elt->head.cleanup == 0 && STREQ (elt->arg.v, tag))
212 return 1;
213 elt = elt->head.next;
214 }
215 return 0;
216}
217
726f6388
JA
218/* **************************************************************** */
219/* */
28ef6c31 220/* The Actual Functions */
726f6388
JA
221/* */
222/* **************************************************************** */
223
224static void
225add_unwind_protect_internal (cleanup, arg)
226 Function *cleanup;
227 char *arg;
228{
229 UNWIND_ELT *elt;
230
7117c2d2 231 uwpalloc (elt);
f73dda09
JA
232 elt->head.next = unwind_protect_list;
233 elt->head.cleanup = cleanup;
234 elt->arg.v = arg;
726f6388
JA
235 unwind_protect_list = elt;
236}
237
238static void
28ef6c31
JA
239remove_unwind_protect_internal (ignore1, ignore2)
240 char *ignore1, *ignore2;
726f6388 241{
d166f048 242 UNWIND_ELT *elt;
726f6388 243
d166f048 244 elt = unwind_protect_list;
726f6388
JA
245 if (elt)
246 {
f73dda09 247 unwind_protect_list = unwind_protect_list->head.next;
7117c2d2 248 uwpfree (elt);
726f6388
JA
249 }
250}
251
252static void
28ef6c31
JA
253run_unwind_protects_internal (ignore1, ignore2)
254 char *ignore1, *ignore2;
726f6388 255{
f73dda09 256 unwind_frame_run_internal ((char *) NULL, (char *) NULL);
726f6388
JA
257}
258
259static void
28ef6c31
JA
260clear_unwind_protects_internal (flag, ignore)
261 char *flag, *ignore;
262{
f73dda09 263 if (flag)
28ef6c31
JA
264 {
265 while (unwind_protect_list)
266 remove_unwind_protect_internal ((char *)NULL, (char *)NULL);
267 }
268 unwind_protect_list = (UNWIND_ELT *)NULL;
269}
270
271static void
272unwind_frame_discard_internal (tag, ignore)
273 char *tag, *ignore;
726f6388
JA
274{
275 UNWIND_ELT *elt;
495aee44 276 int found;
726f6388 277
495aee44 278 found = 0;
726f6388
JA
279 while (elt = unwind_protect_list)
280 {
f73dda09
JA
281 unwind_protect_list = unwind_protect_list->head.next;
282 if (elt->head.cleanup == 0 && (STREQ (elt->arg.v, tag)))
726f6388 283 {
7117c2d2 284 uwpfree (elt);
495aee44 285 found = 1;
726f6388
JA
286 break;
287 }
288 else
7117c2d2 289 uwpfree (elt);
726f6388 290 }
495aee44
CR
291
292 if (found == 0)
293 internal_warning ("unwind_frame_discard: %s: frame not found", tag);
726f6388
JA
294}
295
f73dda09
JA
296/* Restore the value of a variable, based on the contents of SV.
297 sv->desired_setting is a block of memory SIZE bytes long holding the
298 value itself. This block of memory is copied back into the variable. */
299static inline void
300restore_variable (sv)
301 SAVED_VAR *sv;
302{
303 FASTCOPY (sv->desired_setting, sv->variable, sv->size);
304}
305
726f6388 306static void
28ef6c31
JA
307unwind_frame_run_internal (tag, ignore)
308 char *tag, *ignore;
726f6388
JA
309{
310 UNWIND_ELT *elt;
495aee44 311 int found;
726f6388 312
495aee44 313 found = 0;
726f6388
JA
314 while (elt = unwind_protect_list)
315 {
f73dda09 316 unwind_protect_list = elt->head.next;
726f6388
JA
317
318 /* If tag, then compare. */
495aee44 319 if (elt->head.cleanup == 0)
726f6388 320 {
f73dda09 321 if (tag && STREQ (elt->arg.v, tag))
726f6388 322 {
7117c2d2 323 uwpfree (elt);
495aee44 324 found = 1;
726f6388
JA
325 break;
326 }
726f6388
JA
327 }
328 else
329 {
f73dda09
JA
330 if (elt->head.cleanup == (Function *) restore_variable)
331 restore_variable (&elt->sv.v);
332 else
333 (*(elt->head.cleanup)) (elt->arg.v);
726f6388 334 }
726f6388 335
7117c2d2 336 uwpfree (elt);
f73dda09 337 }
495aee44
CR
338 if (tag && found == 0)
339 internal_warning ("unwind_frame_run: %s: frame not found", tag);
d166f048 340}
726f6388 341
726f6388 342static void
f73dda09
JA
343unwind_protect_mem_internal (var, psize)
344 char *var;
345 char *psize;
726f6388 346{
f73dda09
JA
347 int size, allocated;
348 UNWIND_ELT *elt;
726f6388 349
f73dda09
JA
350 size = *(int *) psize;
351 allocated = size + offsetof (UNWIND_ELT, sv.v.desired_setting[0]);
352 elt = (UNWIND_ELT *)xmalloc (allocated);
353 elt->head.next = unwind_protect_list;
354 elt->head.cleanup = (Function *) restore_variable;
355 elt->sv.v.variable = var;
356 elt->sv.v.size = size;
357 FASTCOPY (var, elt->sv.v.desired_setting, size);
358 unwind_protect_list = elt;
726f6388
JA
359}
360
361/* Save the value of a variable so it will be restored when unwind-protects
f73dda09
JA
362 are run. VAR is a pointer to the variable. SIZE is the size in
363 bytes of VAR. */
726f6388 364void
f73dda09
JA
365unwind_protect_mem (var, size)
366 char *var;
726f6388
JA
367 int size;
368{
f73dda09 369 without_interrupts (unwind_protect_mem_internal, var, (char *) &size);
726f6388 370}
495aee44
CR
371
372#if defined (DEBUG)
373#include <stdio.h>
374
375void
376print_unwind_protect_tags ()
377{
378 UNWIND_ELT *elt;
379
380 elt = unwind_protect_list;
381 while (elt)
382 {
495aee44
CR
383 if (elt->head.cleanup == 0)
384 fprintf(stderr, "tag: %s\n", elt->arg.v);
a0c0a00f 385 elt = elt->head.next;
495aee44
CR
386 }
387}
388#endif