Coverage Report

Created: 2026-04-12 06:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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