2 ** NetXMS - Network Management System
3 ** NetXMS Foundation Library
4 ** Copyright (C) 2003, 2004, 2005, 2006 Victor Kirhenshtein
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License as published by
8 ** the Free Software Foundation; either version 2 of the License, or
9 ** (at your option) any later version.
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.
16 ** You should have received a copy of the GNU General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "libnetxms.h"
27 #if !HAVE_PTHREAD_RWLOCK && !defined(_USE_GNU_PTH)
30 // Create read/write lock
33 RWLOCK LIBNETXMS_EXPORTABLE
RWLockCreate(void)
37 hLock
= (RWLOCK
)malloc(sizeof(struct __rwlock_data
));
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
);
45 pthread_mutex_init(&hLock
->m_mutex
, NULL
);
46 pthread_cond_init(&hLock
->m_condRead
, NULL
);
47 pthread_cond_init(&hLock
->m_condWrite
, NULL
);
49 hLock
->m_dwWaitReaders
= 0;
50 hLock
->m_dwWaitWriters
= 0;
51 hLock
->m_iRefCount
= 0;
59 // Destroy read/write lock
62 void LIBNETXMS_EXPORTABLE
RWLockDestroy(RWLOCK hLock
)
66 if (hLock
->m_iRefCount
== 0)
69 CloseHandle(hLock
->m_mutex
);
70 CloseHandle(hLock
->m_condRead
);
71 CloseHandle(hLock
->m_condWrite
);
73 pthread_mutex_destroy(&hLock
->m_mutex
);
74 pthread_cond_destroy(&hLock
->m_condRead
);
75 pthread_cond_destroy(&hLock
->m_condWrite
);
84 // Lock read/write lock for reading
87 BOOL LIBNETXMS_EXPORTABLE
RWLockReadLock(RWLOCK hLock
, DWORD dwTimeOut
)
92 // Check if handle is valid
97 DWORD dwStart
, dwElapsed
;
98 BOOL bTimeOut
= FALSE
;
100 // Acquire access to handle
101 WaitForSingleObject(hLock
->m_mutex
, INFINITE
);
105 if ((hLock
->m_iRefCount
== -1) || (hLock
->m_dwWaitWriters
> 0))
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
)
121 if (dwTimeOut
!= INFINITE
)
123 dwTimeOut
-= min(dwElapsed
, dwTimeOut
);
129 hLock
->m_iRefCount
++;
132 } while((!bResult
) && (!bTimeOut
));
134 ReleaseMutex(hLock
->m_mutex
);
136 // Acquire access to handle
137 if (pthread_mutex_lock(&hLock
->m_mutex
) != 0)
138 return FALSE
; // Problem with mutex
140 if ((hLock
->m_iRefCount
== -1) || (hLock
->m_dwWaitWriters
> 0))
142 // Object is locked for writing or somebody wish to lock it for writing
143 hLock
->m_dwWaitReaders
++;
145 if (dwTimeOut
== INFINITE
)
147 retcode
= pthread_cond_wait(&hLock
->m_condRead
, &hLock
->m_mutex
);
151 #if HAVE_PTHREAD_COND_RELTIMEDWAIT_NP
152 struct timespec timeout
;
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
);
159 struct timespec timeout
;
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
);
168 hLock
->m_dwWaitReaders
--;
171 assert(hLock
->m_iRefCount
!= -1);
172 hLock
->m_iRefCount
++;
178 hLock
->m_iRefCount
++;
182 pthread_mutex_unlock(&hLock
->m_mutex
);
190 // Lock read/write lock for writing
193 BOOL LIBNETXMS_EXPORTABLE
RWLockWriteLock(RWLOCK hLock
, DWORD dwTimeOut
)
195 BOOL bResult
= FALSE
;
198 // Check if handle is valid
203 DWORD dwStart
, dwElapsed
;
204 BOOL bTimeOut
= FALSE
;
206 WaitForSingleObject(hLock
->m_mutex
, INFINITE
);
207 // Reset reader event because it can be set by previous Unlock() call
208 ResetEvent(hLock
->m_condRead
);
212 if (hLock
->m_iRefCount
!= 0)
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
)
227 if (dwTimeOut
!= INFINITE
)
229 dwTimeOut
-= min(dwElapsed
, dwTimeOut
);
235 hLock
->m_iRefCount
--;
238 } while((!bResult
) && (!bTimeOut
));
240 ReleaseMutex(hLock
->m_mutex
);
242 if (pthread_mutex_lock(&hLock
->m_mutex
) != 0)
243 return FALSE
; // Problem with mutex
245 if (hLock
->m_iRefCount
!= 0)
247 // Object is locked, wait for unlock
248 hLock
->m_dwWaitWriters
++;
250 if (dwTimeOut
== INFINITE
)
252 retcode
= pthread_cond_wait(&hLock
->m_condWrite
, &hLock
->m_mutex
);
256 #if HAVE_PTHREAD_COND_RELTIMEDWAIT_NP
257 struct timespec timeout
;
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
);
264 struct timespec timeout
;
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
);
273 hLock
->m_dwWaitWriters
--;
276 assert(hLock
->m_iRefCount
== 0);
277 hLock
->m_iRefCount
--;
283 hLock
->m_iRefCount
--;
287 pthread_mutex_unlock(&hLock
->m_mutex
);
295 // Unlock read/write lock
298 void LIBNETXMS_EXPORTABLE
RWLockUnlock(RWLOCK hLock
)
300 // Check if handle is valid
304 // Acquire access to handle
306 WaitForSingleObject(hLock
->m_mutex
, INFINITE
);
308 if (pthread_mutex_lock(&hLock
->m_mutex
) != 0)
309 return; // Problem with mutex
313 if (hLock
->m_iRefCount
> 0)
314 hLock
->m_iRefCount
--;
315 else if (hLock
->m_iRefCount
== -1)
316 hLock
->m_iRefCount
= 0;
318 // Notify waiting threads
319 if (hLock
->m_dwWaitWriters
> 0)
321 if (hLock
->m_iRefCount
== 0)
323 SetEvent(hLock
->m_condWrite
);
325 pthread_cond_signal(&hLock
->m_condWrite
);
328 else if (hLock
->m_dwWaitReaders
> 0)
331 SetEvent(hLock
->m_condRead
);
333 pthread_cond_broadcast(&hLock
->m_condRead
);
338 ReleaseMutex(hLock
->m_mutex
);
340 pthread_mutex_unlock(&hLock
->m_mutex
);
344 #endif /* !HAVE_PTHREAD_RWLOCK */