mirror of
https://github.com/kenshineto/kern.git
synced 2025-04-10 12:37:26 +00:00
185 lines
4.3 KiB
C
185 lines
4.3 KiB
C
#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[N_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
|
|
}
|