Fixes in rwlock implementation
[public/netxms.git] / include / rwlock.h
1 /*
2 ** NetXMS - Network Management System
3 ** NetXMS Foundation Library
4 ** Copyright (C) 2003, 2004, 2005, 2006 Victor Kirhenshtein
5 **
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.
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 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, DWORD 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, DWORD 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 #else /* HAVE_PTHREAD_RWLOCK */
148
149 struct __rwlock_data
150 {
151 #ifdef _WIN32
152 HANDLE m_mutex;
153 HANDLE m_condRead;
154 HANDLE m_condWrite;
155 #else
156 pthread_mutex_t m_mutex;
157 pthread_cond_t m_condRead;
158 pthread_cond_t m_condWrite;
159 #endif
160 DWORD m_dwWaitReaders;
161 DWORD m_dwWaitWriters;
162 int m_iRefCount; // -1 for write lock, otherwise number of read locks
163 };
164
165 typedef struct __rwlock_data * RWLOCK;
166
167 RWLOCK LIBNETXMS_EXPORTABLE RWLockCreate(void);
168 void LIBNETXMS_EXPORTABLE RWLockDestroy(RWLOCK hLock);
169 BOOL LIBNETXMS_EXPORTABLE RWLockReadLock(RWLOCK hLock, DWORD dwTimeOut);
170 BOOL LIBNETXMS_EXPORTABLE RWLockWriteLock(RWLOCK hLock, DWORD dwTimeOut);
171 void LIBNETXMS_EXPORTABLE RWLockUnlock(RWLOCK hLock);
172
173 #endif
174
175 #endif