0de57f7135c3dbafc23a1650196ce742b584aeab
[strongswan.git] / src / libstrongswan / threading / windows / rwlock.c
1 /*
2 * Copyright (C) 2013 Martin Willi
3 * Copyright (C) 2013 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "thread.h"
17
18 #include <utils/debug.h>
19 #include <threading/rwlock.h>
20 #include <threading/rwlock_condvar.h>
21 #include <threading/thread_value.h>
22
23 typedef struct private_rwlock_t private_rwlock_t;
24 typedef struct private_rwlock_condvar_t private_rwlock_condvar_t;
25
26 /**
27 * private data of rwlock
28 */
29 struct private_rwlock_t {
30
31 /**
32 * public functions
33 */
34 rwlock_t public;
35
36 /**
37 * wrapped rwlock
38 */
39 SRWLOCK srw;
40
41 /**
42 * Thread specific shared lock count
43 */
44 thread_value_t *shared;
45 };
46
47 /**
48 * private data of condvar
49 */
50 struct private_rwlock_condvar_t {
51
52 /**
53 * public interface
54 */
55 rwlock_condvar_t public;
56
57 /**
58 * condition variable
59 */
60 CONDITION_VARIABLE cv;
61 };
62
63 METHOD(rwlock_t, read_lock, void,
64 private_rwlock_t *this)
65 {
66 uintptr_t count;
67
68 /* Recursive read locks are not supported. Use a thread specific
69 * recursiveness counter. */
70
71 count = (uintptr_t)this->shared->get(this->shared);
72 if (count == 0)
73 {
74 AcquireSRWLockShared(&this->srw);
75 }
76 this->shared->set(this->shared, (void*)(count + 1));
77 }
78
79 METHOD(rwlock_t, write_lock, void,
80 private_rwlock_t *this)
81 {
82 AcquireSRWLockExclusive(&this->srw);
83 }
84
85 METHOD(rwlock_t, try_write_lock, bool,
86 private_rwlock_t *this)
87 {
88 /* TODO: causes random failures and segfaults. Bug? */
89 return FALSE;
90 return TryAcquireSRWLockExclusive(&this->srw);
91 }
92
93 METHOD(rwlock_t, unlock, void,
94 private_rwlock_t *this)
95 {
96 uintptr_t count;
97
98 count = (uintptr_t)this->shared->get(this->shared);
99 switch (count)
100 {
101 case 0:
102 ReleaseSRWLockExclusive(&this->srw);
103 break;
104 case 1:
105 ReleaseSRWLockShared(&this->srw);
106 /* fall */
107 default:
108 this->shared->set(this->shared, (void*)(count - 1));
109 break;
110 }
111 }
112
113 METHOD(rwlock_t, destroy, void,
114 private_rwlock_t *this)
115 {
116 this->shared->destroy(this->shared);
117 free(this);
118 }
119
120 /*
121 * see header file
122 */
123 rwlock_t *rwlock_create(rwlock_type_t type)
124 {
125 private_rwlock_t *this;
126
127 INIT(this,
128 .public = {
129 .read_lock = _read_lock,
130 .write_lock = _write_lock,
131 .try_write_lock = _try_write_lock,
132 .unlock = _unlock,
133 .destroy = _destroy,
134 },
135 .shared = thread_value_create(NULL),
136 );
137
138 InitializeSRWLock(&this->srw);
139
140 return &this->public;
141 }
142
143 METHOD(rwlock_condvar_t, timed_wait, bool,
144 private_rwlock_condvar_t *this, rwlock_t *pubrwlock, u_int timeout)
145 {
146 private_rwlock_t *rwlock = (private_rwlock_t*)pubrwlock;
147 bool ret;
148
149 thread_set_active_condvar(&this->cv);
150
151 ret = SleepConditionVariableSRW(&this->cv, &rwlock->srw, timeout, 0);
152
153 thread_set_active_condvar(NULL);
154
155 return ret == 0;
156 }
157
158 METHOD(rwlock_condvar_t, wait_, void,
159 private_rwlock_condvar_t *this, rwlock_t *lock)
160 {
161 timed_wait(this, lock, INFINITE);
162 }
163
164 METHOD(rwlock_condvar_t, timed_wait_abs, bool,
165 private_rwlock_condvar_t *this, rwlock_t *lock, timeval_t tv)
166 {
167 DWORD timeout;
168 timeval_t now, diff;
169
170 time_monotonic(&now);
171 if (timercmp(&now, &tv, >))
172 {
173 return TRUE;
174 }
175 timersub(&tv, &now, &diff);
176 timeout = diff.tv_sec * 1000 + diff.tv_usec / 1000;
177
178 return timed_wait(this, lock, timeout);
179 }
180
181 METHOD(rwlock_condvar_t, signal_, void,
182 private_rwlock_condvar_t *this)
183 {
184 WakeConditionVariable(&this->cv);
185 }
186
187 METHOD(rwlock_condvar_t, broadcast, void,
188 private_rwlock_condvar_t *this)
189 {
190 WakeAllConditionVariable(&this->cv);
191 }
192
193 METHOD(rwlock_condvar_t, condvar_destroy, void,
194 private_rwlock_condvar_t *this)
195 {
196 free(this);
197 }
198
199 /*
200 * see header file
201 */
202 rwlock_condvar_t *rwlock_condvar_create()
203 {
204 private_rwlock_condvar_t *this;
205
206 INIT(this,
207 .public = {
208 .wait = _wait_,
209 .timed_wait = _timed_wait,
210 .timed_wait_abs = _timed_wait_abs,
211 .signal = _signal_,
212 .broadcast = _broadcast,
213 .destroy = _condvar_destroy,
214 },
215 );
216
217 InitializeConditionVariable(&this->cv);
218
219 return &this->public;
220 }