Пример #1
0
int gtthread_join(gtthread_t thread, void **status){
  int i = 0;
  steque_node_t* current;
  //TODO: No need to block and unblock signals?
  if (gtthread_equal(thread, gtthread_self())){
    printf("cannot join same thread\n");
    return -1;
  }

  //Searching for node with gtthread_t thread
  current = q->front;
  for (i = 0; (i < q->N); i++) {
    if(gtthread_equal(thread, ((node_t*)current -> item) -> id)) {
      break;
    }
    current = current -> next;
  }

  //Checking for canceled thread, blocking otherwise
  while (1){
    if (((node_t*)current -> item) -> canceled == 1){
      if(status != NULL){
        *status = ((node_t*)current -> item) -> returns;
      }
      break;
    }
    gtthread_yield();
  }     

  return 0;
}
Пример #2
0
void *func4(void *arg) {
	gtthread_t *t3_self = (gtthread_t*) arg;
	gtthread_t gtt = gtthread_self();
	int res = gtthread_equal(gtt, *t3_self);
	printf("Fourth test is not equal: %s\n", !res ? "correct" : "incorrect");
	return NULL;
}
Пример #3
0
/*
  The gtthread_cancel() function is analogous to pthread_cancel,
  allowing one thread to terminate another asynchronously.
 */
int gtthread_cancel(gtthread_t thread)
{
    /* if a thread cancel itself */
    if (gtthread_equal(current->tid, thread))
        gtthread_exit(0);

    sigprocmask(SIG_BLOCK, &vtalrm, NULL);
    thread_t* t = thread_get(thread);
    if (t == NULL)
    {
        sigprocmask(SIG_UNBLOCK, &vtalrm, NULL);    
        return -1;
    }
    if (t->state == GTTHREAD_DONE)
    {
        sigprocmask(SIG_UNBLOCK, &vtalrm, NULL); 
        return -1;
    }
    if (t->state == GTTHREAD_CANCEL)
    {
        sigprocmask(SIG_UNBLOCK, &vtalrm, NULL);  
        return -1;
    }
    else
        t->state = GTTHREAD_CANCEL;

    free(t->ucp->uc_stack.ss_sp);
    free(t->ucp);
    t->ucp = NULL;
    t->joining = 0;
    steque_enqueue(&zombie_queue, t);
    sigprocmask(SIG_UNBLOCK, &vtalrm, NULL);
    return 0;
}
Пример #4
0
void* thr2(void *in) {
  if(gtthread_equal(gtthread_self(), t1)) {
    printf("Failure.\n");
  } else {
    printf("Success\n");
  }
  return NULL;
}
Пример #5
0
void* thr(void *in) {
  if(gtthread_equal(gtthread_self(), t)) {
    printf("Success");
  } else {
    printf("Failure");
  }
  return NULL;
}
Пример #6
0
void *func2(void *arg) {
	gtt_tuple *tuple = (gtt_tuple*) arg;
	gtthread_yield(); // ensure that the tuple is set first
	gtthread_yield();
	gtthread_yield();
	int res = gtthread_equal(tuple->gtt1, tuple->gtt2);
	printf("Second test is not equal: %s\n", !res ? "correct" : "incorrect");
	return NULL;
}
Пример #7
0
void *func1(void *arg) {
	gtthread_t *gtt = (gtthread_t*) arg;
	gtthread_yield(); // ensure that the global is set first
	gtthread_yield();
	gtthread_yield();
	int res = gtthread_equal(g_gtt, *gtt);
	printf("First test is equal:      %s\n", res ? "correct" : "incorrect");
	return NULL;
}
Пример #8
0
void* worker(void* arg)
{
	gtthread_t tid = gtthread_self();

	if(gtthread_equal(g_th2, tid))
		printf("same\n");
	else
		printf("diff\n");
}
Пример #9
0
void *func3(void *arg) {
	gtthread_t gtt = gtthread_self();
	gtthread_yield(); // ensure that the global is set first
	gtthread_yield();
	gtthread_yield();
	int res = gtthread_equal(g_gtt, gtt);
	printf("Third test is equal:      %s\n", res ? "correct" : "incorrect");
	gtthread_t *ret = malloc(sizeof(gtt));
	memcpy(ret, &gtt, sizeof(gtt));
	return ret;
}
Пример #10
0
void thread2fn()
{
  
  if(gtthread_equal(*thread1, gtthread_self()) != 0)
  {
  	fprintf(stderr, "\nSame");
  }
  else
  {
 	fprintf(stderr, "\nDiff");
  }
}
Пример #11
0
int main() {
  printf("test4b. Should print 'Success'.\n");

  gtthread_init(50000L);
  gtthread_t t;
  gtthread_create( &t, thr, NULL);
  if(gtthread_equal(gtthread_self(), t)) {
    printf("Failure.");
  } else {
    printf("Success");
  }
  return EXIT_SUCCESS;
}
Пример #12
0
/*
  The gtthread_cancel() function is analogous to pthread_cancel,
  allowing one thread to terminate another asynchronously.
 */
int  gtthread_cancel(gtthread_t thread){
  int i = 0;
  steque_node_t* current = q->front;
  block_signal();
  if (gtthread_equal(thread, gtthread_self())){
    gtthread_exit((void*)GTTHREAD_CANCELED);
  }
  for (i = 0; (i < q->N); i++) {
    if(gtthread_equal(thread, ((node_t*)current -> item) -> id)) {
      if (((node_t*)current -> item) -> canceled == 1){
        return ESRCH;
      }
      else{
        ((node_t*)current -> item) -> canceled = 1;
        ((node_t*)current -> item) -> returns = (void*)GTTHREAD_CANCELED;
        break;
      }      
    }
    current = current -> next;
  }
  unblock_signal();
  return 0;
}
Пример #13
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);
}
Пример #14
0
/*
 The gtthread_cancel() function is analogous to pthread_cancel,
 allowing one thread to terminate another asynchronously.
*/
int gtthread_cancel(gtthread_t thread) {
  steque_enqueue(&g_cancelatorium, (void *) thread.id);
  if(gtthread_equal(thread, gtthread_self()))
    alarm_safe_yield();
  return 0;
}
Пример #15
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;
}