pthread_once.c 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. /*
  2. * This file is subject to the terms and conditions of the LGPL V2.1
  3. * License. See the file "COPYING" in the main directory of this archive
  4. * for more details.
  5. *
  6. * Copyright (C) 2019 Kalray Inc.
  7. */
  8. #include "pthreadP.h"
  9. #include <lowlevellock.h>
  10. unsigned long int __fork_generation attribute_hidden;
  11. static void
  12. clear_once_control (void *arg)
  13. {
  14. pthread_once_t *once_control = (pthread_once_t *) arg;
  15. *once_control = 0;
  16. lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
  17. }
  18. int
  19. __pthread_once (once_control, init_routine)
  20. pthread_once_t *once_control;
  21. void (*init_routine) (void);
  22. {
  23. while (1)
  24. {
  25. int oldval, val, newval;
  26. val = *once_control;
  27. do
  28. {
  29. /* Check if the initialized has already been done. */
  30. if ((val & 2) != 0)
  31. return 0;
  32. oldval = val;
  33. newval = (oldval & 3) | __fork_generation | 1;
  34. val = atomic_compare_and_exchange_val_acq (once_control, newval, oldval);
  35. } while (__builtin_expect (val != oldval, 0));
  36. /* Check if another thread already runs the initializer. */
  37. if ((oldval & 1) != 0)
  38. {
  39. /* Check whether the initializer execution was interrupted
  40. * by a fork. */
  41. if (((oldval ^ newval) & -4) == 0)
  42. {
  43. /* Same generation, some other thread was faster. Wait. */
  44. lll_futex_wait (once_control, newval, LLL_PRIVATE);
  45. continue;
  46. }
  47. }
  48. /* This thread is the first here. Do the initialization.
  49. * Register a cleanup handler so that in case the thread gets
  50. * interrupted the initialization can be restarted. */
  51. pthread_cleanup_push (clear_once_control, once_control);
  52. init_routine ();
  53. pthread_cleanup_pop (0);
  54. /* Add one to *once_control. */
  55. atomic_increment (once_control);
  56. /* Wake up all other threads. */
  57. lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
  58. break;
  59. }
  60. return 0;
  61. }
  62. weak_alias (__pthread_once, pthread_once)
  63. strong_alias (__pthread_once, __pthread_once_internal)