Пример #1
0
void alarm_handler(int sig){

  gtthread_blk_t *cur, *next;

  DEBUG_MSG("alarm_handler\n");

  cur = (gtthread_blk_t *)steque_front(&thread_queue);
  if(cur->state == RUNNING){                                       // avoid update state when it's already done
    cur->state = READY;
    steque_cycle(&thread_queue);
  }

  /*if((cur->state == TERMINATED) && (cur->tID == 1)){

    while(!steque_isempty(&thread_queue)){
      steque_pop(&thread_queue);
    }

    return;

  } */

  while((next = (gtthread_blk_t *)steque_front(&thread_queue))){ 
  
    if(next->state == READY){
      next->state = RUNNING;
      DEBUG_MSG("Schedule #%ld thread\n", next->tID);
      break;
    }
    else if(next->state == JOINED){
      steque_pop(&thread_queue);
      DEBUG_MSG("POP #%ld thread\n", next->tID);
    }
    else if(next->state == TERMINATED)
      steque_cycle(&thread_queue);
    else{
      steque_pop(&thread_queue);
      DEBUG_MSG("ERROR! RUNNING thread?\n");
    }
  } 

  DEBUG_MSG("swap: cur thread: # %ld, next thread: # %ld\n", cur->tID, next->tID);
  reset_timer();

  if (swapcontext(&cur->uctx, &next->uctx) != 0)
    DEBUG_MSG("ERROR! Swap failed?\n");
  DEBUG_MSG("GOOD! Swap SUCCESS!\n");

  list_thread();

}
Пример #2
0
/**
 * Cycles through the join_steque to update the waiting status of any threads that may
 * be waiting on a thread to join. 
 */
static void joininator(gtthread_t *joinee) {
  int i;
  for(i=0; i<steque_size(&g_join_steque); i++) {
    gtthread_t *curr = steque_front(&g_join_steque);
    
    if(curr->wait_tid == joinee->id) {
      curr->is_joined = 1;
      curr->joinee = joinee;
    }
    
    steque_cycle(&g_join_steque);
  }
}
Пример #3
0
void alarm_handler(int sig)
{
  void* current = (node_t*)malloc(sizeof(node_t));
  void* next = (node_t*)malloc(sizeof(node_t));

  block_signal();
  current = steque_front(q);

  steque_cycle(q);
  while(1) {
    next = steque_front(q);
    if((((node_t*)next)->canceled) == 0){
      break;
    }
    steque_cycle(q);
  }

  set_alarm();  
  
  swapcontext (((node_t*)current)->thread_ctx, ((node_t*)next)->thread_ctx);
  unblock_signal();
}
Пример #4
0
/*
 The gtthread_exit() function is analogous to pthread_exit.
*/
void gtthread_exit(void* retval) {
  sigprocmask(SIG_BLOCK, &vtalrm, NULL);
  gtthread_t *thread = steque_front(&g_threads_steque);
  thread->is_finished = 1;
  
  if(retval != NULL)
    thread->retval = retval;
  
  /* If this was the last thread in the queue, clean up and exit */
  if(steque_size(&g_threads_steque) == 1) {
    gtthread_t *dead_thread;
    int num = steque_size(&g_dead_threads_steque);

    while(num > 0) {
      dead_thread = steque_front(&g_dead_threads_steque);
      if(dead_thread->context && dead_thread->context->uc_stack.ss_sp)
        free(dead_thread->context->uc_stack.ss_sp);
      if(dead_thread->context)
        free(dead_thread->context);
      if(dead_thread->id == 0)
        free(dead_thread);

      if(steque_size(&g_dead_threads_steque) > 1)
        steque_cycle(&g_dead_threads_steque);
      num--;
    }
	
    if(thread->context)
      free(thread->context); 

    // Main thread was the only one that was dynamically allocated.
    if(thread->id == 0)
      free(thread);

    steque_destroy(&g_threads_steque);
    steque_destroy(&g_dead_threads_steque);
    steque_destroy(&g_cancelatorium);
    steque_destroy(&g_join_steque);


    /*
    So apparently we can't free the stack of the thread that is running.
    */
    // if(thread->context && thread->context->uc_stack.ss_sp)
      //  free(thread->context->uc_stack.ss_sp);
    exit(0);
    }
  
  sigprocmask(SIG_UNBLOCK, &vtalrm, NULL);
  alarm_safe_yield();
}
Пример #5
0
/* will swap out currently running thread for next thread in the queue*/
void alrm_handler(int sig)
{

	gtthread *currentThread;
	/* block signals */
	sigset_t oldset;
	
	sigprocmask(SIG_BLOCK, &alrm, &oldset);
	currentThread = (gtthread *) gtthread_self();
    /* currently running thread has reached the end of its time slice */
	/* push this thread to the back of the queue */
	steque_cycle(&currently_running); 
	scheduleNextAndSwap(currentThread);
	
	sigprocmask(SIG_UNBLOCK, &alrm, NULL);
}
Пример #6
0
/* to find thread with threadId in the globalQ */
gtthread* getThread(gtthread_t threadId)
{
  int size = steque_size(&globalQ);
  int i = 0;
  gtthread *temp, *returnThread;

  returnThread = NULL;
 /* Get front of queue in temp, compare id
    Do this till you find a match, save it in returnThread and continue loop to restore
    original order  */
  while(i < size)
  {
	temp = (gtthread *) steque_front(&globalQ);
	if(temp -> id == threadId)
	{
		returnThread = temp;
	}
	steque_cycle(&globalQ);
	i++;
  }

  return returnThread;
}
Пример #7
0
/**
 * Helper function for yield.
 */
