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; }
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; }
/* 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; }
void* thr2(void *in) { if(gtthread_equal(gtthread_self(), t1)) { printf("Failure.\n"); } else { printf("Success\n"); } return NULL; }
void* thr(void *in) { if(gtthread_equal(gtthread_self(), t)) { printf("Success"); } else { printf("Failure"); } return NULL; }
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; }
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; }
void* worker(void* arg) { gtthread_t tid = gtthread_self(); if(gtthread_equal(g_th2, tid)) printf("same\n"); else printf("diff\n"); }
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, >t, sizeof(gtt)); return ret; }
void thread2fn() { if(gtthread_equal(*thread1, gtthread_self()) != 0) { fprintf(stderr, "\nSame"); } else { fprintf(stderr, "\nDiff"); } }
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; }
/* 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; }
/** * 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); }
/* 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; }
/* 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; }