1/* unwind_prot.c - a simple unwind-protect system for internal variables */ 2 3/* I can't stand it anymore! Please can't we just write the 4 whole Unix system in lisp or something? */ 5 6/* Copyright (C) 1987-2009 Free Software Foundation, Inc. 7 8 This file is part of GNU Bash, the Bourne Again SHell. 9 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. 14 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. 19 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*/ 23 24/* **************************************************************** */ 25/* */ 26/* Unwind Protection Scheme for Bash */ 27/* */ 28/* **************************************************************** */ 29#include "config.h" 30 31#include "bashtypes.h" 32#include "bashansi.h" 33 34#if defined (HAVE_UNISTD_H) 35# include <unistd.h> 36#endif 37 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 46#include "command.h" 47#include "general.h" 48#include "unwind_prot.h" 49#include "quit.h" 50#include "sig.h" 51 52/* Structure describing a saved variable and the value to restore it to. */ 53typedef struct { 54 char *variable; 55 int size; 56 char desired_setting[1]; /* actual size is `size' */ 57} SAVED_VAR; 58 59/* If HEAD.CLEANUP is null, then ARG.V contains a tag to throw back to. 60 If HEAD.CLEANUP is restore_variable, then SV.V contains the saved 61 variable. Otherwise, call HEAD.CLEANUP (ARG.V) to clean up. */ 62typedef union uwp { 63 struct uwp_head { 64 union uwp *next; 65 Function *cleanup; 66 } head; 67 struct { 68 struct uwp_head uwp_head; 69 char *v; 70 } arg; 71 struct { 72 struct uwp_head uwp_head; 73 SAVED_VAR v; 74 } sv; 75} UNWIND_ELT; 76 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 179int 180have_unwind_protects () 181{ 182 return (unwind_protect_list != 0); 183} 184 185/* **************************************************************** */ 186/* */ 187/* The Actual Functions */ 188/* */ 189/* **************************************************************** */ 190 191static void 192add_unwind_protect_internal (cleanup, arg) 193 Function *cleanup; 194 char *arg; 195{ 196 UNWIND_ELT *elt; 197 198 uwpalloc (elt); 199 elt->head.next = unwind_protect_list; 200 elt->head.cleanup = cleanup; 201 elt->arg.v = arg; 202 unwind_protect_list = elt; 203} 204 205static void 206remove_unwind_protect_internal (ignore1, ignore2) 207 char *ignore1, *ignore2; 208{ 209 UNWIND_ELT *elt; 210 211 elt = unwind_protect_list; 212 if (elt) 213 { 214 unwind_protect_list = unwind_protect_list->head.next; 215 uwpfree (elt); 216 } 217} 218 219static void 220run_unwind_protects_internal (ignore1, ignore2) 221 char *ignore1, *ignore2; 222{ 223 unwind_frame_run_internal ((char *) NULL, (char *) NULL); 224} 225 226static void 227clear_unwind_protects_internal (flag, ignore) 228 char *flag, *ignore; 229{ 230 if (flag) 231 { 232 while (unwind_protect_list) 233 remove_unwind_protect_internal ((char *)NULL, (char *)NULL); 234 } 235 unwind_protect_list = (UNWIND_ELT *)NULL; 236} 237 238static void 239unwind_frame_discard_internal (tag, ignore) 240 char *tag, *ignore; 241{ 242 UNWIND_ELT *elt; 243 244 while (elt = unwind_protect_list) 245 { 246 unwind_protect_list = unwind_protect_list->head.next; 247 if (elt->head.cleanup == 0 && (STREQ (elt->arg.v, tag))) 248 { 249 uwpfree (elt); 250 break; 251 } 252 else 253 uwpfree (elt); 254 } 255} 256 257/* Restore the value of a variable, based on the contents of SV. 258 sv->desired_setting is a block of memory SIZE bytes long holding the 259 value itself. This block of memory is copied back into the variable. */ 260static inline void 261restore_variable (sv) 262 SAVED_VAR *sv; 263{ 264 FASTCOPY (sv->desired_setting, sv->variable, sv->size); 265} 266 267static void 268unwind_frame_run_internal (tag, ignore) 269 char *tag, *ignore; 270{ 271 UNWIND_ELT *elt; 272 273 while (elt = unwind_protect_list) 274 { 275 unwind_protect_list = elt->head.next; 276 277 /* If tag, then compare. */ 278 if (!elt->head.cleanup) 279 { 280 if (tag && STREQ (elt->arg.v, tag)) 281 { 282 uwpfree (elt); 283 break; 284 } 285 } 286 else 287 { 288 if (elt->head.cleanup == (Function *) restore_variable) 289 restore_variable (&elt->sv.v); 290 else 291 (*(elt->head.cleanup)) (elt->arg.v); 292 } 293 294 uwpfree (elt); 295 } 296} 297 298static void 299unwind_protect_mem_internal (var, psize) 300 char *var; 301 char *psize; 302{ 303 int size, allocated; 304 UNWIND_ELT *elt; 305 306 size = *(int *) psize; 307 allocated = size + offsetof (UNWIND_ELT, sv.v.desired_setting[0]); 308 elt = (UNWIND_ELT *)xmalloc (allocated); 309 elt->head.next = unwind_protect_list; 310 elt->head.cleanup = (Function *) restore_variable; 311 elt->sv.v.variable = var; 312 elt->sv.v.size = size; 313 FASTCOPY (var, elt->sv.v.desired_setting, size); 314 unwind_protect_list = elt; 315} 316 317/* Save the value of a variable so it will be restored when unwind-protects 318 are run. VAR is a pointer to the variable. SIZE is the size in 319 bytes of VAR. */ 320void 321unwind_protect_mem (var, size) 322 char *var; 323 int size; 324{ 325 without_interrupts (unwind_protect_mem_internal, var, (char *) &size); 326} 327