+void
+trans_throw_exc(struct exception *x)
+{
+ struct ucwlib_context *c = ucwlib_thread_context();
+ struct trans *t = c->current_trans;
+ DBG("Throwing exception %s (%s) in trans %p", x->id, x->msg, t);
+ if (!t)
+ die("%s", x->msg);
+
+ // If we are already handling an exception (i.e., throw from a catch handler),
+ // fold the current transaction into its parent.
+ while (t->thrown_exc)
+ {
+ if (!t->prev_trans)
+ die("%s", x->msg);
+ t->thrown_exc = NULL;
+ trans_fold();
+ t = c->current_trans;
+ DBG("... recursive throw propagated to parent trans %p", t);
+ }
+
+ // And jump overboard.
+ t->thrown_exc = x;
+ longjmp(t->jmp, 1);
+}
+
+void
+trans_throw(const char *id, void *object, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ trans_vthrow(id, object, fmt, args);
+}
+
+void
+trans_vthrow(const char *id, void *object, const char *fmt, va_list args)
+{
+ struct mempool *mp = trans_get_pool();
+ if (!mp)
+ vdie(fmt, args);
+ struct exception *x = mp_alloc(mp, sizeof(*x));
+ x->id = id;
+ x->object = object;
+ x->msg = mp_vprintf(mp, fmt, args);
+ trans_throw_exc(x);
+}
+
+struct exception *
+trans_current_exc(void)
+{
+ return trans_get_current() -> thrown_exc;
+}
+