/src/hdf5/src/H5TSsemaphore.h
Line | Count | Source |
1 | | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
2 | | * Copyright by The HDF Group. * |
3 | | * All rights reserved. * |
4 | | * * |
5 | | * This file is part of HDF5. The full HDF5 copyright notice, including * |
6 | | * terms governing use, modification, and redistribution, is contained in * |
7 | | * the LICENSE file, which can be found at the root of the source code * |
8 | | * distribution tree, or in https://www.hdfgroup.org/licenses. * |
9 | | * If you do not have access to either file, you may request a copy from * |
10 | | * help@hdfgroup.org. * |
11 | | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
12 | | |
13 | | /* |
14 | | * Purpose: This file contains support for semaphores, equivalent to POSIX |
15 | | * semaphore's capabilities. The implementation is based on the |
16 | | * "lightweight semaphore" describend here: |
17 | | *https://preshing.com/20150316/semaphores-are-surprisingly-versatile/ and implemented here: |
18 | | *https://github.com/preshing/cpp11-on-multicore/blob/master/common/sema.h |
19 | | * |
20 | | * Note: Because this threadsafety framework operates outside the library, |
21 | | * it does not use the error stack (although it does use error macros |
22 | | * that don't push errors on a stack) and only uses the "namecheck only" |
23 | | * FUNC_ENTER_* / FUNC_LEAVE_* macros. |
24 | | */ |
25 | | |
26 | | /****************/ |
27 | | /* Module Setup */ |
28 | | /****************/ |
29 | | |
30 | | /***********/ |
31 | | /* Headers */ |
32 | | /***********/ |
33 | | |
34 | | /****************/ |
35 | | /* Local Macros */ |
36 | | /****************/ |
37 | | |
38 | | /******************/ |
39 | | /* Local Typedefs */ |
40 | | /******************/ |
41 | | |
42 | | /********************/ |
43 | | /* Local Prototypes */ |
44 | | /********************/ |
45 | | |
46 | | /*********************/ |
47 | | /* Package Variables */ |
48 | | /*********************/ |
49 | | |
50 | | /*****************************/ |
51 | | /* Library Private Variables */ |
52 | | /*****************************/ |
53 | | |
54 | | /*******************/ |
55 | | /* Local Variables */ |
56 | | /*******************/ |
57 | | |
58 | | #if defined(_WIN32) |
59 | | /*------------------------------------------------------------------------- |
60 | | * Function: H5TS_semaphore_signal |
61 | | * |
62 | | * Purpose: Increments (unlocks) the semaphore. If the semaphore's value |
63 | | * becomes greater than zero, then another thread blocked in a wait |
64 | | * call will be woken up and proceed to lock the semaphore. |
65 | | * |
66 | | * Return: Non-negative on success / Negative on failure |
67 | | * |
68 | | *------------------------------------------------------------------------- |
69 | | */ |
70 | | static inline herr_t |
71 | | H5TS_semaphore_signal(H5TS_semaphore_t *sem) |
72 | | { |
73 | | /* Check argument */ |
74 | | if (H5_UNLIKELY(NULL == sem)) |
75 | | return FAIL; |
76 | | |
77 | | if (H5_UNLIKELY(0 == ReleaseSemaphore(*sem, 1, NULL))) |
78 | | return FAIL; |
79 | | |
80 | | return SUCCEED; |
81 | | } /* end H5TS_semaphore_signal() */ |
82 | | |
83 | | /*------------------------------------------------------------------------- |
84 | | * Function: H5TS_semaphore_wait |
85 | | * |
86 | | * Purpose: Decrements (locks) the semaphore. If the semaphore's value is |
87 | | * greater than zero, then the decrement proceeds, and the function |
88 | | * returns immediately. If the semaphore currently has a value of |
89 | | * zero or less, then the call blocks until it becomes possible to |
90 | | * perform the decrement (i.e. the semaphore value rises above zero). |
91 | | * |
92 | | * Return: Non-negative on success / Negative on failure |
93 | | * |
94 | | *------------------------------------------------------------------------- |
95 | | */ |
96 | | static inline herr_t |
97 | | H5TS_semaphore_wait(H5TS_semaphore_t *sem) |
98 | | { |
99 | | /* Check argument */ |
100 | | if (H5_UNLIKELY(NULL == sem)) |
101 | | return FAIL; |
102 | | |
103 | | if (H5_UNLIKELY(WAIT_OBJECT_0 != WaitForSingleObject(*sem, INFINITE))) |
104 | | return FAIL; |
105 | | |
106 | | return SUCCEED; |
107 | | } /* end H5TS_semaphore_wait() */ |
108 | | |
109 | | #elif defined(__unix__) && !defined(__MACH__) |
110 | | /* |
111 | | * POSIX semaphores |
112 | | */ |
113 | | |
114 | | /*------------------------------------------------------------------------- |
115 | | * Function: H5TS_semaphore_signal |
116 | | * |
117 | | * Purpose: Increments (unlocks) the semaphore. If the semaphore's value |
118 | | * becomes greater than zero, then another thread blocked in a wait |
119 | | * call will be woken up and proceed to lock the semaphore. |
120 | | * |
121 | | * Return: Non-negative on success / Negative on failure |
122 | | * |
123 | | *------------------------------------------------------------------------- |
124 | | */ |
125 | | static inline herr_t |
126 | | H5TS_semaphore_signal(H5TS_semaphore_t *sem) |
127 | 0 | { |
128 | 0 | /* Check argument */ |
129 | 0 | if (H5_UNLIKELY(NULL == sem)) |
130 | 0 | return FAIL; |
131 | 0 |
|
132 | 0 | if (H5_UNLIKELY(0 != sem_post(sem))) |
133 | 0 | return FAIL; |
134 | 0 |
|
135 | 0 | return SUCCEED; |
136 | 0 | } /* end H5TS_semaphore_signal() */ Unexecuted instantiation: H5Eint.c:H5TS_semaphore_signal Unexecuted instantiation: H5.c:H5TS_semaphore_signal |
137 | | |
138 | | /*------------------------------------------------------------------------- |
139 | | * Function: H5TS_semaphore_wait |
140 | | * |
141 | | * Purpose: Decrements (locks) the semaphore. If the semaphore's value is |
142 | | * greater than zero, then the decrement proceeds, and the function |
143 | | * returns immediately. If the semaphore currently has a value of |
144 | | * zero or less, then the call blocks until it becomes possible to |
145 | | * perform the decrement (i.e. the semaphore value rises above zero). |
146 | | * |
147 | | * Return: Non-negative on success / Negative on failure |
148 | | * |
149 | | *------------------------------------------------------------------------- |
150 | | */ |
151 | | static inline herr_t |
152 | | H5TS_semaphore_wait(H5TS_semaphore_t *sem) |
153 | 0 | { |
154 | 0 | int rc; |
155 | 0 |
|
156 | 0 | /* Check argument */ |
157 | 0 | if (H5_UNLIKELY(NULL == sem)) |
158 | 0 | return FAIL; |
159 | 0 |
|
160 | 0 | /* Loop because of: |
161 | 0 | * http://stackoverflow.com/questions/2013181/gdb-causes-sem-wait-to-fail-with-eintr-error |
162 | 0 | */ |
163 | 0 | do { |
164 | 0 | rc = sem_wait(sem); |
165 | 0 | } while (rc == -1 && errno == EINTR); |
166 | 0 |
|
167 | 0 | if (H5_UNLIKELY(0 != rc)) |
168 | 0 | return FAIL; |
169 | 0 |
|
170 | 0 | return SUCCEED; |
171 | 0 | } /* end H5TS_semaphore_wait() */ Unexecuted instantiation: H5Eint.c:H5TS_semaphore_wait Unexecuted instantiation: H5.c:H5TS_semaphore_wait |
172 | | #else |
173 | | /* |
174 | | * Emulate semaphore w/mutex & condition variable |
175 | | */ |
176 | | |
177 | | /*------------------------------------------------------------------------- |
178 | | * Function: H5TS_semaphore_signal |
179 | | * |
180 | | * Purpose: Increments (unlocks) the semaphore. If the semaphore's value |
181 | | * becomes greater than zero, then another thread blocked in a wait |
182 | | * call will proceed to lock the semaphore. |
183 | | * |
184 | | * Return: Non-negative on success / Negative on failure |
185 | | * |
186 | | *------------------------------------------------------------------------- |
187 | | */ |
188 | | static inline herr_t |
189 | | H5TS_semaphore_signal(H5TS_semaphore_t *sem) |
190 | | { |
191 | | /* Check argument */ |
192 | | if (H5_UNLIKELY(NULL == sem)) |
193 | | return FAIL; |
194 | | |
195 | | /* Acquire the mutex for the semaphore */ |
196 | | if (H5_UNLIKELY(H5TS_mutex_lock(&sem->mutex) < 0)) |
197 | | return FAIL; |
198 | | |
199 | | /* Wake a thread up, if any are waiting */ |
200 | | if (sem->waiters) |
201 | | if (H5_UNLIKELY(H5TS_cond_signal(&sem->cond) < 0)) { |
202 | | H5TS_mutex_unlock(&sem->mutex); |
203 | | return FAIL; |
204 | | } |
205 | | |
206 | | /* Increment the semaphore's value */ |
207 | | sem->counter++; |
208 | | |
209 | | /* Release the mutex for the semaphore */ |
210 | | if (H5_UNLIKELY(H5TS_mutex_unlock(&sem->mutex) < 0)) |
211 | | return FAIL; |
212 | | |
213 | | return SUCCEED; |
214 | | } /* end H5TS_semaphore_signal() */ |
215 | | |
216 | | /*------------------------------------------------------------------------- |
217 | | * Function: H5TS_semaphore_wait |
218 | | * |
219 | | * Purpose: Decrements (locks) the semaphore. If the semaphore's value is |
220 | | * greater than zero, then the decrement proceeds, and the function |
221 | | * returns immediately. If the semaphore currently has a value of |
222 | | * zero or less, then the call blocks until it becomes possible to |
223 | | * perform the decrement (i.e. the semaphore value rises above zero). |
224 | | * |
225 | | * Return: Non-negative on success / Negative on failure |
226 | | * |
227 | | *------------------------------------------------------------------------- |
228 | | */ |
229 | | static inline herr_t |
230 | | H5TS_semaphore_wait(H5TS_semaphore_t *sem) |
231 | | { |
232 | | /* Check argument */ |
233 | | if (H5_UNLIKELY(NULL == sem)) |
234 | | return FAIL; |
235 | | |
236 | | /* Acquire the mutex for the semaphore */ |
237 | | if (H5_UNLIKELY(H5TS_mutex_lock(&sem->mutex) < 0)) |
238 | | return FAIL; |
239 | | |
240 | | /* Wait for semaphore value > 0 */ |
241 | | while (0 == sem->counter) { |
242 | | herr_t ret; |
243 | | |
244 | | /* Wait for signal that semaphore count has been incremented */ |
245 | | sem->waiters++; |
246 | | ret = H5TS_cond_wait(&sem->cond, &sem->mutex); |
247 | | sem->waiters--; |
248 | | |
249 | | /* Check for error */ |
250 | | if (H5_UNLIKELY(ret < 0)) { |
251 | | H5TS_mutex_unlock(&sem->mutex); |
252 | | return FAIL; |
253 | | } |
254 | | } |
255 | | |
256 | | /* Decrement the semaphore's value */ |
257 | | sem->counter--; |
258 | | |
259 | | /* Release the mutex for the semaphore */ |
260 | | if (H5_UNLIKELY(H5TS_mutex_unlock(&sem->mutex) < 0)) |
261 | | return FAIL; |
262 | | |
263 | | return SUCCEED; |
264 | | } /* end H5TS_semaphore_wait() */ |
265 | | #endif |