Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
B
bs
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Peter Gerwinski
bs
Commits
9cd23492
Commit
9cd23492
authored
2 years ago
by
Peter Gerwinski
Browse files
Options
Downloads
Patches
Plain Diff
Notizen und Beispiel 20.6.2022
parent
68bc4bfd
No related branches found
No related tags found
No related merge requests found
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
20220620/bs-20220620.txt
+60
-0
60 additions, 0 deletions
20220620/bs-20220620.txt
20220620/sched.c
+171
-0
171 additions, 0 deletions
20220620/sched.c
with
231 additions
and
0 deletions
20220620/bs-20220620.txt
0 → 100644
+
60
−
0
View file @
9cd23492
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.
This diff is collapsed.
Click to expand it.
20220620/sched.c
0 → 100644
+
171
−
0
View file @
9cd23492
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
.
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment