1 /* -*-C-*-
2
3 Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
4 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
5 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Massachusetts
6 Institute of Technology
7
8 This file is part of MIT/GNU Scheme.
9
10 MIT/GNU Scheme 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 2 of the License, or (at
13 your option) any later version.
14
15 MIT/GNU Scheme is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with MIT/GNU Scheme; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
23 USA.
24
25 */
26
27 #include "config.h"
28 #include "outf.h"
29 #include "dstack.h"
30
31 static void error (const char *, const char *) NORETURN;
32
33 static void
error(const char * procedure_name,const char * message)34 error (const char * procedure_name, const char * message)
35 {
36 outf_fatal ("%s: %s\n", procedure_name, message);
37 outf_flush_fatal ();
38 abort ();
39 }
40
41 enum transaction_state { active, aborting, committing };
42
43 struct transaction
44 {
45 void * checkpoint;
46 enum transaction_state state;
47 };
48
49 static struct transaction * current_transaction;
50
51 static void
guarantee_current_transaction(const char * proc)52 guarantee_current_transaction (const char * proc)
53 {
54 if (current_transaction == 0)
55 error (proc, "no transaction");
56 switch (current_transaction -> state)
57 {
58 case committing: error (proc, "commit in progress"); break;
59 case aborting: error (proc, "abort in progress"); break;
60 case active: break;
61 }
62 }
63
64 void
transaction_initialize(void)65 transaction_initialize (void)
66 {
67 current_transaction = 0;
68 }
69
70 void
transaction_begin(void)71 transaction_begin (void)
72 {
73 void * checkpoint = dstack_position;
74 struct transaction * transaction =
75 (dstack_alloc (sizeof (struct transaction)));
76 (transaction -> checkpoint) = checkpoint;
77 (transaction -> state) = active;
78 dstack_bind ((¤t_transaction), transaction);
79 }
80
81 void
transaction_abort(void)82 transaction_abort (void)
83 {
84 guarantee_current_transaction ("transaction_abort");
85 (current_transaction -> state) = aborting;
86 dstack_set_position (current_transaction -> checkpoint);
87 }
88
89 void
transaction_commit(void)90 transaction_commit (void)
91 {
92 guarantee_current_transaction ("transaction_commit");
93 (current_transaction -> state) = committing;
94 dstack_set_position (current_transaction -> checkpoint);
95 }
96
97 struct action
98 {
99 enum transaction_action_type type;
100 void (*procedure) (void * environment);
101 void * environment;
102 };
103
104 static void
execute_action(void * action)105 execute_action (void * action)
106 {
107 if ((((struct action *) action) -> type) !=
108 (((current_transaction -> state) == committing)
109 ? tat_abort : tat_commit))
110 (* (((struct action *) action) -> procedure))
111 (((struct action *) action) -> environment);
112 }
113
114 void
transaction_record_action(enum transaction_action_type type,void (* procedure)(void * environment),void * environment)115 transaction_record_action (enum transaction_action_type type,
116 void (*procedure) (void * environment),
117 void * environment)
118 {
119 guarantee_current_transaction ("transaction_record_action");
120 {
121 struct action * action = (dstack_alloc (sizeof (struct action)));
122 (action -> type) = type;
123 (action -> procedure) = procedure;
124 (action -> environment) = environment;
125 dstack_protect (execute_action, action);
126 }
127 }
128