]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/plr/server/src/fault_handlers/lock_observer.cc
update
[l4.git] / l4 / pkg / plr / server / src / fault_handlers / lock_observer.cc
1 /*
2  * lock_observer.cc --
3  *
4  *     Deterministic lock acquisition
5  *
6  * (c) 2012-2013 Björn Döbel <doebel@os.inf.tu-dresden.de>,
7  *     economic rights: Technische Universität Dresden (Germany)
8  * This file is part of TUD:OS and distributed under the terms of the
9  * GNU General Public License 2.
10  * Please see the COPYING-GPL-2 file for details.
11  */
12
13 #include "lock_observer.h"
14
15 #define DEBUGt(t) DEBUG() <<  "[" << t->vcpu() << "] "
16
17 #define EVENT(event, ptr) \
18     do { \
19                 Measurements::GenericEvent* ev = Romain::_the_instance_manager->logbuf()->next(); \
20                 ev->header.tsc                 = Romain::_the_instance_manager->logbuf()->getTime(Log::logLocalTSC); \
21                 ev->header.vcpu                = (l4_uint32_t)t->vcpu(); \
22                 ev->header.type                = Measurements::Locking; \
23                 ev->data.lock.eventType        = event; \
24                 ev->data.lock.lockPtr          = ptr; \
25     } while (0)
26
27 Romain::PThreadLockObserver*
28 Romain::PThreadLockObserver::Create()
29 { return new PThreadLock_priv(); }
30
31 namespace Romain {
32         extern InstanceManager* _the_instance_manager;
33 }
34
35 void Romain::PThreadLock_priv::status() const
36 {
37         INFO() << "[lock] LOCK.lock   = " << det_lock_count;
38         INFO() << "[lock] LOCK.unlock = " << det_unlock_count;
39         INFO() << "[lock] MTX.lock    = " << mtx_lock_count;
40         INFO() << "[lock] MTX.unlock  = " << mtx_unlock_count;
41         INFO() << "[lock] pt.lock     = " << pt_lock_count;
42         INFO() << "[lock] pt.unlock   = " << pt_unlock_count;
43         INFO() << "[lock] # ignored   = " << ignore_count;
44         INFO() << "[lock] Total count = " << total_count;
45 }
46
47
48 Romain::Observer::ObserverReturnVal
49 Romain::PThreadLock_priv::notify(Romain::App_instance* inst,
50                                  Romain::App_thread*   thread,
51                                  Romain::Thread_group* group,
52                                  Romain::App_model*    model)
53 {
54         if (!entry_reason_is_int3(thread->vcpu(), inst, model)) {
55                 return Romain::Observer::Ignored;
56         }
57
58         DEBUG() << "LOCK observer";
59         l4util_inc32(&total_count);
60
61         /*
62          * HACK: intercept notifications coming from the replication-
63          *       aware pthread library.
64          */
65         if (thread->vcpu()->r()->ip == 0xA021) {
66                 l4util_inc32(&det_lock_count);
67                 det_lock(inst, thread, group, model);
68                 //thread->vcpu()->r()->flags |= TrapFlag;
69                 return Romain::Observer::Replicatable;
70         } else if (thread->vcpu()->r()->ip == 0xA041) {
71                 l4util_inc32(&det_unlock_count);
72                 det_unlock(inst, thread, group, model);
73                 return Romain::Observer::Replicatable;
74         }
75
76 #define HANDLE_BP(var, handler) do { \
77                 if(_functions[(var)].orig_address == thread->vcpu()->r()->ip - 1) { \
78                         (handler)(inst, thread, group, model); \
79                         return Romain::Observer::Replicatable; \
80                 } \
81         } while (0)
82
83         HANDLE_BP(mutex_lock_id, mutex_lock);
84         HANDLE_BP(mutex_unlock_id, mutex_unlock);
85         //HANDLE_BP(mutex_init_id, mutex_init);
86         HANDLE_BP(pt_lock_id, lock);
87         HANDLE_BP(pt_unlock_id, unlock);
88
89 #undef HANDLE_BP
90
91         l4util_inc32(&ignore_count);
92         return Romain::Observer::Ignored;
93 }
94
95
96 void Romain::PThreadLock_priv::attach_lock_info_page(Romain::App_model *am)
97 {
98         _lip_ds           = am->alloc_ds(L4_PAGESIZE);
99         _lip_local        = am->local_attach_ds(_lip_ds, L4_PAGESIZE, 0);
100         INFO() << "Local LIP address: " << std::hex << _lip_local;
101         void* remote__lip = (void*)am->prog_attach_ds(Romain::LOCK_INFO_PAGE,
102                                                       L4_PAGESIZE, _lip_ds, 0, 0,
103                                                       "lock info page",
104                                                       _lip_local, true);
105         _check(reinterpret_cast<l4_umword_t>(remote__lip) != Romain::LOCK_INFO_PAGE,
106                "LIP did not attach to proper remote location");
107
108         am->lockinfo_local(_lip_local);
109         am->lockinfo_remote(Romain::LOCK_INFO_PAGE);
110
111         memset((void*)_lip_local, 0, L4_PAGESIZE);
112 }
113
114
115 void Romain::PThreadLock_priv::startup_notify(Romain::App_instance *inst,
116                                               Romain::App_thread *,
117                                               Romain::Thread_group *,
118                                               Romain::App_model *am)
119 {
120         static unsigned callCount  = 0;
121         lock_info *lip             = reinterpret_cast<lock_info*>(_lip_local);
122
123 #if INTERNAL_DETERMINISM
124         if (!callCount) {
125                 /*
126                  * For internal determinism, we make sure that we only attach the
127                  * lock info page once (for the first replica), because the LIP
128                  * is shared across all replicas.
129                  */
130                 attach_lock_info_page(am);
131                 lip                    = reinterpret_cast<lock_info*>(_lip_local);
132                 lip->locks[0].lockdesc = 0xFAFAFAFA;
133                 lip->locks[0].owner    = 0xDEADBEEF;
134
135 #endif
136                 //DEBUG() << "Replica LIP address: " << std::hex << remote_lock_info;
137
138                 /*
139                  * Breakpoints / patching of function entries is only done once,
140                  * because code is shared across all replicas.
141                  */
142                 for (unsigned idx = 0; idx < pt_max_wrappers; ++idx) {
143                         //DEBUG() << idx;
144                         _functions[idx].activate(inst, am);
145                 }
146 #if INTERNAL_DETERMINISM
147         }
148         callCount++;
149         lip->replica_count += 1;
150 #endif
151         //enter_kdebug();
152 }
153
154
155 /*
156  * pthread_mutex_init()
157  *   - mutex address    @ ESP + 4
158  *   - mutex attrib ptr @ ESP + 8
159  *   - returns int in EAX
160  */
161 void Romain::PThreadLock_priv::mutex_init(Romain::App_instance *inst,
162                                           Romain::App_thread *t,
163                                           Romain::Thread_group *tg,
164                                           Romain::App_model *am)
165 {
166         l4_addr_t stack  = am->rm()->remote_to_local(t->vcpu()->r()->sp, inst->id());
167         l4_umword_t ret  = *(l4_umword_t*)stack;
168         l4_umword_t lock = *(l4_umword_t*)(stack + 1*sizeof(l4_umword_t));
169         l4_umword_t attr = *(l4_umword_t*)(stack + 2*sizeof(l4_umword_t));
170
171         DEBUG() << "INIT: lock @ " << std::hex << lock << ", attr " << attr;
172         if (attr != 0) {
173                 enter_kdebug("init with attributes");
174         }
175
176         _locks[lock] = new PThreadMutex(false /*XXX*/);
177
178         t->vcpu()->r()->ax  = 0;
179         t->return_to(ret);
180 }
181
182
183 /*
184  * __pthread_lock():
185  *              - called with lock pointer in EAX
186  *              - returns void
187  */
188 void Romain::PThreadLock_priv::lock(Romain::App_instance *inst,
189                                     Romain::App_thread *t,
190                                     Romain::Thread_group *tg,
191                                     Romain::App_model *am)
192 {
193         l4util_inc32(&pt_lock_count);
194         l4_addr_t stack  = am->rm()->remote_to_local(t->vcpu()->r()->sp, inst->id());
195         l4_umword_t ret  = *(l4_umword_t*)stack;
196         l4_umword_t lock = t->vcpu()->r()->ax;
197
198         EVENT(Measurements::LockEvent::lock, lock);
199
200         DEBUG() << "Stack ptr " << std::hex << t->vcpu()->r()->sp << " => "
201                 << stack;
202         DEBUG() << "Lock @ " << std::hex << lock;
203         DEBUG() << "Return addr " << std::hex << ret;
204
205         lookup_or_create(lock)->lock(tg);
206
207         t->return_to(ret);
208 }
209
210
211 /*
212  * __pthread_unlock():
213  *              - called with lock pointer as single stack argument
214  *              - returns int
215  */
216 void Romain::PThreadLock_priv::unlock(Romain::App_instance *inst,
217                                       Romain::App_thread *t,
218                                       Romain::Thread_group *tg,
219                                       Romain::App_model *am)
220 {
221         l4util_inc32(&pt_unlock_count);
222         l4_addr_t stack     = am->rm()->remote_to_local(t->vcpu()->r()->sp, inst->id());
223         l4_umword_t retaddr = *(l4_umword_t*)stack;
224         l4_umword_t lock    = *(l4_umword_t*)(stack + 1*sizeof(l4_umword_t));
225
226         EVENT(Measurements::LockEvent::unlock, lock);
227
228         DEBUG() << "Return addr " << std::hex << retaddr;
229         DEBUG() << "Lock @ " << std::hex << lock;
230
231         //enter_kdebug("unlock");
232
233         int ret = lookup_or_fail(lock)->unlock();
234
235         t->vcpu()->r()->ax  = ret;
236         t->return_to(retaddr);
237 }
238
239 /*
240  * pthread_mutex_lock()
241  *              - mutex   @ ESP + 4
242  *              - returns int
243  */
244 void Romain::PThreadLock_priv::mutex_lock(Romain::App_instance* inst, Romain::App_thread* t,
245                                           Romain::Thread_group* group, Romain::App_model* model)
246 {
247         l4util_inc32(&mtx_lock_count);
248
249         l4_addr_t stack     = model->rm()->remote_to_local(t->vcpu()->r()->sp, inst->id());
250         l4_umword_t retaddr = *(l4_umword_t*)stack;
251         l4_umword_t lock    = *(l4_umword_t*)(stack + 1*sizeof(l4_umword_t));
252
253         EVENT(Measurements::LockEvent::mtx_lock, lock);
254
255         DEBUG() << "lock @ " << std::hex << lock << " ESP.local = " << stack;
256         PThreadMutex* mtx = _locks[lock];
257         if (!mtx) {
258                 /*
259                  * Can't use the shortcut here. We found a yet unknown lock. Now we need to 
260                  * figure out whether it should be recursive. The respective member in the
261                  * pthread data structure is at offset 12 (dec) from the mutex pointer
262                  * we received as the argument.
263                  */
264                 l4_umword_t mtx_kind_ptr = model->rm()->remote_to_local(lock + 12, inst->id());
265 #if 0
266                 DEBUG() << "log kind: " << *(l4_umword_t*)mtx_kind_ptr
267                         << " RECURSIVE: " << PTHREAD_MUTEX_RECURSIVE_NP;
268 #endif
269
270                 mtx              = new PThreadMutex(*(l4_umword_t*)mtx_kind_ptr == PTHREAD_MUTEX_RECURSIVE_NP);
271                 _locks[lock]     = mtx;
272         }
273
274         int ret = mtx->lock(group);
275
276         t->vcpu()->r()->ax  = ret;
277         t->return_to(retaddr);
278 }
279
280
281 void Romain::PThreadLock_priv::mutex_unlock(Romain::App_instance* inst, Romain::App_thread* t,
282                                             Romain::Thread_group* group, Romain::App_model* model)
283 {
284         l4util_inc32(&mtx_unlock_count);
285
286         l4_addr_t stack     = model->rm()->remote_to_local(t->vcpu()->r()->sp, inst->id());
287         l4_umword_t retaddr = *(l4_umword_t*)stack;
288         l4_umword_t lock    = *(l4_umword_t*)(stack + 1*sizeof(l4_umword_t));
289
290         EVENT(Measurements::LockEvent::mtx_unlock, lock);
291
292         int ret = lookup_or_fail(lock)->unlock();
293         DEBUG() << "unlock @ " << std::hex << lock << " = " << ret;
294
295         t->vcpu()->r()->ax  = ret;
296         t->return_to(retaddr);
297 }