The examples of this section are the solutions of exercise 44 on page 219 of book [MINIX3_OS_BOOK]. The exact wording of the exercise, cited from the book [MINIX3_OS_BOOK], is the following: „Add code to the MINIX 3 kernel to keep track of the number of messages sent from process (or task) i to process (or task) j. Print this matrix when the F4 key is hit.”
In the author's Operating System courses between 2008 and 2010,
the solutions of this task were used as typical examples to illustrate
the Minix kernel programming. At that time, the Minix
kernel was 3.1, and our students were helped to solve this exercise by
the following notes: DEIK_MIPPOS_2008tavasz_BN_KiemeltOttoni_OR168_38.pdf.
But remember, Minix is a living system, its code is changing rapidly,
and therefore we may find several points, in this linked document,
where the source code has already changed. This is a common phenomenon
in informatics. For example, being restricted to Minix only, in the
Minix book we can read about managing penalty points in
sched() and we can see it in source code in the
appendix of the book, but it is not included in the
current version of the Minix kernel.
In this section we are working with MINIX 3.2.1. At the time of the writing
of this book, it is the current version and it has just been
installed in the section „The
installation of MINIX3
system”
The PCB is an abstraction of the processes of the operating
system, which is typically realised as a C structure. In Minix this
structure is the struct proc that is defined in
kernel/proc.h source file.
The process table in Minix is simply a structure array of
NR_TASKS + NR_PROCS PCB elements.
If you have no experience in Minix kernel programming we suggest that you should suspend the elaboration of this example and first start by solving the following exercise.
300 processes
When you log into the machine a special process called the shell will be created. If you enter a command in the shell, a (child) process will be created to execute the command. Web servers may fork processes to handle client requests and the list goes on. Many situations can be listed in which processes play significant roles. Actually, it is not suprising because processes are abstractions of computer programs. But it is obvious that the number of processes is limited by the size of the process table array anyway. Therefore, it is a legitimate exercise to increase the size of the process table: set the number of possible processes to 300 (from 256).
We may set the value of NR_PROCS in the source file include/minix/sys_config.h
Set the value of NR_PROCS to 300 from 256.
After setting the NR_PROCS, it will be interesting to see the size of the process table. It can be done easily by following the previous exercise in Section The first MINIX kernel hacking.
Example 2.1. Number of processes
We have also done this exercise ourselves.
After the above two steps we can see in the next figure that the size of the PCB is equal to 1664 bytes and the size of the process table is 507520 (=1664*(5+300)). If the reader completes this exercise by himself/herself, he or she will see that the result will be different due to the fact that we have already used a modified version of PCB. Because our PCB has already contains a vector in which the number of elements is dependent on the value of NR_PROCS too.
Example 2.2. The size of the PCB
Print the size of the PCB and the size of the process table from kernel.
This exercise was solved as an implicit part of the previous exercise.
Returning to the original exercise, the MINIX PCB is being
extended with an array of integers (called in Hungrian
uzenetszam that means the number of
messages). The i-th element of this array says how many
messages were sent to the i-th process.
In principle, we know where to store the number of sent messages, now we are going to program the counting procedure itself.
++(caller_ptr->uzenetszam[dst_ptr->p_nr + NR_TASKS]);
The appropriate element of the
uzenetszam array in the caller's PCB is being
incremented. Here, it is necessary to add +
NR_TASKS to the array index because the numbering of
processes starts from -NR_TASKS.
To avoid complication (in the first approach), this increment
statement has been placed into the source file
kernel/proc.c, into the begining of the
function mini_send.
We have already mentioned that the numbering of processes starts from -NR_TASKS. It can be seen not only in the kernel sources but also if you press F1 key:
In GNU/Linux
systems, the /proc virtual
file system serves for monitoring the running kernel. Minix kernel
has no such tool like this. We can obtain information about the
running kernel over the Information Server (is), which is located in
the server part of the Minix microkernel architecture. If we are going to debug the running kernel (in our case to print out the
added PCB vectors), we need to use Information Server.
We can link debug functions to function keys in the source file
servers/is/dmp.c, right now to the F4.
The debug function uzenetszam_dmp first
prints the process names of the non-empty slots of the process table
as a header line. We may have noticed that we are in the server layer of the kernel tree to
be more precise we have worked in the is
server, where to the process table is copied from the bottom layer
of the kernel by the system call
sys_getproctab. The
uzenetszam_dmp function works this copied
instance of the process table, because the bottom layer of the
kernel cannot be seen from the layer of servers.
After the header line, the next lines will contain the vectors of non-empty PCBs.
At the end of printing the matrix, the
mennyitol (in English it means „from number”)
variable will be incremented by 21, it implements a kind of paging
for displaying the „IPC matrix”. To be more precise, if the F4 key
has been pressed, a submatrix of size 22x9 will be printed from the
actual value of mennyitol.
Since the function uzenetszam_dmp is also
used outside of the source file
servers/is/dmp_kernel.c, we must declare it,
therefore we give its prototype in the source file servers/is/proto.h.
After this, all we have to do is to compile the kernel, then to boot the new kernel. And after the login, if we press F4 the following debug screen appears:
Example 2.3. Non-empty slots
Print out the non-empty slots of the kernel process table in
the form of [process name]-[p_quantum_size_ms]-[p_cpu_time_left]
when F1 key is pressed (that is using the
is Information Server).
By solving this exercise, you must know the struct
proc structure members
p_quantum_size_ms and
p_cpu_time_left defined in the kernel
part of Minix PCB in the source file kernel/proc.h.
In the previous section, we modified the PCB. Then (using the
sys_getproctab system call) we
copied the kernel process table to the layer of server processes.
Now, outside the PCB, but inside the kernel we create a data
structure: a matrix of integers to store the „IPC matrix”. To access
this matrix, we create a new system call.
Define a 2 dimensional array of size (NR_TASKS +
NR_PROCS)*(NR_TASKS + NR_PROCS) outside
the PCB structure
Counting of IPC messages will be done in the same manner as
described in the previous section. But now, the
uzenetszam array will be accessed directly and
not through the PCB.
The uzenetszam array of the kernel is also
defined with the same name in the server layer.
Use the sys_getmatrix system call that
will be newly developed for copying the IPC matrix from kernel level
to the server level.
Printing the matrix has changed very little only in one line:
printf("%7d|", uzenetszam[rp->p_nr +
NR_TASKS][i]);In the source file include/minix/syslib.h, write the
sys_getmatrix macro. This macro will call the
system call do_getinfo that will do the real
work. The sys_getmatrix macro helps simplify
using the do_getinfo.
The GET_MATRIX constant (used in the
sys_getmatrix macro) is defined in source
include/minix/com.h, its
value is chosen to be equal to 255.
There is not much for us to do to add a case branch to the
switch of do_getinfo in order to handle the
calls of the sys_getmatrix.
Now we are ready to recompile and boot the new kernel. Then, after pressing F4, we can see the fruits of our labour.
It is interesting to compare the two solutions. For example, what happens if processes are created then destroyed after they have been finished and so on.
The two presented solutions are available in a VirtualBox virtual machine that can be found at http://www.inf.unideb.hu/~nbatfai/MINIX3.2.ova