I recently purchased this book to get a better understanding of how operating systems work. I am on the second chapter and I'm stuck on this problem and my OS does not boot with code I have added. The code below was added to proc.c at the start of the pic_proc function to try and modify the scheduler.
Modification.
int realtime;
clock_t recent_time[NR_TASKS + NR_PROCS];
clock_t stopwatch;
realtime = getuptime();
recent_time[proc_ptr->p_nr + NR_TASKS] = realtime - stopwatch;
stopwatch = realtime;
Original Code:
PRIVATE void pick_proc()
{
register struct proc *rp; /* process to run */
int q; /* iterate over queues */
/* Modified Code here */
for (q=0; q < NR_SCHED_QUEUES; q++) {
if ( (rp = rdy_head[q]) != NIL_PROC) {
next_ptr = rp;
if (priv(rp)->s_flags & BILLABLE)
bill_ptr = rp;
return;
}
}
}
Book Operating Systems Design and Implementation. 3rd, Edition The Minix Book, P219, #45. Modify the Minix 3 scheduler to keep track of how much CPU time each user process has had recently. When no task or server wants to run, pick the user process that has had the smallest share of the CPU.
Based on your new code [and the pick_proc
function body], the only possible failures are the ones I've described above in my top comments.
That is, proc_ptr
must be valid (i.e. non-NULL) and proc_ptr->p_nr
must be in range to prevent UB.
What are the NR_TASKS
and NR_PROCS
values? Can recent_time
fit on the stack? Stack size in a kernel is usually very limited. For example, under linux, you can only have about 4KB of stack.
So, if NR_PROCS
was (e.g.) 32767, then recent_time
could not be placed on the stack.
And, I don't see a reason the have an independent array for this on the stack as it won't persist past the call.
So, to aid in debug, I'd add static
to the recent_time
definition
You'll need to add some debug code to see what the issue is.
Here's a sample. Adjust the printf
et. al. to suit the minux
kernel's print mechanism [assuming you can print at the state your code is called in]:
#ifdef DEBUG
#define dbgprt(_fmt...) \
printf(_fmt)
#else
#define dbgprt(_fmt...) \
do { } while (0)
#endif
PRIVATE void
pick_proc()
{
register struct proc *rp; /* process to run */
int q; /* iterate over queues */
/* Modified Code here */
int realtime;
static clock_t recent_time[NR_TASKS + NR_PROCS];
clock_t stopwatch;
do {
// bad pointer
dbgprt("pick_proc: proc_ptr=%p\n",proc_ptr);
if (proc_ptr == NULL)
break;
// out of range process number
dbgprt("pick_proc: p_nr=%u\n",proc_ptr->p_nr);
if (proc_ptr->p_nr >= NR_PROCS)
break;
realtime = getuptime();
dbgprt("pick_proc: realtime=%d\n",realtime);
recent_time[proc_ptr->p_nr + NR_TASKS] = realtime - stopwatch;
stopwatch = realtime;
} while (0);
for (q = 0; q < NR_SCHED_QUEUES; q++) {
if ((rp = rdy_head[q]) != NIL_PROC) {
next_ptr = rp;
if (priv(rp)->s_flags & BILLABLE)
bill_ptr = rp;
return;
}
}
}
UPDATE:
I can't emphasize enough the importance of assert
and/or if
statements to pre-validate anything you do to prevent UB. And, debug printf
, such as:
TRACE(VF_PICKPROC,printf("hello world\n"););
BTW, I pulled the minix
source code from github:
git clone https://github.com/Stichting-MINIX-Research-Foundation/minix.git
It appears that you may have outdated source because the pick_proc
in that repo has more SMP related code.
The NR_TASKS + NR_PROCS should be the time quanta taken from the process table. I orginally declared the Array and stopwatch in proc.h but the pic_proc function did not have access to them.
You really want to either use the existing fields in struct proc
or add some of your own vs. creating a separate array [indexed by process number].
I added some screen shots of code that calls pic_proc. I think i need to modify sched and leave pic_proc alone. The array in pic_proc should be getting the time quanta from each process from the process table
Yes, hopefully elapsed CPU time for each process is in struct proc
. If not, you'll have to add a field. I suspect that p_user_time
[and/or p_sys_time
] may be what you want. And, maybe, p_cpu_time_left
. Other possibilities: p_accounting.time_in_queue
. Or, p_cycles
pick_proc
just looks at the head of a given run queue. So, you may need to change the code that actually inserts a given process into that queue. That might be enqueue
and/or dequeue
. They appear to honor process priority [p_priority
] and preemption.
I've skimmed the kernel code, and at a guess, sched_proc
may be of interest.
But, I really think you'll need to examine the kernel code more closely to see what functions actually add a process to a given run queue. And, how they select a process and from which queue.
When adding a process, it may just append to the tail. That code would need to scan the queue and [assuming the priority is the same], insert based on lowest CPU usage.