====== 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 [[https://computing.llnl.gov/tutorials/pthreads/ | 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()'')…