Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <assert.h>
- #include <stdlib.h>
- #include <ucontext.h>
- #include "thread.h"
- #include "interrupt.h"
- #include <stdbool.h>
- //Struct
- /* This is the wait queue structure */
- struct wait_queue {
- struct thread* wait_info;
- struct wait_queue* next;
- };
- /* This is the thread control block */
- struct thread {
- ucontext_t* thread_context;
- Tid thread_id;
- bool kill_status;
- };
- /* This is the ready queue structure */
- struct ready_queue {
- struct thread* thread_info;
- struct ready_queue* next;
- };
- //Globals
- int thread_tracker[THREAD_MAX_THREADS];
- struct thread* current_thread;
- struct ready_queue* ready_q;
- struct ready_queue* exit_q;
- //Functions
- void insert_ready_queue(struct ready_queue* new_node);
- void exit_queue(struct ready_queue* new_node);
- void destroy_exit_q();
- void insert_wait_queue(struct wait_queue* wq,struct wait_queue* new_node);
- void
- thread_init(void) {
- //initialize array of threads that keeps track of all thread id's and kill status in particular
- for (int i = 0; i < THREAD_MAX_THREADS; i++) {
- thread_tracker[i] = 0;
- }
- //initialize exit queue
- exit_q = (struct ready_queue*) malloc(sizeof (struct ready_queue));
- exit_q->next = NULL;
- exit_q->thread_info = NULL;
- //initialize ready queue
- ready_q = (struct ready_queue*) malloc(sizeof (struct ready_queue));
- ready_q->next = NULL;
- ready_q->thread_info = NULL;
- //set the current_thread id to 0
- current_thread = (struct thread*) malloc(sizeof (struct thread));
- current_thread->thread_context = (ucontext_t*) malloc(sizeof (ucontext_t));
- current_thread->thread_id = 0;
- current_thread->kill_status = false;
- thread_tracker[0] = 1;
- }
- void
- thread_stub(void (*thread_main)(void *), void *arg) {
- interrupts_set(1);
- thread_main(arg);
- thread_exit();
- }
- /*This function returns the thread identifier of the currently running thread*/
- Tid
- thread_id() {
- return current_thread->thread_id;
- }
- /*This function creates a thread*/
- Tid
- thread_create(void (*fn) (void *), void *parg) {
- int enabled = interrupts_set(0);
- assert(!interrupts_enabled());
- //search the array to find an id that is usable
- int free_id = 0;
- while (free_id < THREAD_MAX_THREADS && thread_tracker[free_id] != 0) {
- free_id++;
- if (free_id == THREAD_MAX_THREADS) {
- interrupts_set(enabled);
- return THREAD_NOMORE;
- }
- }
- //no space to create more threads
- if (free_id == 0) {
- interrupts_set(enabled);
- return THREAD_NOMORE;
- }
- //create the new thread
- struct thread* new_thread = (struct thread*) malloc(sizeof (struct thread));
- if (new_thread == NULL) {
- interrupts_set(enabled);
- return THREAD_NOMEMORY;
- }
- new_thread->thread_context = (ucontext_t*) malloc(sizeof (ucontext_t));
- if (new_thread == NULL) {
- interrupts_set(enabled);
- return THREAD_NOMEMORY;
- }
- assert(!interrupts_enabled());
- getcontext(new_thread->thread_context);
- new_thread->thread_id = free_id;
- thread_tracker[free_id] = 1;
- //initialize the thread context
- new_thread->thread_context->uc_mcontext.gregs[REG_RIP] = (unsigned long) &thread_stub;
- void* new_stack = (void*) malloc(THREAD_MIN_STACK);
- if (new_stack == NULL) {
- interrupts_set(enabled);
- return THREAD_NOMEMORY;
- }
- new_thread->thread_context->uc_stack.ss_sp = new_stack;
- new_thread->thread_context->uc_stack.ss_size = THREAD_MIN_STACK;
- new_thread->thread_context->uc_mcontext.gregs[REG_RSP] = (unsigned long) (new_stack + THREAD_MIN_STACK + 8);
- new_thread->thread_context->uc_mcontext.gregs[REG_RDI] = (unsigned long) fn;
- new_thread->thread_context->uc_mcontext.gregs[REG_RSI] = (unsigned long) parg;
- new_thread->kill_status = false;
- //insert it into the ready queue
- struct ready_queue* queue_new_thread;
- queue_new_thread = (struct ready_queue*) malloc(sizeof (struct ready_queue));
- queue_new_thread->next = NULL;
- queue_new_thread->thread_info = new_thread;
- insert_ready_queue(queue_new_thread);
- interrupts_set(enabled);
- return free_id;
- }
- /*This function suspends the caller and activates the thread given by the identifier tid*/
- Tid
- thread_yield(Tid want_tid) {
- int enabled = interrupts_set(0);
- assert(!interrupts_enabled());
- if(exit_q->next!=NULL){
- destroy_exit_q();
- }
- if (want_tid == THREAD_SELF) {
- interrupts_set(enabled);
- return current_thread->thread_id;
- }
- if (current_thread->thread_id == want_tid) {
- interrupts_set(enabled);
- return current_thread->thread_id;
- }
- if (want_tid<-2 || want_tid >= THREAD_MAX_THREADS) {
- interrupts_set(enabled);
- return THREAD_INVALID;
- }
- if (thread_tracker[want_tid] == 0 && want_tid != THREAD_ANY) {
- interrupts_set(enabled);
- return THREAD_INVALID;
- }
- if (want_tid == THREAD_ANY) {
- if (ready_q->next == NULL) {
- interrupts_set(enabled);
- return THREAD_NONE;
- }
- }
- if (want_tid == THREAD_ANY) {
- assert(!interrupts_enabled());
- //get the next thread to run
- struct ready_queue* next_node = ready_q->next;
- ready_q->next = ready_q->next->next;
- next_node->next = NULL;
- //add the current thread to the ready queue
- struct thread* next_thread = next_node->thread_info;
- volatile int next_node_id = next_node->thread_info->thread_id;
- next_node->thread_info = current_thread;
- current_thread = next_thread;
- insert_ready_queue(next_node);
- //setcontext of the next thread
- volatile int setcontext_called = 0;
- getcontext(next_node->thread_info->thread_context);
- if (setcontext_called) {
- int enabled = interrupts_set(0);
- if (exit_q->next != NULL) {
- destroy_exit_q();
- }
- if (current_thread->kill_status == 1) {
- thread_exit();
- }
- interrupts_set(enabled);
- return next_node_id;
- //return want_tid;
- }
- setcontext_called = 1;
- setcontext(current_thread->thread_context);
- }
- else {
- //looking for the specific thread to run in ready_queue
- struct ready_queue* next_node = ready_q->next;
- struct ready_queue* prev_node = ready_q;
- while (next_node != NULL && next_node->thread_info->thread_id != want_tid) {
- prev_node = next_node;
- next_node = next_node->next;
- }
- prev_node->next = next_node->next;
- next_node->next = NULL;
- //add the current thread to the ready queue
- struct thread* next_thread = next_node->thread_info;
- volatile int next_node_id = next_node->thread_info->thread_id;
- next_node->thread_info = current_thread;
- current_thread = next_thread;
- insert_ready_queue(next_node);
- //setcontext of the next thread
- volatile int setcontext_called = 0;
- getcontext(next_node -> thread_info -> thread_context);
- if (setcontext_called) {
- int enabled = interrupts_set(0);
- if (exit_q->next != NULL) {
- destroy_exit_q();
- }
- if (current_thread->kill_status == 1) {
- thread_exit();
- }
- interrupts_set(enabled);
- return next_node_id;
- //return want_tid;
- }
- setcontext_called = 1;
- setcontext(current_thread->thread_context);
- }
- interrupts_set(enabled);
- return THREAD_FAILED;
- }
- void
- thread_exit() {
- //int enabled = interrupts_off();
- //assert(!interrupts_enabled());
- //exit the current thread
- if (ready_q->next == NULL) {
- //interrupts_set(enabled);
- exit(0);
- } else {
- struct ready_queue* next_node;
- next_node = ready_q->next;
- ready_q->next = ready_q->next->next;
- next_node->next = NULL;
- struct thread* next_thread = next_node->thread_info;
- next_node->thread_info = current_thread;
- current_thread = next_thread;
- exit_queue(next_node);
- setcontext(current_thread->thread_context);
- //interrupts_set(enabled);
- }
- }
- Tid
- thread_kill(Tid tid) {
- int enabled = interrupts_off();
- assert(!interrupts_enabled());
- if (tid == THREAD_SELF) {
- interrupts_set(enabled);
- return THREAD_INVALID;
- }if (current_thread->thread_id == tid) {
- interrupts_set(enabled);
- return THREAD_INVALID;
- }if (tid < 0 || tid >= THREAD_MAX_THREADS) {
- interrupts_set(enabled);
- return THREAD_INVALID;
- }if (thread_tracker[tid] == 0) {
- interrupts_set(enabled);
- return THREAD_INVALID;
- }else{
- struct ready_queue* kill_node = ready_q->next;
- while (kill_node != NULL && kill_node->thread_info->thread_id != tid) {
- kill_node = kill_node->next;
- }
- kill_node->thread_info->kill_status=1;
- }
- interrupts_set(enabled);
- return tid;
- }
- /*******************************************************************
- * Important: The rest of the code should be implemented in Lab 3. *
- *******************************************************************/
- /* make sure to fill the wait_queue structure defined above */
- struct wait_queue *
- wait_queue_create() {
- struct wait_queue *wq;
- wq = malloc(sizeof (struct wait_queue));
- assert(wq);
- //initialize wait_queue
- wq->wait_info=NULL;
- wq->next=NULL;
- return wq;
- }
- void
- wait_queue_destroy(struct wait_queue *wq) {
- TBD();
- free(wq);
- }
- Tid
- thread_sleep(struct wait_queue *queue) {
- if(queue==NULL){
- return THREAD_INVALID;
- }
- if(ready_q->next==NULL){
- return THREAD_NONE;
- }
- //get the next thread to run
- struct ready_queue* next_node = ready_q->next;
- ready_q->next = ready_q->next->next;
- next_node->next = NULL;
- struct thread* next_thread=next_node->thread_info;
- free(next_node);
- //add the current thread to the wait_queue
- struct wait_queue* new_node=(struct wait_queue*)malloc(sizeof (struct wait_queue));
- new_node->wait_info=next_thread;
- new_node->next=NULL;
- current_thread = next_thread;
- insert_wait_queue(queue,new_node);
- //setcontext of the next thread
- volatile int setcontext_called = 0;
- getcontext(next_node -> thread_info -> thread_context);
- if (setcontext_called) {
- return current_thread->thread_id;
- }
- setcontext_called = 1;
- setcontext(current_thread->thread_context);
- return current_thread->thread_id;
- }
- /* when the 'all' parameter is 1, wakeup all threads waiting in the queue.
- * returns whether a thread was woken up on not. */
- int
- thread_wakeup(struct wait_queue *queue, int all) {
- if(queue==NULL||queue->next==NULL){
- return 0;
- }
- if(all==1){
- int threads_awake=0;
- while (queue != NULL){
- threads_awake+=1;
- struct wait_queue* run_node=queue->next;
- queue->next=queue->next->next;
- struct thread* new_thread=run_node->wait_info;
- run_node->next=NULL;
- free(run_node);
- struct ready_queue* new_node=(struct ready_queue*)malloc(sizeof(struct ready_queue));
- new_node->thread_info=new_thread;
- new_node->next=NULL;
- insert_ready_queue(new_node);
- }
- return threads_awake;
- }else{
- //get the next thread in the wait queue
- struct wait_queue* next_node = queue->next;
- queue->next = queue->next->next;
- next_node->next = NULL;
- struct thread* new_thread=next_node->wait_info;
- free(next_node);
- //add it to the ready queue
- struct ready_queue* new_node=(struct ready_queue*)malloc(sizeof(struct ready_queue));
- new_node->thread_info=new_thread;
- new_node->next=NULL;
- insert_ready_queue(new_node);
- return 1;
- }
- return 0;
- }
- /* suspend current thread until Thread tid exits */
- Tid
- thread_wait(Tid tid) {
- TBD();
- return 0;
- }
- struct lock {
- /* ... Fill this in ... */
- };
- struct lock *
- lock_create() {
- struct lock *lock;
- lock = malloc(sizeof (struct lock));
- assert(lock);
- TBD();
- return lock;
- }
- void
- lock_destroy(struct lock *lock) {
- assert(lock != NULL);
- TBD();
- free(lock);
- }
- void
- lock_acquire(struct lock *lock) {
- assert(lock != NULL);
- TBD();
- }
- void
- lock_release(struct lock *lock) {
- assert(lock != NULL);
- TBD();
- }
- struct cv {
- /* ... Fill this in ... */
- };
- struct cv *
- cv_create() {
- struct cv *cv;
- cv = malloc(sizeof (struct cv));
- assert(cv);
- TBD();
- return cv;
- }
- void
- cv_destroy(struct cv *cv) {
- assert(cv != NULL);
- TBD();
- free(cv);
- }
- void
- cv_wait(struct cv *cv, struct lock *lock) {
- assert(cv != NULL);
- assert(lock != NULL);
- TBD();
- }
- void
- cv_signal(struct cv *cv, struct lock *lock) {
- assert(cv != NULL);
- assert(lock != NULL);
- TBD();
- }
- void
- cv_broadcast(struct cv *cv, struct lock *lock) {
- assert(cv != NULL);
- assert(lock != NULL);
- TBD();
- }
- /*******************************************************************
- * Helper Functions Lab 2 *
- *******************************************************************/
- void exit_queue(struct ready_queue* new_node) {
- //if list is empty
- if (exit_q->next == NULL) {
- exit_q->next = new_node;
- } //list has elements
- else {
- struct ready_queue* iterator = exit_q;
- while (iterator->next != NULL) {
- iterator = iterator->next;
- }
- iterator->next = new_node;
- }
- }
- void insert_ready_queue(struct ready_queue* new_node) {
- if (ready_q->next == NULL) {
- ready_q->next = new_node;
- } //list has elements
- else {
- struct ready_queue* iterator;
- iterator = ready_q;
- while (iterator->next != NULL) {
- iterator = iterator->next;
- }
- iterator->next = new_node;
- }
- }
- void destroy_exit_q() {
- struct ready_queue* iterator = exit_q->next;
- while (iterator != NULL) {
- struct ready_queue* kill = iterator;
- iterator = iterator->next;
- exit_q->next = iterator;
- thread_tracker[kill->thread_info->thread_id] = 0;
- free(kill->thread_info->thread_context->uc_stack.ss_sp);
- free(kill->thread_info->thread_context);
- free(kill->thread_info);
- kill->next = NULL;
- free(kill);
- kill = NULL;
- }
- }
- /*******************************************************************
- * Helper Functions Lab 3 *
- *******************************************************************/
- void insert_wait_queue(struct wait_queue* wq,struct wait_queue* new_node) {
- //if list is empty
- if (wq->next == NULL) {
- wq->next = new_node;
- } //list has elements
- else {
- struct wait_queue* iterator = wq;
- while (iterator->next != NULL) {
- iterator = iterator->next;
- }
- iterator->next = new_node;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement