[haiku-commits] r42064 - haiku/branches/developer/bonefish/signals/src/system/libroot/posix/pthread

  • From: ingo_weinhold@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Thu, 9 Jun 2011 01:06:55 +0200 (CEST)

Author: bonefish
Date: 2011-06-09 01:06:55 +0200 (Thu, 09 Jun 2011)
New Revision: 42064
Changeset: https://dev.haiku-os.org/changeset/42064

Modified:
   
haiku/branches/developer/bonefish/signals/src/system/libroot/posix/pthread/pthread_once.cpp
Log:
pthread_once(): The initialization function may be a cancellation point. So
push a cleanup function that resets the control state before executing it. The
whole function must loop now for that to work.


Modified: 
haiku/branches/developer/bonefish/signals/src/system/libroot/posix/pthread/pthread_once.cpp
===================================================================
--- 
haiku/branches/developer/bonefish/signals/src/system/libroot/posix/pthread/pthread_once.cpp
 2011-06-08 22:25:04 UTC (rev 42063)
+++ 
haiku/branches/developer/bonefish/signals/src/system/libroot/posix/pthread/pthread_once.cpp
 2011-06-08 23:06:55 UTC (rev 42064)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008, Ingo Weinhold, ingo_weinhold@xxxxxxx
+ * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@xxxxxxx
  * Distributed under the terms of the MIT License.
  */
 
@@ -16,6 +16,27 @@
 };
 
 
+/*!    Called when the thread performing the initialization function was 
canceled.
+
+       \param data Pointer to the \c pthread_once_t structure in question.
+*/
+static void
+init_function_canceled(void* data)
+{
+       pthread_once_t* onceControl = (pthread_once_t*)data;
+
+       // reset the control state to uninitialized
+       int32 value = atomic_set((vint32*)&onceControl->state, 
STATE_UNINITIALIZED);
+
+       // If someone has set a semaphore, delete it.
+       if (value >= 0)
+               delete_sem(value);
+}
+
+
+// #pragma mark -
+
+
 int
 pthread_once(pthread_once_t* onceControl, void (*initRoutine)(void))
 {
@@ -32,57 +53,59 @@
        // STATE_INITIALIZED: Set by the first thread when it returns from
        // initRoutine. All following threads will return right away.
 
-       int32 value = atomic_test_and_set((vint32*)&onceControl->state,
-               STATE_INITIALIZING, STATE_UNINITIALIZED);
+       while (true) {
+               int32 value = atomic_test_and_set((vint32*)&onceControl->state,
+                       STATE_INITIALIZING, STATE_UNINITIALIZED);
 
-       if (value == STATE_INITIALIZED)
-               return 0;
+               if (value == STATE_INITIALIZED)
+                       return 0;
 
-       if (value == STATE_UNINITIALIZED) {
-               // we're the first -- perform the initialization
-               initRoutine();
+               if (value == STATE_UNINITIALIZED) {
+                       // we're the first -- perform the initialization
+                       pthread_cleanup_push(&init_function_canceled, 
onceControl);
+                       initRoutine();
+                       pthread_cleanup_pop(false);
 
-               value = atomic_set((vint32*)&onceControl->state, 
STATE_INITIALIZED);
+                       value = atomic_set((vint32*)&onceControl->state, 
STATE_INITIALIZED);
 
-               // If someone else is waiting, we need to delete the semaphore.
-               if (value >= 0)
-                       delete_sem(value);
+                       // If someone else is waiting, we need to delete the 
semaphore.
+                       if (value >= 0)
+                               delete_sem(value);
 
-               return 0;
-       }
+                       return 0;
+               }
 
-       if (value == STATE_INITIALIZING) {
-               // someone is initializing -- we need to create a semaphore we 
can wait
-               // on
-               sem_id semaphore = create_sem(0, "pthread once");
-               if (semaphore >= 0) {
-                       // successfully created -- set it
-                       value = 
atomic_test_and_set((vint32*)&onceControl->state,
-                               semaphore, STATE_INITIALIZING);
-                       if (value == STATE_INITIALIZING)
-                               value = semaphore;
-                       else
-                               delete_sem(semaphore);
-               } else {
-                       // Failed to create the semaphore. Can only happen when 
the system
-                       // runs out of semaphores, but we can still handle the 
situation
-                       // gracefully by spinning.
-                       value = 
atomic_test_and_set((vint32*)&onceControl->state,
-                               STATE_SPINNING, STATE_INITIALIZING);
-                       if (value == STATE_INITIALIZING)
-                               value = STATE_SPINNING;
+               if (value == STATE_INITIALIZING) {
+                       // someone is initializing -- we need to create a 
semaphore we can
+                       // wait on
+                       sem_id semaphore = create_sem(0, "pthread once");
+                       if (semaphore >= 0) {
+                               // successfully created -- set it
+                               value = 
atomic_test_and_set((vint32*)&onceControl->state,
+                                       semaphore, STATE_INITIALIZING);
+                               if (value == STATE_INITIALIZING)
+                                       value = semaphore;
+                               else
+                                       delete_sem(semaphore);
+                       } else {
+                               // Failed to create the semaphore. Can only 
happen when the
+                               // system runs out of semaphores, but we can 
still handle the
+                               // situation gracefully by spinning.
+                               value = 
atomic_test_and_set((vint32*)&onceControl->state,
+                                       STATE_SPINNING, STATE_INITIALIZING);
+                               if (value == STATE_INITIALIZING)
+                                       value = STATE_SPINNING;
+                       }
                }
-       }
 
-       if (value >= 0) {
-               // wait on the semaphore
-               while (acquire_sem(value) == B_INTERRUPTED);
+               if (value >= 0) {
+                       // wait on the semaphore
+                       while (acquire_sem(value) == B_INTERRUPTED);
 
-               return 0;
-       } else if (value == STATE_SPINNING) {
-               // out of semaphores -- spin
-               while (atomic_get((vint32*)&onceControl->state) == 
STATE_SPINNING);
+                       return 0;
+               } else if (value == STATE_SPINNING) {
+                       // out of semaphores -- spin
+                       while (atomic_get((vint32*)&onceControl->state) == 
STATE_SPINNING);
+               }
        }
-
-       return 0;
 }


Other related posts:

  • » [haiku-commits] r42064 - haiku/branches/developer/bonefish/signals/src/system/libroot/posix/pthread - ingo_weinhold