void thread_exit(void *ret) { thread_t *t = current_thread; sanity_check_threadcounts(); tdebug("current=%s\n", current_thread?current_thread->name : "NULL"); if (current_thread == main_thread && main_exited == 0) { // the case when the user calls thread_exit() in main thread is complicated // we cannot simply terminate the main thread, because we need that stack to terminate the // whole program normally. so we call exit() to make the c runtime help us get the stack // context where we can just return to terminate the whole program // this will call exit_func() and in turn call thread_exit() again main_exited = 1; exit (0); } // note the thread exit in the blocking graph t->curr_stats.node = bg_exit_node; current_thread->prev_stats.node->num_here--; current_thread->curr_stats.node->num_here++; if( bg_save_stats ) { bg_update_stats(); } // update thread counts num_runnable_threads--; if( t->daemon ) num_daemon_threads--; t->state = ZOMBIE; num_zombie_threads++; // deallocate the TCB // keep the thread, if the thread is Joinable, and we want the return value for something if ( !( t->joinable ) ) { // tell the scheduler thread to delete the current one current_thread_exited = 1; } else { t->ret = ret; if (t->join_thread) thread_resume(t->join_thread); } sanity_check_threadcounts(); // squirrel away the stack limit--not that we'll need it again current_thread->stack_bottom = stack_bottom; current_thread->stack_fingerprint = stack_fingerprint; // give control back to the scheduler #ifdef NO_SCHEDULER_THREAD do_scheduler(NULL); #else co_call(scheduler_thread->coro, NULL); #endif }
static void do_service(config_t *cpe, config_t *config, struct rs_config *rs_config) { struct rs_start *rs_start = &rs_config->rs_start; config_t *cp; /* At this point we expect one sublist that contains the varios * resource allocations */ if (!(cpe->flags & CFG_SUBLIST)) { fatal("do_service: expected list at %s:%d", cpe->file, cpe->line); } if (cpe->next != NULL) { cpe= cpe->next; fatal("do_service: expected end of list at %s:%d", cpe->file, cpe->line); } cpe= cpe->list; /* Process the list */ for (cp= cpe; cp; cp= cp->next) { if (!(cp->flags & CFG_SUBLIST)) { fatal("do_service: expected list at %s:%d", cp->file, cp->line); } cpe= cp->list; if ((cpe->flags & CFG_STRING) || (cpe->flags & CFG_SUBLIST)) { fatal("do_service: expected word at %s:%d", cpe->file, cpe->line); } if (strcmp(cpe->word, KW_CLASS) == 0) { do_class(cpe->next, config, rs_config); continue; } if (strcmp(cpe->word, KW_UID) == 0) { do_uid(cpe->next, rs_start); continue; } if (strcmp(cpe->word, KW_SIGMGR) == 0) { do_sigmgr(cpe->next, rs_start); continue; } if (strcmp(cpe->word, KW_TYPE) == 0) { do_type(cpe->next, rs_config); continue; } if (strcmp(cpe->word, KW_DESCR) == 0) { do_descr(cpe->next, rs_config); continue; } if (strcmp(cpe->word, KW_SCHEDULER) == 0) { do_scheduler(cpe->next, rs_start); continue; } if (strcmp(cpe->word, KW_PRIORITY) == 0) { do_priority(cpe->next, rs_start); continue; } if (strcmp(cpe->word, KW_QUANTUM) == 0) { do_quantum(cpe->next, rs_start); continue; } if (strcmp(cpe->word, KW_CPU) == 0) { do_cpu(cpe->next, rs_start); continue; } if (strcmp(cpe->word, KW_IRQ) == 0) { do_irq(cpe->next, rs_start); continue; } if (strcmp(cpe->word, KW_IO) == 0) { do_io(cpe->next, rs_start); continue; } if (strcmp(cpe->word, KW_PCI) == 0) { do_pci(cpe->next, rs_start); continue; } if (strcmp(cpe->word, KW_SYSTEM) == 0) { do_system(cpe->next, rs_start); continue; } if (strcmp(cpe->word, KW_IPC) == 0) { do_ipc(cpe->next, rs_start); continue; } if (strcmp(cpe->word, KW_VM) == 0) { do_vm(cpe->next, rs_start); continue; } if (strcmp(cpe->word, KW_CONTROL) == 0) { do_control(cpe->next, rs_start); continue; } } }
/** * perform necessary management to yield the current thread * if suspended == TRUE && timeout != 0 -> the thread is added * to the sleep queue and later waken up when the clock times out * returns FALSE if time-out actually happens, TRUE if waken up * by other threads, INTERRUPTED if interrupted by a signal **/ static int thread_yield_internal(int suspended, unsigned long long timeout) { // now we use a per-thread errno stored in thread_t int savederrno; int rv = OK; tdebug("current_thread=%p\n",current_thread); savederrno = errno; // decide what to do with the thread if( !suspended ) // just add it to the runlist sched_add_thread( current_thread ); else if( timeout ) // add to the sleep list sleepq_add_thread( current_thread, timeout); { #ifdef SHOW_EDGE_TIMES cpu_tick_t start, end, rstart, rend; GET_CPU_TICKS(start); GET_REAL_CPU_TICKS(rstart); #endif // figure out the current node in the graph if( !conf_no_stacktrace ) bg_backtrace_set_node(); // FIXME: fake out what cil would do... current_thread->curr_stats.node = bg_dummy_node; // we should already have been told the node by CIL or directly by the programmer assert( current_thread->curr_stats.node != NULL ); // update node counts current_thread->prev_stats.node->num_here--; current_thread->curr_stats.node->num_here++; // update the blocking graph info if( bg_save_stats ) bg_update_stats(); #ifdef SHOW_EDGE_TIMES GET_CPU_TICKS(end); GET_REAL_CPU_TICKS(rend); { thread_stats_t *curr = ¤t_thread->curr_stats; thread_stats_t *prev = ¤t_thread->prev_stats; output(" %3d -> %-3d %7lld ticks (%lld ms) %7lld rticks (%lld ms) ", prev->node->node_num, curr->node->node_num, curr->cpu_ticks - prev->cpu_ticks, (curr->cpu_ticks - prev->cpu_ticks) / ticks_per_millisecond, # ifdef USE_PERFCTR curr->real_ticks - prev->real_ticks, (curr->real_ticks - prev->real_ticks) / ticks_per_millisecond # else curr->cpu_ticks - prev->cpu_ticks, (curr->cpu_ticks - prev->cpu_ticks) / ticks_per_millisecond # endif ); output("update bg node %d: %lld (%lld ms) real: %lld (%lld ms)\n", current_thread->curr_stats.node->node_num, (end-start), (end-start)/ticks_per_millisecond, (rend-rstart), (rend-rstart)/ticks_per_millisecond); } #endif } // squirrel away the stack limit for next time current_thread->stack_bottom = stack_bottom; current_thread->stack_fingerprint = stack_fingerprint; // switch to the scheduler thread #ifdef NO_SCHEDULER_THREAD do_scheduler(NULL); #else co_call(scheduler_thread->coro, NULL); #endif // set up stack limit for new thread stack_bottom = current_thread->stack_bottom; stack_fingerprint = current_thread->stack_fingerprint; // rotate the stats if( bg_save_stats ) { current_thread->prev_stats = current_thread->curr_stats; // update thread time, to skip time asleep GET_CPU_TICKS( current_thread->prev_stats.cpu_ticks ); current_thread->prev_stats.cpu_ticks -= ticks_diff; // FIXME: subtract out time to do debug output #ifdef USE_PERFCTR GET_REAL_CPU_TICKS( current_thread->prev_stats.real_ticks ); current_thread->prev_stats.real_ticks -= ticks_rdiff; // FIXME: subtract out time to do debug output #endif } else { current_thread->prev_stats.node = current_thread->curr_stats.node; } // check whether time-out happens if (suspended && timeout && current_thread->timeout) { rv = TIMEDOUT; current_thread->timeout = 0; } // check for and process pending signals if ( likely(!current_thread->sig_waiting) ) { if (sig_process_pending()) rv = INTERRUPTED; } else { // if sig_waiting is 1, sigwait() itself will handle the remaining rv = INTERRUPTED; } errno = savederrno; return rv; }