]> mj.ucw.cz Git - libucw.git/commitdiff
Trans: more documentation
authorMartin Mares <mj@ucw.cz>
Sun, 17 Apr 2011 19:00:33 +0000 (21:00 +0200)
committerMartin Mares <mj@ucw.cz>
Sun, 17 Apr 2011 19:00:33 +0000 (21:00 +0200)
ucw/doc/trans.txt
ucw/trans.h

index 5e5ec71e5c99a6c98a92d0fc5b37e5e57c23dfbe..d2c10df31ba6b2753075000edaddfb34eb9e92f1 100644 (file)
@@ -32,48 +32,50 @@ operating on resources work on both active and in-active pools.
 Transactions: ucw/trans.h
 -------------------------
 
-Assorted notes:
-
-- A transaction is tied to a thread which has created it. A transaction
-  can create a sub-transaction, so every thread keeps a stack of running
-  transactions in its per-thread data. Calling @trans_init() is optional,
-  but @trans_cleanup() should be used before a thread exits in order to
-  free resources used by transaction system.
-
-- Every transaction keeps a resource pool containing resources, which
-  have been created during the transaction. Whenever the transaction is
-  running, this pool is set as current. You are allowed to switch to
-  a different pool, but please do so carefully.
-+
-  When a transaction ends, the pool is destroyed and the previous active
-  pool is popped off the transaction stack. The fate of the resources
-  inside the pool depends on the operation used to end the transaction:
-       * commit -- all resources are detached from the pool
-       * rollback -- all resources are freed
-       * fold -- instead of destroying the pool, it is added as a subpool
-         to the parent transaction (which must exist)
-
-- Each transaction also includes a memory pool, from which all temporary
-  structures (including all resources created by the transaction) are
-  allocated. Feel free to allocate your temporary data from this pool, too;
-  they will be freed when the transaction is committed or rolled back.
-  When the transaction ends with a fold, this pool gets included inside
-  the parent transaction's pool.
-+
-  (To be true, there is actually a shared transaction pool per thread
-  and the transaction logic uses @mp_push() and @mp_pop() to keep a stack
-  of per-transaction data.)
-
-- Transactions are usually used together with exceptions (which are similar
-  to how exceptions work in other languages, but they differ in subtle details,
-  so please read carefully). When a failure condition of some kind is detected,
-  an exception is raised. It involves creating an exception object and jumping
-  out of the transaction by a `longjmp()`. The exception object (`struct exception`)
-  contains an identification of the error and possibly additional data.
-+
-  Usually, creation of an transaction and handling of exceptions is done
-  using helper macros (it is not strictly necessary, but highly recommended):
-+
+Upon the resource pools, a transactional mechanism is built. A transaction
+consists of a piece of code and a resource pool for temporary objects created
+by the code. Whenever the transaction is running, this pool is set as current.
+You are allowed to switch to a different pool, but please do so carefully.
+
+When a transaction ends, the pool is destroyed and the previous active
+pool is popped off the transaction stack. The fate of the resources
+inside the pool depends on the operation used to end the transaction:
+
+* *commit* -- all resources are detached from the pool
+* *rollback* -- all resources are freed
+* *fold* -- instead of destroying the pool, it is added as a subpool
+  to the parent transaction (which must exist)
+
+A transaction is tied to a thread which has created it. A transaction
+can create a sub-transaction, so every thread keeps a stack of running
+transactions in its per-thread data. Calling @trans_init() is optional,
+but @trans_cleanup() should be used before a thread exits in order to
+free resources used by transaction system.
+
+Each transaction also includes a memory pool, from which all temporary
+structures (including all resources created by the transaction) are
+allocated. Feel free to allocate your temporary data from this pool, too;
+they will be freed when the transaction is committed or rolled back.
+When the transaction ends with a fold, this pool gets included inside
+the parent transaction's pool.
+
+(More precisely, there is actually a shared transaction pool per thread
+and the transaction logic uses @mp_push() and @mp_pop() to keep a stack
+of per-transaction data.)
+
+=== Exceptions ===
+
+Transactions are commonly used together with exceptions (which are similar
+to how exceptions work in other languages, but they differ in subtle details,
+so please read carefully). When a failure condition of some kind is detected,
+an exception is *raised* ("*thrown*" is also sometimes used). It involves
+creating an exception object and jumping out of the transaction by
+a `longjmp()`. The exception object (`struct exception`) contains an
+identification of the error and possibly additional data.
+
+Usually, creation of an transaction and handling of exceptions is done
+using *helper macros* (it is not strictly necessary, but highly recommended):
+
        TRANS_TRY
          {
            // Code that runs inside the transaction.
@@ -84,40 +86,44 @@ Assorted notes:
          }
        TRANS_END;
 
