diff --git a/repos/libports/src/lib/pthread/thread.cc b/repos/libports/src/lib/pthread/thread.cc index 4a8bf5fb0..2bb333032 100644 --- a/repos/libports/src/lib/pthread/thread.cc +++ b/repos/libports/src/lib/pthread/thread.cc @@ -598,4 +598,50 @@ extern "C" { return 0; } + + + int pthread_once(pthread_once_t *once, void (*init_once)(void)) + { + if (!once || ((once->state != PTHREAD_NEEDS_INIT) && + (once->state != PTHREAD_DONE_INIT))) + return EINTR; + + if (!once->mutex) { + pthread_mutex_t p = new (env()->heap()) pthread_mutex(0); + /* be paranoid */ + if (!p) + return EINTR; + + static Lock lock; + + lock.lock(); + if (!once->mutex) { + once->mutex = p; + p = nullptr; + } + lock.unlock(); + + /* + * If another thread concurrently allocated a mutex and was faster, + * free our mutex since it is not used. + */ + if (p) + destroy(env()->heap(), p); + } + + once->mutex->lock(); + + if (once->state == PTHREAD_DONE_INIT) { + once->mutex->unlock(); + return 0; + } + + init_once(); + + once->state = PTHREAD_DONE_INIT; + + once->mutex->unlock(); + + return 0; + } }