2 * The UCW Library -- Transactions
4 * (c) 2008--2011 Martin Mares <mj@ucw.cz>
5 * (c) 2021 Pavel Charvat <pchar@ucw.cz>
7 * This software may be freely distributed and used according to the terms
8 * of the GNU Lesser General Public License.
14 #include <ucw/trans.h>
15 #include <ucw/resource.h>
16 #include <ucw/mempool.h>
23 struct ucwlib_context *c = ucwlib_thread_context();
25 c->trans_pool = mp_new(1024);
31 struct ucwlib_context *c = ucwlib_thread_context();
34 mp_delete(c->trans_pool);
37 c->current_trans = NULL;
44 struct ucwlib_context *c = ucwlib_thread_context();
45 struct mempool *mp = c->trans_pool;
47 struct mempool_state *mst = mp_push(mp);
48 struct trans *t = mp_alloc(mp, sizeof(*t));
49 t->trans_pool_state = mst;
51 struct respool *rp = rp_new("trans", mp);
53 t->prev_rpool = rp_switch(rp);
56 t->prev_trans = c->current_trans;
58 DBG("Opened transaction %p", t);
63 trans_get_current(void)
65 return ucwlib_thread_context() -> current_trans;
71 return ucwlib_thread_context() -> trans_pool;
75 trans_pop(struct trans *t, struct ucwlib_context *c)
77 DBG("... popping trans %p", t);
78 rp_switch(t->prev_rpool);
79 c->current_trans = t->prev_trans;
83 trans_drop(struct trans *t, struct ucwlib_context *c)
85 DBG("... dropping trans %p", t);
86 mp_restore(c->trans_pool, t->trans_pool_state);
92 struct ucwlib_context *c = ucwlib_thread_context();
93 struct trans *t = c->current_trans;
94 DBG("Committing transaction %p", t);
96 ASSERT(!t->thrown_exc);
105 struct ucwlib_context *c = ucwlib_thread_context();
106 struct trans *t = c->current_trans;
107 DBG("Rolling back transaction %p", t);
109 ASSERT(!t->thrown_exc);
118 struct ucwlib_context *c = ucwlib_thread_context();
119 struct trans *t = c->current_trans;
120 DBG("Folding transaction %p", t);
122 ASSERT(!t->thrown_exc);
124 ASSERT(c->current_trans); // Ensure that the parent exists
125 res_subpool(t->rpool);
126 t->rpool = NULL; // To stop people from using the trans
132 // Exception has been finally caught. Roll back the current transaction,
133 // including all sub-transactions that have been folded to it during
135 struct trans *t = trans_get_current();
136 struct exception *x = t->thrown_exc;
138 DBG("... exception %p caught", x);
139 t->thrown_exc = NULL;
146 struct trans *t = trans_get_current();
149 puts("No transaction open.");
155 printf("Transaction %p:\n", t);
156 struct exception *x = t->thrown_exc;
158 printf(" Exception %s (%s) in flight\n", x->id, x->msg);
159 rp_dump(t->rpool, 4);
165 trans_throw_exc(struct exception *x)
167 struct ucwlib_context *c = ucwlib_thread_context();
168 struct trans *t = c->current_trans;
169 DBG("Throwing exception %s (%s) in trans %p", x->id, x->msg, t);
173 // If we are already handling an exception (i.e., throw from a catch handler),
174 // fold the current transaction into its parent.
175 while (t->thrown_exc)
179 t->thrown_exc = NULL;
181 t = c->current_trans;
182 DBG("... recursive throw propagated to parent trans %p", t);
185 // And jump overboard.
191 trans_throw(const char *id, void *object, const char *fmt, ...)
195 trans_vthrow(id, object, fmt, args);
199 trans_vthrow(const char *id, void *object, const char *fmt, va_list args)
201 struct mempool *mp = trans_get_pool();
204 struct exception *x = mp_alloc(mp, sizeof(*x));
205 x->id = mp_strdup(mp, id);
207 x->msg = mp_vprintf(mp, fmt, args);
212 trans_current_exc(void)
214 return trans_get_current() -> thrown_exc;
219 static void trc_free(struct resource *r)
221 printf("Freeing object #%d\n", (int)(intptr_t) r->priv);
224 static struct res_class trc = {
233 res_new(&trc, (void *)(intptr_t) 1);
234 res_malloc(64, NULL);
237 res_new(&trc, (void *)(intptr_t) 2);
238 res_malloc(128, NULL);
239 trans_throw("ucw.test", "inn", "Universe failure: %d+%d=%d", 1, 2, 4);
243 printf("Inner catch: %s\n", x->msg);
247 res_malloc(256, NULL);
248 trans_throw("ucw.test.nested", "nest", "Something is wrong recursively");
252 printf("Yet another layer: %s\n", y->msg);
254 // trans_throw_exc(y);
257 trans_throw("ucw.test2", "out", "Error: %s", x->msg);
263 printf("Outer catch: %s\n", x->msg);
267 trans_throw("ucw.test3", "glob", "Global error. Reboot globe.");
270 res_malloc(64, NULL);