|
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 |
}
|