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/respool.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
129 trans_caught(struct exception *x)
131 // Exception has been finally caught. Roll back the current transaction,
132 // including all sub-transactions that have been folded to it during
134 DBG("... exception %p caught", x);
135 struct trans *t = trans_get_current();
136 ASSERT(t->thrown_exc == x);
137 t->thrown_exc = NULL;
144 struct trans *t = trans_get_current();
147 puts("No transaction open.");
153 printf("Transaction %p:\n", t);
154 struct exception *x = t->thrown_exc;
156 printf(" Exception %s (%s) in flight\n", x->id, x->msg);
157 rp_dump(t->rpool, 4);
163 trans_throw_exc(struct exception *x)
165 struct ucwlib_context *c = ucwlib_thread_context();
166 struct trans *t = c->current_trans;
167 DBG("Throwing exception %s (%s) in trans %p", x->id, x->msg, t);
171 // If we are already handling an exception (i.e., throw from a catch handler),
172 // fold the current transaction into its parent.
177 t->thrown_exc = NULL;
179 t = c->current_trans;
180 DBG("... recursive throw propagated to parent trans %p", t);
183 // And jump overboard.
189 trans_throw(const char *id, void *object, const char *fmt, ...)
193 trans_vthrow(id, object, fmt, args);
197 trans_vthrow(const char *id, void *object, const char *fmt, va_list args)
199 struct mempool *mp = trans_get_pool();
202 struct exception *x = mp_alloc(mp, sizeof(*x));
205 x->msg = mp_vprintf(mp, fmt, args);
210 trans_current_exc(void)
212 return trans_get_current() -> thrown_exc;
217 static void trc_free(struct resource *r)
219 printf("Freeing object #%d\n", (int)(intptr_t) r->priv);
222 static struct res_class trc = {
231 res_new(&trc, (void *)(intptr_t) 1);
232 res_malloc(64, NULL);
235 res_new(&trc, (void *)(intptr_t) 2);
236 res_malloc(128, NULL);
237 trans_throw("ucw.test", "inn", "Universe failure: %d+%d=%d", 1, 2, 4);
241 printf("Inner catch: %s\n", x->msg);
243 trans_throw("ucw.test2", "out", "Error: %s", x->msg);
249 printf("Outer catch: %s\n", x->msg);
253 trans_throw("ucw.test3", "glob", "Global error. Reboot globe.");
256 res_malloc(64, NULL);