windows-once.c 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. /* Once-only control (native Windows implementation).
  2. Copyright (C) 2005-2021 Free Software Foundation, Inc.
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 3, or (at your option)
  6. any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, see <https://www.gnu.org/licenses/>. */
  13. /* Written by Bruno Haible <bruno@clisp.org>, 2005.
  14. Based on GCC's gthr-win32.h. */
  15. #include <config.h>
  16. /* Specification. */
  17. #include "windows-once.h"
  18. #include <stdlib.h>
  19. void
  20. glwthread_once (glwthread_once_t *once_control, void (*initfunction) (void))
  21. {
  22. if (once_control->inited <= 0)
  23. {
  24. if (InterlockedIncrement (&once_control->started) == 0)
  25. {
  26. /* This thread is the first one to come to this once_control. */
  27. InitializeCriticalSection (&once_control->lock);
  28. EnterCriticalSection (&once_control->lock);
  29. once_control->inited = 0;
  30. initfunction ();
  31. once_control->inited = 1;
  32. LeaveCriticalSection (&once_control->lock);
  33. }
  34. else
  35. {
  36. /* Don't let once_control->started grow and wrap around. */
  37. InterlockedDecrement (&once_control->started);
  38. /* Some other thread has already started the initialization.
  39. Yield the CPU while waiting for the other thread to finish
  40. initializing and taking the lock. */
  41. while (once_control->inited < 0)
  42. Sleep (0);
  43. if (once_control->inited <= 0)
  44. {
  45. /* Take the lock. This blocks until the other thread has
  46. finished calling the initfunction. */
  47. EnterCriticalSection (&once_control->lock);
  48. LeaveCriticalSection (&once_control->lock);
  49. if (!(once_control->inited > 0))
  50. abort ();
  51. }
  52. }
  53. }
  54. }