I appreciate the OP's efforts, certainly sharing code is a good thing. And one of the benefits of the sharing is to get a lot of feedback. Criticizing implementation details is important to spot, discuss and hopefully fix potential problems.
As for the alternatives, well return values never killed anyone, did they? You can use gotos to simplify the control flow within the functions. Other than that, there really isn't much to explain.
I don't like longjmp because I never expect them in C. I never think "hey, the control flow might jump to some point 20 stack frames above at any moment when I enter this library". And then I use mutexes. Cue the drama. You can't even protect yourself from the stack unwinding with handler-case or try ... catch/except.