Blame src/w32-lock.c

Packit fc043f
/* w32-lock.c - GPGRT lock functions for Windows
Packit fc043f
   Copyright (C) 2014 g10 Code GmbH
Packit fc043f
Packit fc043f
   This file is part of libgpg-error.
Packit fc043f
Packit fc043f
   libgpg-error is free software; you can redistribute it and/or
Packit fc043f
   modify it under the terms of the GNU Lesser General Public License
Packit fc043f
   as published by the Free Software Foundation; either version 2.1 of
Packit fc043f
   the License, or (at your option) any later version.
Packit fc043f
Packit fc043f
   libgpg-error is distributed in the hope that it will be useful, but
Packit fc043f
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit fc043f
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit fc043f
   Lesser General Public License for more details.
Packit fc043f
Packit fc043f
   You should have received a copy of the GNU Lesser General Public
Packit fc043f
   License along with this program; if not, see <https://www.gnu.org/licenses/>.
Packit fc043f
 */
Packit fc043f
Packit fc043f
#if HAVE_CONFIG_H
Packit fc043f
#include <config.h>
Packit fc043f
#endif
Packit fc043f
Packit fc043f
#ifndef HAVE_W32_SYSTEM
Packit fc043f
# error This module may only be build for Windows.
Packit fc043f
#endif
Packit fc043f
Packit fc043f
#include <stdlib.h>
Packit fc043f
#include <stdio.h>
Packit fc043f
#include <string.h>
Packit fc043f
#include <errno.h>
Packit fc043f
#define WIN32_LEAN_AND_MEAN
Packit fc043f
#include <windows.h>
Packit fc043f
Packit fc043f
#include "gpgrt-int.h"
Packit fc043f
#include "lock.h"
Packit fc043f
#include "w32-lock-obj.h"
Packit fc043f
Packit fc043f
Packit fc043f
Packit fc043f
static _gpgrt_lock_t *
Packit fc043f
get_lock_object (gpgrt_lock_t *lockhd)
Packit fc043f
{
Packit fc043f
  _gpgrt_lock_t *lock = (_gpgrt_lock_t*)lockhd;
Packit fc043f
Packit fc043f
  if (lock->vers != LOCK_ABI_VERSION)
Packit fc043f
    abort ();
Packit fc043f
Packit fc043f
  return lock;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
gpg_err_code_t
Packit fc043f
_gpgrt_lock_init (gpgrt_lock_t *lockhd)
Packit fc043f
{
Packit fc043f
  _gpgrt_lock_t *lock = (_gpgrt_lock_t*)lockhd;
Packit fc043f
Packit fc043f
  /* If VERS is zero we assume that no static initialization has been
Packit fc043f
     done, so we setup our ABI version right here.  The caller might
Packit fc043f
     have called us to test whether lock support is at all available. */
Packit fc043f
  if (!lock->vers)
Packit fc043f
    {
Packit fc043f
      if (sizeof (gpgrt_lock_t) < sizeof (_gpgrt_lock_t))
Packit fc043f
        abort ();
Packit fc043f
      lock->vers = LOCK_ABI_VERSION;
Packit fc043f
    }
Packit fc043f
  else /* Run the usual check.  */
Packit fc043f
    {
Packit fc043f
      lock = get_lock_object (lockhd);
Packit fc043f
      if (sizeof (gpgrt_lock_t) < sizeof (_gpgrt_lock_t))
Packit fc043f
        abort ();
Packit fc043f
    }
Packit fc043f
Packit fc043f
  InitializeCriticalSection (&lock->csec);
Packit fc043f
  lock->initdone = 1;
Packit fc043f
  return 0;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
gpg_err_code_t
Packit fc043f
_gpgrt_lock_lock (gpgrt_lock_t *lockhd)
Packit fc043f
{
Packit fc043f
  _gpgrt_lock_t *lock = get_lock_object (lockhd);
Packit fc043f
Packit fc043f
  if (!lock->initdone)
Packit fc043f
    {
Packit fc043f
      if (!InterlockedIncrement (&lock->started))
Packit fc043f
        {
Packit fc043f
          /* The new value of started is 0.  Because the initial value
Packit fc043f
             if the variable was -1 we known that this thread is the
Packit fc043f
             first who needs this lock.  Thus we initialize now.  All
Packit fc043f
             other threads won't get 0 back from InterlockedIncrement
Packit fc043f
             and thus fall into the wait loop below.  We ignore that
Packit fc043f
             STARTED may in theory overflow if this thread starves for
Packit fc043f
             too long.  */
Packit fc043f
          _gpgrt_lock_init (lockhd);
Packit fc043f
        }
Packit fc043f
      else
Packit fc043f
        {
Packit fc043f
          while (!lock->initdone)
Packit fc043f
            Sleep (0);
Packit fc043f
        }
Packit fc043f
    }
Packit fc043f
Packit fc043f
  _gpgrt_pre_syscall ();
Packit fc043f
  EnterCriticalSection (&lock->csec);
Packit fc043f
  _gpgrt_post_syscall ();
Packit fc043f
  return 0;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
gpg_err_code_t
Packit fc043f
_gpgrt_lock_trylock (gpgrt_lock_t *lockhd)
Packit fc043f
{
Packit fc043f
  _gpgrt_lock_t *lock = get_lock_object (lockhd);
Packit fc043f
Packit fc043f
  if (!lock->initdone)
Packit fc043f
    {
Packit fc043f
      if (!InterlockedIncrement (&lock->started))
Packit fc043f
        {
Packit fc043f
          _gpgrt_lock_init (lockhd);
Packit fc043f
        }
Packit fc043f
      else
Packit fc043f
        {
Packit fc043f
          while (!lock->initdone)
Packit fc043f
            Sleep (0);
Packit fc043f
        }
Packit fc043f
    }
Packit fc043f
Packit fc043f
  if (!TryEnterCriticalSection (&lock->csec))
Packit fc043f
    return GPG_ERR_EBUSY;
Packit fc043f
  return 0;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
gpg_err_code_t
Packit fc043f
_gpgrt_lock_unlock (gpgrt_lock_t *lockhd)
Packit fc043f
{
Packit fc043f
  _gpgrt_lock_t *lock = get_lock_object (lockhd);
Packit fc043f
Packit fc043f
  if (!lock->initdone)
Packit fc043f
    return GPG_ERR_INV_LOCK_OBJ;
Packit fc043f
  LeaveCriticalSection (&lock->csec);
Packit fc043f
  return 0;
Packit fc043f
}
Packit fc043f
Packit fc043f
Packit fc043f
/* Note: Use this function only if no other thread holds or waits for
Packit fc043f
   this lock.  */
Packit fc043f
gpg_err_code_t
Packit fc043f
_gpgrt_lock_destroy (gpgrt_lock_t *lockhd)
Packit fc043f
{
Packit fc043f
  _gpgrt_lock_t *lock = get_lock_object (lockhd);
Packit fc043f
Packit fc043f
  if (!lock->initdone)
Packit fc043f
    return GPG_ERR_INV_LOCK_OBJ;
Packit fc043f
  DeleteCriticalSection (&lock->csec);
Packit fc043f
  lock->initdone = 0;
Packit fc043f
  lock->started = -1;
Packit fc043f
  return 0;
Packit fc043f
}