license headers in libnetxms changed to LGPL
[public/netxms.git] / src / libnetxms / rwlock.cpp
CommitLineData
5039dede
AK
1/*
2** NetXMS - Network Management System
3** NetXMS Foundation Library
68f384ea 4** Copyright (C) 2003-2010 Victor Kirhenshtein
5039dede
AK
5**
6** This program is free software; you can redistribute it and/or modify
68f384ea
VK
7** it under the terms of the GNU Lesser General Public License as published
8** by the Free Software Foundation; either version 3 of the License, or
5039dede
AK
9** (at your option) any later version.
10**
11** This program is distributed in the hope that it will be useful,
12** but WITHOUT ANY WARRANTY; without even the implied warranty of
13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14** GNU General Public License for more details.
15**
68f384ea 16** You should have received a copy of the GNU Lesser General Public License
5039dede
AK
17** along with this program; if not, write to the Free Software
18** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19**
20** File: rwlock.cpp
21**
22**/
23
24#include "libnetxms.h"
25#include <assert.h>
26
27#if !HAVE_PTHREAD_RWLOCK && !defined(_USE_GNU_PTH)
28
29//
30// Create read/write lock
31//
32
33RWLOCK LIBNETXMS_EXPORTABLE RWLockCreate(void)
34{
35 RWLOCK hLock;
36
37 hLock = (RWLOCK)malloc(sizeof(struct __rwlock_data));
38 if (hLock != NULL)
39 {
40#ifdef _WIN32
41 hLock->m_mutex = CreateMutex(NULL, FALSE, NULL);
42 hLock->m_condRead = CreateEvent(NULL, TRUE, FALSE, NULL);
43 hLock->m_condWrite = CreateEvent(NULL, FALSE, FALSE, NULL);
44#else
45 pthread_mutex_init(&hLock->m_mutex, NULL);
46 pthread_cond_init(&hLock->m_condRead, NULL);
47 pthread_cond_init(&hLock->m_condWrite, NULL);
48#endif
49 hLock->m_dwWaitReaders = 0;
50 hLock->m_dwWaitWriters = 0;
51 hLock->m_iRefCount = 0;
52 }
53
54 return hLock;
55}
56
57
58//
59// Destroy read/write lock
60//
61
62void LIBNETXMS_EXPORTABLE RWLockDestroy(RWLOCK hLock)
63{
64 if (hLock != NULL)
65 {
66 if (hLock->m_iRefCount == 0)
67 {
68#ifdef _WIN32
69 CloseHandle(hLock->m_mutex);
70 CloseHandle(hLock->m_condRead);
71 CloseHandle(hLock->m_condWrite);
72#else
73 pthread_mutex_destroy(&hLock->m_mutex);
74 pthread_cond_destroy(&hLock->m_condRead);
75 pthread_cond_destroy(&hLock->m_condWrite);
76#endif
77 free(hLock);
78 }
79 }
80}
81
82
83//
84// Lock read/write lock for reading
85//
86
87BOOL LIBNETXMS_EXPORTABLE RWLockReadLock(RWLOCK hLock, DWORD dwTimeOut)
88{
89 BOOL bResult = FALSE;
90 int retcode;
91
92 // Check if handle is valid
93 if (hLock == NULL)
94 return FALSE;
95
96#ifdef _WIN32
97 DWORD dwStart, dwElapsed;
98 BOOL bTimeOut = FALSE;
99
100 // Acquire access to handle
101 WaitForSingleObject(hLock->m_mutex, INFINITE);
102
103 do
104 {
105 if ((hLock->m_iRefCount == -1) || (hLock->m_dwWaitWriters > 0))
106 {
107 // Object is locked for writing or somebody wish to lock it for writing
108 hLock->m_dwWaitReaders++;
109 ReleaseMutex(hLock->m_mutex);
110 dwStart = GetTickCount();
111 retcode = WaitForSingleObject(hLock->m_condRead, dwTimeOut);
112 dwElapsed = GetTickCount() - dwStart;
113 WaitForSingleObject(hLock->m_mutex, INFINITE); // Re-acquire mutex
114 hLock->m_dwWaitReaders--;
115 if (retcode == WAIT_TIMEOUT)
116 {
117 bTimeOut = TRUE;
118 }
119 else
120 {
121 if (dwTimeOut != INFINITE)
122 {
123 dwTimeOut -= min(dwElapsed, dwTimeOut);
124 }
125 }
126 }
127 else
128 {
129 hLock->m_iRefCount++;
130 bResult = TRUE;
131 }
132 } while((!bResult) && (!bTimeOut));
133
134 ReleaseMutex(hLock->m_mutex);
135#else
136 // Acquire access to handle
137 if (pthread_mutex_lock(&hLock->m_mutex) != 0)
138 return FALSE; // Problem with mutex
139
140 if ((hLock->m_iRefCount == -1) || (hLock->m_dwWaitWriters > 0))
141 {
142 // Object is locked for writing or somebody wish to lock it for writing
143 hLock->m_dwWaitReaders++;
144
145 if (dwTimeOut == INFINITE)
146 {
147 retcode = pthread_cond_wait(&hLock->m_condRead, &hLock->m_mutex);
148 }
149 else
150 {
151#if HAVE_PTHREAD_COND_RELTIMEDWAIT_NP
152 struct timespec timeout;
153
154 timeout.tv_sec = dwTimeOut / 1000;
155 timeout.tv_nsec = (dwTimeOut % 1000) * 1000000;
156 retcode = pthread_cond_reltimedwait_np(&hLock->m_condRead, &hLock->m_mutex, &timeout);
157#else
158 struct timeval now;
159 struct timespec timeout;
160
161 gettimeofday(&now, NULL);
162 timeout.tv_sec = now.tv_sec + (dwTimeOut / 1000);
163 timeout.tv_nsec = ( now.tv_usec + ( dwTimeOut % 1000 ) * 1000) * 1000;
164 retcode = pthread_cond_timedwait(&hLock->m_condRead, &hLock->m_mutex, &timeout);
165#endif
166 }
167
168 hLock->m_dwWaitReaders--;
169 if (retcode == 0)
170 {
171 assert(hLock->m_iRefCount != -1);
172 hLock->m_iRefCount++;
173 bResult = TRUE;
174 }
175 }
176 else
177 {
178 hLock->m_iRefCount++;
179 bResult = TRUE;
180 }
181
182 pthread_mutex_unlock(&hLock->m_mutex);
183#endif
184
185 return bResult;
186}
187
188
189//
190// Lock read/write lock for writing
191//
192
193BOOL LIBNETXMS_EXPORTABLE RWLockWriteLock(RWLOCK hLock, DWORD dwTimeOut)
194{
195 BOOL bResult = FALSE;
196 int retcode;
197
198 // Check if handle is valid
199 if (hLock == NULL)
200 return FALSE;
201
202#ifdef _WIN32
203 DWORD dwStart, dwElapsed;
204 BOOL bTimeOut = FALSE;
205
206 WaitForSingleObject(hLock->m_mutex, INFINITE);
207 // Reset reader event because it can be set by previous Unlock() call
208 ResetEvent(hLock->m_condRead);
209
210 do
211 {
212 if (hLock->m_iRefCount != 0)
213 {
214 hLock->m_dwWaitWriters++;
215 ReleaseMutex(hLock->m_mutex);
216 dwStart = GetTickCount();
217 retcode = WaitForSingleObject(hLock->m_condWrite, dwTimeOut);
218 dwElapsed = GetTickCount() - dwStart;
219 WaitForSingleObject(hLock->m_mutex, INFINITE); // Re-acquire mutex
220 hLock->m_dwWaitWriters--;
221 if (retcode == WAIT_TIMEOUT)
222 {
223 bTimeOut = TRUE;
224 }
225 else
226 {
227 if (dwTimeOut != INFINITE)
228 {
229 dwTimeOut -= min(dwElapsed, dwTimeOut);
230 }
231 }
232 }
233 else
234 {
235 hLock->m_iRefCount--;
236 bResult = TRUE;
237 }
238 } while((!bResult) && (!bTimeOut));
239
240 ReleaseMutex(hLock->m_mutex);
241#else
242 if (pthread_mutex_lock(&hLock->m_mutex) != 0)
243 return FALSE; // Problem with mutex
244
245 if (hLock->m_iRefCount != 0)
246 {
247 // Object is locked, wait for unlock
248 hLock->m_dwWaitWriters++;
249
250 if (dwTimeOut == INFINITE)
251 {
252 retcode = pthread_cond_wait(&hLock->m_condWrite, &hLock->m_mutex);
253 }
254 else
255 {
256#if HAVE_PTHREAD_COND_RELTIMEDWAIT_NP
257 struct timespec timeout;
258
259 timeout.tv_sec = dwTimeOut / 1000;
260 timeout.tv_nsec = (dwTimeOut % 1000) * 1000000;
261 retcode = pthread_cond_reltimedwait_np(&hLock->m_condWrite, &hLock->m_mutex, &timeout);
262#else
263 struct timeval now;
264 struct timespec timeout;
265
266 gettimeofday(&now, NULL);
267 timeout.tv_sec = now.tv_sec + (dwTimeOut / 1000);
268 timeout.tv_nsec = ( now.tv_usec + ( dwTimeOut % 1000 ) * 1000) * 1000;
269 retcode = pthread_cond_timedwait(&hLock->m_condWrite, &hLock->m_mutex, &timeout);
270#endif
271 }
272
273 hLock->m_dwWaitWriters--;
274 if (retcode == 0)
275 {
276 assert(hLock->m_iRefCount == 0);
277 hLock->m_iRefCount--;
278 bResult = TRUE;
279 }
280 }
281 else
282 {
283 hLock->m_iRefCount--;
284 bResult = TRUE;
285 }
286
287 pthread_mutex_unlock(&hLock->m_mutex);
288#endif
289
290 return bResult;
291}
292
293
294//
295// Unlock read/write lock
296//
297
298void LIBNETXMS_EXPORTABLE RWLockUnlock(RWLOCK hLock)
299{
300 // Check if handle is valid
301 if (hLock == NULL)
302 return;
303
304 // Acquire access to handle
305#ifdef _WIN32
306 WaitForSingleObject(hLock->m_mutex, INFINITE);
307#else
308 if (pthread_mutex_lock(&hLock->m_mutex) != 0)
309 return; // Problem with mutex
310#endif
311
312 // Remove lock
313 if (hLock->m_iRefCount > 0)
314 hLock->m_iRefCount--;
315 else if (hLock->m_iRefCount == -1)
316 hLock->m_iRefCount = 0;
317
318 // Notify waiting threads
319 if (hLock->m_dwWaitWriters > 0)
320 {
321 if (hLock->m_iRefCount == 0)
322#ifdef _WIN32
323 SetEvent(hLock->m_condWrite);
324#else
325 pthread_cond_signal(&hLock->m_condWrite);
326#endif
327 }
328 else if (hLock->m_dwWaitReaders > 0)
329 {
330#ifdef _WIN32
331 SetEvent(hLock->m_condRead);
332#else
333 pthread_cond_broadcast(&hLock->m_condRead);
334#endif
335 }
336
337#ifdef _WIN32
338 ReleaseMutex(hLock->m_mutex);
339#else
340 pthread_mutex_unlock(&hLock->m_mutex);
341#endif
342}
343
344#endif /* !HAVE_PTHREAD_RWLOCK */