coperating-systemminix

Modifying Minix 3 Scheduler


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.

Enqueue Code

Sched part 1

Sched part 2


Solution

  • 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.