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/list.h>
20 #include <util/fifo.h>
21
22 namespace Genode {
23
24 /**
25 * Semaphore queue interface
26 */
27 class Semaphore_queue
28 {
29 public:
30
31 /**
32 * Semaphore-queue elements
33 *
34 * A queue element represents a thread blocking on the
35 * semaphore.
36 */
37 class Element : Lock
38 {
39 public:
40
41 /**
42 * Constructor
43 */
44 Element() : Lock(LOCKED) { }
45
46 void block() { lock(); }
47 void wake_up() { unlock(); }
48 };
49
50 /**
51 * Add new queue member that is going to block
52 */
53 void enqueue(Element *e);
54
55 /**
56 * Dequeue queue member to wake up next
57 */
58 Element *dequeue();
59 };
60
61
62 /**
63 * First-in-first-out variant of the semaphore-queue interface
64 */
65 class Fifo_semaphore_queue : public Semaphore_queue
66 {
67 public:
68
69 class Element : public Semaphore_queue::Element,
70 public Fifo<Element>::Element { };
71
72 private:
73
74 Fifo<Element> _fifo;
75
76 public:
77
78 void enqueue(Element *e) { _fifo.enqueue(e); }
79
80 Element *dequeue() { return _fifo.dequeue(); }
81 };
82
83
84 /**
85 * Semaphore base template
86 *
87 * \param QT semaphore wait queue type implementing the
88 * `Semaphore_queue` interface
89 * \param QTE wait-queue element type implementing the
90 * `Semaphore_queue::Element` interface
91 *
92 * The queuing policy is defined via the QT and QTE types.
93 * This way, the platform-specific semaphore-queueing policies
94 * such as priority-sorted queueing can be easily supported.
95 */
96 template <typename QT, typename QTE>
97 class Semaphore_template
98 {
99 protected:
100
101 int _cnt;
102 Lock _meta_lock;
103 QT _queue;
104
105 public:
106
107 /**
108 * Constructor
109 *
110 * \param n initial counter value of the semphore
111 */
112 Semaphore_template(int n = 0) : _cnt(n) { }
113
114 ~Semaphore_template()
115 {
116 /* synchronize destruction with unfinished `up()` */
117 try { _meta_lock.lock(); } catch (...) { }
118 }
119
120 void up()
121 {
122 Lock::Guard lock_guard(_meta_lock);
123
124 if (++_cnt > 0)
125 return;
126
127 /*
128 * Remove element from queue and wake up the corresponding
129 * blocking thread
130 */
131 Semaphore_queue::Element * element = _queue.dequeue();
132 if (element)
133 element->wake_up();
134 }
135
136 void down()
137 {
138 _meta_lock.lock();
139
140 if (--_cnt < 0) {
141
142 /*
143 * Create semaphore queue element representing the thread
144 * in the wait queue.
145 */
146 QTE queue_element;
147 _queue.enqueue(&queue_element);
148 _meta_lock.unlock();
149
150 /*
151 * The thread is going to block on a local lock now,
152 * waiting for getting waked from another thread
153 * calling `up()`
154 * */
155 queue_element.block();
156
157 } else {
158 _meta_lock.unlock();
159 }
160 }
161
162 /**
163 * Return current semaphore counter
164 */
165 int cnt() { return _cnt; }
166 };
167
168
169 /**
170 * Semaphore with default behaviour
171 */
172 typedef Semaphore_template<Fifo_semaphore_queue, Fifo_semaphore_queue::Element> Semaphore;
173 }
174
175 #endif /* _INCLUDE__BASE__SEMAPHORE_H_ */