1
/*
2
* \brief Semaphore
3
* \author Norman Feske
4
* \author Christian Prochaska
5
* \date 2006-09-22
6
*/
7
8
/*
9
* Copyright (C) 2006-2013 Genode Labs GmbH
10
*
11
* This file is part of the Genode OS framework, which is distributed
12
* under the terms of the GNU General Public License version 2.
13
*/
14
15
#
ifndef _INCLUDE__BASE__SEMAPHORE_H_
16
#
define _INCLUDE__BASE__SEMAPHORE_H_
17
18
#
include <base/lock.h>
19
#
include <util/fifo.h>
20
21
namespace
Genode {
class
Semaphore;
}
22
23
24
class
Genode::
Semaphore
25
{
26
protected
:
27
28
int _cnt;
29
Lock _meta_lock;
30
31
struct
Element :
Fifo<
Element
>
::
Element
32
{
33
Lock lock {
Lock::
LOCKED }
;
34
35
void
block(
)
{
lock.
lock(
)
;
}
36
void
wake_up(
)
{
lock.
unlock(
)
;
}
37
}
;
38
39
Fifo<
Element
>
_queue;
40
41
public
:
42
43
/**
44
* Constructor
45
*
46
* \param n initial counter value of the semphore
47
*/
48
Semaphore(
int
n
=
0
)
:
_cnt(
n)
{
}
49
50
~
Semaphore(
)
51
{
52
/* synchronize destruction with unfinished `up()` */
53
try
{
_meta_lock.
lock(
)
;
}
catch
(
.
.
.
)
{
}
54
}
55
56
/**
57
* Increment semphore counter
58
*
59
* This method may wake up another thread that currently blocks on
60
* a `down` call at the same semaphore.
61
*/
62
void
up(
)
63
{
64
Element *
element =
nullptr;
65
66
{
67
Lock::
Guard
lock_guard(
_meta_lock
)
;
68
69
if
(
++
_cnt >
0)
70
return
;
71
72
/*
73
* Remove element from queue and wake up the corresponding
74
* blocking thread
75
*/
76
element =
_queue.
dequeue(
)
;
77
}
78
79
/* do not hold the lock while unblocking a waiting thread */
80
if
(
element)
element->
wake_up(
)
;
81
}
82
83
/**
84
* Decrement semaphore counter, block if the counter reaches zero
85
*/
86
void
down(
)
87
{
88
_meta_lock.
lock(
)
;
89
90
if
(
--
_cnt <
0)
{
91
92
/*
93
* Create semaphore queue element representing the thread
94
* in the wait queue.
95
*/
96
Element queue_element;
97
_queue.
enqueue(
&
queue_element)
;
98
_meta_lock.
unlock(
)
;
99
100
/*
101
* The thread is going to block on a local lock now,
102
* waiting for getting waked from another thread
103
* calling `up()`
104
* */
105
queue_element.
block(
)
;
106
107
}
else
{
108
_meta_lock.
unlock(
)
;
109
}
110
}
111
112
/**
113
* Return current semaphore counter
114
*/
115
int
cnt(
)
{
return
_cnt
;
}
116
}
;
117
118
#
endif /* _INCLUDE__BASE__SEMAPHORE_H_ */