User Tools

Site Tools


negix:painisntalwaysincode

Pain isn't always in code

“Sciatic pain syndrome”. Three simple words, but I tell you, they can turn your world into a swamp of misery. Just like the code we have to endure sometimes. So bear with me if this post isn’t the same quality as the others.

These days I had to refactor some code to make it thread-safe. Oh, it had POSIX Threads Library (pthread) mutexes in it allright, added by the original coder. Since the code was C++, and having to manually release a mutex is cumbersome if you can have destructors, he added a wrapper class for the mutexes.

But later on, some other developer discovered that some code tried to re-lock a mutex already locked by the thread. (The bane of historically-grown software that gets extended beyond its initial conception.) As the default behaviour of pthread mutexes in this case is to deadlock (to save the additional clock-cycles required to test for the condition), this developer added a bool isLocked to the class. Needless to say, querying / setting the boolean and locking / unlocking the thread isn’t an atomic operation, so what we’ve got was a nice little race condition.

Hey, no problemo, the pthread library offers a way to add error-checking to a mutex, which would be the solution to our problem.

The problem being the completely braindead way pthread mutexes are initialized.

Behold, a default pthread mutex, defined at global scope:

pthread_mutex_t default_mutex = PTHREAD_MUTEX_INITIALIZER;

There you go, a mutex, initialized with default attributes and ready to use. Now, how about having some error-checking to go with it?

Erm… please allow me to write this without error handling, it’s long enough as it is:

pthread_mutex_t errorchecking_mutex;
pthread_once_t mutex_init_once = PTHREAD_ONCE_INIT;
void init_mutex()
{
    pthread_mutexattr_t mutexattr;
    pthread_mutexattr_init( &mutexattr );
    pthread_mutexattr_settype( &mutexattr, PTHREAD_MUTEX_ERRORCHECK );
    pthread_mutex_init( &errorchecking_mutex, &mutexattr );
    pthread_mutexattr_destroy( &mutexattr );
}
 
void init()
{
    pthread_once( &mutex_init_once, mutex_init );
    // ...
}

Ye flipping gods. I can understand that a mutex might be a difficult data structure that cannot be set up by OR-ing together some values as most other APIs do, but this is insane. You have to set up, init, and modify an “attribute object”, which is then passed (by reference, why?) to the init routine for the mutex. I added the destroy() function allthough the documentation doesn’t say I have to, but given the nature of POSIX documentation, who knows whether I would leak memory if I didn’t. It smells like it, anyway. And of course I have to protext the whole shebang against concurrent initialization, because I can’t do it statically, and as this is a library I don’t have control over int main() to do it there.

I cannot help but stare in awe at this example of… I don’t even know what it’s an example for, but I am awed nevertheless.

And here I am at a word count of almost 500, and I haven’t even told you about the odyssey of piecing together the code above from the manpages (pthread_mutex_lock() mentioning PTHREAD_MUTEX_ERRORCHECK but not having a reference to pthread_mutex_init() not having a reference to pthread_mutexattr_init() not having a reference to pthread_mutexattr_settype())…

negix/painisntalwaysincode.txt · Last modified: 2018/09/10 16:21 (external edit)