Updating to version 1.13. Libgcrypt depends on libgpg-error
[platform/upstream/libgpg-error.git] / src / w32-lock.c
1 /* w32-lock.c - GPGRT lock functions for Windows
2    Copyright (C) 2014 g10 Code GmbH
3
4    This file is part of libgpg-error.
5
6    libgpg-error is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public License
8    as published by the Free Software Foundation; either version 2.1 of
9    the License, or (at your option) any later version.
10
11    libgpg-error is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #if HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #ifndef HAVE_W32_SYSTEM
25 # error This module may only be build for Windows.
26 #endif
27
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <gpg-error.h>
33 #define WIN32_LEAN_AND_MEAN
34 #include <windows.h>
35
36 #include "lock.h"
37 #include "w32-lock-obj.h"
38
39
40 static _gpgrt_lock_t *
41 get_lock_object (gpgrt_lock_t *lockhd)
42 {
43   _gpgrt_lock_t *lock = (_gpgrt_lock_t*)lockhd;
44
45   if (lock->vers != LOCK_ABI_VERSION)
46     abort ();
47
48   return lock;
49 }
50
51
52 gpg_err_code_t
53 gpgrt_lock_init (gpgrt_lock_t *lockhd)
54 {
55   _gpgrt_lock_t *lock = (_gpgrt_lock_t*)lockhd;
56
57   /* If VERS is zero we assume that no static initialization has been
58      done, so we setup our ABI version right here.  The caller might
59      have called us to test whether lock support is at all available. */
60   if (!lock->vers)
61     {
62       if (sizeof (gpgrt_lock_t) < sizeof (_gpgrt_lock_t))
63         abort ();
64       lock->vers = LOCK_ABI_VERSION;
65     }
66   else /* Run the usual check.  */
67     {
68       lock = get_lock_object (lockhd);
69       if (sizeof (gpgrt_lock_t) < sizeof (_gpgrt_lock_t))
70         abort ();
71     }
72
73   InitializeCriticalSection (&lock->csec);
74   lock->initdone = 1;
75 }
76
77
78 gpg_err_code_t
79 gpgrt_lock_lock (gpgrt_lock_t *lockhd)
80 {
81   _gpgrt_lock_t *lock = get_lock_object (lockhd);
82
83   if (!lock->initdone)
84     {
85       if (!InterlockedIncrement (&lock->started))
86         {
87           /* The new value of started is 0.  Because the initial value
88              if the variable was -1 we known that this thread is the
89              first who needs this lock.  Thus we initialize now.  All
90              other threads won't get 0 back from InterlockedIncrement
91              and thus fall into the wait loop below.  We ignore that
92              STARTED may in theory overflow if this thread starves for
93              too long.  */
94           gpgrt_lock_init (lockhd);
95         }
96       else
97         {
98           while (!lock->initdone)
99             Sleep (0);
100         }
101     }
102
103   EnterCriticalSection (&lock->csec);
104   return 0;
105 }
106
107
108 gpg_err_code_t
109 gpgrt_lock_unlock (gpgrt_lock_t *lockhd)
110 {
111   _gpgrt_lock_t *lock = get_lock_object (lockhd);
112
113   if (!lock->initdone)
114     return GPG_ERR_INV_LOCK_OBJ;
115   LeaveCriticalSection (&lock->csec);
116   return 0;
117 }
118
119
120 /* Note: Use this function only if no other thread holds or waits for
121    this lock.  */
122 gpg_err_code_t
123 gpgrt_lock_destroy (gpgrt_lock_t *lockhd)
124 {
125   _gpgrt_lock_t *lock = get_lock_object (lockhd);
126
127   if (!lock->initdone)
128     return GPG_ERR_INV_LOCK_OBJ;
129   DeleteCriticalSection (&lock->csec);
130   lock->initdone = 0;
131   lock->started = -1;
132   return 0;
133 }