tags:

views:

349

answers:

5

I'm writing a concurrent transaction library in C and found the following problem. Let's consider a sample transaction member pseudo-code, where the "transaction" represents a communication channel with the transaction master:

transaction = trans_join();

do_some_ops();

/* receive the data from the master */
trans_rcv(transaction, data);

do_some_ops();

trans_send(transaction, answer);

/* wait for the possibility for voting */
trans_ready(transaction);

/* vote for commiting and wait for the voting results. */
if(trans_commit(answer))
{
   printf("Final commiting the changes.\n");
}
else
{
   printf("Rolling back the changes.\n");
}

In concurrent transactions, we can vote only if we are asked for the vote by the master. However, the master can call trans_abort(member) at any time, forcing the specified member to cancel the transaction. The ABORT message can be received by the member at any stage of execution and in this case unsually it should not wait till the execution reaches trans_ready() call. For example, if there is a trans_rcv() call in the later code, the process would hang on waiting for the data from the master which will be never sent.

Now, the point. I have already the code to register the aborting function that rolls back the changes, but I would also like to have an extra mechanism that would allow to skip the rest of the remaining operations and jump to the voting code immediately. I have an idea to use goto here to simulate exceptions:

if(!trans_rcv()) /* fail, we received the abort message */
{
   goto abort_code;
}

...

abort_code:
trans_ready(transaction);
/* etc. */

However, writing ifs for every call of trans_rcv or trans_send is not very comfortable, especially if the transaction code is complex. Have you got any idea for a better solution or is this the only way? It does not have to use goto, by the way :).

+5  A: 

If typing the IFs is the problem, you could use a macro, like:

#define trans_rcv_CHK do { \
     if (!trans_rcv()) \
     { \
          goto abort_code; \
     } \
} while(0)

If trans_rcv has parameters, this should work (in gcc, at least):

#define trans_rcv_CHK(...) do { \
     if (!trans_rcv(__VA_ARGS__)) \
     { \
          goto abort_code; \
     } \
} while (0)
tsg
Macros... how strange I forgot about them. Thanks in advance!
Zyx
Make sure you wrap the if in a do while false. That let's you call trans_rcv_CHK with a semicolon at the end and not have any unintended consequences. See: http://c2.com/cgi/wiki/Wiki?TrivialDoWhileLoop
sharth
@sharth: good point, thanks. I added the loop to the answer.
tsg
+3  A: 

Personally I would code this by using a while loop with a switch based state machine inside of it.

ChrisBD
+7  A: 

goto works only inside one function, which is probably too much a limitation for exception mechanism.

I'd suggest to use setjmp/longjmp functions - see Wikipedia for details.

qrdl
+3  A: 

One of the best source for exception handling in C. Basically how people at RTOS implemented exceptions for their RTFile module. Beware of the dreadful slip into assembly language past the second half of the article.

You can call me Chuck
+1  A: 

See Hanson's "C Interfaces and Implementations: Techniques for Creating Reusable Software". It provides an exception mechanism based on setjmp() and longjmp(). The code is available with an MIT licence.

Jonathan Leffler