P99

◆ P99_UNWIND_PROTECT

#define P99_UNWIND_PROTECT

Unwind execution from several levels of nesting inside a function.

This macro allows several levels of block statements to be unwound safely.

// do something
while (cond0) {
for (;cond1;) {
if (cond2) P99_UNWIND(-1);
}
}
// do some cleanup here
// if everything went well ::p99_unwind_code has value 0 otherwise it
// receives a value from P99_UNWIND
}

Here P99_UNWIND terminates the execution of the inner blocks and resumes execution at the special "label" P99_PROTECT, if present.

The argument to P99_UNWIND controls how many levels are unwound. If it is positive, at most the specified number of levels is unwound, but never more levels than there are on the call stack of the enclosing function. If it is negative, all levels on the stack of the enclosing function are unwound and during unwinding, this negative argument (that was passed to P99_UNWIND) is accessible through p99_unwind_code.

Warning
Variables that are modified before the call to P99_UNWIND are only guaranteed to have their new value in the protected part if they are declared volatile.

Let us see this at an example. The natural way with P99_UNWIND_PROTECT to check for a valid return of malloc could look like this:

unsigned char*volatile buffer = 0;
buffer = malloc(bignumber);
if (!buffer || IamSick) P99_UNWIND 1;
// do something complicated with buffer
free(buffer);
}

If we would not declare buffer to be volatile, the update to buffer with the new value would perhaps not be visible at the point that we call free. Under normal circumstance the compiler is allowed to optimize the store operation away (implied by the assignment), if he can prove that the only visible value of it comes from the last assignment. I could then just use a cached value (e.g in a register) to pass as an argument to free. The volatile qualifier inhibits such an optimization and forces memory-store operations when there is a modification and memory-load operations when there is access to the variable.

Warning
There should be no plain return statement in the depending block before the P99_PROTECT label.
See also
"test-p99-block.c" for a more sophisticated example of nested P99_UNWIND_PROTECT.
P99_UNWIND
P99_UNWIND_RETURN for a replacement of return that respects the protected parts
P99_CHECK_RETURN to check for suspicious bare return statements
p99_unwind_code
p99_unwind_level
P99_TRY and P99_THROW for a construct that can be used across function calls.

Definition at line 604 of file p99_block.h.