fixed makefile
[public/netxms.git] / include / rwlock.h
1 /*
2 ** NetXMS - Network Management System
3 ** NetXMS Foundation Library
4 ** Copyright (C) 2003-2010 Victor Kirhenshtein
5 **
6 ** This program is free software; you can redistribute it and/or modify
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
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 **
16 ** You should have received a copy of the GNU Lesser 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.
19 **
20 ** File: rwlock.h
21 **
22 **/
23
24 #ifndef _rwlock_h_
25 #define _rwlock_h_
26
27 #if HAVE_PTHREAD_RWLOCK
28
29 typedef pthread_rwlock_t * RWLOCK;
30
31 inline RWLOCK RWLockCreate(void)
32 {
33 RWLOCK hLock;
34
35 hLock = (RWLOCK)malloc(sizeof(pthread_rwlock_t));
36 if (pthread_rwlock_init(hLock, NULL) != 0)
37 {
38 free(hLock);
39 hLock = NULL;
40 }
41 return hLock;
42 }
43
44 inline void RWLockDestroy(RWLOCK hLock)
45 {
46 if (hLock != NULL)
47 {
48 pthread_rwlock_destroy(hLock);
49 free(hLock);
50 }
51 }
52
53 inline BOOL RWLockReadLock(RWLOCK hLock, UINT32 dwTimeOut)
54 {
55 BOOL ret = FALSE;
56
57 if (hLock != NULL)
58 {
59 if (dwTimeOut == INFINITE)
60 {
61 if (pthread_rwlock_rdlock(hLock) == 0)
62 {
63 ret = TRUE;
64 }
65 }
66 else
67 {
68 #if HAVE_PTHREAD_RWLOCK_TIMEDRDLOCK
69 struct timeval now;
70 struct timespec timeout;
71
72 // FIXME: there should be more accurate way
73 gettimeofday(&now, NULL);
74 timeout.tv_sec = now.tv_sec + (dwTimeOut / 1000);
75
76 now.tv_usec += (dwTimeOut % 1000) * 1000;
77 timeout.tv_sec += now.tv_usec / 1000000;
78 timeout.tv_nsec = (now.tv_usec % 1000000) * 1000;
79
80 ret = (pthread_rwlock_timedrdlock(hLock, &timeout) == 0);
81 #else
82 for(int i = (dwTimeOut / 50) + 1; i > 0; i--)
83 {
84 if (pthread_rwlock_tryrdlock(hLock) == 0)
85 {
86 ret = TRUE;
87 break;
88 }
89 ThreadSleepMs(50);
90 }
91 #endif
92 }
93 }
94 return ret;
95 }
96
97 inline BOOL RWLockWriteLock(RWLOCK hLock, UINT32 dwTimeOut)
98 {
99 BOOL ret = FALSE;
100
101 if (hLock != NULL)
102 {
103 if (dwTimeOut == INFINITE)
104 {
105 if (pthread_rwlock_wrlock(hLock) == 0)
106 {
107 ret = TRUE;
108 }
109 }
110 else
111 {
112 #if HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
113 struct timeval now;
114 struct timespec timeout;
115
116 // FIXME: there should be more accurate way
117 gettimeofday(&now, NULL);
118 timeout.tv_sec = now.tv_sec + (dwTimeOut / 1000);
119
120 now.tv_usec += (dwTimeOut % 1000) * 1000;
121 timeout.tv_sec += now.tv_usec / 1000000;
122 timeout.tv_nsec = (now.tv_usec % 1000000) * 1000;
123
124 ret = (pthread_rwlock_timedwrlock(hLock, &timeout) == 0);
125 #else
126 for(int i = (dwTimeOut / 50) + 1; i > 0; i--)
127 {
128 if (pthread_rwlock_trywrlock(hLock) == 0)
129 {
130 ret = TRUE;
131 break;
132 }
133 ThreadSleepMs(50);
134 }
135 #endif
136 }
137 }
138 return ret;
139 }
140
141 inline void RWLockUnlock(RWLOCK hLock)
142 {
143 if (hLock != NULL)
144 pthread_rwlock_unlock(hLock);
145 }
146
147 #elif defined(_USE_GNU_PTH)
148
149 typedef pth_rwlock_t * RWLOCK;
150
151 inline RWLOCK RWLockCreate(void)
152 {
153 RWLOCK hLock;
154
155 hLock = (RWLOCK)malloc(sizeof(pth_rwlock_t));
156 if (!pth_rwlock_init(hLock))
157 {
158 free(hLock);
159 hLock = NULL;
160 }
161 return hLock;
162 }
163
164 inline void RWLockDestroy(RWLOCK hLock)
165 {
166 if (hLock != NULL)
167 {
168 free(hLock);
169 }
170 }
171
172 inline BOOL RWLockReadLock(RWLOCK hLock, UINT32 dwTimeOut)
173 {
174 BOOL ret = FALSE;
175
176 if (hLock != NULL)
177 {
178 if (dwTimeOut == INFINITE)
179 {
180 if (pth_rwlock_acquire(hLock, PTH_RWLOCK_RD, FALSE, NULL))
181 {
182 ret = TRUE;
183 }
184 }
185 else
186 {
187 pth_event_t ev;
188
189 ev = pth_event(PTH_EVENT_TIME, pth_timeout(dwTimeOut / 1000, (dwTimeOut % 1000) * 1000));
190 if (pth_rwlock_acquire(hLock, PTH_RWLOCK_RD, FALSE, ev))
191 {
192 ret = TRUE;
193 }
194 pth_event_free(ev, PTH_FREE_ALL);
195 }
196 }
197 return ret;
198 }
199
200 inline BOOL RWLockWriteLock(RWLOCK hLock, UINT32 dwTimeOut)
201 {
202 BOOL ret = FALSE;
203
204 if (hLock != NULL)
205 {
206 if (dwTimeOut == INFINITE)
207 {
208 if (pth_rwlock_acquire(hLock, PTH_RWLOCK_RW, FALSE, NULL))
209 {
210 ret = TRUE;
211 }
212 }
213 else
214 {
215 pth_event_t ev;
216
217 ev = pth_event(PTH_EVENT_TIME, pth_timeout(dwTimeOut / 1000, (dwTimeOut % 1000) * 1000));
218 if (pth_rwlock_acquire(hLock, PTH_RWLOCK_RW, FALSE, ev))
219 {
220 ret = TRUE;
221 }
222 pth_event_free(ev, PTH_FREE_ALL);
223 }
224 }
225 return ret;
226 }
227
228 inline void RWLockUnlock(RWLOCK hLock)
229 {
230 if (hLock != NULL)
231 pth_rwlock_release(hLock);
232 }
233
234 #else /* not HAVE_PTHREAD_RWLOCK and not defined _USE_GNU_PTH */
235
236 struct __rwlock_data
237 {
238 #ifdef _WIN32
239 HANDLE m_mutex;
240 HANDLE m_condRead;
241 HANDLE m_condWrite;
242 #else
243 pthread_mutex_t m_mutex;
244 pthread_cond_t m_condRead;
245 pthread_cond_t m_condWrite;
246 #endif
247 UINT32 m_dwWaitReaders;
248 UINT32 m_dwWaitWriters;
249 int m_iRefCount; // -1 for write lock, otherwise number of read locks
250 };
251
252 typedef struct __rwlock_data * RWLOCK;
253
254 RWLOCK LIBNETXMS_EXPORTABLE RWLockCreate();
255 void LIBNETXMS_EXPORTABLE RWLockDestroy(RWLOCK hLock);
256 BOOL LIBNETXMS_EXPORTABLE RWLockReadLock(RWLOCK hLock, UINT32 dwTimeOut);
257 BOOL LIBNETXMS_EXPORTABLE RWLockWriteLock(RWLOCK hLock, UINT32 dwTimeOut);
258 void LIBNETXMS_EXPORTABLE RWLockUnlock(RWLOCK hLock);
259
260 #endif
261
262 inline void RWLockPreemptiveWriteLock(RWLOCK hLock, UINT32 dwTimeout, UINT32 dwSleep)
263 {
264 while(!RWLockWriteLock(hLock, dwTimeout))
265 ThreadSleepMs(dwSleep);
266 }
267
268 #endif