2 * The UCW Library -- Transactions
4 * (c) 2008--2011 Martin Mares <mj@ucw.cz>
6 * This software may be freely distributed and used according to the terms
7 * of the GNU Lesser General Public License.
13 #include <ucw/trans.h>
14 #include <ucw/resource.h>
15 #include <ucw/mempool.h>
22 struct ucwlib_context *c = ucwlib_thread_context();
24 c->trans_pool = mp_new(1024);
30 struct ucwlib_context *c = ucwlib_thread_context();
33 mp_delete(c->trans_pool);
36 c->current_trans = NULL;
43 struct ucwlib_context *c = ucwlib_thread_context();
44 struct mempool *mp = c->trans_pool;
46 struct mempool_state *mst = mp_push(mp);
47 struct trans *t = mp_alloc(mp, sizeof(*t));
48 t->trans_pool_state = mst;
50 struct respool *rp = rp_new("trans", mp);
52 t->prev_rpool = rp_switch(rp);
55 t->prev_trans = c->current_trans;
57 DBG("Opened transaction %p", t);
62 trans_get_current(void)
64 return ucwlib_thread_context() -> current_trans;
70 return ucwlib_thread_context() -> trans_pool;
74 trans_pop(struct trans *t, struct ucwlib_context *c)
76 DBG("... popping trans %p", t);
77 rp_switch(t->prev_rpool);
78 c->current_trans = t->prev_trans;
82 trans_drop(struct trans *t, struct ucwlib_context *c)
84 DBG("... dropping trans %p", t);
85 mp_restore(c->trans_pool, t->trans_pool_state);
91 struct ucwlib_context *c = ucwlib_thread_context();
92 struct trans *t = c->current_trans;
93 DBG("Committing transaction %p", t);
95 ASSERT(!t->thrown_exc);
104 struct ucwlib_context *c = ucwlib_thread_context();
105 struct trans *t = c->current_trans;
106 DBG("Rolling back transaction %p", t);
108 ASSERT(!t->thrown_exc);
117 struct ucwlib_context *c = ucwlib_thread_context();
118 struct trans *t = c->current_trans;
119 DBG("Folding transaction %p", t);
121 ASSERT(!t->thrown_exc);
123 ASSERT(c->current_trans); // Ensure that the parent exists
124 res_subpool(t->rpool);
125 t->rpool = NULL; // To stop people from using the trans
131 // Exception has been finally caught. Roll back the current transaction,
132 // including all sub-transactions that have been folded to it during
134 struct trans *t = trans_get_current();
135 struct exception *x = t->thrown_exc;
137 DBG("... exception %p caught", x);
138 t->thrown_exc = NULL;
145 struct trans *t = trans_get_current();
148 puts("No transaction open.");
154 printf("Transaction %p:\n", t);
155 struct exception *x = t->thrown_exc;
157 printf(" Exception %s (%s) in flight\n", x->id, x->msg);
158 rp_dump(t->rpool, 4);
164 trans_throw_exc(struct exception *x)
166 struct ucwlib_context *c = ucwlib_thread_context();
167 struct trans *t = c->current_trans;
168 DBG("Throwing exception %s (%s) in trans %p", x->id, x->msg, t);
172 // If we are already handling an exception (i.e., throw from a catch handler),
173 // fold the current transaction into its parent.
174 while (t->thrown_exc)
178 t->thrown_exc = NULL;
180 t = c->current_trans;
181 DBG("... recursive throw propagated to parent trans %p", t);
184 // And jump overboard.
190 trans_throw(const char *id, void *object, const char *fmt, ...)
194 trans_vthrow(id, object, fmt, args);
198 trans_vthrow(const char *id, void *object, const char *fmt, va_list args)
200 struct mempool *mp = trans_get_pool();
203 struct exception *x = mp_alloc(mp, sizeof(*x));
206 x->msg = mp_vprintf(mp, fmt, args);
211 trans_current_exc(void)
213 return trans_get_current() -> thrown_exc;
218 static void trc_free(struct resource *r)
220 printf("Freeing object #%d\n", (int)(intptr_t) r->priv);
223 static struct res_class trc = {
232 res_new(&trc, (void *)(intptr_t) 1);
233 res_malloc(64, NULL);
236 res_new(&trc, (void *)(intptr_t) 2);
237 res_malloc(128, NULL);
238 trans_throw("ucw.test", "inn", "Universe failure: %d+%d=%d", 1, 2, 4);
242 printf("Inner catch: %s\n", x->msg);
246 res_malloc(256, NULL);
247 trans_throw("ucw.test.nested", "nest", "Something is wrong recursively");
251 printf("Yet another layer: %s\n", y->msg);
253 // trans_throw_exc(y);
256 trans_throw("ucw.test2", "out", "Error: %s", x->msg);
262 printf("Outer catch: %s\n", x->msg);
266 trans_throw("ucw.test3", "glob", "Global error. Reboot globe.");
269 res_malloc(64, NULL);