diff --git a/20220620/bs-20220620.txt b/20220620/bs-20220620.txt
new file mode 100644
index 0000000000000000000000000000000000000000..9d8e8d26c291dab75e8e05e3a01e9351e59d3de0
--- /dev/null
+++ b/20220620/bs-20220620.txt
@@ -0,0 +1,60 @@
+Macro zum Setzen eines Wertes (RP6-Bibliothek):
+
+  #define setStopwatch1(__VALUE__) stopwatches.watch1 = __VALUE__
+
+Benutzung:
+
+  setStopwatch1 (0);
+
+Falsche Benutzung:
+
+  setStopwatch1 (0) + 42;  /* kein sinnvoller Funktionsaufruf */
+
+expandiert zu
+
+  stopwatches.watch1 = 0 + 42;
+
+--> Falsche Benutzung ist möglich.
+
+
+Macro im Linux-Kernel:
+
+  
+  #define spin_lock_mutex(lock, flags) \
+    do \
+     { \
+         spin_lock (lock); \
+         (void) (flags); \
+     } \
+    while (0)
+
+"do xxx while (0)" bedeutet: "mache xxx genau einaml".
+
+Benutzung:
+
+  spin_lock_mutex (my_lock, my_flags);
+
+expandiert zu
+
+  do
+   {
+       spin_lock (my_lock);
+       (void) (my_flags);
+   }
+  while (0);
+
+Falsche Benutzung:
+
+  spin_lock_mutex (my_lock, my_flags) + 42;
+
+  do
+   {
+       spin_lock (my_lock);
+       (void) (my_flags);
+   }
+  while (0) + 42;
+
+--> Falsche Benutzung ist nicht möglich.
+
+Fazit: "do xxx while (0)" ermöglicht die Verwendung des Macros
+wie eine Funktion, ohne dadurch eine falsche Benutzung zu ermöglichen.
diff --git a/20220620/sched.c b/20220620/sched.c
new file mode 100644
index 0000000000000000000000000000000000000000..3cec73a4d18b4efd840affb3dae794617a71498f
--- /dev/null
+++ b/20220620/sched.c
@@ -0,0 +1,171 @@
+struct task_struct *task[NR_TASKS];
+
+/*
+ *  'schedule()' is the scheduler function. This is GOOD CODE! There
+ * probably won't be any reason to change this, as it should work well
+ * in all circumstances (ie gives IO-bound processes good response etc).
+ * The one thing you might take a look at is the signal-handler code here.
+ *
+ *   NOTE!!  Task 0 is the 'idle' task, which gets called when no other
+ * tasks can run. It can not be killed, and it cannot sleep. The 'state'
+ * information in task[0] is never used.
+ */
+void schedule(void)
+{
+	int i,next,c;
+	struct task_struct ** p;
+
+/* check alarm, wake up any interruptible tasks that have got a signal */
+
+	for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
+		if (*p) {
+			if ((*p)->alarm && (*p)->alarm < jiffies) {
+					(*p)->signal |= (1<<(SIGALRM-1));
+					(*p)->alarm = 0;
+				}
+			if ((*p)->signal && (*p)->state==TASK_INTERRUPTIBLE)
+				(*p)->state=TASK_RUNNING;
+		}
+
+/* this is the scheduler proper: */
+
+	while (1) {
+		c = -1;
+		next = 0;
+		i = NR_TASKS;
+		p = &task[NR_TASKS];  /* außerhalb des Arrays! */
+		while (--i) {
+			if (!*--p)  /* jetzt innerhalb des Arrays */
+				continue;
+			if ((*p)->state == TASK_RUNNING && (*p)->counter > c)
+				c = (*p)->counter, next = i;
+		}
+		if (c) break;
+		for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
+			if (*p)
+				(*p)->counter = ((*p)->counter >> 1) +
+						(*p)->priority;
+	}
+	switch_to(next);
+}
+
+--------------------------------------------------------------------------------
+
+		while (--i) {
+			if (!*--p)  /* jetzt innerhalb des Arrays */
+				; /* do nothing */
+			else if ((*p)->state == TASK_RUNNING && (*p)->counter > c)
+				c = (*p)->counter, next = i;
+		}
+
+--------------------------------------------------------------------------------
+
+
+		while (--i) {
+			if (*--p)  /* jetzt innerhalb des Arrays */
+                                if ((*p)->state == TASK_RUNNING && (*p)->counter > c)
+                                        c = (*p)->counter, next = i;
+		}
+
+--------------------------------------------------------------------------------
+
+struct task_struct *task[NR_TASKS];
+
+/* ... */
+
+	struct task_struct ** p;
+
+/* ... */
+
+                /* Das zweite if wird ausgeführt, wenn *p != NULL ist,
+                 * wenn also der Zeiger-Zeiger p auf einen Zeiger != NULL zeigt.
+                 */
+
+		c = -1;
+		next = 0;
+		i = NR_TASKS;
+		p = &task[NR_TASKS];  /* außerhalb des Arrays! */
+		while (--i) {
+			if (!*--p)  /* jetzt innerhalb des Arrays */
+				continue;
+			if ((*p)->state == TASK_RUNNING && (*p)->counter > c)
+				c = (*p)->counter, next = i;
+		}
+
+                /* Diese Schleife ermittelt den größten Wert von (*p)->counter
+                 * innerhalb des Arrays, setzt c auf diesen Counter und
+                 * setzt next auf den Index, wo der Counter gefunden wurde.
+                 *
+	         * Das anschließende switch_to(next); gibt also demnigen Programm
+                 * Rechenzeit, dessen (*p)->counter am größten ist.
+                 */
+
+--------------------------------------------------------------------------------
+                 
+                   Wie funktioniert diese Zeile?
+
+                     c = (*p)->counter, next = i;
+
+                   Üblicher wäre:
+
+			if ((*p)->state == TASK_RUNNING && (*p)->counter > c) {
+				c = (*p)->counter;
+                                next = i;
+                        }
+
+                   Die Zeile enhält einen Komma-Operator:
+
+                     c = (*p)->counter, next = i;
+
+                   "Berechne den Ausdruck 'c = (*p)->counter', vergiß ihn wieder,
+                   und berechne stattdessen den Ausdruck 'next = i'."
+                   Das Ergebnis des Ausdrucks wird dann wieder verworfen.
+                   Beide Teilausdrücke haben jedoch Seiteneffekte, nämlich die
+                   Zuweisungen.
+
+                   --> "c = (*p)->counter, next = i;" führt in einem Befehl zwei
+                       Zuweisungen aus. Dies funktioniert nur, weil beide Ausdrücke
+                       denselben Typ (int) haben.
+                       Wir sparen uns auf diese Weise ein Semikolon und ein Paar
+                       geschweifter Klammern. (Jedoch keine Rechenzeit. Der erzeugte
+                       Code ist identisch.)
+
+--------------------------------------------------------------------------------
+
+		if (c) break;  /* c kann nur 0 sein, wenn alle counter 0 sind. */
+
+                /* Wenn alle counter 0 sind, verteile die Rechenzeit neu. */
+
+		for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
+			if (*p)
+				(*p)->counter = ((*p)->counter >> 1) +
+						(*p)->priority;
+
+              Wenn kein Programm mehr einen (*p)->counter > 0 hat,
+              bekommen alle Programme neue Rechenzeit zugewiesen,
+              nämlich ihre (*p)->priority plus den verbleibenden counter >> 1.
+
+              counter >> 1  ist dasselbe wie  counter / 2.
+
+              Wieso berücksichtigen wir den counter, wenn der doch = 0 ist?
+
+              Wegen der zusätzlichen Bedingung mit TASK_RUNNING
+
+			if ((*p)->state == TASK_RUNNING && (*p)->counter > c)
+				c = (*p)->counter, next = i;
+
+              werden bei der Ermittlung von c nur solche Programme berücksichtigt,
+              deren status == TASK_RUNNING ist, also nur Programme, die tatsächlich
+              Rechenzeit haben wollen. Programme, die auf etwas warten, können einen
+              counter > 0 haben, ohne daß dadurch c > 0 würde.
+              (Beispiel: Programm, das auf einen Tastendruck wartet)
+
+              Ergebnis: Bei der Zuteilung neuer Rechenzeit kann man Rechenzeit
+              "ansparen", aber nicht unbegrenzt (weil wir durch 2 dividieren).
+              Rechenzeit verfällt daher exponentiell, wächst gleichzeitig linear,
+              bleibt daher endlich.
+
+              Gesamtergebnis: Interaktive Programme können, während sie auf einen
+              Tastendruck warten, Rechenzeit "ansparen", die sie dann zur Verfügung
+              haben, sobald der Tastendruck kommt.
+