]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/mp_lock.cpp
update
[l4.git] / kernel / fiasco / src / kern / mp_lock.cpp
1 INTERFACE:
2
3 #include "queue.h"
4
5 class Mp_lock
6 {
7 public:
8   enum Status { Not_locked, Locked, Invalid };
9
10 private:
11   /** queue of blocked threads */
12   Queue _q;
13 };
14
15
16 //----------------------------------------------------------------------------
17 IMPLEMENTATION:
18
19 #include "context.h"
20 #include "cpu_lock.h"
21 #include "globals.h"
22 #include "kdb_ke.h"
23 #include "lock_guard.h"
24 #include "thread_state.h"
25 //#include "logdefs.h"
26
27 PUBLIC inline NEEDS["context.h", "cpu_lock.h", "globals.h",
28                     "kdb_ke.h", "lock_guard.h", "thread_state.h"]
29 Mp_lock::Status
30 Mp_lock::test_and_set()
31 {
32   //assert_kdb (cpu_lock.test());
33
34   Context *const c = current();
35
36   auto g = lock_guard(cpu_lock);
37
38     {
39       auto guard = lock_guard(_q.q_lock());
40       if (EXPECT_FALSE(_q.invalid()))
41         return Invalid;
42
43       if (!_q.blocked())
44         {
45           // lock was free, take it
46           _q.block();
47           return Not_locked;
48         }
49
50       _q.enqueue(c->queue_item());
51     }
52   // LOG_MSG_3VAL(c, "block", (Mword)this, current_cpu(), *((Mword*)this));
53   assert_kdb (!(c->state() & Thread_drq_ready));
54   while (1)
55     {
56       c->state_change_dirty(~Thread_ready, Thread_waiting);
57       c->schedule();
58
59       if (!c->queue_item()->queued())
60         break;
61     }
62
63   c->state_del_dirty(Thread_waiting);
64
65   // LOG_MSG_3VAL(c, "woke", (Mword)this, current_cpu(), 0);
66
67   switch (c->queue_item()->status())
68     {
69     case Queue_item::Ok:      return Not_locked;
70     case Queue_item::Invalid: return Invalid;
71     case Queue_item::Retry:   assert_kdb (false);
72     }
73
74   return Invalid;
75 }
76
77 PUBLIC inline NEEDS[Mp_lock::test_and_set]
78 Mp_lock::Status
79 Mp_lock::lock()
80 { return test_and_set(); }
81
82 PUBLIC inline NEEDS["context.h", "cpu_lock.h", "globals.h",
83                     "kdb_ke.h", "lock_guard.h"]
84 void
85 Mp_lock::clear()
86 {
87   //assert_kdb (cpu_lock.test());
88
89   Queue_item *f;
90
91     {
92       auto guard = lock_guard(_q.q_lock());
93       //LOG_MSG_3VAL(current(), "clear", (Mword)this, current_cpu(), *((Mword*)this));
94       assert_kdb (_q.blocked());
95
96       f = _q.first();
97       if (!f)
98         {
99           _q.unblock();
100           return;
101         }
102
103       _q.dequeue(f, Queue_item::Ok);
104     }
105   // LOG_MSG_3VAL(current(), "wake", Mword(context_of(f)), (Mword)this, current_cpu());
106   assert_kdb (current()->state() & Thread_ready_mask);
107   context_of(f)->activate();
108 }
109
110 PUBLIC inline NEEDS["kdb_ke.h"]
111 void
112 Mp_lock::wait_free()
113 {
114
115   Context *const c = current();
116
117   auto g = lock_guard(cpu_lock);
118
119     {
120       auto guard = lock_guard(_q.q_lock());
121       assert_kdb (invalid());
122
123       if (!_q.blocked())
124         return;
125
126       _q.enqueue(c->queue_item());
127     }
128
129   while (1)
130     {
131       c->state_change_dirty(~Thread_ready, Thread_waiting);
132       c->schedule();
133
134       if (!c->queue_item()->queued())
135         break;
136     }
137
138   c->state_del_dirty(Thread_waiting);
139 }
140
141 PUBLIC inline
142 bool
143 Mp_lock::test() const
144 { return _q.blocked(); }
145
146
147 PUBLIC inline NEEDS[Mp_lock::clear]
148 void
149 Mp_lock::set(Status s)
150 {
151   if (s == Not_locked)
152     clear();
153 }
154
155 PUBLIC
156 void
157 Mp_lock::invalidate()
158 {
159     {
160       auto guard = lock_guard(_q.q_lock());
161       _q.invalidate();
162     }
163       
164   Queue_item *f;
165   while (1)
166     {
167       auto guard = lock_guard(_q.q_lock());
168       f = _q.first();
169
170       //LOG_MSG_3VAL(current(), "deq", Mword(f), 0, 0);
171       if (!f)
172         break;
173
174       _q.dequeue(f, Queue_item::Invalid);
175       context_of(f)->activate();
176     }
177 }
178
179 PUBLIC inline
180 bool
181 Mp_lock::invalid() const
182 { return _q.invalid(); }