/*
 * This is the loop for the CPU threads.  The general idea:
 *
 *   1) Each CPU thread has a state variable.  While the library is using the
 *      CPU thread to simulate a process, this variable is set to CPU_RUNNING.
 *
 *   2) To "simulate" a process, we simply block on a condition variable.
 *      Each CPU thread has a dedicated condition variable.
 *
 *   3) For simplicity, the supervisor thread actually does all of the work.
 *      This makes synchronization in the simulator much easier, since all
 *      the real work is done by a single thread.  So, when the supervisor
 *      wants to dispatch an event to a CPU thread, it needs to unblock the
 *      CPU thread.  It does this by setting the CPU thread's state variable
 *      to inform the CPU thread of the event, then it signals the condition
 *      variable.
 *
 *   4) Once the CPU thread unblocks, it calls the students event handler,
 *      then goes back to step 1.
 *
 * There is one special case: idle.  Idle is simulated by the student's code,
 * not the library's.  So we simply set the state variable to CPU_IDLE, and
 * call the student's code.
 */
static void simulator_cpu_thread(unsigned int cpu_id) {
  simulator_cpu_state_t state;

  while (1) {
    pthread_mutex_lock(&simulator_mutex);
    if (simulator_cpu_data[cpu_id].current == NULL) {
      /* the idle process was selected */
      simulator_cpu_data[cpu_id].state = CPU_IDLE;
    } else {
      /* a process was scheduled */
      simulator_cpu_data[cpu_id].state = CPU_RUNNING;

      while (simulator_cpu_data[cpu_id].state == CPU_RUNNING)
        pthread_cond_wait(&simulator_cpu_data[cpu_id].wakeup, &simulator_mutex);
    }
    state = simulator_cpu_data[cpu_id].state;
    pthread_mutex_unlock(&simulator_mutex);

    /* Call student's code */
    switch (state) {
      case CPU_IDLE:
        /*
         * We can't lock the student_lock for idle(); otherwise we can't
         * print statistics while any CPU is idling.
         */
        idle(cpu_id);
        break;

      case CPU_PREEMPT:
        IRWL_WRITER_LOCK(student_lock)
        preempt(cpu_id);
        IRWL_WRITER_UNLOCK(student_lock)
        break;

      case CPU_YIELD:
        IRWL_WRITER_LOCK(student_lock)
        yield(cpu_id);
        IRWL_WRITER_UNLOCK(student_lock)
        break;

      case CPU_TERMINATE:
        processes_terminated++;
        IRWL_WRITER_LOCK(student_lock)
        terminate(cpu_id);
        IRWL_WRITER_UNLOCK(student_lock)
        break;

      case CPU_RUNNING:
        /* This should never happen!!! */
        break;
    }
  }
}
Пример #2
0
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);
    }
}
Пример #3
0
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++;
  }
}
Пример #5
0
/*
 * 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);
}