diff --git a/ntnu/21v/ttk4145/summary/summary.md b/ntnu/21v/ttk4145/summary/summary.md index 8f5d2ea..e67e7e0 100644 --- a/ntnu/21v/ttk4145/summary/summary.md +++ b/ntnu/21v/ttk4145/summary/summary.md @@ -63,9 +63,9 @@ This is some of the error handling real time programming have. * Handling of unexpected errors * More threads hanles errors * Can not test the conventional way - * Can only show extistence of errors - * Can not find errors in specification - * Can not find race conditions + * Can only show extistence of errors + * Can not find errors in specification + * Can not find race conditions The fault path is shown under. @@ -103,8 +103,8 @@ To test how the systems responds for a unknown error is to insert a failed accep **Dynammic redunancy** * Relies on detecting the error and recovering - * Resend if timeout and not receiving "ack" - * Go with default if no messages have been received + * Resend if timeout and not receiving "ack" + * Go with default if no messages have been received * The acceptancetest must be good. @@ -128,29 +128,29 @@ Find the failure modes: What could go wrong? **Step 3: Handling with redundancy** * Have multiple copies of the the information - * Use only the newest + * Use only the newest #### Example with communication function **Step 1: Failure modes** * Message - * Lost - * Delayed - * Corrupted - * Duplicated - * Wrong recipient + * Lost + * Delayed + * Corrupted + * Duplicated + * Wrong recipient **Step 2: Detection, Merging of errormodes and error injection** * Adding information to message - * Checksum - * Session ID - * Sequence number + * Checksum + * Session ID + * Sequence number * Adding "ack" on well recieved messages * All errors will be treaded as "Lost message" * Injection - * Occasionally throw away some messages + * Occasionally throw away some messages **Step 3: Handling with redundancy** @@ -179,7 +179,7 @@ There are three solutions: * Store a checkpoint * Do the "side effects" 2. Process pairs - * Crash and let an another process take over + * Crash and let an another process take over 3. Presistent processes @@ -207,31 +207,31 @@ A transaction is a design framework for Damage Confinement and Error Recovery. **Async Notification (AN) = Low level thread interaction** * Async event handling. ("Signals") (resumption) - * Modeled after a HW interrupt - * Can be sent to the correct thread - * Can be handled, ignored, blocked --> The domain can be controlled. - * Often lead to polling - * Could rather skip the signal and poll a status variable or a message queue - * Useless + * Modeled after a HW interrupt + * Can be sent to the correct thread + * Can be handled, ignored, blocked --> The domain can be controlled. + * Often lead to polling + * Could rather skip the signal and poll a status variable or a message queue + * Useless * ATC --> Async transfer of Control (termination) - * Canceling threads - * setjmpt/longjmp could convert signals to ATC (not really, but still) - * ADA: a strictured mechanism for ATV is integraded with the selected statement - * RT Java: A structured mechanism for ATC is integraded with the exception-handling mechanism + * Canceling threads + * setjmpt/longjmp could convert signals to ATC (not really, but still) + * ADA: a strictured mechanism for ATV is integraded with the selected statement + * RT Java: A structured mechanism for ATC is integraded with the exception-handling mechanism #### Cancelling threads **Yes, killing threads is ATC!** * Can make termination model by letting domain be a thread - * "Create a `doWork` thread, and kill it if the action fails" + * "Create a `doWork` thread, and kill it if the action fails" * Ca still control domain by disabling "cancelstate" **But, but, but: It leaves ut in undifined state!?** * Not if we have... - * Full control over changed state (like logs or recovery points) or some other way of recovering well. - * A lock manager that can unlock on behalf of killed thread - * Some control of where we were killed (like nok in the middle of a lock manager or log call) + * Full control over changed state (like logs or recovery points) or some other way of recovering well. + * A lock manager that can unlock on behalf of killed thread + * Some control of where we were killed (like nok in the middle of a lock manager or log call) * An this is what we have! @@ -284,24 +284,24 @@ while(true) { {% highlight c %} /** - * scheduler_registerThread(function, time, priority) - * Higher priority numer means higher priority in scheduler - */ + * scheduler_registerThread(function, time, priority) + * Higher priority numer means higher priority in scheduler + */ main() { - scheduler_registrerThread(controlPump, 0.1, 3); - scheduler_registrerThread(calculatePumpReference, 1, 2); - scheduler_registrerThread(handleUserEvents, 0.2, 1); - scheduler_mainLoop(); + scheduler_registrerThread(controlPump, 0.1, 3); + scheduler_registrerThread(calculatePumpReference, 1, 2); + scheduler_registrerThread(handleUserEvents, 0.2, 1); + scheduler_mainLoop(); } {% endhighlight %} **Some notes on priorities** * Priority is generally not important; rather, the main rule is to give higher priority to shorter-deadline tasks. - * This allows tasks to reach its deadlines. + * This allows tasks to reach its deadlines. * ... but this is not always the case - if e.g. the tasks are cooperating * We still handle overload badly * And: What connection between deadline and priority to start with? - * Is this a good dependency seen from a code quality perspective? + * Is this a good dependency seen from a code quality perspective? ### Pros and cons of nonpreemptive scheduling @@ -318,4 +318,59 @@ main() { +### Preemptive Kernel + +* Preemption, thread objects and the timer interrupt +* Enabling synchronization: Busy waiting, tes-and-set, disabling the timer interrupt +* Blocking and suspend & resume +* An API for synchronization? Semaphores! + + +#### Preemption + +* Make a handler for a timer interrupt +* Store all registers (including IP & SP) in a "thread object" +* Organize queue of processes (Round Robin e.g. - a collection of thread objects?) +* Can synchronize by: while(!ready); (busy wating, "spin locks") + +**Bad solution** + +{% highlight c%} +while(lock==1) {} +lock = 1; + // We may run +lock = 0; +{% endhighlight %} + +**Better solution** + +{% highlight c%} +void t1() { + flag1 = 1; // Declare my intention + turn = 2; // But try to be polite + while(flag2 == 1 && turn == 2) {} + // We may run + flag1 = 0; +} +{% endhighlight %} + +##### Looking more closely at the arsenal + +**How can we make basic synchronization under preemption?** + +* Spin locks (wasting time and cpu) +* Test&Set (swap) assembly instruction (atomic, but not obvious) +* Disable interrupt (steals control from OS/scheduler) + +**But** +* If we disable the timer interrupt we don not have preemption any more +* And... Are these good abstractions in the application programmer domain? + +#### Blocked threads + +**Let us introduce another queue; the collection of threads not running, waiting for something** + +* Fixes the bad performance of spin locks. Is conceptually better. +* "Suspend" moves a thread object from "run" queue to "blocked" queue +* "Resume" moves it back.