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