int mypthread_join(mypthread_t thread, void **retval) { kargs *tempargs; tempargs = (kargs *)malloc(sizeof(kargs)); tempargs->thread = thread; tempargs->kmode = 2; mythread_scheduler((void *)tempargs); /* //sem_wait(&sem_main); int target_thread_id = thread.pthread->thread_id; mypthread_t *current_thread = search_thread(mythread_q,cur_thread_id); mypthread_t *target_thread = search_thread(mythread_q,target_thread_id); if (target_thread->pthread->thread_state != PS_ACTIVE) { //sem_post(&sem_main); return 0; } else { current_thread->pthread->thread_state = PS_BLOCKED; target_thread->pthread->joined_from_th = cur_thread_id; cur_thread_id = target_thread_id; //sem_post(&sem_main); swapcontext(current_thread->pthread->ucontext, target_thread->pthread->ucontext); } */ return 0; }
int mypthread_yield(void) { mypthread_t thread; kargs *tempargs; tempargs = (kargs *)malloc(sizeof(kargs)); tempargs->thread = thread; tempargs->kmode = 3; mythread_scheduler((void *)tempargs); /* //sem_wait(&sem_main); printf("Inside thread yield\n"); mypthread_t *current_thread = search_thread(mythread_q, cur_thread_id); mypthread_t *next_thread = next_active_thread(mythread_q); printf("Current thread id = %d , next thread id = %d\n", cur_thread_id, next_thread->pthread->thread_id); if (cur_thread_id == next_thread->pthread->thread_id) { //sem_post(&sem_main); return 0; } printf("Thread %d Yielding\n",cur_thread_id); cur_thread_id = next_thread->pthread->thread_id; // sem_post(&sem_main); swapcontext(current_thread->pthread->ucontext, next_thread->pthread->ucontext); */ return 0; }
int mythread_leave_kernel(){ mythread_t self = mythread_self(); repeat: if(self->reschedule == 1){ self->reschedule = 0; /* Reschedule here*/ if(mythread_readyq()!=NULL && self->attr.attr == 0){ /*The threads time is up and since there's some thread waiting in readyq, it needs to preempt itself */ mythread_scheduler(); } else{ /*If Ready queue is empty or time is not up, continue executing */ mythread_leave_kernel_nonpreemptive(); } } else{ mythread_leave_kernel_nonpreemptive(); } /* Check again in case of a rescheduling since leaving kernel */ if(self->reschedule == 1){ mythread_enter_kernel(); goto repeat; } return 0; }
void mypthread_exit(void *retval) { mypthread_t thread; kargs *tempargs; tempargs = (kargs *)malloc(sizeof(kargs)); tempargs->thread = thread; tempargs->kmode = 1; mythread_scheduler((void *)tempargs); /* //sem_wait(&sem_main); mypthread_t* cur_thread = search_thread(mythread_q, cur_thread_id); cur_thread->pthread->thread_state = PS_DEAD; free(cur_thread->pthread->ucontext); if (cur_thread->pthread->joined_from_th != 0) { mypthread_t *join_thread = search_thread(mythread_q,cur_thread->pthread->joined_from_th); join_thread->pthread->thread_state = PS_ACTIVE; } mypthread_t* next_thread = return_head(mythread_q); cur_thread_id = next_thread->pthread->thread_id; //sem_post(&sem_main); setcontext(next_thread->pthread->ucontext); */ return; }
int ksched(void *args) { while (next_active_thread(mythread_q) != NULL) { sem_wait(&sem_kern); mythread_scheduler(args); sem_post(&sem_kern); } }
/* * Helper function that creates mykthread_t node and executes next active user thread from runnable queue */ int schedule_kthread() { mykthread_t *k_th = (mykthread_t *) malloc(sizeof(mykthread_t)); k_th->kth_id = gettid(); //This value will be populated by mythread_scheduler k_th->th = NULL; //Add to the kthread list mykthread_add(k_th); mythread_scheduler(k_th, 0); return 0; }
/* * Functionality for pthread_join() */ int mypthread_join(mypthread_t thread, void **retval) { //Search for target thread sem_wait(&mypthread_sem); mypthread_t* target_thread = mypthread_get(thread.th_id); sem_wait(&kthread_sem); mykthread_t* current_kthread = mykthread_get(gettid()); sem_post(&kthread_sem); sem_post(&mypthread_sem); if (target_thread == NULL) { if (mykthread_is_running(thread.th_id)) { // Thread is currently running by some other kthread //Change status of the current thread and run next active thread current_kthread->th->state = PS_WAITING; current_kthread->th->dependent_th = thread.th_id; sem_wait(&mypthread_sem); mypthread_enqueue(current_kthread->th); sem_post(&mypthread_sem); //Swap context to the next active thread mythread_scheduler(current_kthread, 1); return 0; } else { //Immediately return if no thread is waiting return 0; } } else { if (target_thread->state != PS_DEAD) { //Current thread is currently waiting due to other thread //Change status of the current thread and run next active thread current_kthread->th->state = PS_WAITING; current_kthread->th->dependent_th = thread.th_id; sem_wait(&mypthread_sem); mypthread_enqueue(current_kthread->th); sem_post(&mypthread_sem); //Swap context to the next active thread mythread_scheduler(current_kthread, 1); return 0; } else { //No need to wait. Immediately return return 0; } } }
/* * Functionality for pthread_yield() */ int mypthread_yield(void) { //get current thread and change the status to PS_ACTIVE mykthread_t* current_kthread = mykthread_get(gettid()); current_kthread->th->state = PS_ACTIVE; sem_wait(&mypthread_sem); mypthread_enqueue(current_kthread->th); sem_post(&mypthread_sem); //Swap context to next runnable thread mythread_scheduler(current_kthread, 1); return 0; }
/* * Functionality for pthread_exit() */ void mypthread_exit(void *retval) { //First get the current executing kthread mykthread_t* current_kthread = mykthread_get(gettid()); //First make all other waiting threads active sem_wait(&mypthread_sem); mypthread_count--; current_kthread->th->state = PS_DEAD; mypthread_update_waiting_threads(current_kthread->th->th_id); sem_post(&mypthread_sem); //Free pthread free(current_kthread->th->ctx); //Just destroy the mypthread node and run the next active thread mythread_scheduler(current_kthread, 0); }
/* * Functionality for pthread_cond_wait() */ int mypthread_cond_wait(mypthread_cond_t *cond, mypthread_mutex_t *mutex) { sem_wait(&cond_sem); //Unblock all threads locked by mutex mypthread_mutex_unlock(mutex); //Make the current thread wait for the signal mykthread_t* current_kthread = mykthread_get(gettid()); current_kthread->th->state = PS_BLOCKED; ll_add(current_kthread->th, &(cond->cond_q_head), &(cond->cond_q_tail)); sem_wait(&mypthread_sem); mypthread_enqueue(current_kthread->th); sem_post(&mypthread_sem); sem_post(&cond_sem); mythread_scheduler(current_kthread, 1); mypthread_mutex_lock(mutex); return 0; }
/* * Functionality for pthread_mutex_lock() */ int mypthread_mutex_lock(mypthread_mutex_t *mutex) { sem_wait(&mutex_sem); if (!(mutex->lock)) { mutex->lock = true; sem_post(&mutex_sem); } else { mykthread_t* current_kthread = mykthread_get(gettid()); //No need to acquire mypthread_lock as the mypthread_t are not in the run queue current_kthread->th->state = PS_BLOCKED; ll_add(current_kthread->th, &(mutex->blocked_q_head), &(mutex->blocked_q_tail)); //This will ensure that when the blocked thread becomes runnable, it executes the mutex lock logic again makecontext(current_kthread->th->ctx, (void (*)()) mypthread_mutex_lock, 1, mutex); sem_wait(&mypthread_sem); mypthread_enqueue(current_kthread->th); sem_post(&mypthread_sem); sem_post(&mutex_sem); //Set context to the next active thread mythread_scheduler(current_kthread, 0); } return 0; }