pthread_once.c 806 B

12345678910111213141516171819202122232425262728293031323334353637
  1. #include "pthread_impl.h"
  2. static void undo(void *control)
  3. {
  4. a_store(control, 0);
  5. __wake(control, 1, 0);
  6. }
  7. int pthread_once(pthread_once_t *control, void (*init)(void))
  8. {
  9. static int waiters;
  10. /* Return immediately if init finished before */
  11. if (*control == 2) return 0;
  12. /* Try to enter initializing state. Three possibilities:
  13. * 0 - we're the first or the other cancelled; run init
  14. * 1 - another thread is running init; wait
  15. * 2 - another thread finished running init; just return */
  16. for (;;) switch (a_swap(control, 1)) {
  17. case 0:
  18. pthread_cleanup_push(undo, control);
  19. init();
  20. pthread_cleanup_pop(0);
  21. a_store(control, 2);
  22. if (waiters) __wake(control, -1, 0);
  23. return 0;
  24. case 1:
  25. __wait(control, &waiters, 1, 0);
  26. continue;
  27. case 2:
  28. a_store(control, 2);
  29. return 0;
  30. }
  31. }