]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/plr/server/src/redundancy.h
Some minor fixes.
[l4.git] / l4 / pkg / plr / server / src / redundancy.h
1 #pragma once
2
3 /*
4  * redundancy.h --
5  *
6  *  Interface for handling redundancy comparisons
7  *
8  * (c) 2011-2013 Björn Döbel <doebel@os.inf.tu-dresden.de>,
9  *     economic rights: Technische Universität Dresden (Germany)
10  * This file is part of TUD:OS and distributed under the terms of the
11  * GNU General Public License 2.
12  * Please see the COPYING-GPL-2 file for details.
13  */
14
15 #include "app"
16 #include "thread_group.h"
17 #include <pthread-l4.h>
18 #include <atomic>
19
20 namespace Romain {
21
22         class App_model;
23         class App_thread;
24         class App_instance;
25
26         class Replicator {
27
28                 /*
29                  * Register and UTCB state used for replicatable syscalls
30                  */
31                 l4_vcpu_regs_t  _regs;
32                 char            _utcb[L4_UTCB_OFFSET]; // max UTCB size
33
34                 public:
35                         Replicator()
36                         {
37                                 memset(&_regs, 0, sizeof(l4_vcpu_regs_t));
38                                 memset(_utcb,  0, L4_UTCB_OFFSET);
39                         }
40
41                         void put(Romain::App_thread* t);
42                         void get(Romain::App_thread* t);
43         };
44
45         /*
46          * Generic interface for a redundancy checker
47          *
48          * An object matching this interface is used by the vCPU fault handler (see
49          * server/src/handler.cc:VCPU_handler) to track redundant handler
50          * execution.
51          */
52         class RedundancyCallback
53         {
54                 Replicator      _replicator;
55
56                 public:
57
58                         Replicator& replicator() { return _replicator; }
59
60                         /*
61                          * Return value from enter() call.
62                          */
63                         enum EnterReturnVal {
64                                 Invalid,
65                                 /*
66                                  * You are the first to exec this fault handler
67                                  * -> for replicatable system calls this triggers the initial
68                                  *    execution whose result is then copied to all other
69                                  *    replicas.
70                                  */
71                                 First_syscall,
72                                 /*
73                                  * This tells us that we are not the initial executor of the
74                                  * syscall, but it is to be repeated by every replica itself.
75                                  */
76                                 Repeat_syscall,
77                                 /*
78                                  * Skip the handler completely.
79                                  */
80                                 Skip_syscall,
81                                 /*
82                                  * Got watchdog interrupt and everything went fine.
83                                  */
84                                 Watchdog,
85                                 /*
86                                  * We are in watchdog single-stepping or breakpointing but 
87                                  * we were passed by a syscall or exception.
88                                  */
89                                 Watchdog_passed
90                         };
91
92                         virtual void recover(Romain::App_model *am) = 0;
93 #if WATCHDOG
94                         Romain::Watchdog* _watchdog;
95                         void set_watchdog(Romain::Watchdog *w) { _watchdog = w; }
96 #endif
97
98                         /*
99                          * Enter redundant handler.
100                          *
101                          * Determines if the handler needs to be executed.
102                          */
103                         virtual EnterReturnVal enter(Romain::App_instance *i, Romain::App_thread *t,
104                                                      Romain::Thread_group* tg, Romain::App_model *a) = 0;
105
106                         /*
107                          * Function for the master replica to notify subsequent ones to
108                          * not execute a handler, but use the master's return state (UTCB, vCPU)
109                          * instead.
110                          */
111                         virtual void leader_replicate(Romain::App_instance *i, Romain::App_thread *t,
112                                                       Romain::App_model *a) = 0;
113
114                         /*
115                          * Master telling the replicas to run the fault handler
116                          * themselves.
117                          */
118                         virtual void leader_repeat(Romain::App_instance *i, Romain::App_thread *t,
119                                                    Romain::App_model *a) = 0;
120
121                         /*
122                          * Function called by each replica before resuming execution
123                          * or handling of the next pending fault.
124                          */
125                         virtual void resume(Romain::App_instance *i, Romain::App_thread *t,
126                                             Romain::Thread_group* tg, Romain::App_model *a) = 0;
127
128                         /*
129                          * Block this replica until explicitly woken up.
130                          */
131                         virtual void wait(Romain::App_instance *i, Romain::App_thread *t,
132                                           Romain::App_model *a) = 0;
133
134                         /*
135                          * Wait until all other replicas got into wait state.
136                          */
137                         virtual void silence(Romain::App_instance *i, Romain::App_thread *t,
138                                              Romain::App_model *a) = 0;
139
140                         /*
141                          * Wake up all other replicas.
142                          */
143                         virtual void wakeup(Romain::App_instance *i, Romain::App_thread *t,
144                                             Romain::App_model *a) = 0;
145
146         };
147
148
149         class NoRed : public Romain::RedundancyCallback
150         {
151                 public:
152                         virtual EnterReturnVal enter(Romain::App_instance *, Romain::App_thread *,
153                                                      Romain::Thread_group* tg, Romain::App_model *)
154                         { return Romain::RedundancyCallback::First_syscall; }
155                         virtual void leader_replicate(Romain::App_instance *, Romain::App_thread *,
156                                                       Romain::App_model *) {}
157                         virtual void leader_repeat(Romain::App_instance *, Romain::App_thread *,
158                                                    Romain::App_model *) {}
159                         virtual void resume(Romain::App_instance *, Romain::App_thread *,
160                                             Romain::Thread_group* tg, Romain::App_model *) {}
161                         virtual void wait(Romain::App_instance *i, Romain::App_thread *t,
162                                           Romain::App_model *a)
163                         { enter_kdebug("single instances should never wait."); }
164                         virtual void silence(Romain::App_instance *i, Romain::App_thread *t,
165                                              Romain::App_model *a) {}
166                         virtual void wakeup(Romain::App_instance *i, Romain::App_thread *t,
167                                             Romain::App_model *a)  {}
168         };
169
170
171         /*
172          * N-way modular redundancy.
173          *
174          * For details on the internal protocol used, see redundancy/dmr.cc
175          */
176         class DMR : public Romain::RedundancyCallback
177         {
178                 /* Replica sync points */
179
180                 /* Sync 1: everyone waits upon entering the fault handler */
181                 pthread_cond_t  _enter;
182                 pthread_mutex_t _enter_mtx;
183                 std::atomic_uint _enter_count;
184
185                 /* Sync 2: everyone waits before leaving the fault handler */
186                 pthread_cond_t  _leave;
187                 pthread_mutex_t _leave_mtx;
188                 std::atomic_uint _leave_count;
189
190                 /* Sync 3: additional sync point used by the fault injection framework
191                  * XXX: should this be here? */
192                 pthread_cond_t  _block;
193                 pthread_mutex_t _block_mtx;
194                 l4_umword_t        _block_count;
195                 unsigned long long ts_lead;
196
197                 EnterReturnVal  _rv;
198
199                 /*
200                  * Effective number of running instances
201                  *
202                  * -> this number may change at runtime (if we switch off some replicas
203                  *    for a while). In this case, _num_instances_bak contains the original
204                  *    number of instances.
205                  */
206                 l4_umword_t        _num_instances;
207                 l4_umword_t        _num_instances_bak;
208
209                 /*
210                  * List of replicas waiting to execute their fault handler
211                  */
212                 Romain::App_thread* _orig_vcpu[Romain::MAX_REPLICAS];
213
214                 /*
215                  * Checksum all replicas, return if they match.
216                  */
217                 bool checksum_replicas(Romain::App_instance *i, Romain::Thread_group* tg, Romain::App_thread *t);
218
219 #if WATCHDOG
220                 pthread_cond_t  _watchdog_cond;
221                 pthread_mutex_t _watchdog_mtx;
222                 unsigned        _watchdog_count;
223
224                 /*
225                  * Watchdog: determine whether a replica got the watchdog interrupt
226                  *           or another trap
227                  */
228                 bool    _got_watchdog, _help_got_watchdog;
229                 bool    _got_other_trap, _help_got_other_trap;
230                 bool    _other_trap_chance;
231 #endif
232
233                 /*
234                  * Recover after checksum mismatch.
235                  */
236                 void recover(Romain::App_model*);
237
238                 public:
239                         DMR(l4_umword_t instances);
240
241                         virtual EnterReturnVal enter(Romain::App_instance *i, Romain::App_thread *t,
242                                                      Romain::Thread_group* tg, Romain::App_model *a);
243                         virtual void leader_replicate(Romain::App_instance *i, Romain::App_thread *t,
244                                                       Romain::App_model *a);
245                         virtual void leader_repeat(Romain::App_instance *i, Romain::App_thread *t,
246                                                    Romain::App_model *a);
247                         virtual void resume(Romain::App_instance *i, Romain::App_thread *t,
248                                             Romain::Thread_group* tg, Romain::App_model *a);
249                         virtual void wait(Romain::App_instance *i, Romain::App_thread *t,
250                                           Romain::App_model *a);
251                         virtual void silence(Romain::App_instance *i, Romain::App_thread *t,
252                                              Romain::App_model *a);
253                         virtual void wakeup(Romain::App_instance *i, Romain::App_thread *t,
254                                             Romain::App_model *a);
255 #if WATCHDOG
256                         virtual void watchdog_prepare(Romain::App_model *a);
257 #endif
258         };
259 }