]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/plr/server/src/redundancy.h
update
[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
19 namespace Romain {
20
21         class App_model;
22         class App_thread;
23         class App_instance;
24
25         class Replicator {
26
27                 /*
28                  * Register and UTCB state used for replicatable syscalls
29                  */
30                 l4_vcpu_regs_t  _regs;
31                 char            _utcb[L4_UTCB_OFFSET]; // max UTCB size
32
33                 public:
34                         Replicator()
35                         {
36                                 memset(&_regs, 0, sizeof(l4_vcpu_regs_t));
37                                 memset(_utcb,  0, L4_UTCB_OFFSET);
38                         }
39
40                         void put(Romain::App_thread* t);
41                         void get(Romain::App_thread* t);
42         };
43
44         /*
45          * Generic interface for a redundancy checker
46          *
47          * An object matching this interface is used by the vCPU fault handler (see
48          * server/src/handler.cc:VCPU_handler) to track redundant handler
49          * execution.
50          */
51         class RedundancyCallback
52         {
53                 Replicator      _replicator;
54
55                 public:
56
57                         Replicator& replicator() { return _replicator; }
58
59                         /*
60                          * Return value from enter() call.
61                          */
62                         enum EnterReturnVal {
63                                 Invalid,
64                                 /*
65                                  * You are the first to exec this fault handler
66                                  * -> for replicatable system calls this triggers the initial
67                                  *    execution whose result is then copied to all other
68                                  *    replicas.
69                                  */
70                                 First_syscall,
71                                 /*
72                                  * This tells us that we are not the initial executor of the
73                                  * syscall, but it is to be repeated by every replica itself.
74                                  */
75                                 Repeat_syscall,
76                                 /*
77                                  * Skip the handler completely.
78                                  */
79                                 Skip_syscall,
80                         };
81
82                         /*
83                          * Enter redundant handler.
84                          *
85                          * Determines if the handler needs to be executed.
86                          */
87                         virtual EnterReturnVal enter(Romain::App_instance *i, Romain::App_thread *t,
88                                                      Romain::App_model *a) = 0;
89
90                         /*
91                          * Function for the master replica to notify subsequent ones to
92                          * not execute a handler, but use the master's return state (UTCB, vCPU)
93                          * instead.
94                          */
95                         virtual void leader_replicate(Romain::App_instance *i, Romain::App_thread *t,
96                                                       Romain::App_model *a) = 0;
97
98                         /*
99                          * Master telling the replicas to run the fault handler
100                          * themselves.
101                          */
102                         virtual void leader_repeat(Romain::App_instance *i, Romain::App_thread *t,
103                                                    Romain::App_model *a) = 0;
104
105                         /*
106                          * Function called by each replica before resuming execution
107                          * or handling of the next pending fault.
108                          */
109                         virtual void resume(Romain::App_instance *i, Romain::App_thread *t,
110                                             Romain::App_model *a) = 0;
111
112                         /*
113                          * Block this replica until explicitly woken up.
114                          */
115                         virtual void wait(Romain::App_instance *i, Romain::App_thread *t,
116                                           Romain::App_model *a) = 0;
117
118                         /*
119                          * Wait until all other replicas got into wait state.
120                          */
121                         virtual void silence(Romain::App_instance *i, Romain::App_thread *t,
122                                              Romain::App_model *a) = 0;
123
124                         /*
125                          * Wake up all other replicas.
126                          */
127                         virtual void wakeup(Romain::App_instance *i, Romain::App_thread *t,
128                                             Romain::App_model *a) = 0;
129         };
130
131
132         class NoRed : public Romain::RedundancyCallback
133         {
134                 public:
135                         virtual EnterReturnVal enter(Romain::App_instance *, Romain::App_thread *,
136                                                      Romain::App_model *)
137                         { return Romain::RedundancyCallback::First_syscall; }
138                         virtual void leader_replicate(Romain::App_instance *, Romain::App_thread *,
139                                                       Romain::App_model *) {}
140                         virtual void leader_repeat(Romain::App_instance *, Romain::App_thread *,
141                                                    Romain::App_model *) {}
142                         virtual void resume(Romain::App_instance *, Romain::App_thread *,
143                                             Romain::App_model *) {}
144                         virtual void wait(Romain::App_instance *i, Romain::App_thread *t,
145                                           Romain::App_model *a)
146                         { enter_kdebug("single instances should never wait."); }
147                         virtual void silence(Romain::App_instance *i, Romain::App_thread *t,
148                                              Romain::App_model *a) {}
149                         virtual void wakeup(Romain::App_instance *i, Romain::App_thread *t,
150                                             Romain::App_model *a)  {}
151         };
152
153
154         /*
155          * N-way modular redundancy.
156          *
157          * For details on the internal protocol used, see redundancy/dmr.cc
158          */
159         class DMR : public Romain::RedundancyCallback
160         {
161                 /* Replica sync points */
162
163                 /* Sync 1: everyone waits upon entering the fault handler */
164                 pthread_cond_t  _enter;
165                 pthread_mutex_t _enter_mtx;
166                 unsigned        _enter_count;
167
168                 /* Sync 2: everyone waits before leaving the fault handler */
169                 pthread_cond_t  _leave;
170                 pthread_mutex_t _leave_mtx;
171                 unsigned        _leave_count;
172
173                 /* Sync 3: additional sync point used by the fault injection framework
174                  * XXX: should this be here? */
175                 pthread_cond_t  _block;
176                 pthread_mutex_t _block_mtx;
177                 unsigned        _block_count;
178
179                 EnterReturnVal  _rv;
180
181                 /*
182                  * Effective number of running instances
183                  *
184                  * -> this number may change at runtime (if we switch off some replicas
185                  *    for a while). In this case, _num_instances_bak contains the original
186                  *    number of instances.
187                  */
188                 unsigned        _num_instances;
189                 unsigned        _num_instances_bak;
190
191                 /*
192                  * List of replicas waiting to execute their fault handler
193                  */
194                 Romain::App_thread* _orig_vcpu[Romain::MAX_REPLICAS];
195
196                 /*
197                  * Checksum all replicas, return if they match.
198                  */
199                 bool checksum_replicas();
200
201                 /*
202                  * Recover after checksum mismatch.
203                  */
204                 void recover(Romain::App_model*);
205
206                 public:
207
208                         DMR(unsigned instances);
209
210                         virtual EnterReturnVal enter(Romain::App_instance *i, Romain::App_thread *t,
211                                                      Romain::App_model *a);
212                         virtual void leader_replicate(Romain::App_instance *i, Romain::App_thread *t,
213                                                       Romain::App_model *a);
214                         virtual void leader_repeat(Romain::App_instance *i, Romain::App_thread *t,
215                                                    Romain::App_model *a);
216                         virtual void resume(Romain::App_instance *i, Romain::App_thread *t,
217                                             Romain::App_model *a);
218                         virtual void wait(Romain::App_instance *i, Romain::App_thread *t,
219                                           Romain::App_model *a);
220                         virtual void silence(Romain::App_instance *i, Romain::App_thread *t,
221                                              Romain::App_model *a);
222                         virtual void wakeup(Romain::App_instance *i, Romain::App_thread *t,
223                                             Romain::App_model *a);
224         };
225 }