//---------------------------------------------------------------------- // // ProcessFreeResources // // Free the resources associated with a process. This assumes the // process isn't currently on any queue. // //---------------------------------------------------------------------- void ProcessFreeResources (PCB *pcb) { int i; int npages; QueueInsertLast (&freepcbs, &pcb->l); // Free the process's memory. This is easy with a one-level page // table, but could get more complex with two-level page tables. npages = pcb->npages; for (i=0; i<npages; i++) { MemoryFreeSharedPte(pcb, i); // *MUST* be called before calling // MemoryFreePte. MemoryFreePte does not know // anything about shared pages, and hence it // might screw up big time } for (i = 0; i < pcb->npages; i++) { MemoryFreePte (pcb->pagetable[i]); } // Free the page allocated for the system stack MemoryFreePage (pcb->sysStackArea / MEMORY_PAGE_SIZE); ProcessSetStatus (pcb, PROCESS_STATUS_FREE); }
//---------------------------------------------------------------------- // // ProcessWakeup // // Wake up a process from its slumber. This only involves putting // it on the run queue; it's not guaranteed to be the next one to // run. // // NOTE: This must only be called from an interrupt or trap. It // need not be followed immediately by ProcessSchedule() because // the currently running process is unaffected. // //---------------------------------------------------------------------- void ProcessWakeup (PCB *wakeup) { int i, sleeptime_inseconds; float temp_estcpu, power; dbprintf ('p',"Waking up PCB 0x%x.\n", wakeup); // Make sure it's not yet a runnable process. ASSERT (wakeup->flags & PROCESS_STATUS_WAITING, "Trying to wake up a non-sleeping process!\n"); sleeptime_inseconds = (my_timer_get() - wakeup->sleeptime)/1000; // Adjust the estimated CPU time if(sleeptime_inseconds >= 1) { temp_estcpu = ((((float)2 * wakeup->load)/((float)2 * wakeup->load + 1)) * wakeup->estcpu); // Base power = temp_estcpu; for(i = 1; i < sleeptime_inseconds; i++) { temp_estcpu *= power; // To the power of sleeptime_inseconds } wakeup->estcpu = (int)temp_estcpu; } // Recalculate priority wakeup->prio = PUSER + (wakeup->estcpu/4) + (2*wakeup->p_nice); wakeup->runQueueNum = wakeup->prio/4; // Put the process on a run queue based on Priority ProcessSetStatus (wakeup, PROCESS_STATUS_RUNNABLE); QueueRemove (&wakeup->l); QueueInsertLast (&runQueue[wakeup->runQueueNum], &wakeup->l); }
//---------------------------------------------------------------------- // // ProcessWakeup // // Wake up a process from its slumber. This only involves putting // it on the run queue; it's not guaranteed to be the next one to // run. // // NOTE: This must only be called from an interrupt or trap. It // need not be followed immediately by ProcessSchedule() because // the currently running process is unaffected. // //---------------------------------------------------------------------- void ProcessWakeup (PCB *wakeup) { dbprintf ('p',"Waking up PCB 0x%x.\n", wakeup); // Make sure it's not yet a runnable process. ASSERT (wakeup->flags & PROCESS_STATUS_WAITING, "Trying to wake up a non-sleeping process!\n"); ProcessSetStatus (wakeup, PROCESS_STATUS_RUNNABLE); QueueRemove (&wakeup->l); QueueInsertLast (&runQueue, &wakeup->l); }
//---------------------------------------------------------------------- // // ProcessSuspend // // Place a process in suspended animation until it's // awakened by ProcessAwaken. // // NOTE: This must only be called from an interrupt or trap. It // should be immediately followed by ProcessSchedule(). // //---------------------------------------------------------------------- void ProcessSuspend (PCB *suspend) { // Make sure it's already a runnable process. dbprintf ('p', "Suspending PCB 0x%x (%s).\n", suspend, suspend->name); ASSERT (suspend->flags & PROCESS_STATUS_RUNNABLE, "Trying to suspend a non-running process!\n"); ProcessSetStatus (suspend, PROCESS_STATUS_WAITING); QueueRemove (&suspend->l); QueueInsertLast (&waitQueue, &suspend->l); }
//---------------------------------------------------------------------- // // ProcessSchedule // // Schedule the next process to run. If there are no processes to // run, exit. This means that there should be an idle loop process // if you want to allow the system to "run" when there's no real // work to be done. // // NOTE: the scheduler should only be called from a trap or interrupt // handler. This way, interrupts are disabled. Also, it must be // called consistently, and because it might be called from an interrupt // handler (the timer interrupt), it must ALWAYS be called from a trap // or interrupt handler. // // Note that this procedure doesn't actually START the next process. // It only changes the currentPCB and other variables so the next // return from interrupt will restore a different context from that // which was saved. // //---------------------------------------------------------------------- void ProcessSchedule () { PCB *pcb; int i; dbprintf ('p', "Now entering ProcessSchedule (cur=0x%x, %d ready)\n", currentPCB, QueueLength (&runQueue)); // The OS exits if there's no runnable process. This is a feature, not a // bug. An easy solution to allowing no runnable "user" processes is to // have an "idle" process that's simply an infinite loop. if (QueueEmpty (&runQueue)) { printf ("No runnable processes - exiting!\n"); exitsim (); // NEVER RETURNS } // Move the front of the queue to the end, if it is the running process. pcb = (PCB *)((QueueFirst (&runQueue))->object); if (pcb == currentPCB) { QueueRemove (&pcb->l); QueueInsertLast (&runQueue, &pcb->l); } // Now, run the one at the head of the queue. pcb = (PCB *)((QueueFirst (&runQueue))->object); currentPCB = pcb; dbprintf ('p',"About to switch to PCB 0x%x,flags=0x%x @ 0x%x\n", pcb, pcb->flags, pcb->sysStackPtr[PROCESS_STACK_IAR]); // Clean up zombie processes here. This is done at interrupt time // because it can't be done while the process might still be running while (!QueueEmpty (&zombieQueue)) { pcb = (PCB *)(QueueFirst (&zombieQueue)->object); dbprintf ('p', "Freeing zombie PCB 0x%x.\n", pcb); QueueRemove (&pcb->l); ProcessFreeResources (pcb); } // Set the timer so this process gets at most a fixed quantum of time. TimerSet (processQuantum); dbprintf ('p', "Leaving ProcessSchedule (cur=0x%x)\n", currentPCB); }
//---------------------------------------------------------------------- // // SemWait // // Wait on a semaphore. As described in Section 6.4 of _OSC_, // we decrement the counter and suspend the process if the // semaphore's value is less than 0. To ensure atomicity, // interrupts are disabled for the entire operation. Note that, // if the process is put to sleep, interrupts will be OFF when // it returns from sleep. Thus, we enable interrupts at the end of // the routine. // //---------------------------------------------------------------------- void SemWait (Sem *sem) { Link *l; int intrval; intrval = DisableIntrs (); dbprintf ('I', "Old interrupt value was 0x%x.\n", intrval); dbprintf ('s', "Proc 0x%x waiting on sem 0x%x, count=%d.\n", currentPCB, sem, sem->count); sem->count -= 1; if (sem->count < 0) { l = QueueAllocLink (); QueueLinkInit (l, (void *)currentPCB); dbprintf ('s', "Suspending current proc (0x%x).\n", currentPCB); QueueInsertLast (&sem->waiting, l); ProcessSleep (); } RestoreIntrs (intrval); }
//---------------------------------------------------------------------- // // ProcessWakeup // // Wake up a process from its slumber. This only involves putting // it on the run queue; it's not guaranteed to be the next one to // run. // // NOTE: This must only be called from an interrupt or trap. It // need not be followed immediately by ProcessSchedule() because // the currently running process is unaffected. // //---------------------------------------------------------------------- void ProcessWakeup (PCB *wakeup) { uint32 currTime; int i; dbprintf ('p',"Waking up PCB 0x%x.\n", wakeup); // Make sure it's not yet a runnable process. ASSERT (wakeup->flags & PROCESS_STATUS_WAITING, "Trying to wake up a non-sleeping process!\n"); ProcessSetStatus (wakeup, PROCESS_STATUS_RUNNABLE); QueueRemove (&wakeup->l); currTime = my_timer_get(); if (currTime - wakeup->sleeptime >= 10) { //printf("Updating prio after long wakeup"); for (i = 0; i < (currTime - wakeup->sleeptime); i++) wakeup->estcpu *= (2.0f/(2 + 1)); wakeup->prio = PUSER + (int)(wakeup->estcpu/4) + 2*wakeup->p_nice; } wakeup->processed = 1 - processedFlag; QueueInsertLast (&runQueue[wakeup->prio/4], &wakeup->l); }
//---------------------------------------------------------------------- // // ProcessFreeResources // // Free the resources associated with a process. This assumes the // process isn't currently on any queue. // //---------------------------------------------------------------------- void ProcessFreeResources (PCB *pcb) { int i; int npages; QueueInsertLast (&freepcbs, &pcb->l); // Free the process's memory. This is easy with a one-level page // table, but could get more complex with two-level page tables. //------------------------------------------ // You may change the code below //------------------------------------------ npages = pcb->npages; for (i = 0; i < pcb->npages; i++) { MemoryFreePte (pcb->pagetable[i]); } // Free the page allocated for the system stack MemoryFreePage (pcb->sysStackArea / MEMORY_PAGE_SIZE); ProcessSetStatus (pcb, PROCESS_STATUS_FREE); }
//---------------------------------------------------------------------- // // ProcessFork // // Create a new process and make it runnable. This involves the // following steps: // * Allocate resources for the process (PCB, memory, etc.) // * Initialize the resources // * Place the PCB on the runnable queue // // NOTE: This code has been tested for system processes, but not // for user processes. // //---------------------------------------------------------------------- int ProcessFork (VoidFunc func, uint32 param, int p_nice, int p_info,char *name, int isUser) { int i, j, fd, n; Link *l; int start, codeS, codeL, dataS, dataL; uint32 *stackframe; int newPage; PCB *pcb; int addr = 0; int intrs; unsigned char buf[100]; uint32 dum[MAX_ARGS+8], count, offset; char *str; intrs = DisableIntrs (); dbprintf ('I', "Old interrupt value was 0x%x.\n", intrs); dbprintf ('p', "Entering ProcessFork args=0x%x 0x%x %s %d\n", func, param, name, isUser); // Get a free PCB for the new process if (QueueEmpty (&freepcbs)) { printf ("FATAL error: no free processes!\n"); exitsim (); // NEVER RETURNS! } l = QueueFirst (&freepcbs); dbprintf ('p', "Got a link @ 0x%x\n", l); QueueRemove (l); pcb = (PCB *)(l->object); // This prevents someone else from grabbing this process ProcessSetStatus (pcb, PROCESS_STATUS_RUNNABLE); // At this point, the PCB is allocated and nobody else can get it. // However, it's not in the run queue, so it won't be run. Thus, we // can turn on interrupts here. dbprintf ('I', "Before restore interrupt value is 0x%x.\n", CurrentIntrs()); RestoreIntrs (intrs); dbprintf ('I', "New interrupt value is 0x%x.\n", CurrentIntrs()); // Copy the process name into the PCB. dstrcpy (pcb->name, name); //---------------------------------------------------------------------- // This section initializes the memory for this process //---------------------------------------------------------------------- // For now, we'll use one user page and a page for the system stack. // For system processes, though, all pages must be contiguous. // Of course, system processes probably need just a single page for // their stack, and don't need any code or data pages allocated for them. pcb->npages = 1; newPage = MemoryAllocPage (); if (newPage == 0) { printf ("aFATAL: couldn't allocate memory - no free pages!\n"); exitsim (); // NEVER RETURNS! } pcb->pagetable[0] = MemorySetupPte (newPage); newPage = MemoryAllocPage (); if (newPage == 0) { printf ("bFATAL: couldn't allocate system stack - no free pages!\n"); exitsim (); // NEVER RETURNS! } pcb->sysStackArea = newPage * MEMORY_PAGE_SIZE; //--------------------------------------- // Lab3: initialized pcb member for your scheduling algorithm here //-------------------------------------- pcb->p_nice = p_nice < 0 ? 0 : p_nice; pcb->p_info = p_info; pcb->sleeptime = my_timer_get(); pcb->estcpu = 0; pcb->prio = PUSER; pcb->processed = 1 - processedFlag; pcb->estcputime = 0; //---------------------------------------------------------------------- // Stacks grow down from the top. The current system stack pointer has // to be set to the bottom of the interrupt stack frame, which is at the // high end (address-wise) of the system stack. stackframe = ((uint32 *)(pcb->sysStackArea + MEMORY_PAGE_SIZE)) - (PROCESS_STACK_FRAME_SIZE + 8); // The system stack pointer is set to the base of the current interrupt // stack frame. pcb->sysStackPtr = stackframe; // The current stack frame pointer is set to the same thing. pcb->currentSavedFrame = stackframe; dbprintf ('p', "Setting up PCB @ 0x%x (sys stack=0x%x, mem=0x%x, size=0x%x)\n", pcb, pcb->sysStackArea, pcb->pagetable[0], pcb->npages * MEMORY_PAGE_SIZE); //---------------------------------------------------------------------- // This section sets up the stack frame for the process. This is done // so that the frame looks to the interrupt handler like the process // was "suspended" right before it began execution. The standard // mechanism of swapping in the registers and returning to the place // where it was "interrupted" will then work. //---------------------------------------------------------------------- // The previous stack frame pointer is set to 0, meaning there is no // previous frame. stackframe[PROCESS_STACK_PREV_FRAME] = 0; // Set the base of the level 1 page table. If there's only one page // table level, this is it. For 2-level page tables, put the address // of the level 1 page table here. For 2-level page tables, we'll also // have to build up the necessary tables.... stackframe[PROCESS_STACK_PTBASE] = (uint32)&(pcb->pagetable[0]); // Set the size (maximum number of entries) of the level 1 page table. // In our case, it's just one page, but it could be larger. stackframe[PROCESS_STACK_PTSIZE] = pcb->npages; // Set the number of bits for both the level 1 and level 2 page tables. // This can be changed on a per-process basis if desired. For now, // though, it's fixed. stackframe[PROCESS_STACK_PTBITS] = (MEMORY_L1_PAGE_SIZE_BITS + (MEMORY_L2_PAGE_SIZE_BITS << 16)); if (isUser) { dbprintf ('p', "About to load %s\n", name); fd = ProcessGetCodeInfo (name, &start, &codeS, &codeL, &dataS, &dataL); if (fd < 0) { // Free newpage and pcb so we don't run out... ProcessFreeResources (pcb); return (-1); } dbprintf ('p', "File %s -> start=0x%08x\n", name, start); dbprintf ('p', "File %s -> code @ 0x%08x (size=0x%08x)\n", name, codeS, codeL); dbprintf ('p', "File %s -> data @ 0x%08x (size=0x%08x)\n", name, dataS, dataL); while ((n = ProcessGetFromFile (fd, buf, &addr, sizeof (buf))) > 0) { dbprintf ('p', "Placing %d bytes at vaddr %08x.\n", n, addr - n); // Copy the data to user memory. Note that the user memory needs to // have enough space so that this copy will succeed! MemoryCopySystemToUser (pcb, buf, addr - n, n); } FsClose (fd); stackframe[PROCESS_STACK_ISR] = PROCESS_INIT_ISR_USER; // Set the initial stack pointer correctly. Currently, it's just set // to the top of the (single) user address space allocated to this // process. str = (char *)param; stackframe[PROCESS_STACK_IREG+29] = MEMORY_PAGE_SIZE - SIZE_ARG_BUFF; // Copy the initial parameter to the top of stack MemoryCopySystemToUser (pcb, (char *)str, (char *)stackframe[PROCESS_STACK_IREG+29], SIZE_ARG_BUFF-32); offset = get_argument((char *)param); dum[2] = MEMORY_PAGE_SIZE - SIZE_ARG_BUFF + offset; for(count=3;;count++) { offset=get_argument(NULL); dum[count] = MEMORY_PAGE_SIZE - SIZE_ARG_BUFF + offset; if(offset==0) { break; } } dum[0] = count-2; dum[1] = MEMORY_PAGE_SIZE - SIZE_ARG_BUFF - (count-2)*4; MemoryCopySystemToUser (pcb, (char *)dum, (char *)(stackframe[PROCESS_STACK_IREG+29]-count*4), (count)*sizeof(uint32)); stackframe[PROCESS_STACK_IREG+29] -= 4*count; // Set the correct address at which to execute a user process. stackframe[PROCESS_STACK_IAR] = (uint32)start; pcb->flags |= PROCESS_TYPE_USER; } else { // Set r31 to ProcessExit(). This will only be called for a system // process; user processes do an exit() trap. stackframe[PROCESS_STACK_IREG+31] = (uint32)ProcessExit; // Set the stack register to the base of the system stack. stackframe[PROCESS_STACK_IREG+29]=pcb->sysStackArea + MEMORY_PAGE_SIZE-32; // Set the initial parameter properly by placing it on the stack frame // at the location pointed to by the "saved" stack pointer (r29). *((uint32 *)(stackframe[PROCESS_STACK_IREG+29])) = param; // Set up the initial address at which to execute. This is done by // placing the address into the IAR slot of the stack frame. stackframe[PROCESS_STACK_IAR] = (uint32)func; // Set the initial value for the interrupt status register stackframe[PROCESS_STACK_ISR] = PROCESS_INIT_ISR_SYS; // Mark this as a system process. pcb->flags |= PROCESS_TYPE_SYSTEM; } // Place the PCB onto the run queue. intrs = DisableIntrs (); QueueInsertLast (&runQueue[pcb->prio/4], l); RestoreIntrs (intrs); // If this is the first process, make it the current one if (currentPCB == NULL) { dbprintf ('p', "Setting currentPCB=0x%x, stackframe=0x%x\n", pcb, pcb->currentSavedFrame); currentPCB = pcb; } dbprintf ('p', "Leaving ProcessFork (%s)\n", name); // Return the process number (found by subtracting the PCB number // from the base of the PCB array). return (pcb - pcbs); }
//---------------------------------------------------------------------- // // ProcessSchedule // // Schedule the next process to run. If there are no processes to // run, exit. This means that there should be an idle loop process // if you want to allow the system to "run" when there's no real // work to be done. // // NOTE: the scheduler should only be called from a trap or interrupt // handler. This way, interrupts are disabled. Also, it must be // called consistently, and because it might be called from an interrupt // handler (the timer interrupt), it must ALWAYS be called from a trap // or interrupt handler. // // Note that this procedure doesn't actually START the next process. // It only changes the currentPCB and other variables so the next // return from interrupt will restore a different context from that // which was saved. // //---------------------------------------------------------------------- // You should modify this function to use 4.4BSD scheduling policy // void ProcessSchedule () { PCB *pcb; int i; int empty; int count = 0; float pinfotime; PCB* tailPtrs[32]; PCB *curr; total_num_quanta++; currentPCB->estcpu++; currentPCB->estcputime++; if (currentPCB->p_info) { pinfotime = currentPCB->estcputime *.1; printf(TIMESTRING1, (int)GetCurrentPid()); printf(TIMESTRING2, pinfotime); printf(TIMESTRING3, (int)GetCurrentPid()); printf(TIMESTRING4, currentPCB->prio); } empty = 1; for (i = 0; i < 32; i++) { count += QueueLength(&runQueue[i]); } dbprintf ('p', "Now entering ProcessSchedule (cur=0x%x, %d ready)\n", currentPCB, count); // The OS exits if there's no runnable process. This is a feature, not a // bug. An easy solution to allowing no runnable "user" processes is to // have an "idle" process that's simply an infinite loop. if (!count) { printf ("No runnable processes - exiting!\n"); exitsim (); // NEVER RETURNS } dbprintf('p', "About to check if estcpu is divisible by 4 (cur=0x%x\n", currentPCB); if ((int)currentPCB->estcputime % 4 == 0) { //printf("Updating prio"); currentPCB->prio = PUSER + (int)(currentPCB->estcpu/4) + 2*currentPCB->p_nice; } dbprintf('p', "About to move to end of queue (cur=0x%x\n", currentPCB); // Move the front of the queue to the end, if it is the running process. for (i = 0; i < 32; i++) { pcb = (PCB *)((QueueFirst (&runQueue[i]))->object); if (pcb == currentPCB) { QueueRemove(&pcb->l); QueueInsertLast(&runQueue[pcb->prio/4], &pcb->l); break; } } dbprintf('p', "Before decay (cur=0x%x\n", currentPCB); //decay if (!(total_num_quanta % 10)) { //printf("Looping through all to update everything"); for (i = 0; i < 32; i++) { // loop through each queue if (!QueueLength(&runQueue[i])) continue; curr = QueueFirst(&runQueue[i])->object; dbprintf('p', "Processing PCB in queue %d: 0x%x\n", i, curr); while (curr && curr->processed != processedFlag) { // all the elements not previously processed in the queue curr->estcpu = 2.0f/(2 + 1) *curr->estcpu + curr->p_nice; curr->prio = PUSER + (int)(curr->estcpu/4) + 2*curr->p_nice; curr->processed = processedFlag; QueueRemove(&curr->l); QueueInsertLast(&runQueue[curr->prio/4], &curr->l); curr = QueueFirst(&runQueue[i])->object; dbprintf('p', "Processing PCB in queue %d: 0x%x\n", i, curr); } } processedFlag = 1 - processedFlag; } // Now, run the one at the head of the queue. dbprintf ('p',"About to switch 0x%x", currentPCB); for (i = 0; i < 32; i++) { if (!QueueLength(&runQueue[i])) continue; pcb = (PCB *)((QueueFirst (&runQueue[i]))->object); currentPCB = pcb; dbprintf ('p',"About to switch to PCB 0x%x,flags=0x%x @ 0x%x\n", pcb, pcb->flags, pcb->sysStackPtr[PROCESS_STACK_IAR]); break; } // Clean up zombie processes here. This is done at interrupt time // because it can't be done while the process might still be running while (!QueueEmpty (&zombieQueue)) { pcb = (PCB *)(QueueFirst (&zombieQueue)->object); dbprintf ('p', "Freeing zombie PCB 0x%x.\n", pcb); QueueRemove (&pcb->l); ProcessFreeResources (pcb); } // Set the timer so this process gets at most a fixed quantum of time. TimerSet (processQuantum); dbprintf ('p', "Leaving ProcessSchedule (cur=0x%x)\n", currentPCB); }
//---------------------------------------------------------------------- // // ProcessSchedule // // Schedule the next process to run. If there are no processes to // run, exit. This means that there should be an idle loop process // if you want to allow the system to "run" when there's no real // work to be done. // // NOTE: the scheduler should only be called from a trap or interrupt // handler. This way, interrupts are disabled. Also, it must be // called consistently, and because it might be called from an interrupt // handler (the timer interrupt), it must ALWAYS be called from a trap // or interrupt handler. // // Note that this procedure doesn't actually START the next process. // It only changes the currentPCB and other variables so the next // return from interrupt will restore a different context from that // which was saved. // //---------------------------------------------------------------------- // You should modify this function to use 4.4BSD scheduling policy // void ProcessSchedule () { PCB *pcb; int i, j, n; int atEndOfQueue = FALSE; // To be used as a boolean value Link *links[32]; // The OS exits if there's no runnable process. This is a feature, not a // bug. An easy solution to allowing no runnable "user" processes is to // have an "idle" process that's simply an infinite loop. /* if (QueueEmpty (&runQueue)) { printf ("No runnable processes - exiting!\n"); exitsim (); // NEVER RETURNS }*/ dbprintf('p', "Entering ProcessSchedule [context switch] with current PCB: %p\n",currentPCB); currentPCB->p_quanta++; totalQuanta++; pcb = ProcessHighestPriority(); currentPCB->runtime += my_timer_get() - startTime; if (currentPCB->p_info == 1) { printf(TIMESTRING1, currentPCB - pcbs); printf(TIMESTRING2, currentPCB->runtime / (float)1000); printf(TIMESTRING3, currentPCB - pcbs, currentPCB->prio); } startTime = my_timer_get(); if (!pcb) { printf ("No runnable processes - exiting!\n"); exitsim (); } dbprintf('p', "PCB (%p) currentPCB (%p)\n",pcb,currentPCB); // If last run process is still the highest priority (ie. not asleep/a zombie) if (pcb == currentPCB) { currentPCB->estcpu++; QueueRemove (&pcb->l); QueueInsertLast (&runQueue[pcb->runQueueNum], &pcb->l); dbprintf('p', "\tProcess quanta: %i estcpu: %i\n",currentPCB->p_quanta,currentPCB->estcpu); if((currentPCB->p_quanta % PROCESS_QUANTA_MAX) == 0) { dbprintf('p', "Recalculating priority of currentPCB\n"); currentPCB->prio = PUSER + (currentPCB->estcpu/4) + (2*currentPCB->p_nice); dbprintf('p', "run queue: %i new run queue: %i prio: %i\n",currentPCB->runQueueNum,currentPCB->prio/4,currentPCB->prio); currentPCB->runQueueNum = currentPCB->prio/4; QueueRemove(¤tPCB->l); QueueInsertLast(&runQueue[currentPCB->runQueueNum], ¤tPCB->l); dbprintf('p', "Recalculated priority\n"); } } if(totalQuanta % TOTAL_QUANTA_MAX == 0) { dbprintf('p', "Full reshuffle\n"); // dbprintf('p', "Process quanta exceeded max\n"); // Store all the tails of all of the RunQueues for(i = 0; i < 32; i++) { links[i] = QueueLast(&runQueue[i]); } dbprintf('p', "Last links registered\n"); for(i = 0; i < 32; i++) { // if(QueueEmpty(&runQueue[i])) atEndOfQueue = TRUE; n = (&runQueue[i])->nitems; // while(!atEndOfQueue) { for (j = 0; j < n; j++) { pcb = (PCB *)((QueueFirst(&runQueue[i]))->object); pcb->estcpu = (int)((((float)2 * pcb->load)/((float)2 * pcb->load + 1)) * pcb->estcpu) + pcb->p_nice; // Decay the estimated CPU time of all processes pcb->prio = PUSER + (pcb->estcpu/4) + (2 * pcb->p_nice); // Recalculate the priority of all processes dbprintf('p', "\tRun queue shift (%p->%d)\n",pcb,pcb->prio); dbprintf('p', "At link: %p for last link: %p\n",&pcb->l,links[i]); if(links[i] == &pcb->l || (&pcb->l)->next == NULL) atEndOfQueue = TRUE; pcb->runQueueNum = pcb->prio/4; QueueRemove(&pcb->l); QueueInsertLast(&runQueue[pcb->runQueueNum], &pcb->l); } } pcb = ProcessHighestPriority(); if (currentPCB == pcb) { QueueRemove(¤tPCB->l); QueueInsertLast(&runQueue[currentPCB->runQueueNum], ¤tPCB->l); } } //} pcb = ProcessHighestPriority(); // } currentPCB = pcb; // currentPCB = ProcessHighestPriority(); // Move the front of the queue to the end, if it is the running process. /* pcb = (PCB *)((QueueFirst (&runQueue))->object); if (pcb == currentPCB) { QueueRemove (&pcb->l); QueueInsertLast (&runQueue, &pcb->l); } // Now, run the one at the head of the queue. pcb = (PCB *)((QueueFirst (&runQueue))->object); currentPCB = pcb; dbprintf ('p',"About to switch to PCB 0x%x,flags=0x%x @ 0x%x\n", pcb, pcb->flags, pcb->sysStackPtr[PROCESS_STACK_IAR]); */ // Clean up zombie processes here. This is done at interrupt time // because it can't be done while the process might still be running while (!QueueEmpty (&zombieQueue)) { pcb = (PCB *)(QueueFirst (&zombieQueue)->object); dbprintf ('p', "Freeing zombie PCB 0x%x.\n", pcb); QueueRemove (&pcb->l); ProcessFreeResources (pcb); } // Set the timer so this process gets at most a fixed quantum of time. TimerSet (processQuantum); dbprintf ('p', "Leaving ProcessSchedule (cur=0x%x)\n", currentPCB); }