/* The gtthread_join() function is analogous to pthread_join. All gtthreads are joinable. */ int gtthread_join(gtthread_t thread, void **status) { /* if a thread tries to join itself */ if (thread == current->tid) return -1; thread_t* t; /* if a thread is not created */ if ((t = thread_get(thread)) == NULL) return -1; /* check if that thread is joining on me */ if (t->joining == current->tid) return -1; current->joining = t->tid; /* wait on the thread to terminate */ while (t->state == GTTHREAD_RUNNING) { sigprocmask(SIG_UNBLOCK, &vtalrm, NULL); sigvtalrm_handler(SIGVTALRM); sigprocmask(SIG_BLOCK, &vtalrm, NULL); } if (status == NULL) return 0; if (t->state == GTTHREAD_CANCEL) *status = (void*) GTTHREAD_CANCEL; else if (t->state == GTTHREAD_DONE) *status = t->retval; return 0; }
/* The gtthread_cancel() function is analogous to pthread_cancel, allowing one thread to terminate another asynchronously. */ int gtthread_cancel(gtthread_t thread) { /* if a thread cancel itself */ if (gtthread_equal(current->tid, thread)) gtthread_exit(0); sigprocmask(SIG_BLOCK, &vtalrm, NULL); thread_t* t = thread_get(thread); if (t == NULL) { sigprocmask(SIG_UNBLOCK, &vtalrm, NULL); return -1; } if (t->state == GTTHREAD_DONE) { sigprocmask(SIG_UNBLOCK, &vtalrm, NULL); return -1; } if (t->state == GTTHREAD_CANCEL) { sigprocmask(SIG_UNBLOCK, &vtalrm, NULL); return -1; } else t->state = GTTHREAD_CANCEL; free(t->ucp->uc_stack.ss_sp); free(t->ucp); t->ucp = NULL; t->joining = 0; steque_enqueue(&zombie_queue, t); sigprocmask(SIG_UNBLOCK, &vtalrm, NULL); return 0; }
static int gen_traffic(void *priv, enum VSL_tag_e tag, unsigned fd, unsigned len, unsigned spec, const char *ptr, uint64_t bitmap) { struct replay_thread *thr; struct message *msg; (void)priv; (void)bitmap; if (fd == 0 || !(spec & VSL_S_CLIENT)) return (0); thread_log(3, 0, "%d %s", fd, VSL_tags[tag]); thr = thread_get(fd, replay_thread); if (thr == NULL) return (0); msg = malloc(sizeof (struct message)); msg->tag = tag; msg->len = len; msg->ptr = malloc(len); AN(msg->ptr); memcpy(msg->ptr, ptr, len); mailbox_put(&thr->mbox, msg); return (0); }
static void thread_block_mutex(ThreadId tid, struct mutex *mx) { struct thread *th = thread_get(tid); if (th == NULL) { /* should an unknown thread doing something make it spring to life? */ thread_report(tid, THE_NotExist, "blocking on mutex"); return; } switch(th->state) { case TS_Dead: case TS_Zombie: thread_report(th->tid, THE_NotAlive, "blocking on mutex"); break; case TS_MutexBlocked: case TS_CVBlocked: case TS_JoinBlocked: thread_report(th->tid, THE_Blocked, "blocking on mutex"); break; case TS_Alive: case TS_Running: /* OK */ break; } do_thread_block_mutex(th, mx); }
int event_remv(int id, int event) { struct thread *thread = thread_get(id); if (!thread) { return 1; } if (event < 0 || event >= EV_COUNT) { return 1; } if (!evqueue[event].front_thread) { return 1; } if (evqueue[event].front_thread == thread) { evqueue[event].front_thread = thread->next; if (evqueue[event].back_thread == thread) { evqueue[event].back_thread = NULL; } return 0; } else for (struct thread *t = evqueue[event].front_thread; t->next; t = t->next) { if (t->next == thread) { t->next = thread->next; if (evqueue[event].back_thread == thread) { evqueue[event].back_thread = t; } return 0; } } return 1; }
static void thread_unblock_mutex(ThreadId tid, struct mutex *mx, const Char *action) { struct thread *th = thread_get(tid); if (th == NULL) { /* should an unknown thread doing something make it spring to life? */ thread_report(tid, THE_NotExist, "giving up on mutex"); return; } switch(th->state) { case TS_MutexBlocked: /* OK */ break; case TS_Alive: case TS_Running: thread_report(tid, THE_NotBlocked, action); break; case TS_CVBlocked: case TS_JoinBlocked: thread_report(tid, THE_Blocked, action); break; case TS_Dead: case TS_Zombie: thread_report(tid, THE_NotAlive, action); break; } do_thread_run(th); }
static int gen_traffic(void *priv, enum shmlogtag tag, unsigned fd, unsigned len, unsigned spec, const char *ptr) { struct replay_thread *thr; const char *end; struct message *msg; (void)priv; end = ptr + len; if (fd == 0 || !(spec & VSL_S_CLIENT)) return (0); thread_log(3, 0, "%d %s", fd, VSL_tags[tag]); thr = thread_get(fd, replay_thread); if (thr == NULL) return (0); msg = malloc(sizeof (struct message)); msg->tag = tag; msg->len = len; msg->ptr = strndup(ptr, len); mailbox_put(&thr->mbox, msg); return (0); }
t_error ia32_thread_store(i_thread thr, t_thread_context* ctx) { o_thread* o; thread_get(thr, &o); ctx->sp = o->machdep.named.esp; ctx->pc = o->machdep.named.eip; return ERROR_NONE; }
/* Mostly copied from thread_wakeup() */ static void _thread_wake_wo_yield(kernel_pid_t pid) { unsigned old_state = irq_disable(); thread_t *other_thread = (thread_t *) thread_get(pid); sched_set_status(other_thread, STATUS_RUNNING); irq_restore(old_state); }
t_error ia32_thread_load(i_thread thr,t_thread_context ctx) { o_thread* o; thread_get(thr, &o); o->machdep.named.esp = ctx.sp; //printf("[%i", o->machdep.named.esp = ctx.sp); //printf("@%i]\n", &(o->machdep.named)); o->machdep.named.eip = ctx.pc; gdt_build_selector(PMODE_GDT_CORE_CS, ia32_prvl_supervisor, &o->machdep.named.cs); return ERROR_NONE; }
/* Finish unlocking a Mutex. The mutex can validly be in one of three states: - Unlocking - Locked, owned by someone else (someone else got it in the meantime) - Free (someone else completed a lock-unlock cycle) */ void VG_(tm_mutex_unlock)(ThreadId tid, Addr mutexp) { struct mutex *mx; struct thread *th; mx = mutex_check_initialized(tid, mutexp, "unlocking mutex"); th = thread_get(tid); if (th == NULL) thread_report(tid, THE_NotExist, "unlocking mutex"); else { switch(th->state) { case TS_Alive: case TS_Running: /* OK */ break; case TS_Dead: case TS_Zombie: thread_report(tid, THE_NotAlive, "unlocking mutex"); break; case TS_JoinBlocked: case TS_CVBlocked: case TS_MutexBlocked: thread_report(tid, THE_Blocked, "unlocking mutex"); do_thread_run(th); break; } } switch(mx->state) { case MX_Locked: /* Someone else might have taken ownership in the meantime */ if (mx->owner == tid) mutex_report(tid, mutexp, MXE_Locked, "unlocking"); break; case MX_Free: /* OK - nothing to do */ break; case MX_Unlocking: /* OK - we need to complete the unlock */ VG_TRACK( post_mutex_unlock, tid, (void *)mutexp ); mutex_setstate(tid, mx, MX_Free); break; case MX_Init: case MX_Dead: vg_assert(0); } }
t_error ia32_thread_stack(i_thread th, t_stack stack) { o_thread* oth; if (thread_get(th, &oth) != ERROR_NONE) THREAD_LEAVE(thread, ERROR_UNKNOWN); oth->machdep.named.ebp = oth->stack - oth->stacksz; oth->machdep.named.esp = oth->stack - oth->stacksz; return ERROR_NONE; }
/* Try unlocking a lock. This will move it into a state where it can either be unlocked, or change ownership to another thread. If unlock fails, it will remain locked. */ void VG_(tm_mutex_tryunlock)(ThreadId tid, Addr mutexp) { struct thread *th; struct mutex *mx; mx = mutex_check_initialized(tid, mutexp, "try-unlocking"); th = thread_get(tid); if (th == NULL) thread_report(tid, THE_NotExist, "try-unlocking mutex"); else { switch(th->state) { case TS_Alive: case TS_Running: /* OK */ break; case TS_Dead: case TS_Zombie: thread_report(tid, THE_NotAlive, "try-unlocking mutex"); break; case TS_JoinBlocked: case TS_CVBlocked: case TS_MutexBlocked: thread_report(tid, THE_Blocked, "try-unlocking mutex"); do_thread_run(th); break; } } switch(mx->state) { case MX_Locked: if (mx->owner != tid) mutex_report(tid, mutexp, MXE_NotOwner, "try-unlocking"); break; case MX_Free: mutex_report(tid, mutexp, MXE_NotLocked, "try-unlocking"); break; case MX_Unlocking: mutex_report(tid, mutexp, MXE_NotLocked, "try-unlocking"); break; case MX_Init: case MX_Dead: vg_assert(0); } mutex_setstate(tid, mx, MX_Unlocking); }
void VG_(tm_thread_detach)(ThreadId tid) { struct thread *th = thread_get(tid); if (th == NULL) thread_report(tid, THE_NotExist, "detaching"); else { if (th->detached) thread_report(tid, THE_Detached, "detaching"); else { /* XXX look for waiters */ th->detached = True; } } }
t_status interface_thread_attribute_state(o_syscall* message) { o_thread* o; if (thread_get(message->u.request.u.thread_attribute_state.arg1, &o) != STATUS_OK) { message->u.reply.error = STATUS_ERROR; } else { message->u.reply.error = STATUS_OK; message->u.reply.u.thread_attribute_state.result1 = o->state; } return (STATUS_OK); }
static void irq_notify(void) { Context* context = get_context(); uint8_t irq = IRQ(context->num); if (!irqThread[irq]) return; Thread* receiver = thread_get(irqThread[irq]); if (receiver->state == WAIT_RECEIVING && receiver->waitingFor == 0 && receiver->waitingIrq == irq) { irqPending[irq] = false; scheduler_unblock(receiver); } else irqPending[irq] = true; }
static bool _is_iface(kernel_pid_t iface) { #ifdef MODULE_NG_NETIF kernel_pid_t ifs[NG_NETIF_NUMOF]; size_t numof = ng_netif_get(ifs); for (size_t i = 0; i < numof && i < NG_NETIF_NUMOF; i++) { if (ifs[i] == iface) { return true; } } return false; #else return (thread_get(iface) != NULL); #endif }
/* A thread is terminating itself - fails if tid has already terminated - if detached, tid becomes invalid for all further operations - if not detached, the thread remains in a Zombie state until someone joins on it */ void VG_(tm_thread_exit)(ThreadId tid) { struct thread *th = thread_get(tid); if (th == NULL) thread_report(tid, THE_NotExist, "exiting"); else { struct thread *joiner; switch(th->state) { case TS_Dead: case TS_Zombie: /* already exited once */ thread_report(tid, THE_NotAlive, "exiting"); break; case TS_MutexBlocked: case TS_CVBlocked: case TS_JoinBlocked: thread_report(tid, THE_Blocked, "exiting"); break; case TS_Alive: case TS_Running: /* OK */ break; } /* ugly - walk all threads to find people joining with us */ /* In pthreads its an error to have multiple joiners, but that seems a bit specific to implement here; there should a way for the thread library binding to handle this. */ VG_(OSet_ResetIter)(threadSet); while ((joiner = VG_(OSet_Next)(threadSet)) != NULL) { if (joiner->state == TS_JoinBlocked && joiner->th_blocked == th) { /* found someone - wake them up */ do_thread_run(joiner); /* we're dead */ do_thread_dead(th); } } if (th->state != TS_Dead) do_thread_block_zombie(th); } }
void thread_stack_print(void) { /* Print the current stack to stdout. */ #if defined(DEVELHELP) volatile thread_t* task = thread_get(sched_active_pid); if (task) { char* stack_top = task->stack_start + task->stack_size; int size = stack_top - task->sp; printf("Printing current stack of thread %" PRIkernel_pid "\n", thread_getpid()); esp_hexdump((void*)(task->sp), size >> 2, 'w', 8); } #else NOT_SUPPORTED(); #endif }
t_error ia32_thread_reserve(i_task tsk, i_thread* th) { o_thread *oth; ao_thread_named *src; o_task* otsk; o_as* oas; if (thread_get(*th, &oth) != ERROR_NONE) THREAD_LEAVE(thread, ERROR_UNKNOWN); src = &(oth->machdep.named); if (task_get(oth->taskid, &otsk) != ERROR_NONE) TASK_LEAVE(task, ERROR_UNKNOWN); if (as_get(otsk->asid, &oas) != ERROR_NONE) AS_LEAVE(as, ERROR_UNKNOWN); src->cr3 = (t_uint32) oas->machdep.pd; return ERROR_NONE; }
/* Add pending read thread. */ struct thread * thread_add_read_pend (struct lib_globals *zg, int (*func) (struct thread *), void *arg, int val) { struct thread *thread; struct thread_master *m = zg->master; pal_assert (m != NULL); thread = thread_get (zg, THREAD_READ_PEND, func, arg); if (thread == NULL) return NULL; thread->u.val = val; thread_list_add (&m->read_pend, thread); return thread; }
/* Add low priority event thread. */ struct thread * thread_add_event_low (struct lib_globals *zg, int (*func) (struct thread *), void *arg, int val) { struct thread *thread; struct thread_master *m = zg->master; pal_assert (m != NULL); thread = thread_get (zg, THREAD_EVENT_LOW, func, arg); if (thread == NULL) return NULL; thread->u.val = val; thread_list_add (&m->event_low, thread); return thread; }
/* Add simple event thread. */ struct thread * thread_add_event (struct thread_master *master, int (*func) (struct thread *), void *arg, int val) { struct thread *thread; struct thread_master *m = master; assert (m != NULL); thread = thread_get (m, THREAD_EVENT, func, arg); if (thread == NULL) return NULL; thread->u.val = val; thread_list_add (&m->event, thread); return thread; }
struct thread *kthread_create(uintptr_t code, int argc, char *argv[]) { int tid; struct thread *t; tid = thread_create(kproc, code, argc, argv, THREAD_CREATEF_NOSTART_THREAD); if (tid < 0) return NULL; t = thread_get(kproc, tid); /* XXX: I am not sure this is possible, will see while testing. If this * happens it will be worth recovering */ if (!t) kernel_panic("Thread get == NULL after thread_create()"); return t; }
int event_wait(int id, int event) { struct thread *thread = thread_get(id); if (!thread) { return 1; } if (event < 0) { if (irqstate[~event]) { return 1; } return 0; } if (event < 0 || event >= EV_COUNT) { return 1; } if (irqstate[event]) { thread_save(thread); schedule_push(thread); thread->state = TS_QUEUED; } else { /* queue thread */ if (!evqueue[event].back_thread) { evqueue[event].front_thread = thread; } else { evqueue[event].back_thread->next_evqueue = thread; } evqueue[event].back_thread = thread; thread->next_evqueue = NULL; thread->event = event; thread_save(thread); thread->state = TS_WAITING; } return 0; }
/* Wait for a condition, putting thread into blocked state. Fails if: - condp has not been initialized - thread doesn't hold mutexp - thread is blocked on some other object - thread is already blocked on mutex */ void VG_(tm_cond_wait)(ThreadId tid, Addr condp, Addr mutexp) { struct thread *th = thread_get(tid); struct mutex *mx; struct condvar *cv; struct condvar_waiter *waiter; /* Condvar must exist */ cv = condvar_check_initialized(tid, condp, "waiting"); /* Mutex must exist */ mx = mutex_check_initialized(tid, mutexp, "waiting on condvar"); /* Thread must own mutex */ if (mx->state != MX_Locked) { mutex_report(tid, mutexp, MXE_NotLocked, "waiting on condvar"); VG_(tm_mutex_trylock)(tid, mutexp); VG_(tm_mutex_acquire)(tid, mutexp); } else if (mx->owner != tid) { mutex_report(tid, mutexp, MXE_NotOwner, "waiting on condvar"); mx->owner = tid; } /* Thread must not be already waiting for condvar */ waiter = get_waiter(cv, tid); if (waiter != NULL) condvar_report(tid, condp, CVE_Blocked, "waiting"); else { waiter = VG_(arena_malloc)(VG_AR_CORE, sizeof(*waiter)); waiter->condvar = cv; waiter->mutex = mx; waiter->next = cv->waiters; cv->waiters = waiter; } /* Thread is now blocking on condvar */ do_thread_block_condvar(th, cv); /* (half) release mutex */ VG_(tm_mutex_tryunlock)(tid, mutexp); }
static void thread_report(ThreadId tid, enum thread_error err, const Char *action) { Char *errstr = "?"; struct thread *th = thread_get(tid); struct thread_error_data errdata; switch(err) { case THE_NotExist: errstr = "non existent"; break; case THE_NotAlive: errstr = "not alive"; break; case THE_Rebirth: errstr = "re-born"; break; case THE_Blocked: errstr = "blocked"; break; case THE_NotBlocked: errstr = "not blocked"; break; case THE_Detached: errstr = "detached"; break; } errdata.err = err; errdata.th = th; errdata.action = action; VG_(maybe_record_error)(VG_(get_running_tid)(), ThreadErr, 0, errstr, &errdata); }
void send_receive(uint16_t to, uint16_t from) { Thread *sender, *receiver, *current = scheduler_current(); if (to) { receiver = thread_get(to); if (receiver->state != WAIT_RECEIVING || !(receiver->waitingFor == (uint16_t)-1 || receiver->waitingFor == current->tid)) { if (from) return scheduler_wait(to, WAIT_SEND_RECV); else return scheduler_wait(to, WAIT_SENDING); } deliver(current, receiver); scheduler_unblock(receiver); } if (from) { if (!list_empty(¤t->waitingList)) { sender = list_item(list_pop(¤t->waitingList), Thread, queueLink); deliver(sender, current); if (sender->state == WAIT_SENDING) scheduler_unblock(sender); else sender->state = WAIT_RECEIVING; } else scheduler_wait(from, WAIT_RECEIVING); } return; }
int main(void) { puts("START"); kernel_pid_t pid = thread_create(stack, sizeof(stack), THREAD_PRIORITY_MAIN - 1, THREAD_CREATE_STACKTEST, _thread, NULL, "second_thread"); thread_t *thread = (thread_t*) thread_get(pid); _set(thread, 0x1); _set(thread, 0x64); _set(thread, 0x1); _set(thread, 0x8); _set(thread, 0x2); _set(thread, 0x4); while(!done) {}; puts("main: setting 100ms timeout..."); xtimer_t t; uint32_t before = xtimer_now_usec(); xtimer_set_timeout_flag(&t, TIMEOUT); thread_flags_wait_any(THREAD_FLAG_TIMEOUT); uint32_t diff = xtimer_now_usec() - before; printf("main: timeout triggered. time passed: %uus\n", (unsigned)diff); if (diff < (TIMEOUT + THRESHOLD)) { puts("SUCCESS"); return 0; } puts("FAILURE"); return 1; }
/* Add timer event thread. */ struct thread * thread_add_timer_timeval (struct lib_globals *zg, int (*func) (struct thread *), void *arg, struct pal_timeval timer) { struct thread_master *m = zg->master; struct pal_timeval timer_now; struct thread *thread; pal_assert (m != NULL); thread = thread_get (zg, THREAD_TIMER, func, arg); if (thread == NULL) return NULL; /* Do we need jitter here? */ pal_time_tzcurrent (&timer_now, NULL); timer_now.tv_sec += timer.tv_sec; timer_now.tv_usec += timer.tv_usec; while (timer_now.tv_usec >= TV_USEC_PER_SEC) { timer_now.tv_sec++; timer_now.tv_usec -= TV_USEC_PER_SEC; } /* Correct negative value. */ if (timer_now.tv_sec < 0) timer_now.tv_sec = PAL_TIME_MAX_TV_SEC; if (timer_now.tv_usec < 0) timer_now.tv_usec = PAL_TIME_MAX_TV_USEC; thread->u.sands = timer_now; /* Common process. */ thread_add_timer_common (m, thread); return thread; }