1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
|
#include <common.h>
/**
** Initial process; it starts the other top-level user processes.
**
** Prints a message at startup, '+' after each user process is spawned,
** and '!' before transitioning to wait() mode to the SIO, and
** startup and transition messages to the console. It also reports
** each child process it collects via wait() to the console along
** with that child's exit status.
*/
/*
** "Spawn table" process entry. Similar to the one in shell.c, but
** this version has a field to hold the PID of the spawned process
** to allow 'init' to respawn it when it terminates.
*/
typedef struct proc_s {
uint_t index; // process table index
uint_t pid; // its PID (when spawned)
uint8_t e_prio; // process priority
char select[3]; // identifying character, NUL, extra
char *args[MAX_ARGS]; // argument vector strings
} proc_t;
/*
** Create a spawn table entry for a process with a string literal
** as its argument buffer. We rely on the fact that the C standard
** ensures our array of pointers will be filled out with NULLs
*/
#define PROCENT(e, p, s, ...) \
{ \
e, 0, p, s, \
{ \
__VA_ARGS__, NULL \
} \
}
// sentinel value for the end of the table - must be updated
// if you have more than 90,210 user programs in the table
#define TBLEND 90210
/*
** This table contains one entry for each process that should be
** started by 'init'. Typically, this includes the 'idle' process
** and a 'shell' process.
*/
static proc_t spawn_table[] = {
// the idle process; it runs at Deferred priority,
// so it will only be dispatched when there is
// nothing else available to be dispatched
PROCENT(Idle, PRIO_DEFERRED, "!", "idle", "."),
// the user shell
PROCENT(Shell, PRIO_STD, "@", "shell"),
// PROCENT( 0, 0, 0, 0 )
{ TBLEND }
};
// character to be printed by init when it spawns a process
static char ch = '+';
/**
** process - spawn all user processes listed in the supplied table
**
** @param proc pointer to the spawn table entry to be used
*/
static void process(proc_t *proc)
{
char buf[128];
// kick off the process
int32_t p = fork();
if (p < 0) {
// error!
sprint(buf, "INIT: fork for #%d failed\n", (uint32_t)(proc->index));
cwrites(buf);
} else if (p == 0) {
// change child's priority
(void)setprio(proc->e_prio);
// now, send it on its way
exec(proc->index, proc->args);
// uh-oh - should never get here!
sprint(buf, "INIT: exec(0x%08x) failed\n", (uint32_t)(proc->index));
cwrites(buf);
} else {
// parent just reports that another one was started
swritech(ch);
proc->pid = p;
}
}
/*
** The initial user process. Should be invoked with zero or one
** argument; if provided, the first argument should be the ASCII
** character 'init' will print to indicate the spawning of a process.
*/
USERMAIN(main)
{
char buf[128];
// check to see if we got a non-standard "spawn" character
if (argc > 1) {
// maybe - check it to be sure it's printable
uint_t i = argv[1][0];
if (i > ' ' && i < 0x7f) {
ch = argv[1][0];
}
}
cwrites("Init started\n");
// home up, clear on a TVI 925
swritech('\x1a');
// wait a bit
DELAY(SHORT);
// a bit of Dante to set the mood :-)
swrites("\n\nSpem relinquunt qui huc intrasti!\n\n\r");
/*
** Start all the user processes
*/
cwrites("INIT: starting user processes\n");
proc_t *next;
for (next = spawn_table; next->index != TBLEND; ++next) {
process(next);
}
swrites(" !!!\r\n\n");
/*
** At this point, we go into an infinite loop waiting
** for our children (direct, or inherited) to exit.
*/
cwrites("INIT: transitioning to wait() mode\n");
for (;;) {
int32_t status;
int whom = waitpid(0, &status);
// PIDs must be positive numbers!
if (whom <= 0) {
sprint(buf, "INIT: waitpid() returned %d???\n", whom);
cwrites(buf);
} else {
// got one; report it
sprint(buf, "INIT: pid %d exit(%d)\n", whom, status);
cwrites(buf);
// figure out if this is one of ours
for (next = spawn_table; next->index != TBLEND; ++next) {
if (next->pid == whom) {
// one of ours - reset the PID field
// (in case the spawn attempt fails)
next->pid = 0;
// and restart it
process(next);
break;
}
}
}
}
/*
** SHOULD NEVER REACH HERE
*/
cwrites("*** INIT IS EXITING???\n");
exit(1);
return (1); // shut the compiler up
}
|