This is an individual or group project, based mostly on your choice for project 2. You may collaborate with anybody else and search the web, as long as all the code you turn in is authored by you personally. You may use any libraries that are part of the standard Minix distribution.
The project is due Friday, February 16th 2004, any time. Submission is by email. Please send me the following:
Remember (book, p. 126) that the files in /usr/include/ are are automatically updated from the files in /usr/src/include/.
Please send in your project on time -- late submissions will not be accepted, and I prefer to have partially-working projects rather than no project at all.
As usual, you are welcome to study any materials on the web, inlcuding the RT-Minix project. As always, be sure that the code you turn is code that you wrote (and copying does not count as writing!)
I want you to add a new system call, setdl, to your Minix process manager (pm -- the call could go into fs, but it really belongs in pm, and in any case please implement it in pm for this project). The system call "setdl (long deadline)" takes as argument a deadline, expressed in ticks from the time of the call, and uses it and the Earliest Deadline First algorithm to decide when to schedule the process. Implementing this system call requires changing the process table entries to record the deadline for the process (if any, since most processes will not have deadlines), and changing the scheduler (function pick_prock in file kernel/proc.c, but you may also need to change sched) to give maximum priority to the user process with the earliest deadline, if any. Processes with deadlines should never have their quantum expire -- this may (or may not) require some changes in kernel/clock.c. Before a process has reached its deadline, it must call setdl again with a new value, either 0 (to cancel the real-time nature of the process), or a new value of the deadline. A process with a deadline in the past can be treated by the scheduler as a process with no deadline.
The deadline given to setdl is a releative one, and the system must (logically) decrement each real-time process's deadline every clock tick, until the deadline reaches zero, at which point the process is assumed to have completed its work (normally the process will call setdl before then to change the deadline). Note that with this scheme the system has to decrement the deadline for each realtime process on every clock tick. A more realistic implementation might add the given deadline to the realtime variable, available from get_uptime(), and store the resulting value in the process table. This means the scheduler can simply compare deadlines when inserting a process into the queues, and never has to change or decrement the value.
An example of the use of setdl is as in the following code (which I call testrt.c), which expects to execute its main loop at least once every second for one hundred seconds.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <time.h>
#include <sys/resource.h>
extern int setdl (long); /* system call */
void testrt (void)
{
time_t recent, new; /* times */
int count, inner;
setdl (120); /* let all other RT processes start up */
sleep (1); /* while we sleep */
recent = time (NULL);
count = 0;
while (count < 100) {
while ((new = time (NULL)) == recent) { /* still on the same second */
setdl (60); /* check time again within one second */
setpriority (PRIO_PROCESS, getpid (), -3); /* get higher priority */
}
if (new == (recent + 1)) { /* new second: did we skip any? */
count++; /* no -- still working in realtime */
setpriority (PRIO_PROCESS, getpid (), 0); /* get regular priority */
} else { /* missed the deadline */
setdl (0); /* no longer real time */
printf ("missed deadline after %d seconds\n", count);
return;
}
recent = new;
}
setdl (0); /* no longer real time */
printf ("successfully met %d successive deadlines\n", count);
}
int main (int argc, char ** argv)
{
testrt ();
return 0;
}
In the absence of competing processes, this process can be expected to execute fine even without a real-time scheduler, so be sure to test this by running at least five (I have run up to ten) copies of the code simultaneously. In all my tests so far, in the absence of a real-time scheduler, at least one of the processes (out of five or more) always fails, and the last process to remain running will complete all iterations.
Real-time user processes should have the highest priority of all user processes, but should not pre-empt tasks, device drivers, or servers -- if you give any user process higher priority than these system tasks, (a) you will have to do a lot more work, and (b) your system calls will stop working. It is therefore a good idea to keep executing operating system code before user code.
The files that you must turn in are only a subset of the files you will have to modify. In particular, you will have to study and perhaps modify pm/param.h to figure out how to pass parameters to a system call in the process manager.
Skip this section if you like to figure things out yourself.
Most of these are drawn from my own experience and mistakes implementing this project. If you make mistakes, don't worry -- it is very normal, since above all you are trying to understand what you are doing. If you find a mistake, just figure out what the problem is, and fix it. As you make progress, make sure you can recover as gracefully as possible.
Be prepared to re-install Minix if necessary. If you are running on a real machine, keep a copy of the files you have changed on a floppy or a USB drive or on a machine that is connected via the network, or on a different partition that Minix doesn't usually mount. If you are running on a virtual machine, you can keep a copy of a "clean" install (though re-installing doesn't take that long) as well as the above.
Also, watch for errors and warnings in the compile, they probably indicate a problem with your coding.
You must implement a library function (in library/posix and library/syscall) which sends a message to a system call, setdl, implemented in pm. The message may or may not contain the process number of the process requesting a change in deadline (you may call getpid(2) from _setdl.c if you need to get the process ID in user code), and you will have to send the number of clock ticks until the deadline expires (this is the parameter to setdl) This means you must select one of the possible minix messages. For a system call, you will also need a new system call number. Finally, be sure to appropriately modify the Makefiles.
After you have modified the library (to add the new syscall), be sure to make install from /usr/src/lib. You may want to back up your libraries first if there is any possibility you might be breaking the library. Once you install the library, you should be able to compile programs that refer to setdl, though you may also need a forward declaration of the form
extern int setdl (int deadline);to avoid compiler warnings.
As well as the library functions, you have to modify the process manager to accept the message. This is done by providing the appropriate function (which can go into an existing file or into its own file in servers/pm/), and entering the name of that function in servers/pm/table.c. Of course you have to change the number of calls and update the table in the file server as well.
This is a good time to pause in your work and make sure you can write a user program that can make the system call, and that the code you wrote in pm actually receives that call. Any problems you find at this point are confined to the code you have written so far.
Next you can implement the system call. You presumably need to add a field to the process table entry to record the deadline for the process. This has to be in the kernel portion of the process table, since the kernel is the one scheduling. So next you must have the ability to set that field.
A system call in pm cannot directly access the kernel portion of the process table, nor the variable realtime which must be added to the parameter to the system call to yield the actual deadline. Therefore, your implementation of the setdl system call in pm must send a message to either the clock task or the system task asking it to set the deadline for this process. Therefore, before modifying the scheduler, you will have to change the clock task or the system task appropriately. Also, in order to send such a message, you must define it, which you do in include/minix/com.h.
It is probably a good idea to make your message a sendrec, though this is at your discretion, and you can use a send if you wish. Just be sure the sender and the receiver agree on which is being used, since if the system task blocks on sending the reply, you can be sure your system will hang very effectively.
Once you've done all this, you can test again to make sure the system task is indeed setting the value as you expect it to. It would be a particularly good idea to print out the deadline, the current time, and the process ID whenever the deadline gets set (it would be a particularly bad idea to print this information out whenever the scheduler executes!).
As part of the process of debugging the system call thoroughly, you can use F1 to print process IDs of running processes, or use "&" at the end of the command to put the command in the background and print its process ID. In short, make sure you are passing in the correct deadline and for the correct process.
At this point all the plumbing is in place. You are able to get the required information into the kernel process table, and all that is left to do is to actually implement the fun part, the real-time scheduling. This almost certainly belongs in kernel/proc.h. You should use Earliest Deadline First, executing whichever process has the earliest deadline. How you modify the scheduler data structures to accomplish this is up to you. In a production environment you would be worried about efficiency, but for this project that is not necessary, for example it would be acceptable to search through the entire process table on every process switch.
It is good to remember that:
There are many ways of doing this project, and you should feel absolutely free to deviate from any of these suggestions (and to have fun)