static void simulate_io(void) { if (io_queue_head == NULL) return; /* There are no I/O requests */ if (io_queue_head->execution_time-- <= 0) { io_request *completed = io_queue_head; pcb_t *pcb; /* Move the programs "PC" to the next "instruction" */ completed->pcb->pc = ((op_t*)completed->pcb->pc) + 1; /* * Remove the I/O request from the queue before calling the student's * code. We must do this, because once we release the simulator_mutex, * the I/O queue may have changed. */ pcb = completed->pcb; io_queue_head = completed->next; if (io_queue_head == NULL) io_queue_tail = NULL; free(completed); /* Call the student's wake_up() handler */ pthread_mutex_unlock(&simulator_mutex); IRWL_WRITER_LOCK(student_lock); wake_up(pcb); IRWL_WRITER_UNLOCK(student_lock); pthread_mutex_lock(&simulator_mutex); } }
extern void force_preempt(unsigned int cpu_id) { assert(cpu_id < cpu_count); IRWL_WRITER_UNLOCK(student_lock); pthread_mutex_lock(&simulator_mutex); /* * It is possible that the student's code calls force_preempt() at the * same time the process was already going to yield or terminate. We * check for that case by only preempting if the CPU is set to CPU_RUNNING. */ if (simulator_cpu_data[cpu_id].state == CPU_RUNNING) { simulator_cpu_data[cpu_id].state = CPU_PREEMPT; pthread_cond_signal(&simulator_cpu_data[cpu_id].wakeup); /* Ensure the scheduler gets run before the simulator */ pthread_cond_wait(&simulator_cpu_data[cpu_id].wakeup, &simulator_mutex); } pthread_mutex_unlock(&simulator_mutex); IRWL_WRITER_LOCK(student_lock); }
static void simulate_creat(void) { static int processes_created = 0; if ((simulator_time % 10) == 0 && processes_created < PROCESS_COUNT) { /* Call student's wake_up() handler */ pthread_mutex_unlock(&simulator_mutex); IRWL_WRITER_LOCK(student_lock); wake_up(&processes[processes_created]); IRWL_WRITER_UNLOCK(student_lock); pthread_mutex_lock(&simulator_mutex); processes_created++; } }
/* * context_switch() and force_preempt() are the two functions available to * student's code. */ extern void context_switch(unsigned int cpu_id, pcb_t *pcb, int preemption_time) { assert(cpu_id < cpu_count); assert(pcb == NULL || (pcb >= processes && pcb <= processes + PROCESS_COUNT - 1)); context_switches++; IRWL_WRITER_UNLOCK(student_lock); pthread_mutex_lock(&simulator_mutex); simulator_cpu_data[cpu_id].current = pcb; simulator_cpu_data[cpu_id].preemption_timer = preemption_time; pthread_mutex_unlock(&simulator_mutex); IRWL_WRITER_LOCK(student_lock); }
extern void force_preempt(unsigned int cpu_id) { // printf("UUUUUUUUUUU-- force_preempt: %d\n", cpu_id); // fflush(stdout); assert(cpu_id < cpu_count); IRWL_WRITER_UNLOCK(student_lock); pthread_mutex_lock(&simulator_mutex); /* * It is possible that the student's code calls force_preempt() at the * same time the process was already going to yield or terminate. We * check for that case by only preempting if the CPU is set to CPU_RUNNING. */ if (simulator_cpu_data[cpu_id].state == CPU_RUNNING) { simulator_cpu_data[cpu_id].state = CPU_PREEMPT; pthread_cond_signal(&simulator_cpu_data[cpu_id].wakeup); // wait to make sure thread finishes preempt and context switch pthread_cond_wait(&thread_yielded, &simulator_mutex); } pthread_mutex_unlock(&simulator_mutex); IRWL_WRITER_LOCK(student_lock); }