void lock_release(struct lock *lock) { assert(lock != NULL); int enabled = interrupts_set(0); lock->lock_state = 0; thread_wakeup(lock->queue, 1); interrupts_set(enabled); }
Tid thread_create(void (*fn) (void *), void *parg) { int enabled = interrupts_set(0); Tid new_id = assign_thread_id(); if (new_id < 0) return THREAD_NOMORE; struct thread *new_thread = (struct thread *) malloc(sizeof (struct thread)); if (new_thread == NULL) return THREAD_NOMEMORY; getcontext(&(new_thread->thread_context)); new_thread->tid = new_id; thread_id_array[new_id] = 1; new_thread->state = NEW_STATE; new_thread->next = NULL; new_thread->flag = 0; void *sp = malloc((THREAD_MIN_STACK + 16) / 16 * 16); if (sp == NULL) return THREAD_NOMEMORY; new_thread->sp = sp; new_thread->thread_context.uc_mcontext.gregs[15] = (unsigned long) (sp + THREAD_MIN_STACK - 8); new_thread->thread_context.uc_mcontext.gregs[REG_RBP] = (unsigned long) sp; 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->thread_context.uc_mcontext.gregs[REG_RIP] = (unsigned long) thread_stub; insert_thread_to_ready(new_thread); interrupts_set(enabled); return new_thread->tid; }
int main(int argc, char **argv) { int enabled; thread_init(); /* show interrupt handler output */ register_interrupt_handler(1); test(1); /* test interrupts_on/off/set */ enabled = interrupts_off(); assert(enabled); test(0); enabled = interrupts_off(); assert(!enabled); test(0); enabled = interrupts_set(1); assert(!enabled); test(1); enabled = interrupts_set(1); assert(enabled); test(1); exit(0); }
Tid thread_create(void (*fn) (void *), void *parg) { int enabled = interrupts_set(0); thread *current; current=first; /*int tc=tcounter(); if (tc+1>=THREAD_MAX_THREADS) return THREAD_NOMORE; */ while (current->next != NULL) { current=current->next; } current->next=malloc(sizeof(thread)); if (current->next == NULL) { interrupts_set(enabled); return THREAD_NOMEMORY; } current=current->next; current->id=id_calc(); current->state=READY; current->next=NULL; current->tcontext=(ucontext_t*)malloc(sizeof(ucontext_t)); if (current->tcontext == NULL) { interrupts_set(enabled); return THREAD_NOMEMORY; } void *sp=(void*)malloc(THREAD_MIN_STACK); if (sp == NULL) { interrupts_set(enabled); return THREAD_NOMEMORY; } getcontext(current->tcontext); current->tcontext->uc_mcontext.gregs[REG_RSP]=(unsigned long)(sp+THREAD_MIN_STACK-8); current->tcontext->uc_mcontext.gregs[REG_RIP]=(unsigned long)thread_stub; current->tcontext->uc_mcontext.gregs[REG_RDI]=(unsigned long)fn; current->tcontext->uc_mcontext.gregs[REG_RSI]=(unsigned long)parg; //printf("current id is %d\n",current->id); interrupts_set(enabled); return current->id; }
void lock_acquire(struct lock *lock) { assert(lock != NULL); int enabled = interrupts_set(0); while(lock->lock_state == 1) thread_sleep(lock->queue); lock->lock_state = 1; interrupts_set(enabled); }
Tid thread_id() { int enabled = interrupts_set(0); if (RUNNING_THREAD != NULL) { Tid id = RUNNING_THREAD->tid; interrupts_set(enabled); return id; } interrupts_set(enabled); return THREAD_INVALID; }
struct wait_queue * wait_queue_create() { int enabled = interrupts_set(0); struct wait_queue *wq; wq = malloc(sizeof(struct wait_queue)); assert(wq); wq->next=NULL; wq->dummy=0; interrupts_set(enabled); return wq; }
static void test_wakeup_thread(int num) { int i; int ret; struct timeval start, end, diff; for (i = 0; i < LOOPS; i++) { int enabled; gettimeofday(&start, NULL); /* track the number of sleeping threads with interrupts * disabled to avoid wakeup races. */ enabled = interrupts_off(); assert(enabled); __sync_fetch_and_add(&nr_sleeping, 1); ret = thread_sleep(queue); assert(thread_ret_ok(ret)); interrupts_set(enabled); gettimeofday(&end, NULL); timersub(&end, &start, &diff); /* thread_sleep should wait at least 4-5 ms */ if (diff.tv_sec == 0 && diff.tv_usec < 4000) { unintr_printf("%s took %ld us. That's too fast." " You must be busy looping\n", __FUNCTION__, diff.tv_usec); goto out; } } out: __sync_fetch_and_add(&done, 1); }
void thread_stub(void (*thread_main)(void *), void *arg) { interrupts_set(1); Tid ret; thread_main(arg); // call thread_main() function with arg ret = thread_exit(THREAD_SELF); assert(ret == THREAD_NONE); exit(0); }
Tid thread_exit(Tid tid) { int enabled = interrupts_set(0); if (tid == THREAD_SELF) { if (READY_HEAD == NULL) return THREAD_NONE; interrupts_enabled(0); struct thread *temp = RUNNING_THREAD; struct thread *new_run = READY_HEAD; READY_HEAD = READY_HEAD->next; temp->next = NULL; thread_id_array[temp->tid] = 0; insert_thread_to_delete(temp); new_run->next = NULL; new_run->state = RECOVER_STATE; RUNNING_THREAD = new_run; setcontext(&(new_run->thread_context)); } else if (tid == THREAD_ANY) { if (READY_HEAD == NULL) return THREAD_NONE; struct thread *temp = READY_HEAD; Tid returned_tid = temp->tid; temp->flag = 1; interrupts_set(enabled); return returned_tid; } else { if (tid > THREAD_MAX_THREADS - 1 || tid < THREAD_FAILED || !thread_id_array[tid]) return THREAD_INVALID; if (READY_HEAD == NULL) return THREAD_NONE; struct thread *temp = READY_HEAD; while (temp->tid != tid) temp = temp->next; Tid returned_tid = temp->tid; temp->flag = 1; interrupts_set(enabled); return returned_tid; } interrupts_set(enabled); return THREAD_FAILED; }
Tid thread_sleep(struct wait_queue *queue) { int enabled = interrupts_set(0); if (queue == NULL) { interrupts_set(enabled); return THREAD_INVALID; } else if (READY_HEAD == NULL) { interrupts_set(enabled); return THREAD_NONE; } else { struct thread *temp = READY_HEAD; READY_HEAD = READY_HEAD->next; temp->next = NULL; Tid returned_tid = temp->tid; insert_thread_to_wait(RUNNING_THREAD, queue); RUNNING_THREAD->state = NEW_STATE; getcontext(&(RUNNING_THREAD->thread_context)); if (RUNNING_THREAD->flag) thread_exit(THREAD_SELF); if (TO_DELETE_THREAD) delete_threads_list(); if (!thread_id_array[returned_tid]) { interrupts_set(enabled); return returned_tid; } if (temp->state == NEW_STATE && RUNNING_THREAD->state != RECOVER_STATE) { temp->state = RECOVER_STATE; RUNNING_THREAD = temp; setcontext(&(temp->thread_context)); } interrupts_set(enabled); return returned_tid; } interrupts_set(enabled); return THREAD_FAILED; }
/* 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) { int enabled = interrupts_set(0); if(queue == NULL){ interrupts_set(enabled); return 0; } else if(queue->wait_head == NULL){ interrupts_set(enabled); return 0; } else{ if(all == 0){ if(queue->size == 1){ insert_thread_to_ready(queue->wait_head); queue->wait_head = NULL; } else{ struct thread *temp = queue->wait_head; queue->wait_head = temp->next; temp->next = NULL; insert_thread_to_ready(temp); } interrupts_set(enabled); return 1; } else if(all == 1){ int size = queue->size; insert_thread_to_ready(queue->wait_head); queue->wait_head = NULL; queue->size = 0; interrupts_set(enabled); return size; } } interrupts_set(enabled); return 0; }
/* turn off interrupts while printing */ int unintr_printf(const char *fmt, ...) { int ret, enabled; va_list args; enabled = interrupts_off(); va_start(args, fmt); ret = vprintf(fmt, args); va_end(args); interrupts_set(enabled); return ret; }
Tid thread_exit(Tid tid) { int enabled = interrupts_set(0); thread *current; //thread *temp; current = first; if (tid==THREAD_ANY) { while(current->state != READY) { current=current->next; if (current==NULL) { interrupts_set(enabled); return THREAD_NONE; } } current->state=EXIT; int x=current->id; aid[x]=0; //make ID available current->id=-99; interrupts_set(enabled); return x; } if (first->next==NULL) { interrupts_set(enabled); return THREAD_NONE; } while ((current->id != tid)) { current=current->next; if (current==NULL) { interrupts_set(enabled); return THREAD_INVALID; } } current->state=EXIT; int x=current->id; aid[x]=0; current->id=-99; interrupts_set(enabled); return x; }
Tid thread_yield(Tid want_tid) { int enabled = interrupts_set(0); if (want_tid == THREAD_ANY) { if (READY_HEAD == NULL) { interrupts_set(enabled); return THREAD_NONE; } struct thread *temp = READY_HEAD; READY_HEAD = READY_HEAD->next; temp->next = NULL; Tid returned_tid = temp->tid; insert_thread_to_ready(RUNNING_THREAD); RUNNING_THREAD->state = NEW_STATE; getcontext(&(RUNNING_THREAD->thread_context)); if (RUNNING_THREAD->flag) thread_exit(THREAD_SELF); if (TO_DELETE_THREAD) delete_threads_list(); if (!thread_id_array[returned_tid]) { interrupts_set(enabled); return returned_tid; } if (temp->state == NEW_STATE && RUNNING_THREAD->state != RECOVER_STATE) { temp->state = RECOVER_STATE; RUNNING_THREAD = temp; setcontext(&(temp->thread_context)); } interrupts_set(enabled); return returned_tid; } else if (want_tid == THREAD_SELF || want_tid == RUNNING_THREAD->tid) { RUNNING_THREAD->state = NEW_STATE; getcontext(&(RUNNING_THREAD->thread_context)); if (RUNNING_THREAD->state == NEW_STATE) { RUNNING_THREAD->state = RECOVER_STATE; setcontext(&(RUNNING_THREAD->thread_context)); } interrupts_set(enabled); return RUNNING_THREAD->tid; } else if (want_tid > THREAD_MAX_THREADS - 1 || want_tid < THREAD_FAILED || !thread_id_array[want_tid]) { interrupts_set(enabled); return THREAD_INVALID; } else { struct thread *temp = READY_HEAD; struct thread *prev = READY_HEAD; while (temp->tid != want_tid) { prev = temp; temp = temp->next; } if (READY_HEAD->tid == want_tid) READY_HEAD = READY_HEAD->next; else prev->next = temp->next; temp->next = NULL; Tid returned_tid = temp->tid; insert_thread_to_ready(RUNNING_THREAD); RUNNING_THREAD->state = NEW_STATE; getcontext(&(RUNNING_THREAD->thread_context)); if (RUNNING_THREAD->flag) thread_exit(THREAD_SELF); if (TO_DELETE_THREAD) delete_threads_list(); if (!thread_id_array[returned_tid]) { interrupts_set(enabled); return returned_tid; } if (temp->state == NEW_STATE && RUNNING_THREAD->state != RECOVER_STATE) { temp->state = RECOVER_STATE; RUNNING_THREAD = temp; setcontext(&(temp->thread_context)); } interrupts_set(enabled); return returned_tid; } return THREAD_FAILED; }
/* 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) { int enabled = interrupts_set(0); thread *current; current = first; wait_queue *q_current; q_current=queue; int counter=0; if (queue==NULL) interrupts_set(enabled); return counter; // dummy=0 means wait queue has been initialized but nothing has been added to wait queue. if (queue->dummy==0) interrupts_set(enabled); return counter; //wake up the the first thread(head) in the sleep queue. if (all==0) { //make current point to the corresponding id in main linked list while (current->id != q_current->id) { current=current->next; if (current==NULL) { interrupts_set(enabled); return counter; } } current->state=READY; queue=queue->next; free(q_current); interrupts_set(enabled); return 1; } if (all==1) { //wake up(put in ready state) for every thread in sleep queue. while (q_current != NULL) { q_current=queue; current=first; while(q_current->id != current->id) { current=current->next; } current->state=READY; queue=queue->next; free(q_current); q_current=queue; counter++; } interrupts_set(enabled); return counter; } interrupts_set(enabled); return 0; }
Tid thread_sleep(struct wait_queue *queue) { int enabled = interrupts_set(0); thread *current; current=first; wait_queue *q_current; q_current=queue; int context_called = 0; if (queue==NULL) { interrupts_set(enabled); return THREAD_INVALID; } //find a thread that is ready, if none return THREAD_NONE while(current->state != READY) { current=current->next; if (current==NULL) { interrupts_set(enabled); return THREAD_NONE; } } //At this point, current is pointing at ready thread //set current running thread's state to sleep. curr->state=SLEEP; getcontext(curr->tcontext); if (context_called==1) { interrupts_set(enabled); return curr->id; } context_called=1; //only runs when there is 0 threads in the sleep queue. //malloc not required if (queue->dummy == 0) { queue->dummy=1; queue->id=curr->id; queue->next=NULL; } //Add current running thread at the end. else { while(q_current->next != NULL) { q_current=q_current->next; } q_current->next=malloc(sizeof(struct wait_queue)); q_current=q_current->next; q_current->id=curr->id; q_current->dummy=1; q_current->next=NULL; } curr=current; curr->state=RUNNING; setcontext(curr->tcontext); interrupts_set(enabled); return curr->id; }
/* enables interrupts. */ int interrupts_on() { return interrupts_set(1); }
/* disables interrupts */ int interrupts_off() { return interrupts_set(0); }
Tid thread_yield(Tid want_tid) { int enabled = interrupts_set(0); int context_called=0; thread *current; current=curr; //int abc=1; //if (current->next==NULL) // current=first; //printf("Yielding from %d to %d\n", curr->id, want_tid); if ((want_tid > (THREAD_MAX_THREADS-1))||(want_tid<-7)) { interrupts_set(enabled); return THREAD_INVALID; } if (want_tid > tcounter()) { interrupts_set(enabled); return THREAD_INVALID; } if (want_tid==THREAD_SELF) //no-op. return current id and continue the execution. { interrupts_set(enabled); return curr->id; } if (want_tid==THREAD_ANY) //run any thread in the ready queue { //print_rdyq(); if (first->next==NULL) //if there is only 1 thread running { interrupts_set(enabled); return THREAD_NONE; } while(current->state != READY) //find the first thread that is in ready state { current=current->next; if (current==NULL) { current=first; while(current->state != READY) { if(current==curr) { interrupts_set(enabled); return THREAD_NONE; } current=current->next; if(current==curr) { interrupts_set(enabled); return THREAD_NONE; } } } } //printf("Yielding from %d to %d \n", curr->id, current->id); curr->state=READY; getcontext(curr->tcontext); if (context_called==1) { interrupts_set(enabled); return curr->id; } context_called=1; curr=current; curr->state=RUNNING; setcontext(curr->tcontext); return curr->id; } current=first; while (current->id != want_tid) { current=current->next; if (current==NULL) { interrupts_set(enabled); return THREAD_INVALID; } } if (current->state == READY) { curr->state=READY; getcontext(curr->tcontext); if (context_called==1) { interrupts_set(enabled); return want_tid; } context_called=1; curr=current; curr->state=RUNNING; setcontext(curr->tcontext); return curr->id; } else if (current->state == RUNNING) { interrupts_set(enabled); return current->id; } //printf("HI\n"); return THREAD_FAILED; }