示例#1
0
int
thread_join(int thread_id, void** ret_val)
{
    struct proc* maint=get_main_thread(proc);

    if(maint->last_tid >= thread_id && proc->tid != thread_id) {
        struct proc *p;
        int havekids;
        void* retval;

        acquire(&ptable.lock);
        for(;;) {
            // Scan through table looking for zombie children.
            havekids = 0;
            for(p = ptable.proc; p < &ptable.proc[NPROC]; p++) {
                if(p->parent != maint || p->tid!=thread_id)
                    continue;

                havekids = 1;
                // check if another thread is waiting for this thread
                if(p->other_thread_waiting >= 0
                        && p->other_thread_waiting != proc->tid) {
                    release(&ptable.lock);
                    return -2;
                }

                // flag that p is waited for
                p->other_thread_waiting=proc->tid;

                if(p->state == ZOMBIE) {
                    // Found one.
                    retval=p->ret_val;
                    clear_thread(p);

                    *ret_val=retval;

                    release(&ptable.lock);
                    return 0;
                }
            }

            // No point waiting if we don't have any children.
            if(!havekids || proc->killed) {
                release(&ptable.lock);
                return -1;
            }

            // Wait for children to exit.  (See wakeup1 call in proc_exit.)
            sleep(proc, &ptable.lock);  //DOC: wait-sleep
        }
    }

    return -1;
}
示例#2
0
文件: prj2.c 项目: hyelong/Algorithms
int main(int argc, char* argv[])
{
  struct timespec event_ts;   // local event timestamp

  int num_thrds = 0;        // number of user threads to simulate
  thread_data_t *tarr = NULL; // array of thread data structures

  int sel_sid = -1;           // index of thread selected by scheduler
  thread_data_t *tsel = NULL; // pointer to the selected thread

  int tmp = 0;
  int (*sched_func)() = NULL; // scheduling function picked at run time

  if (argc < 3) {
    fprintf(stderr, usage, argv[0]);
    exit(1);
  }

  tmp = strlen(argv[1]);
  if (argv[1][tmp-1] == '+') {
    unblock_signal = 1;
    argv[1][tmp-1] = '\0';
  }

  for (int i=0 ; i < NUM_SCHED ; i++) {
    if (strcmp(argv[1], MY_SCHED[i].name) == 0) {
      sched_func = MY_SCHED[i].func;
      break;
    }
  }
  if (sched_func == NULL) {
    errx(1, "Scheduling function %s not found!", argv[1]);
  }

  num_thrds = strtol(argv[2], NULL, 0);
  if (argc > 3)
    min_time = strtol(argv[3], NULL, 0);
  if (argc > 4)
    max_time = strtol(argv[4], NULL, 0);

  // Get simulation start time for logging reference
  clock_gettime(CLOCK_REALTIME, &sim_ts);

  pthread_mutex_init(&simlock, NULL);
  pthread_cond_init(&sched_cv, NULL);
  pthread_cond_init(&run_cv, NULL);
  init_thread_Q(&unblockQ, num_thrds);
  init_thread_Q(&readyQ, num_thrds);
  init_thread_Q(&blockedQ, num_thrds);

  pthread_mutex_lock(&simlock);

  // Create and fork number of threads as requested
  tarr = calloc(num_thrds, sizeof(thread_data_t));
  for (int i=0 ; i < num_thrds ; i++) {
    tarr[i].sid = i;

    // Thread is put to blocked state right after start
    tarr[i].state = BLOCKED;
    add_to_Q_back(&blockedQ, &tarr[i]);

    fork_thread(&tarr[i]);
    LOG("Thread tid=%d created with sid=%d\n", tarr[i].tid, tarr[i].sid);
  }

  run_sid = -1;         // no thread is initially running
  block_sid = -1;       // no thread is initially entering block state

  do {
    if (block_sid != -1) {
      // Scheduler was waken up by the running thread blocking
      // Handle thread entering blocked state from running state
      if (run_sid != -1)
        errx(1, "thread[%d] was blocked while thread[%d] is still running",
             block_sid, run_sid);

      add_to_Q_back(&blockedQ, &tarr[block_sid]);
      block_sid = -1;

    } else if (run_sid != -1) {
      // Scheduler was waken up by the tick_ts timeout
      // Preempt running (and non-blocking) thread to ready state
      thread_data_t *t = &tarr[run_sid];

      if (t->state != RUNNING)
        errx(1, "thread[%d] to be preempted is in %d state",
             run_sid, t->state);

      clock_gettime(CLOCK_REALTIME, &event_ts);
      t->remain_usec -= TIMEUSEC(&t->event_ts, &event_ts);
      t->event_ts = event_ts;

      LOG("%8ld: scheduler preempts running thread[%d] with remain_usec=%d\n",
          TIMEUSEC(&sim_ts, &event_ts), run_sid, t->remain_usec);

      // Change the preempted thread into ready state
      t->state = READY;
      add_to_Q_back(&readyQ, t);
      run_sid = -1;
      // Signal the thread to stop running
      pthread_cond_signal(&run_cv);
    }

    while (unblockQ.head >= 0) {
      // Handle threads unblocking from blocked state into ready state
      thread_data_t *t = remove_from_Q_front(&unblockQ);

      clock_gettime(CLOCK_REALTIME, &event_ts);
      t->event_ts = event_ts;

      LOG("%8ld: scheduler changes thread[%d] with remain_usec=%d to ready\n",
          TIMEUSEC(&sim_ts, &event_ts), t->sid, t->remain_usec);

      // Change the unblocking thread into ready state
      t->state = READY;
      remove_from_Q(&blockedQ, t->sid);
      add_to_Q_back(&readyQ, t);
      // Signal the thread to become formally unblocked
      pthread_cond_signal(&t->block_cv);
    }

    if (unblockQ.head >= 0)     // unblockQ is not empty
      errx(1, "unblockQ has pending threads from %d to %d!?!",
           unblockQ.head, unblockQ.tail);
    if (run_sid != -1)
      errx(1, "scheduler is running with running thread[%d]!?!", run_sid);
    if (block_sid != -1)
      errx(1, "thread[%d] was blocking but not handled!?!", block_sid);

    if (readyQ.head == -1 && blockedQ.head == -1) {
      // no thread is running, neither in ready or blocked list
      clock_gettime(CLOCK_REALTIME, &event_ts);
      LOG("%8ld: all threads appear to have terminated\n",
          TIMEUSEC(&sim_ts, &event_ts));
      break;
    }

    if (tsel != NULL && tsel->state == RUNNING) {
      // Scheduler was waken up (by unblocking or terminating threads) before
      // last selected thread could startrunning -- do not select again
      /*** Do nothing ***/

    } else {
      // Either scheduler did not select a thread last time, or the selected
      // thread is not running any more (blocked, preempted or finished)

      // Run the scheduling algorithm to select a new thread
      sel_sid = sched_func();

      clock_gettime(CLOCK_REALTIME, &event_ts);

      if (sel_sid < 0) {
        tsel = NULL;
        LOG("%8ld: scheduler cannot find any thread to run\n",
            TIMEUSEC(&sim_ts, &event_ts));

      } else {
        tsel = &tarr[sel_sid];

        if (tsel->state != READY)
          errx(1, "scheduler selects thread[%d] not in ready state", sel_sid);

        LOG("%8ld: scheduler selects thread[%d] with remain_usec=%d to run\n",
            TIMEUSEC(&sim_ts, &event_ts), sel_sid, tsel->remain_usec);

        // Change the selected thread to running state
        tsel->state = RUNNING;
        remove_from_Q(&readyQ, tsel->sid);
        // Signal the selected thread to run
        pthread_cond_signal(&tsel->ready_cv);
      }
    }

    // Scheduler wait for either a signal or tick_ts until next preemption
    timeadd(&event_ts, &event_ts, &tick_ts);
    pthread_cond_timedwait(&sched_cv, &simlock, &event_ts);

  } while (1);

  pthread_mutex_unlock(&simlock);
  sched_yield();

  for (int i=0 ; i < num_thrds ; i++) {
    int rv;
    int tid = wait(&rv);        // wait for an (only) child to exit
    LOG("Thread tid=%d exited with status %d\n", tid, WEXITSTATUS(rv));
  }

  for (int i=0 ; i < num_thrds ; i++) {
    clear_thread(&tarr[i]);
  }
  free(tarr);

  destroy_thread_Q(&unblockQ);
  pthread_mutex_destroy(&simlock);
  pthread_cond_destroy(&sched_cv);
  pthread_cond_destroy(&run_cv);
  return 0;
}
示例#3
0
// Exit the current process.  Does not return.
// An exited process remains in the zombie state
// until its parent calls wait() to find out it exited.
void
exit(void)
{
    struct proc *p;
    int fd;
    int rmBrothers=0;

    if(!is_main_thread(proc)) {
        // Kill main thread
        proc->parent->killed=1;
        if(proc->parent->state==SLEEPING)
            proc->parent->state=RUNNABLE;
        //clear_thread(proc);
        rmBrothers=1;
        //return;
    }

    if(proc == initproc)
        panic("init exiting");

    cprintf("#");
    //release(&ptable.lock);
    if(!holding(&ptable.lock)) {
        cprintf("[ex%d]", proc->pid);
        acquire(&ptable.lock);
    }
    cprintf("%");

    // Pass abandoned proc children to init &
    // kill all threads beneath (children who are not procs)
    for(p = ptable.proc; p < &ptable.proc[NPROC]; p++) {
        if(p->parent == proc) {
            if(is_main_thread(p) && rmBrothers==0) {
                p->parent = initproc;
                if(p->state == ZOMBIE)
                    wakeup1(initproc);
            } else {
                clear_thread(p);
            }
        }
    }

    if(rmBrothers)
        goto end;

    // Close all open files.
    for(fd = 0; fd < NOFILE; fd++) {
        if(proc->ofile[fd]) {
            fileclose(proc->ofile[fd]);
            proc->ofile[fd] = 0;
        }
    }

    iput(proc->cwd);
    proc->cwd = 0;

end:
    // Parent might be sleeping in wait().
    wakeup1(proc->parent);

    // Jump into the scheduler, never to return.
    proc->state = ZOMBIE;
    sched();
    panic("zombie exit");
}