Repository navigation
Expand file tree
/
Copy pathprotothread_sem.h
More file actions
56 lines (49 loc) · 1.87 KB
/
Copy pathprotothread_sem.h
File metadata and controls
56 lines (49 loc) · 1.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/**************************************************************/
/* PROTOTHREAD_SEM.H */
/* https://github.com/LarryRuane/protothread */
/* Copyright (c) 2008-present Larry Ruane */
/* Distributed under the MIT software license, see the accompanying */
/* file LICENSE or https://opensource.org/licenses/MIT. */
/* SPDX-License-Identifier: MIT */
/**************************************************************/
#ifndef PROTOTHREAD_SEM_H
#define PROTOTHREAD_SEM_H
#include "protothread.h"
/* Counting semaphore. The public API; pt_i_ names are internal.
* pt_sem_acquire(c, sem_env, value) block until non-zero, then take one
* pt_sem_release(sem_env, value) give one back; never blocks
* pt_sem_env_t one per protothread that acquires
*/
typedef struct pt_sem_env_s {
pt_func_t pt_func ;
} pt_sem_env_t ;
/* This implementation is arguably not fair, because a thread can release
* the semaphore and then acquire it again without blocking, even if there
* are waiters. But this has better performance (fewer context switches).
* If a thread is worried about monopolizing the semaphore, it can call
* pt_yield() just before the sem_acquire() (that's always safe since the
* sem_acquire() can cause a context break anyway).
*
* Semaphore-acquire could be implemented as a macro, which would allow it
* to use the caller's context and not require one of its own.
*/
static inline pt_t
pt_i_sem_acquire(pt_sem_env_t *c, unsigned int *value)
{
pt_resume(c) ;
while (!(*value)) {
pt_wait(c, value) ;
}
(*value) -- ;
return PT_DONE ;
}
#define pt_sem_acquire(c, sem_env, value) \
pt_call(c, pt_i_sem_acquire, sem_env, value)
/* guaranteed not to break context */
static inline void
pt_sem_release(pt_sem_env_t *c, unsigned int *value)
{
(*value) ++ ;
pt_broadcast(pt_get_pt(c), value) ;
}
#endif /* PROTOTHREAD_SEM_H */