github.com/afumu/libc@v0.0.6/musl/src/thread/pthread_once.c (about)

     1  #include "pthread_impl.h"
     2  
     3  static void undo(void *control)
     4  {
     5  	/* Wake all waiters, since the waiter status is lost when
     6  	 * resetting control to the initial state. */
     7  	if (a_swap(control, 0) == 3)
     8  		__wake(control, -1, 1);
     9  }
    10  
    11  hidden int __pthread_once_full(pthread_once_t *control, void (*init)(void))
    12  {
    13  	/* Try to enter initializing state. Four possibilities:
    14  	 *  0 - we're the first or the other cancelled; run init
    15  	 *  1 - another thread is running init; wait
    16  	 *  2 - another thread finished running init; just return
    17  	 *  3 - another thread is running init, waiters present; wait */
    18  
    19  	for (;;) switch (a_cas(control, 0, 1)) {
    20  	case 0:
    21  		pthread_cleanup_push(undo, control);
    22  		init();
    23  		pthread_cleanup_pop(0);
    24  
    25  		if (a_swap(control, 2) == 3)
    26  			__wake(control, -1, 1);
    27  		return 0;
    28  	case 1:
    29  		/* If this fails, so will __wait. */
    30  		a_cas(control, 1, 3);
    31  	case 3:
    32  		__wait(control, 0, 3, 1);
    33  		continue;
    34  	case 2:
    35  		return 0;
    36  	}
    37  }
    38  
    39  int __pthread_once(pthread_once_t *control, void (*init)(void))
    40  {
    41  	/* Return immediately if init finished before, but ensure that
    42  	 * effects of the init routine are visible to the caller. */
    43  	if (*(volatile int *)control == 2) {
    44  		a_barrier();
    45  		return 0;
    46  	}
    47  	return __pthread_once_full(control, init);
    48  }
    49  
    50  weak_alias(__pthread_once, pthread_once);