void test_crt_join_sched(void) { lwt_t chld1, chld2; printf("[TEST] thread creation/join/scheduling\n"); /* functional tests: scheduling */ lwt_yield(LWT_NULL); lwt_chan_t c1 = lwt_chan(0); chld1 = lwt_create(fn_sequence, (void*)1, 0, c1); lwt_chan_t c2 = lwt_chan(0); chld2 = lwt_create(fn_sequence, (void*)2, 0, c2); lwt_join(chld2); lwt_join(chld1); IS_RESET(); /* functional tests: join */ lwt_chan_t c3 = lwt_chan(0); chld1 = lwt_create(fn_null, NULL, 0, c3); lwt_join(chld1); IS_RESET(); lwt_chan_t c4 = lwt_chan(0); chld1 = lwt_create(fn_null, NULL, 0, c4); lwt_yield(LWT_NULL); lwt_join(chld1); IS_RESET(); lwt_chan_t c5 = lwt_chan(0); chld1 = lwt_create(fn_nested_joins, NULL, 0, c5); lwt_join(chld1); IS_RESET(); /* functional tests: join only from parents */ lwt_chan_t c6 = lwt_chan(0); chld1 = lwt_create(fn_identity, (void*)0x37337, 0, c6); lwt_chan_t c7 = lwt_chan(0); chld2 = lwt_create(fn_join, chld1, 0, c7); lwt_yield(LWT_NULL); lwt_yield(LWT_NULL); lwt_join(chld2); lwt_join(chld1); IS_RESET(); /* functional tests: passing data between threads */ lwt_chan_t c8 = lwt_chan(0); chld1 = lwt_create(fn_identity, (void*)0x37337, 0, c8); assert((void*)0x37337 == lwt_join(chld1)); IS_RESET(); /* functional tests: directed yield */ lwt_chan_t c9 = lwt_chan(0); chld1 = lwt_create(fn_null, NULL, 0, c9); lwt_yield(chld1); assert(lwt_info(LWT_INFO_NTHD_ZOMBIES) == 1); lwt_join(chld1); IS_RESET(); }
void test_speed_yield() { lwt_t tid1, tid2; tid1 = lwt_create(fn_bounce, (void*)1, 0, 0); tid2 = lwt_create(fn_bounce, NULL, 0, 0); lwt_yield(LWT_NULL); lwt_join(tid1); lwt_join(tid2); lwt_yield(LWT_NULL); IS_RESET(); }
void test_function_basic() { lwt_t id; IS_RESET(); id = lwt_create(fn_nested_create, 0, 0, 0); lwt_yield(LWT_NULL); printf("join in parent\n"); lwt_join(id); lwt_yield(LWT_NULL); IS_RESET(); }
void * fn_nested_joins(void *d) { lwt_t chld; if (d) { lwt_yield(LWT_NULL); lwt_yield(LWT_NULL); assert(lwt_info(LWT_INFO_NTHD_RUNNABLE) == 1); lwt_die(NULL); } chld = lwt_create(fn_nested_joins, (void*)1); lwt_join(chld); }
void test_crt_join_sched(void) { lwt_t chld1, chld2; /* functional tests: scheduling */ lwt_yield(LWT_NULL); chld1 = lwt_create(fn_sequence, (void*)1); chld2 = lwt_create(fn_sequence, (void*)2); lwt_join(chld2); lwt_join(chld1); IS_RESET(); /* functional tests: join */ chld1 = lwt_create(fn_null, NULL); lwt_join(chld1); IS_RESET(); chld1 = lwt_create(fn_null, NULL); lwt_yield(LWT_NULL); lwt_join(chld1); IS_RESET(); chld1 = lwt_create(fn_nested_joins, NULL); lwt_join(chld1); IS_RESET(); /* functional tests: join only from parents */ chld1 = lwt_create(fn_identity, (void*)0x37337); chld2 = lwt_create(fn_join, chld1); lwt_yield(LWT_NULL); lwt_yield(LWT_NULL); lwt_join(chld2); lwt_join(chld1); IS_RESET(); /* functional tests: passing data between threads */ chld1 = lwt_create(fn_identity, (void*)0x37337); assert((void*)0x37337 == lwt_join(chld1)); IS_RESET(); /* functional tests: directed yield */ chld1 = lwt_create(fn_null, NULL); lwt_yield(chld1); assert(lwt_info(LWT_INFO_NTHD_ZOMBIES) == 1); lwt_join(chld1); IS_RESET(); }
/** * @brief Creates a LWT using the provided function pointer and the data as input for it * @param fn The function pointer to use * @param data The data to the function * @param flags The flags to be associated with the thread * @return A pointer to the initialized LWT */ lwt_t lwt_create(lwt_fnt_t fn, void * data, lwt_flags_t flags){ //wait until there's a free thread while(!head_ready_pool_threads.lh_first){ lwt_yield(LWT_NULL); } //pop the head of the ready pool list lwt_t thread = head_ready_pool_threads.lh_first; LIST_REMOVE(thread, ready_pool_threads); //set thread's parent thread->parent = current_thread; //insert into parent's siblings LIST_INSERT_HEAD(¤t_thread->head_children, thread, siblings); //set status thread->info = LWT_INFO_NTHD_RUNNABLE; thread->start_routine = fn; thread->args = data; thread->flags = flags; //associate with kthd lwt_kthd_t pthread_kthd = __get_kthd(); thread->kthd = pthread_kthd; LIST_INSERT_HEAD(&pthread_kthd->head_lwts_in_kthd, thread, lwts_in_kthd); //insert into runnable list __insert_runnable_tail(thread); return thread; }
void* fn_nested_create(void* data, lwt_chan_t c) { int param = (int)data; lwt_t id; if(param< 5) { printf("create: %d\n", param); id = lwt_create(fn_nested_create, (void*)(param+1), 0, 0); lwt_yield(id); printf("join: %d\n", param); lwt_join(id); } lwt_yield(LWT_NULL); return NULL; }
void * fn_bounce(void *d) { int i; unsigned long long start, end; lwt_yield(LWT_NULL); lwt_yield(LWT_NULL); rdtscll(start); for (i = 0 ; i < ITER ; i++) lwt_yield(LWT_NULL); rdtscll(end); lwt_yield(LWT_NULL); lwt_yield(LWT_NULL); if (!d) printf("Overhead of yield is %lld\n", (end-start)/(ITER*2)); return NULL; }
int test_nojoin() { lwt_create(fn, NULL, LWT_FLAG_NOJOIN, NULL); assert(num_of_threads == 2); lwt_yield(_LWT_NULL); assert(num_of_threads == 1); return 0; }
void* fn_bounce(void* data, lwt_chan_t c) { int i=0; unsigned long long int start, end; lwt_yield(LWT_NULL); rdtscll(start); for(i=0 ; i < ITER; i++) { lwt_yield(LWT_NULL); } rdtscll(end); if((int)data == 1) printf("performance of yield: --> %lld\n", (end-start)/(ITER*2)); return NULL; }
/** * @brief Prepares the current thread to be cleaned up */ void lwt_die(void * value){ current_thread->return_value = value; //check to see if we can return while(current_thread->head_children.lh_first){ current_thread->info = LWT_INFO_NTHD_BLOCKED; lwt_yield(LWT_NULL); } //remove from parent thread if(current_thread->parent){ LIST_REMOVE(current_thread, siblings); //check if parent can be unblocked if(!current_thread->parent->head_children.lh_first && current_thread->parent->info == LWT_INFO_NTHD_BLOCKED){ lwt_signal(current_thread->parent); } } //reset thread as ready in the thread pool if(current_thread->flags == LWT_NOJOIN){ __reinit_lwt(current_thread); } else{ //change status to zombie current_thread->info = LWT_INFO_NTHD_ZOMBIES; } //remove from kthd if(current_thread->kthd){ LIST_REMOVE(current_thread, lwts_in_kthd); //signal the original thread to die if this is the last thread if(!current_thread->kthd->head_lwts_in_kthd.lh_first){ lwt_signal(original_thread); } } //switch to another thread lwt_yield(LWT_NULL); }
void * fn_sequence(void *d) { int i, other, val = (int)d; for (i = 0 ; i < ITER ; i++) { other = curr; curr = (curr + 1) % 2; sched[curr] = val; assert(sched[other] != val); lwt_yield(LWT_NULL); } return NULL; }
int main(int argc, char** argv) { // printf("testing grp_wait...\n"); // test_grp_wait_with_buffer(); // test_nojoin(); test_kthd(); //test_kthd_iter(); printf("back to main\n"); sleep(1); lwt_yield(_LWT_NULL); return EXIT_SUCCESS; }
void * fn_grpwait(lwt_chan_t c) { int i; for (i = 0 ; i < ITER ; i++) { if ((i % 7) == 0) { int j; for (j = 0 ; j < (i % 8) ; j++) lwt_yield(LWT_NULL); } lwt_snd(c, (void*)lwt_id(lwt_current())); } lwt_chan_deref(c); }
/* #define IS_RESET() \ assert( lwt_info(LWT_INFO_NTHD_RUNNABLE) == 1 && \ lwt_info(LWT_INFO_NTHD_ZOMBIES) == 0 && \ lwt_info(LWT_INFO_NTHD_BLOCKED) == 0) */ int main(void) { lwt_t chld1, chld2; int i; unsigned long long start, end; /* Performance tests */ rdtscll(start); for (i = 0 ; i < ITER ; i++) { chld1 = lwt_create(fn_null, NULL); lwt_join(chld1); } rdtscll(end); printf("Overhead for fork/join is %lld\n", (end-start)/ITER); //IS_RESET(); chld1 = lwt_create(fn_bounce, NULL); chld2 = lwt_create(fn_bounce, NULL); lwt_join(chld1); lwt_join(chld2); //IS_RESET(); /* functional tests: scheduling */ lwt_yield(LWT_NULL); chld1 = lwt_create(fn_sequence, (void*)1); chld2 = lwt_create(fn_sequence, (void*)2); lwt_join(chld2); lwt_join(chld1); //IS_RESET(); /* functional tests: join */ chld1 = lwt_create(fn_null, NULL); lwt_join(chld1); //IS_RESET(); chld1 = lwt_create(fn_null, NULL); lwt_yield(LWT_NULL); lwt_join(chld1); //IS_RESET(); chld1 = lwt_create(fn_nested_joins, NULL); lwt_join(chld1); //IS_RESET(); /* functional tests: join only from parents */ chld1 = lwt_create(fn_identity, (void*)0x37337); chld2 = lwt_create(fn_join, chld1); lwt_yield(LWT_NULL); lwt_yield(LWT_NULL); lwt_join(chld2); lwt_join(chld1); //IS_RESET(); /* functional tests: passing data between threads */ chld1 = lwt_create(fn_identity, (void*)0x37337); //TODO assert((void*)0x37337 == lwt_join(chld1)); //IS_RESET(); /* functional tests: directed yield */ chld1 = lwt_create(fn_null, NULL); lwt_yield(chld1); //assert(lwt_info(LWT_INFO_NTHD_ZOMBIES) == 1); lwt_join(chld1); //IS_RESET(); //TODO assert(thd_cnt == ITER+12); }
/** * @brief Blocks the current thread * @param info The state to set the thread */ void lwt_block(lwt_info_t info){ //ensure info isn't LWT_INFO_NRUNNING assert(info != LWT_INFO_NTHD_RUNNABLE); current_thread->info = info; lwt_yield(LWT_NULL); }
/** * @brief Cleans up all remaining threads on exit */ __attribute__((destructor)) void __destroy__(){ lwt_kthd_t pthread_kthd = __get_kthd(); //clean up buffer thread if(pthread_kthd->buffer_thread){ free(pthread_kthd->buffer_thread); } //free threads lwt_t current = head_current.lh_first; lwt_t next = NULL; lwt_chan_t rcv_channels = NULL; lwt_chan_t next_channel = NULL; //check for no-joined threads and switch to them to let them die while(current){ next = current->current_threads.le_next; if(current->flags == LWT_NOJOIN){ lwt_yield(current); } current = next; } current = head_current.lh_first; next = NULL; while(current){ next = current->current_threads.le_next; //remove any channels rcv_channels = current->head_receiver_channel.lh_first; while(rcv_channels){ next_channel = rcv_channels->receiver_channels.le_next; //free buffer if(rcv_channels->async_buffer){ free(rcv_channels->async_buffer); } //free group lwt_cgrp_t group = rcv_channels->channel_group; if(group && group->creator_thread == current){ //free the buffer while(group->head_event.tqh_first){ TAILQ_REMOVE(&group->head_event, group->head_event.tqh_first, events); } free(group); } free(rcv_channels); rcv_channels = next_channel; } if(current != original_thread){ //printf("FREEING STACK!!\n"); //remove stack __lwt_stack_return(current->min_addr_thread_stack); free(current); } current = next; } //free original thread free(original_thread); //free kthd pthread_cond_destroy(&pthread_kthd->blocked_cv); pthread_mutex_destroy(&pthread_kthd->blocked_mutex); free(pthread_kthd); pthread_exit(0); }