Blame gl/tests/windows-once.c

Packit Service 991b93
/* Once-only control (native Windows implementation).
Packit Service 991b93
   Copyright (C) 2005-2020 Free Software Foundation, Inc.
Packit Service 991b93
Packit Service 991b93
   This program is free software; you can redistribute it and/or modify
Packit Service 991b93
   it under the terms of the GNU General Public License as published by
Packit Service 991b93
   the Free Software Foundation; either version 3, or (at your option)
Packit Service 991b93
   any later version.
Packit Service 991b93
Packit Service 991b93
   This program is distributed in the hope that it will be useful,
Packit Service 991b93
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 991b93
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 991b93
   GNU General Public License for more details.
Packit Service 991b93
Packit Service 991b93
   You should have received a copy of the GNU General Public License
Packit Service 991b93
   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
Packit Service 991b93
Packit Service 991b93
/* Written by Bruno Haible <bruno@clisp.org>, 2005.
Packit Service 991b93
   Based on GCC's gthr-win32.h.  */
Packit Service 991b93
Packit Service 991b93
#include <config.h>
Packit Service 991b93
Packit Service 991b93
/* Specification.  */
Packit Service 991b93
#include "windows-once.h"
Packit Service 991b93
Packit Service 991b93
#include <stdlib.h>
Packit Service 991b93
Packit Service 991b93
void
Packit Service 991b93
glwthread_once (glwthread_once_t *once_control, void (*initfunction) (void))
Packit Service 991b93
{
Packit Service 991b93
  if (once_control->inited <= 0)
Packit Service 991b93
    {
Packit Service 991b93
      if (InterlockedIncrement (&once_control->started) == 0)
Packit Service 991b93
        {
Packit Service 991b93
          /* This thread is the first one to come to this once_control.  */
Packit Service 991b93
          InitializeCriticalSection (&once_control->lock);
Packit Service 991b93
          EnterCriticalSection (&once_control->lock);
Packit Service 991b93
          once_control->inited = 0;
Packit Service 991b93
          initfunction ();
Packit Service 991b93
          once_control->inited = 1;
Packit Service 991b93
          LeaveCriticalSection (&once_control->lock);
Packit Service 991b93
        }
Packit Service 991b93
      else
Packit Service 991b93
        {
Packit Service 991b93
          /* Don't let once_control->started grow and wrap around.  */
Packit Service 991b93
          InterlockedDecrement (&once_control->started);
Packit Service 991b93
          /* Some other thread has already started the initialization.
Packit Service 991b93
             Yield the CPU while waiting for the other thread to finish
Packit Service 991b93
             initializing and taking the lock.  */
Packit Service 991b93
          while (once_control->inited < 0)
Packit Service 991b93
            Sleep (0);
Packit Service 991b93
          if (once_control->inited <= 0)
Packit Service 991b93
            {
Packit Service 991b93
              /* Take the lock.  This blocks until the other thread has
Packit Service 991b93
                 finished calling the initfunction.  */
Packit Service 991b93
              EnterCriticalSection (&once_control->lock);
Packit Service 991b93
              LeaveCriticalSection (&once_control->lock);
Packit Service 991b93
              if (!(once_control->inited > 0))
Packit Service 991b93
                abort ();
Packit Service 991b93
            }
Packit Service 991b93
        }
Packit Service 991b93
    }
Packit Service 991b93
}