6 * Interface for handling redundancy comparisons
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.
16 #include "thread_group.h"
17 #include <pthread-l4.h>
29 * Register and UTCB state used for replicatable syscalls
32 char _utcb[L4_UTCB_OFFSET]; // max UTCB size
37 memset(&_regs, 0, sizeof(l4_vcpu_regs_t));
38 memset(_utcb, 0, L4_UTCB_OFFSET);
41 void put(Romain::App_thread* t);
42 void get(Romain::App_thread* t);
46 * Generic interface for a redundancy checker
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
52 class RedundancyCallback
54 Replicator _replicator;
58 Replicator& replicator() { return _replicator; }
61 * Return value from enter() call.
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
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.
78 * Skip the handler completely.
82 * Got watchdog interrupt and everything went fine.
86 * We are in watchdog single-stepping or breakpointing but
87 * we were passed by a syscall or exception.
92 virtual void recover(Romain::App_model *am) = 0;
94 Romain::Watchdog* _watchdog;
95 void set_watchdog(Romain::Watchdog *w) { _watchdog = w; }
99 * Enter redundant handler.
101 * Determines if the handler needs to be executed.
103 virtual EnterReturnVal enter(Romain::App_instance *i, Romain::App_thread *t,
104 Romain::Thread_group* tg, Romain::App_model *a) = 0;
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)
111 virtual void leader_replicate(Romain::App_instance *i, Romain::App_thread *t,
112 Romain::App_model *a) = 0;
115 * Master telling the replicas to run the fault handler
118 virtual void leader_repeat(Romain::App_instance *i, Romain::App_thread *t,
119 Romain::App_model *a) = 0;
122 * Function called by each replica before resuming execution
123 * or handling of the next pending fault.
125 virtual void resume(Romain::App_instance *i, Romain::App_thread *t,
126 Romain::Thread_group* tg, Romain::App_model *a) = 0;
129 * Block this replica until explicitly woken up.
131 virtual void wait(Romain::App_instance *i, Romain::App_thread *t,
132 Romain::App_model *a) = 0;
135 * Wait until all other replicas got into wait state.
137 virtual void silence(Romain::App_instance *i, Romain::App_thread *t,
138 Romain::App_model *a) = 0;
141 * Wake up all other replicas.
143 virtual void wakeup(Romain::App_instance *i, Romain::App_thread *t,
144 Romain::App_model *a) = 0;
149 class NoRed : public Romain::RedundancyCallback
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) {}
172 * N-way modular redundancy.
174 * For details on the internal protocol used, see redundancy/dmr.cc
176 class DMR : public Romain::RedundancyCallback
178 /* Replica sync points */
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;
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;
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;
200 * Effective number of running instances
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.
206 l4_umword_t _num_instances;
207 l4_umword_t _num_instances_bak;
210 * List of replicas waiting to execute their fault handler
212 Romain::App_thread* _orig_vcpu[Romain::MAX_REPLICAS];
215 * Checksum all replicas, return if they match.
217 bool checksum_replicas(Romain::App_instance *i, Romain::Thread_group* tg, Romain::App_thread *t);
220 pthread_cond_t _watchdog_cond;
221 pthread_mutex_t _watchdog_mtx;
222 unsigned _watchdog_count;
225 * Watchdog: determine whether a replica got the watchdog interrupt
228 bool _got_watchdog, _help_got_watchdog;
229 bool _got_other_trap, _help_got_other_trap;
230 bool _other_trap_chance;
234 * Recover after checksum mismatch.
236 void recover(Romain::App_model*);
239 DMR(l4_umword_t instances);
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);
256 virtual void watchdog_prepare(Romain::App_model *a);