-  The code inside the transaction ends with an implicit @trans_commit().
-  If you want to end the transaction in a different way, you can do so,
-  but you need to use a `break` statement to skip the implicit commit.
-
-  The exception handling code gets a local variable `x` pointing to the
-  exception object. When the exception is handled (for example, an error
-  message is logged), @trans_caught() is called automatically, which rolls
-  back the transaction and frees all its resources. Again, you can use the
-  `break` statement to skip this.
-
-  Alternatively, when you are in a nested transaction, you can throw a different
-  exception or re-throw the original one. This raises an exception in the
-  context of the parent transaction. In this case, the child transaction is
-  not rolled back, but its pools are folded as sub-pools of the parent transaction
-  and kept until @trans_caught() is called finally.
-
-* When an exception is thrown outside a transaction, it is converted to
-  a plain @die().
-
-* Memory management and lifetime of various objects and pools deserve special
-  attention, as usually when non-local jumps are taking place. When an exception
-  is raised, the exception structure is allocated from the memory pool of the
-  current transaction. When the exception is propagated through the stack of
-  transactions, no transaction is ever rolled back -- all of them are folded
-  and their pools remain accessible until @trans_caught() is called at the end.
-  Therefore exceptions can carry pointers to the objects which have failed
-  without a risk of the object becoming invalid. However, you need to avoid
-  pointing to on-stack data like local variables of functions, because these
-  are of course destroyed during the `longjmp()`.
-
-FIXME: Interaction between exceptions, pools and other libucw modules.
-
-FIXME: Unit tests
-
-FIXME: Resourcification of more libucw objects
-
-FIXME: Do we want to allow res_alloc() when no pool is active.
+The code inside the transaction ends with an implicit @trans_commit().
+If you want to end the transaction in a different way, you can do so,
+but you need to use a `break` statement to skip the implicit commit.
+
+The exception handling code gets a local variable `x` pointing to the
+exception object. When the exception is handled (for example, an error
+message is logged), @trans_caught() is called automatically, which rolls
+back the transaction and frees all its resources. Again, you can use the
+`break` statement to skip this.
+
+Alternatively, when you are in a *nested transaction*, you can throw a different
+exception or re-throw the original one. This raises an exception in the
+context of the parent transaction. In this case, the child transaction is
+not rolled back, but its pools are folded as sub-pools of the parent transaction
+and kept until @trans_caught() is called finally.
+
+When an exception is thrown *outside a transaction*, it is converted to
+a plain @die().
+
+*Memory management* and lifetime of various objects and pools deserve special
+attention, as usually when non-local jumps are taking place. When an exception
+is raised, the exception structure is allocated from the memory pool of the
+current transaction. When the exception is propagated through the stack of
+transactions, no transaction is ever rolled back -- all of them are folded
+and their pools remain accessible until @trans_caught() is called at the end.
+Therefore exceptions can carry pointers to the objects which have failed
+without a risk of the object becoming invalid. However, you need to avoid
+pointing to on-stack data like local variables of functions, because these
+are of course destroyed during the `longjmp()`.
+
+=== Functions and structures ===
+
+!!ucw/trans.h
+
+== FIXME's ==
+
+- Interaction between exceptions, pools and other libucw modules.
+- Unit tests
+- Resourcification of more libucw objects.
+- Do we want to allow res_alloc() when no pool is active?
+- Structure of exception identifiers: rethink and document
index 608581fade8a96b1f6200a8e28df9aa569aeb3af..15a08fd1824eda7c6ea29b061732723b56e694c3 100644 (file)
@@ -14,8 +14,7 @@
 
 #include <setjmp.h>
 
-/* Transactions */
-
+/** A structure describing a transaction. All fields are for internal use only. **/
 struct trans {
   struct trans *prev_trans;
   struct mempool_state *trans_pool_state;
@@ -25,33 +24,43 @@ struct trans {
   jmp_buf jmp;
 };
 
-void trans_init(void);         // Called automatically on trans_open() if needed
-void trans_cleanup(void);      // Free memory occupied by the transaction system pools
+void trans_init(void);         /** Initializes the transaction system for the current thread. Called automatically as needed. **/
+void trans_cleanup(void);      /** Frees memory occupied by the transaction system pools for the current thread. **/
 
-struct trans *trans_open(void);
-struct trans *trans_get_current(void);
-void trans_commit(void);
-void trans_rollback(void);
-void trans_fold(void);
-void trans_dump(void);
+struct trans *trans_open(void);        /** Creates a new transaction. Used inside `TRANS_TRY`. **/
+struct trans *trans_get_current(void); /** Get a pointer to the currently running transaction, or NULL if there is none. **/
+void trans_commit(void);       /** Commits the current transaction. **/
+void trans_rollback(void);     /** Rolls back the current transaction. **/
+void trans_fold(void);         /** Folds the current transaction to its parent. **/
+void trans_dump(void);         /** Prints out a debugging dump of the transaction stack to stdout. **/
 
 struct mempool *trans_get_pool(void);
 
-/* Exceptions */
-
+/**
+ * Data associated with an exception. Usually, this structure is created
+ * by calling @trans_throw(), but if you want to pass more data, you can
+ * create your own exception and throw it using @trans_throw_exc().
+ **/
 struct exception {
-  const char *id;              // Hierarchic identifier of the exception
+  const char *id;              // Hierarchical identifier of the exception
   const char *msg;             // Error message to present to the user
   void *object;                        // Object on which the exception happened
   // More data specific for the particular `id' can follow
 };
 
-void trans_throw_exc(struct exception *x) NONRET;
+/** Creates an exception and throws it. The error message can contain `printf`-like formatting. **/
 void trans_throw(const char *id, void *object, const char *fmt, ...) FORMAT_CHECK(printf,3,4) NONRET;
+
+/** A `va_list` variant of @trans_throw(). **/
 void trans_vthrow(const char *id, void *object, const char *fmt, va_list args) NONRET;
+
+/** Throw an already constructed exception (or re-throw an exception you have caught). **/
+void trans_throw_exc(struct exception *x) NONRET;
+
+/** Declare the current exception caught and roll back the current transaction. Called from `TRANS_END`. **/
 void trans_caught(void);
 
-struct exception *trans_current_exc(void);
+struct exception *trans_current_exc(void);     /** Return the exception in flight, or NULL if there is none. **/
 
 #define TRANS_TRY do {                         \
   struct trans *_t = trans_open();             \