static void yield_helper(int is_alarm_safe) {
  if(is_alarm_safe)
    sigprocmask(SIG_BLOCK, &vtalrm, NULL);
  
  // Don't need to do anything if there's just one thread in the queue.
  if(steque_size(&g_threads_steque) == 1)
    return;
  
  gtthread_t *old_thread = steque_pop(&g_threads_steque);
  gtthread_t *new_thread = NULL;
  
  /* Find an eligible new thread - i.e., a thread that isn't queued for cancelation. */
  if(!is_alarm_safe)
    sigprocmask(SIG_BLOCK, &vtalrm, NULL);
  
  while(steque_size(&g_threads_steque) > 0) {
    new_thread = steque_front(&g_threads_steque);
    
    /* Cancels threads when it's their turn to run */
    int i;
    int canceled=0;
    for(i=0; i < steque_size(&g_cancelatorium); i++) {
      if((long) steque_front(&g_cancelatorium) == new_thread->id) {
        new_thread->is_finished = 1;
        new_thread->retval = (void *) -1;
        steque_pop(&g_cancelatorium);
        steque_pop(&g_threads_steque);
        steque_enqueue(&g_dead_threads_steque, new_thread);
        
        canceled=1;

        joininator(new_thread); // Attempt to join the thread you just canceled.
        break;
      }
      if(steque_size(&g_cancelatorium) > 0)
        steque_cycle(&g_cancelatorium);
    }
    
    if(!canceled)
      break;
  }
  
  /* If the thread that yielded finsihed executing, put it in the finished steque. */
  if(old_thread->is_finished) {
    steque_enqueue(&g_dead_threads_steque, old_thread);
    joininator(old_thread);
  } else {
    steque_enqueue(&g_threads_steque, old_thread);
  }
  
  if(!is_alarm_safe)
    sigprocmask(SIG_UNBLOCK, &vtalrm, NULL);
  
  // All threads have finished running. Is this necessary?
  if(steque_size(&g_threads_steque) == 0)
    exit(0);
  
  // Don't context switch if the original thread is the only one left in the queue.
  if(gtthread_equal(*((gtthread_t *) steque_front(&g_threads_steque)), *old_thread))
    return;
  
  if(is_alarm_safe) {
    T.it_value.tv_usec = global_period; // Reset timer so that the next period can start immediately.
    sigprocmask(SIG_UNBLOCK, &vtalrm, NULL);
  }
  
  swapcontext(old_thread->context, new_thread->context);
}
Пример #8
0
/*
 The gtthread_join() function is analogous to pthread_join.
 All gtthreads are joinable.
*/
int gtthread_join(gtthread_t thread, void **status) {
  sigprocmask(SIG_BLOCK, &vtalrm, NULL);
  gtthread_t *self = steque_front(&g_threads_steque);
  sigprocmask(SIG_UNBLOCK, &vtalrm, NULL);
  
  /* The range [0, g_thread_id) indicates the range of thread ids that have ever belonged to valid threads.
  Also can't join with self. */
  if(thread.id >= g_thread_id || thread.id == self->id)
    return 1;
  
  sigprocmask(SIG_BLOCK, &vtalrm, NULL);
  self->is_joined = 0;
  self->wait_tid = thread.id;
  sigprocmask(SIG_BLOCK, &vtalrm, NULL);
  int found_among_dead = 0;
  
  /* First look for joinee among threads that have already terminated. */
  int i;
  for(i=0; i<steque_size(&g_dead_threads_steque); i++) {
    sigprocmask(SIG_BLOCK, &vtalrm, NULL);
    gtthread_t *curr = steque_front(&g_dead_threads_steque);
    sigprocmask(SIG_UNBLOCK, &vtalrm, NULL);
    
    if(curr->id == self->wait_tid) {
      found_among_dead = 1;
      sigprocmask(SIG_BLOCK, &vtalrm, NULL);
      self->joinee = curr;
      self->is_joined = 1;
      sigprocmask(SIG_UNBLOCK, &vtalrm, NULL);
      break;
    }
    
    sigprocmask(SIG_BLOCK, &vtalrm, NULL);
    steque_cycle(&g_dead_threads_steque);
    sigprocmask(SIG_UNBLOCK, &vtalrm, NULL);
  }
  
  /* If we haven't found it, wait until it terminates. */
  if(!found_among_dead) {
    // First check to see that the thread I am waiting on is not already waiting on me.
    for(i=0; i<steque_size(&g_join_steque); i++) {
      sigprocmask(SIG_BLOCK, &vtalrm, NULL);
      gtthread_t *curr = steque_front(&g_join_steque);
      sigprocmask(SIG_UNBLOCK, &vtalrm, NULL);
      
      if(curr->wait_tid == self->id && curr->id == self->wait_tid) {
        sigprocmask(SIG_BLOCK, &vtalrm, NULL);
        self->is_joined = -1;
        self->wait_tid = -1L;
        sigprocmask(SIG_UNBLOCK, &vtalrm, NULL);
        return 1;
      }
      sigprocmask(SIG_BLOCK, &vtalrm, NULL);
      steque_cycle(&g_join_steque);
      sigprocmask(SIG_UNBLOCK, &vtalrm, NULL);
    }
    
    // If joinee isn't already waiting on me, enqueue myself in the join queue...
    sigprocmask(SIG_BLOCK, &vtalrm, NULL);
    steque_enqueue(&g_join_steque, self);
    sigprocmask(SIG_UNBLOCK, &vtalrm, NULL);
    
    // ... and wait until joinee terminates.
    while(!self->is_joined)
    alarm_safe_yield();
  }
  
  if(status)
    *status = self->joinee->retval;
  
  sigprocmask(SIG_BLOCK, &vtalrm, NULL);
  self->joinee = NULL;
  self->wait_tid = -1L;
  self->is_joined = -1;
  sigprocmask(SIG_UNBLOCK, &vtalrm, NULL);
  
  /* Remove yourself from the join steque, if you put yourself there. */
  if(!found_among_dead) {
    for(i=0; i<steque_size(&g_join_steque); i++) {
      sigprocmask(SIG_BLOCK, &vtalrm, NULL);
      gtthread_t *curr = steque_front(&g_join_steque);
      sigprocmask(SIG_UNBLOCK, &vtalrm, NULL);
      
      if(gtthread_equal(*self, *curr)) {
        steque_pop(&g_join_steque);
        break;
      }
      if(steque_size(&g_join_steque) > 0) {
        sigprocmask(SIG_BLOCK, &vtalrm, NULL);
        steque_cycle(&g_join_steque);
        sigprocmask(SIG_UNBLOCK, &vtalrm, NULL);
      }
    }
  }
  
  return 0;
}