/* * In this function, you will be modifying the run queue, which can * also be modified from an interrupt context. In order for thread * contexts and interrupt contexts to play nicely, you need to mask * all interrupts before reading or modifying the run queue and * re-enable interrupts when you are done. This is analagous to * locking a mutex before modifying a data structure shared between * threads. Masking interrupts is accomplished by setting the IPL to * high. * * Once you have masked interrupts, you need to remove a thread from * the run queue and switch into its context from the currently * executing context. * * If there are no threads on the run queue (assuming you do not have * any bugs), then all kernel threads are waiting for an interrupt * (for example, when reading from a block device, a kernel thread * will wait while the block device seeks). You will need to re-enable * interrupts and wait for one to occur in the hopes that a thread * gets put on the run queue from the interrupt context. * * The proper way to do this is with the intr_wait call. See * interrupt.h for more details on intr_wait. * * Note: When waiting for an interrupt, don't forget to modify the * IPL. If the IPL of the currently executing thread masks the * interrupt you are waiting for, the interrupt will never happen, and * your run queue will remain empty. This is very subtle, but * _EXTREMELY_ important. * * Note: Don't forget to set curproc and curthr. When sched_switch * returns, a different thread should be executing than the thread * which was executing when sched_switch was called. * * Note: The IPL is process specific. */ void sched_switch(void) { /* Do I need to enque prevthr? * Do I need to continue running prevthr if it is still runnable */ /*for bugs check Run Queue Access Slide */ uint8_t prev_ipl = intr_getipl(); intr_setipl(IPL_HIGH); kthread_t *prevthr = curthr; if (prevthr->kt_state == KT_RUN) ktqueue_enqueue(&kt_runq, prevthr); while (sched_queue_empty(&kt_runq)) { panic("I never actually wait on things here"); intr_setipl(IPL_LOW); intr_wait(); intr_setipl(IPL_HIGH); } /*If there is a thread*/ kthread_t *t = ktqueue_dequeue(&kt_runq); curproc = t->kt_proc; curthr = t; /* NOT_YET_IMPLEMENTED("PROCS: sched_switch");*/ context_switch(&prevthr->kt_ctx, &curthr->kt_ctx); intr_setipl(prev_ipl); }
/* * Since we are modifying the run queue, we _MUST_ set the IPL to high * so that no interrupts happen at an inopportune moment. * Remember to restore the original IPL before you return from this * function. Otherwise, we will not get any interrupts after returning * from this function. * * Using intr_disable/intr_enable would be equally as effective as * modifying the IPL in this case. However, in some cases, we may want * more fine grained control, making modifying the IPL more * suitable. We modify the IPL here for consistency. */ void sched_make_runnable(kthread_t *thr) { //NOT_YET_IMPLEMENTED("PROCS: sched_make_runnable"); uint8_t orig_ipl = intr_getipl(); intr_setipl(IPL_HIGH); thr->kt_state = KT_RUN; ktqueue_enqueue(&kt_runq, thr); intr_setipl(orig_ipl); }
/* * Since we are modifying the run queue, we _MUST_ set the IPL to high * so that no interrupts happen at an inopportune moment. * Remember to restore the original IPL before you return from this * function. Otherwise, we will not get any interrupts after returning * from this function. * * Using intr_disable/intr_enable would be equally as effective as * modifying the IPL in this case. However, in some cases, we may want * more fine grained control, making modifying the IPL more * suitable. We modify the IPL here for consistency. */ void sched_make_runnable(kthread_t *thr) { KASSERT(&kt_runq != thr->kt_wchan); dbg(DBG_PRINT, "(GRADING1A 4.b)\n"); int oldIPL=intr_getipl(); intr_setipl(IPL_HIGH); thr->kt_state = KT_RUN; ktqueue_enqueue(&kt_runq, thr); intr_setipl(oldIPL); /*NOT_YET_IMPLEMENTED("PROCS: sched_make_runnable"); */ }
/* * Since we are modifying the run queue, we _MUST_ set the IPL to high * so that no interrupts happen at an inopportune moment. * Remember to restore the original IPL before you return from this * function. Otherwise, we will not get any interrupts after returning * from this function. * * Using intr_disable/intr_enable would be equally as effective as * modifying the IPL in this case. However, in some cases, we may want * more fine grained control, making modifying the IPL more * suitable. We modify the IPL here for consistency. */ void sched_make_runnable(kthread_t *thr) { uint8_t oldIPL = intr_getipl(); /* Check what currently running IPL is */ intr_setipl(IPL_HIGH); /* Block all hardware interrupts */ /* Add thread to run queue */ ktqueue_enqueue(&kt_runq, thr); /* Make thread runnable (just in case it wasn't already) */ thr->kt_state = KT_RUN; intr_setipl(oldIPL); /* Reset IPL level */ /* NOT_YET_IMPLEMENTED("PROCS: sched_make_runnable"); */ }
void vt_unblock_io(tty_driver_t *ttyd, void *data) { uint8_t oldipl = (uint8_t)(uintptr_t)data; KASSERT(NULL != ttyd); KASSERT(intr_getipl() == INTR_KEYBOARD && "Virtual terminal I/O not blocked"); intr_setipl(oldipl); }
void * vt_block_io(tty_driver_t *ttyd) { uint8_t oldipl; KASSERT(NULL != ttyd); oldipl = intr_getipl(); intr_setipl(INTR_KEYBOARD); return (void *)(uintptr_t)oldipl; }
/* * In this function, you will be modifying the run queue, which can * also be modified from an interrupt context. In order for thread * contexts and interrupt contexts to play nicely, you need to mask * all interrupts before reading or modifying the run queue and * re-enable interrupts when you are done. This is analagous to * locking a mutex before modifying a data structure shared between * threads. Masking interrupts is accomplished by setting the IPL to * high. * * Once you have masked interrupts, you need to remove a thread from * the run queue and switch into its context from the currently * executing context. * * If there are no threads on the run queue (assuming you do not have * any bugs), then all kernel threads are waiting for an interrupt * (for example, when reading from a block device, a kernel thread * will wait while the block device seeks). You will need to re-enable * interrupts and wait for one to occur in the hopes that a thread * gets put on the run queue from the interrupt context. * * The proper way to do this is with the intr_wait call. See * interrupt.h for more details on intr_wait. * * Note: When waiting for an interrupt, don't forget to modify the * IPL. If the IPL of the currently executing thread masks the * interrupt you are waiting for, the interrupt will never happen, and * your run queue will remain empty. This is very subtle, but * _EXTREMELY_ important. * * Note: Don't forget to set curproc and curthr. When sched_switch * returns, a different thread should be executing than the thread * which was executing when sched_switch was called. * * Note: The IPL is process specific. */ void sched_switch(void) { //NOT_YET_IMPLEMENTED("PROCS: sched_switch"); uint8_t orig_ipl = intr_getipl(); intr_setipl(IPL_HIGH); while (sched_queue_empty(&kt_runq)) { intr_setipl(IPL_LOW); intr_wait(); intr_setipl(IPL_HIGH); } kthread_t *thr = ktqueue_dequeue(&kt_runq); context_t *old_context = &(curthr->kt_ctx); context_t *new_context = &(thr->kt_ctx); curthr = thr; curproc = thr->kt_proc; context_switch(old_context, new_context); intr_setipl(orig_ipl); }
/* * In this function, you will be modifying the run queue, which can * also be modified from an interrupt context. In order for thread * contexts and interrupt contexts to play nicely, you need to mask * all interrupts before reading or modifying the run queue and * re-enable interrupts when you are done. This is analagous to * locking a mutex before modifying a data structure shared between * threads. Masking interrupts is accomplished by setting the IPL to * high. * * Once you have masked interrupts, you need to remove a thread from * the run queue and switch into its context from the currently * executing context. * * If there are no threads on the run queue (assuming you do not have * any bugs), then all kernel threads are waiting for an interrupt * (for example, when reading from a block device, a kernel thread * will wait while the block device seeks). You will need to re-enable * interrupts and wait for one to occur in the hopes that a thread * gets put on the run queue from the interrupt context. * * The proper way to do this is with the intr_wait call. See * interrupt.h for more details on intr_wait. * * Note: When waiting for an interrupt, don't forget to modify the * IPL. If the IPL of the currently executing thread masks the * interrupt you are waiting for, the interrupt will never happen, and * your run queue will remain empty. This is very subtle, but * _EXTREMELY_ important. * * Note: Don't forget to set curproc and curthr. When sched_switch * returns, a different thread should be executing than the thread * which was executing when sched_switch was called. * * Note: The IPL is process specific. */ void sched_switch(void) { /* dbg(DBG_PRINT, "(In sched switch)\n");*/ kthread_t *oldthr; int oldIPL; oldIPL=intr_getipl(); intr_setipl(IPL_HIGH); while(sched_queue_empty(&kt_runq)) { intr_disable(); intr_setipl(0); intr_wait(); intr_setipl(IPL_HIGH); } oldthr=curthr; curthr=ktqueue_dequeue(&kt_runq); curproc = curthr->kt_proc; context_switch(&(oldthr->kt_ctx),&(curthr->kt_ctx)); intr_setipl(oldIPL); dbg(DBG_PRINT, "(GRADING1C 1)\n"); /*NOT_YET_IMPLEMENTED("PROCS: sched_switch");*/ }
/* * In this function, you will be modifying the run queue, which can * also be modified from an interrupt context. In order for thread * contexts and interrupt contexts to play nicely, you need to mask * all interrupts before reading or modifying the run queue and * re-enable interrupts when you are done. This is analagous to * locking a mutex before modifying a data structure shared between * threads. Masking interrupts is accomplished by setting the IPL to * high. * * Once you have masked interrupts, you need to remove a thread from * the run queue and switch into its context from the currently * executing context. * * If there are no threads on the run queue (assuming you do not have * any bugs), then all kernel threads are waiting for an interrupt * (for example, when reading from a block device, a kernel thread * will wait while the block device seeks). You will need to re-enable * interrupts and wait for one to occur in the hopes that a thread * gets put on the run queue from the interrupt context. * * The proper way to do this is with the intr_wait call. See * interrupt.h for more details on intr_wait. * * Note: When waiting for an interrupt, don't forget to modify the * IPL. If the IPL of the currently executing thread masks the * interrupt you are waiting for, the interrupt will never happen, and * your run queue will remain empty. This is very subtle, but * _EXTREMELY_ important. * * Note: Don't forget to set curproc and curthr. When sched_switch * returns, a different thread should be executing than the thread * which was executing when sched_switch was called. * * Note: The IPL is process specific. */ void sched_switch(void) { kthread_t *next_thr; /* Somewhere in here: set interrupts to protect run queue intr_setipl(IPL_LOW) or IPL_HIGH, in include/main/interrupt.h */ uint8_t oldIPL = intr_getipl(); /* Check what currently running IPL is */ intr_setipl(IPL_HIGH); /* Block all hardware interrupts */ /* Enqueue requesting thread on run queue if still runnable (dead threads become unschedulable) */ if (curthr->kt_state == KT_RUN) ktqueue_enqueue(&kt_runq, curthr); /* Pick a runnable thread. Take someone off the run queue. */ /* If no threads on run queue, re-enable interrupts and wait for one to occur */ if (sched_queue_empty(&kt_runq)) { intr_wait(); /* Once this returns, there should be a process in the run queue */ } /* Remove a thread from the run queue */ next_thr = ktqueue_dequeue(&kt_runq); /* Manage curproc, curthr */ kthread_t *old_thr = curthr; proc_t *old_proc = curproc; curthr = next_thr; curproc = next_thr->kt_proc; /* Switch context from old context to new context */ context_switch(&old_thr->kt_ctx, &curthr->kt_ctx); /* NOT_YET_IMPLEMENTED("PROCS: sched_switch"); */ }