OK - enough about system call implementation - let's look at some of
XINU's process management routines. I'll list them with a short description
of each. Let me say here that now is an excellent time to start following
along with the lectures by looking at the code for the routines I'll be
talking about. Remember that this whole course is about looking at and
understanding an existing O/S implementation. You can't do that without
looking at an O/S!
suspend(pid) - this suspends the process named in the argument.
The process must either be the current process, or some ready process.
A process is suspended by taking it off the ready list (if it is on the
ready list), and by changing the status to PRSUSP. Does a context
switch need to happen? Think about it. Why would XINU want to restrict
us to only being able to suspend a ready or running process? Think about
it. Think about the implications of suspending, perhaps, a semaphore blocked
process, or maybe a process awaiting I/O or IPC? Sounds ugly to me. The
XINU implementors must have felt the same way.
resume(pid) - this re-readies a previously suspended process.
It's implementation is straight forward. First it check to see that the
process really is suspended (by looking at the pstate entry in the PCB).
If it is, it readies it, and then invokes the scheduler. Do we absolutely
have to invoke the scheduler? Take a look at the code. By adding a test
to resume(), we could avoid a subroutine call in many (probably
most) cases.
kill(pid) - this kills a process an removes it from the system.
All of the expected processing occurs here. For example, if a process is
on a particular queue, it is removed from that queue. The process' stack
is freed, and the pentry that it occupies is marked as being free (state
PRFREE). Think about (and look at the code to see) what you do with a process
that is semaphore blocked when it is killed? Think about the general case
of killing a process that is part of a cooperating group of processes.
create(address, stack-size, priority, name, nargs, args) - this
creates a new process. A process is left in the suspended state. The first
thing to do on process creation is to find a pentry. This also ensures
that we haven't reached our maximum number of processes. At the same time
in the code we allocate the stack (there seems to be a bug in the big "if"
statement at the top of create() - do you agree?) Once we have the pentry
(PCB) for the new process we:
set the state to PRSUSP
copy the processes name into the PCB
set the priority in the PCB
set the initial values for the saved registers. The PC stored in the
register save area is that of the entry point for the process.
the stack is set up with a dummy return address on it so when the entry
subroutine for the process fall off the end, it will automatically invoke
the "userret" XINU function which calls kill().
getprio(pid) - returns the priority of the named process
getpid() - returns the pid of the running process (can you give
me some examples of where this is useful?)
chprio(pid, new-priority) - gives the named process the indicated
priority.