void condition_wait(struct condition* c, struct mutex* m){ mutex_unlock(m); current_thread->state = BLOCKED; thread_enqueue(&c->waiting_threads, current_thread); yield(); mutex_lock(m); };
struct thread* thread_fork(void(*target)(void*), void* arg) { // allocate a new thread control block and stack struct thread* new_thread = malloc(sizeof(struct thread)); new_thread->stack_pointer = malloc(STACK_SIZE) + STACK_SIZE; // Set the new thread's initial argument and initial function. new_thread->initial_function = target; new_thread->initial_argument = arg; // Set the current thread's state to READY and enqueue it on the ready list. if(current_thread->state != BLOCKED) current_thread->state = READY; thread_enqueue(&ready_list, current_thread); // Set the new thread's state to RUNNING. new_thread->state = RUNNING; // allocate mutex lock and condition new_thread->mutexLock = malloc(sizeof(struct mutex)); new_thread->condList = malloc(sizeof(struct condition)); mutex_init(new_thread->mutexLock); condition_init(new_thread->condList); // Save a pointer to the current thread in a temporary variable, then set the current thread to the new thread. struct thread* temp = current_thread; current_thread = new_thread; // Call thread_start with the old current thread as old and the new current thread as new. thread_start(temp, current_thread); return new_thread; };
void condition_signal(struct condition* c){ struct thread* ready_thread = thread_dequeue(&c->waiting_threads); if(ready_thread){ ready_thread->state = READY; thread_enqueue(&ready_list, ready_thread); } };
void thread_fork(void(*target)(void*), void *arg) { // Allocate a new thread control block, and allocate its stack. thread *new_thread = (thread *) malloc(sizeof(thread)); new_thread->stack_pointer = malloc(STACK_SIZE) + STACK_SIZE; //printf("FORK: New Thread allocated\n"); // Set the new thread's initial argument and initial function. new_thread->initial_argument = arg; new_thread->initial_function = target; // Set the current thread's state to READY and enqueue it on the ready list. current_thread->state = READY; thread_enqueue(&ready_list, current_thread); //printf("FORK: Placed current thread onto queue\n"); // Set the new thread's state to RUNNING. new_thread->state = RUNNING; /* Save a pointer to the current thread in a temporary variable, then set the current thread to the new thread. */ thread *temp = current_thread; current_thread = new_thread; /* Call thread_start with the old current thread as old and the new current thread as new. */ //printf("FORK: New current thread running\n"); thread_start(temp, current_thread); }
/** * \brief Wakeup a thread on a foreign dispatcher while disabled. * * \param core_id Core ID to wakeup on * \param thread Pointer to thread to wakeup * \param mydisp Dispatcher this function is running on * * \return SYS_ERR_OK on success. */ static errval_t domain_wakeup_on_coreid_disabled(coreid_t core_id, struct thread *thread, dispatcher_handle_t mydisp) { struct domain_state *ds = get_domain_state(); // XXX: Ugly hack to allow waking up on a core id we don't have a // dispatcher handler for thread->coreid = core_id; // Catch this early assert_disabled(ds != NULL); if (ds->b[core_id] == NULL) { return LIB_ERR_NO_SPANNED_DISP; } thread_enqueue(thread, &ds->remote_wakeup_queue); // Signal the inter-disp waitset of this event struct event_closure closure = { .handler = handle_wakeup_on }; errval_t err = waitset_chan_trigger_closure_disabled(&ds->interdisp_ws, &ds->remote_wakeup_event, closure, mydisp); assert_disabled(err_is_ok(err) || err_no(err) == LIB_ERR_CHAN_ALREADY_REGISTERED); return SYS_ERR_OK; }
errval_t domain_thread_move_to(struct thread *thread, coreid_t core_id) { assert(thread == thread_self()); dispatcher_handle_t mydisp = disp_disable(); struct dispatcher_generic *disp_gen = get_dispatcher_generic(mydisp); struct dispatcher_shared_generic *disp = get_dispatcher_shared_generic(mydisp); struct thread *next = thread->next; thread_remove_from_queue(&disp_gen->runq, thread); errval_t err = domain_wakeup_on_coreid_disabled(core_id, thread, mydisp); if(err_is_fail(err)) { thread_enqueue(thread, &disp_gen->runq); disp_enable(mydisp); return err; } // run the next thread, if any if (next != thread) { disp_gen->current = next; disp_resume(mydisp, &next->regs); } else { disp_gen->current = NULL; disp->haswork = havework_disabled(mydisp); disp_yield_disabled(mydisp); } USER_PANIC("should never be reached"); }
void mutex_lock(struct mutex * m){ if(m->held == 1){ current_thread->state = BLOCKED; thread_enqueue(&m->waiting_threads, current_thread); yield(); }else m->held = 1; };
void condition_broadcast(struct condition* c){ struct thread* ready_thread = thread_dequeue(&c->waiting_threads); while(ready_thread){ ready_thread->state = READY; thread_enqueue(&ready_list, ready_thread); ready_thread = thread_dequeue(&c->waiting_threads); } };
void thread_relinquish() /* call this within a thread to allow scheduling of a new thread */ { if (_setjmp( current->state ) == 0) { thread_enqueue( current, &readylist ); current = thread_dequeue( &readylist ); _longjmp( current->state, 1 ); } }
void thread_signal( struct thread_semaphore * s ) /* call this within a thread to signal a semaphore */ { struct thread * t = thread_dequeue( &s->queue ); if (t == thread_null) { s->count++; } else { thread_enqueue( t, &readylist ); } }
void mutex_unlock(struct mutex * m){ if(is_empty(&m->waiting_threads)){ m->held = 0; }else{ struct thread* temp = thread_dequeue(&m->waiting_threads); if(temp){ temp->state = READY; thread_enqueue(&ready_list, temp); } } };
static void wakeup_thread_request(struct interdisp_binding *b, genvaddr_t taddr) { coreid_t core_id = disp_get_core_id(); struct thread *wakeup = (struct thread *)(uintptr_t)taddr; dispatcher_handle_t handle = disp_disable(); struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle); /* assert_disabled(wakeup->disp == handle); */ assert_disabled(wakeup->coreid == core_id); wakeup->disp = handle; thread_enqueue(wakeup, &disp_gen->runq); disp_enable(handle); }
// yield is very similar to thread_fork, with the main difference being that // it is pulling the next thread to run off of the ready list instead of creating it. yield should: void yield(){ // If the current thread is not DONE, set its state to READY and enqueue it on the ready list. if(current_thread->state != DONE && current_thread->state != BLOCKED){ current_thread->state = READY; thread_enqueue(&ready_list, current_thread); } // Dequeue the next thread from the ready list and set its state to RUNNING. struct thread* next_thread = thread_dequeue(&ready_list); next_thread->state = RUNNING; // Save a pointer to the current thread in a temporary variable, then set the current thread to the next thread. struct thread* temp = current_thread; current_thread = next_thread; // Call thread_switch with the old current thread as old and the new current thread as new. thread_switch(temp, current_thread); };
void thread_wait( struct thread_semaphore * s ) /* call this within a thread to block on a semaphore */ { if (s->count > 0) { s->count--; } else { if (_setjmp( current->state ) == 0) { thread_enqueue( current, &s->queue ); current = thread_dequeue( &readylist ); if (current == thread_null) { /* crisis */ thread_error = "possible deadlock"; _longjmp( thread_death, 1 ); } _longjmp( current->state, 1 ); } } }
void yield() { /* If the current thread is not DONE, set its state to READY and enqueue it on the ready list. */ if (current_thread->state != DONE) { current_thread->state = READY; thread_enqueue(&ready_list, current_thread); //printf("YIELD: current thread not finished, back on queue\n"); } // Dequeue the next thread from the ready list and set its state to RUNNING. thread *next_thread = thread_dequeue(&ready_list); /* Save a pointer to the current thread in a temporary variable, then set the current thread to the next thread. */ thread *temp = current_thread; current_thread = next_thread; /* Call thread_switch with the old current thread as old and the new current thread as new. */ thread_switch(temp, current_thread); //printf("YIELD: Running dequeued thread\n"); }
void thread_launch( int size, void (* proc)(int), int param ) /* call this to launch proc(param) as a thread */ /* may be called from main or from any thread */ { struct thread * t; t = (struct thread *)malloc( sizeof(struct thread) + size ); t->size = size; t->proc = proc; t->param = param; if (_setjmp( t->state )) { /* comes here only when new thread scheduled first time */ (*current->proc)(current->param); thread_exit(); } /* continue initialization */ { long int * s; long int * probe_rec; long int local_base = (long int)&t; /* address of local t */ long int new_base; int i; /* the following code copies the contents of the activation record, just in case it might prove useful; note that we don't know that this is needed on any machine, but it might, so we do it. */ if (stack_direction == 1) { /* grows up */ long int * src; long int * dst; new_base = (long int)t + sizeof( struct thread ) + local_offset; src = (long int *) (local_base - local_offset); dst = (long int *) (new_base - local_offset); for (i = 0; i <= local_offset; i += sizeof(long int)) { *dst++ = *src++; } } else { /* grows down */ long int * src; long int * dst; new_base = (long int)t + sizeof( struct thread ) + size - (local_offset + sizeof(long int)); src = (long int *) (local_base); dst = (long int *) (new_base); for (i = 0; i <= local_offset; i += sizeof(long int)) { *dst++ = *src++; } } /* the following code adjusts the references to the activation record in the saved thread state so that they point to the base of the newly allocated stack */ s = (long int *)(t->state); probe_rec = (long int *)probe_record; for (i = 0; i < sizeof(jmp_buf); i += sizeof(long int) ) { if (*probe_rec != 0) { /* adjust this field of state */ *s += new_base - local_base; } s++; probe_rec++; } } thread_enqueue( t, &readylist ); }