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