/* * Description: This function returns the number of quantums until the thread * with id tid wakes up including the current quantum. If no thread with ID * tid exists it is considered as an error. If the thread is not sleeping, * the function should return 0. * Return value: Number of quantums (including current quantum) until wakeup. */ int uthread_get_time_until_wakeup(int tid) { // Block SIGTVALRM signal sigset_t oldSet; blockSignal(SIGVTALRM, &oldSet); // If no such thread exists, this is an error if (livingThreads.find(tid) == livingThreads.end()) { std::cerr << LIB_ERROR_MSG << "wakeup(" << tid << ") failed - no such thread id. " << std::endl; resetSigMask(&oldSet); return EXIT_FAIL; } else if (livingThreads[tid]->get_state() != uthread::state::SLEEPING) { // If the thread is not sleeping, return SHOULD_WAKE == 0. resetSigMask(&oldSet); return SHOULD_WAKE; } else { // In general, diff shouldn't be negative, but if it does // it shouldn't crash the whole program. int diff = livingThreads[tid]->get_wakeup() - totalQuanta; resetSigMask(&oldSet); return diff >= SHOULD_WAKE ? diff : SHOULD_WAKE; } }
/* * Description: This function resumes a blocked thread with ID tid and moves * it to the READY state. Resuming a thread in the RUNNING, READY or SLEEPING * state has no effect and is not considered as an error. If no thread with * ID tid exists it is considered as an error. * Return value: On success, return 0. On failure, return -1. */ int uthread_resume(int tid) { // Block SIGTVALRM signal sigset_t oldSet; blockSignal(SIGVTALRM, &oldSet); if (livingThreads.find(tid) == livingThreads.end()) { std::cerr << LIB_ERROR_MSG << "resume(" << tid << ") failed - no such thread id" << std::endl; resetSigMask(&oldSet); return EXIT_FAIL; } uthread *curr = livingThreads[tid]; if (curr->get_state() == uthread::state::BLOCKED) { curr->set_state(uthread::state::READY); readyThreads.push_back(curr->get_id()); } // Unblock SIGVTALRM and return resetSigMask(&oldSet); return EXIT_SUCC; }
/** * Function: deleteThread * Deletes a thread from the living threads list, the READY list (if it's * there) and frees its allocated memory. * Assumes the given tid exists in the living threads list. * Calling with tid == MAIN_THREAD_ID does nothing. * DO NOT CALL WITH UNEXISTING THREAD ID */ void deleteThread(uthread::id tid) { // Block SIGVTALRM sigset_t oldSet; blockSignal(SIGVTALRM, &oldSet); if (tid == MAIN_THREAD_ID) { // Unblock and exit resetSigMask(&oldSet); return; } uthread *curr = livingThreads[tid]; // Remove from living threads list livingThreads.erase(tid); // Remove from ready threads list, if it's there auto th = std::find(readyThreads.begin(), readyThreads.end(), tid); if (th != readyThreads.end()) { readyThreads.erase(th); } // Free allocated data delete curr; // Unlblock signal resetSigMask(&oldSet); }
/* * Description: This function terminates the thread with ID tid and deletes * it from all relevant control structures. All the resources allocated by * the library for this thread should be released. If no thread with ID tid * exists it is considered as an error. Terminating the main thread * (tid == 0) will result in the termination of the entire process using * exit(0) [after releasing the assigned library memory]. * Return value: The function returns 0 if the thread was successfully * terminated and -1 otherwise. If a thread terminates itself or the main * thread is terminated, the function does not return. */ int uthread_terminate(int tid) { // Block SIGTVALRM signal sigset_t oldSet; blockSignal(SIGVTALRM, &oldSet); // If main thread is terminated, delete all threads and quit. // The deleteThread function checks and manages data for future // process run, which is un-needed in this point. if (tid == MAIN_THREAD_ID) { for (auto th : livingThreads) { delete th.second; } exit(EXIT_SUCC); } // If no such thread exists, return failure. if (livingThreads.find(tid) == livingThreads.end()) { std::cerr << LIB_ERROR_MSG <<"terminate(" << tid << ") failed - no such thread id" << std::endl; resetSigMask(&oldSet); return EXIT_FAIL; } // Otherwise, delete thread tid, if it's not sleeping. if (livingThreads[tid]->get_state() == uthread::state::SLEEPING) { std::cerr << LIB_ERROR_MSG << "can't terminate a sleeping thread" << std::endl; resetSigMask(&oldSet); return EXIT_FAIL; } // If deleted yourself, goto contextSwitch. if ((uthread::id)tid == currentThread) { // Set this tid as the one that needs to be deleted // in the next contextSwitch toDelete = tid; resetSigMask(&oldSet); contextSwitch(SIGVTALRM); return EXIT_SUCC; // This should not be reached } // Otherwise, delete and return else { // Unblock SIGVTALRM and return resetSigMask(&oldSet); deleteThread(tid); return EXIT_SUCC; } }
/* * Description: This function blocks the thread with ID tid. The thread may * be resumed later using uthread_resume. If no thread with ID tid exists it * is considered as an error. In addition, it is an error to try blocking the * main thread (tid == 0). If a thread blocks itself, a scheduling decision * should be made. Blocking a thread in BLOCKED or SLEEPING states has no * effect and is not considered as an error. * Return value: On success, return 0. On failure, return -1. */ int uthread_block(int tid) { // Block SIGTVALRM signal sigset_t oldSet; blockSignal(SIGVTALRM, &oldSet); // Blocking the main thread is an error if (tid == MAIN_THREAD_ID) { std::cerr << LIB_ERROR_MSG << "can't block main thread." << std::endl; resetSigMask(&oldSet); return EXIT_FAIL; } // If no such thread exists, it is an error if (livingThreads.find(tid) == livingThreads.end()) { std::cerr << LIB_ERROR_MSG << "block(" << tid << ") failed - no such thread id" << std::endl; resetSigMask(&oldSet); return EXIT_FAIL; } // Check if the thread CAN be blocked // if not, do nothing. uthread *curr = livingThreads[tid]; if (curr->get_state() == uthread::state::BLOCKED || curr->get_state() == uthread::state::SLEEPING) { resetSigMask(&oldSet); return EXIT_SUCC; } // If a thread blocks itself switch context and exit // (the return will be executed after the thread is resumed) else if ((uthread::id)tid == currentThread) { curr->set_state(uthread::state::BLOCKED); resetSigMask(&oldSet); contextSwitch(SIGVTALRM); return EXIT_SUCC; } // Otherwise, change the thread's state to BLOCKED and remove it // from the READY list. curr->set_state(uthread::state::BLOCKED); auto th = std::find(readyThreads.begin(), readyThreads.end(), tid); readyThreads.erase(th); resetSigMask(&oldSet); return EXIT_SUCC; }
/* * Description: This function returns the number of quantums the thread with * ID tid was in RUNNING state. On the first time a thread runs, the function * should return 1. Every additional quantum that the thread starts should * increase this value by 1 (so if the thread with ID tid is in RUNNING state * when this function is called, include also the current quantum). If no * thread with ID tid exists it is considered as an error. * Return value: On success, return the number of quantums of the thread with * ID tid. On failure, return -1. */ int uthread_get_quantums(int tid) { // Block SIGTVALRM signal sigset_t oldSet; blockSignal(SIGVTALRM, &oldSet); if (livingThreads.find(tid) == livingThreads.end()) { std::cerr << LIB_ERROR_MSG << "get_qunatums(" << tid << ") failed - no such thread id." << std::endl; resetSigMask(&oldSet); return EXIT_FAIL; } resetSigMask(&oldSet); return livingThreads[tid]->get_runs(); }
static void reaper(int sigraised) { /* * block additional SIGCHLD's until current children have * been reaped. */ blockSignal(); /* * send message to indicate that at least one child is ready * to be reaped. */ _SC_sendMachMessage(CFMachPortGetPort(childReaped), 0); return; }
/* * Description: This function initializes the thread library. * Call before any other thread library function, and exactly once. * The input to the function is the length of a quantum in micro-seconds. * It is an error to call this function with non-positive quantum_usecs. * Return value: On success, return 0. On failure, return -1. */ int uthread_init(int quantum_usecs) { struct sigaction sa; // Make sure the quantum time is positive. if (quantum_usecs <= 0) { std::cerr << LIB_ERROR_MSG << "quantum_usecs argument " << "must be positive" << std::endl; return EXIT_FAIL; } // Block SIGTVALRM signal sigset_t oldSet; blockSignal(SIGVTALRM, &oldSet); // Set up a the context switch func. as SIGVTALRM handler sa.sa_handler = &contextSwitch; sa.sa_flags = SIG_FLAGS; if (sigaction(SIGVTALRM, &sa, NULL) < 0) { std::cerr << SYS_ERROR_MSG << "sigaction failed." << std::endl; exit(SYSTEM_ERROR); } // Create the main thread uthread *mainThread = new uthread(MAIN_THREAD_ID, MAIN_THREAD_FUNC); mainThread->set_state(uthread::state::RUNNING); ++totalQuanta; // Add main's id to live threads list (Default == 0). livingThreads.insert(std::make_pair(mainThread->get_id(), mainThread)); // Set up a timer if (setTimer(quantum_usecs) < 0) { std::cerr << SYS_ERROR_MSG << "setitimer failed." << std::endl; exit(SYSTEM_ERROR); } // Unblock SIGVTALRM and return resetSigMask(&oldSet); return EXIT_SUCC; }
/* * Description: This function creates a new thread, whose entry point is the * function f with the signature void f(void). The thread is added to the end * of the READY threads list. The uthread_spawn function should fail if it * would cause the number of concurrent threads to exceed the limit * (MAX_THREAD_NUM). Each thread should be allocated with a stack of size * STACK_SIZE bytes. * Return value: On success, return the ID of the created thread. * On failure, return -1. */ int uthread_spawn(void (*f)(void)) { // If the current number of threads is MAX_THREAD_NUM, no // more threads can be spawned. if (livingThreads.size() >= MAX_THREAD_NUM) { std::cerr << LIB_ERROR_MSG << "Number of threads exceeded " << "the maximum number allowed." << std::endl; return EXIT_FAIL; } // Block SIGTVALRM signal sigset_t oldSet; blockSignal(SIGVTALRM, &oldSet); // Find the smallest id available, starting from MAIN_ID + 1. uthread::id newId = MAIN_THREAD_ID + 1; for (auto it = ++livingThreads.cbegin(); /* start from the second */ it != livingThreads.cend(); ++it) { if (newId < it->first) { // If the threads ids numbering doesn't match natural // incremental numbering, we found an empty spot. break; } ++newId; } // Create a fresh thread with the found id and entry function f // Then put it in the living threads list and READY list. uthread *newThread = new uthread(newId, f); livingThreads.insert(std::make_pair(newId, newThread)); readyThreads.push_back(newId); // Unblock SIGVTALRM and return resetSigMask(&oldSet); return newId; }
/* * Description: This function puts the RUNNING thread to sleep for a period * of num_quantums (not including the current quantum) after which it is moved * to the READY state. num_quantums must be a positive number. It is an error * to try to put the main thread (tid==0) to sleep. Immediately after a thread * transitions to the SLEEPING state a scheduling decision should be made. * Return value: On success, return 0. On failure, return -1. */ int uthread_sleep(int num_quantums) { // Block SIGTVALRM signal sigset_t oldSet; blockSignal(SIGVTALRM, &oldSet); if (currentThread == MAIN_THREAD_ID) { std::cerr << LIB_ERROR_MSG << "can't put main thread to sleep" << std::endl; resetSigMask(&oldSet); return EXIT_FAIL; } uthread *curr = livingThreads[currentThread]; curr->set_wakeup(totalQuanta + num_quantums); curr->set_state(uthread::state::SLEEPING); contextSwitch(SIGVTALRM); // Unblock SIGVTALRM and return resetSigMask(&oldSet); return EXIT_SUCC; }
///配置运行环境信息 int CwxEchoApp::initRunEnv(){ ///设置系统的时钟间隔,最小刻度为1ms,此为1s。 this->setClick(1000);//1s ///设置工作目录 this->setWorkDir(this->m_config.m_strWorkDir.c_str()); ///设置循环运行日志的数量 this->setLogFileNum(LOG_FILE_NUM); ///设置每个日志文件的大小 this->setLogFileSize(LOG_FILE_SIZE*1024*1024); ///调用架构的initRunEnv,使以上设置的参数生效 if (CwxAppFramework::initRunEnv() == -1 ) return -1; blockSignal(SIGPIPE); //set version this->setAppVersion(ECHO_APP_VERSION); //set last modify date this->setLastModifyDatetime(ECHO_MODIFY_DATE); //set compile date this->setLastCompileDatetime(CWX_COMPILE_DATE(_BUILD_DATE)); ///将加载的配置文件信息输出到日志文件中,以供查看检查 string strConfOut; m_config.outputConfig(strConfOut); CWX_INFO((strConfOut.c_str())); ///注册echo请求的处理handle,echo请求的svr-id为SVR_TYPE_ECHO m_eventHandler = new CwxEchoEventHandler(this); this->getCommander().regHandle(SVR_TYPE_ECHO, m_eventHandler); ///监听TCP连接,其建立的连接的svr-id都为SVR_TYPE_ECHO,接收的消息的svr-id都为SVR_TYPE_ECHO。 ///全部由m_eventHandler对象来处理 if (0 > this->noticeTcpListen(SVR_TYPE_ECHO, this->m_config.m_listen.getHostName().c_str(), this->m_config.m_listen.getPort(), false, CWX_APP_MSG_MODE, CwxEchoApp::setSockAttr, this)) { CWX_ERROR(("Can't register the echo acceptor port: addr=%s, port=%d", this->m_config.m_listen.getHostName().c_str(), this->m_config.m_listen.getPort())); return -1; } ///监听UNIX DOMAIN连接,其建立的连接的svr-id都为SVR_TYPE_ECHO,接收的消息的svr-id都为SVR_TYPE_ECHO。 ///全部由m_eventHandler对象来处理 if (0 > this->noticeLsockListen(SVR_TYPE_ECHO, this->m_config.m_strUnixPathFile.c_str())) { CWX_ERROR(("Can't register the echo unix acceptor port: path=%s", m_config.m_strUnixPathFile.c_str())); return -1; } ///创建线程池对象,此线程池中线程的group-id为2,线程池的线程数量为m_config.m_unThreadNum。 m_threadPool = new CwxThreadPool(m_config.m_unThreadNum, &getCommander()); ///启动线程,线程池中线程的线程栈大小为1M。 if ( 0 != m_threadPool->start(NULL)){ CWX_ERROR(("Failure to start thread pool")); return -1; } return 0; }
Env* rvmStartup(Options* options) { // TODO: Error handling #if defined(IOS) && (defined(RVM_ARMV7) || defined(RVM_THUMBV7)) // Enable IEEE-754 denormal support. // Without this the VFP treats numbers that are close to zero as zero itself. // See http://developer.apple.com/library/ios/#technotes/tn2293/_index.html. fenv_t fenv; fegetenv(&fenv); fenv.__fpscr &= ~__fpscr_flush_to_zero; fesetenv(&fenv); #endif TRACE("Initializing GC"); if (!initGC(options)) return NULL; // Block SIGPIPE signals. SIGPIPE interrupts write() calls which we don't // want. Dalvik does this too in dalvikvm/Main.cpp. if (!blockSignal(SIGPIPE)) return NULL; // Block SIGXFSZ signals. SIGXFSZ is raised when writing beyond the RLIMIT_FSIZE // of the current process (at least on Darwin) using pwrite(). if (!blockSignal(SIGXFSZ)) return NULL; VM* vm = rvmCreateVM(options); if (!vm) return NULL; Env* env = rvmCreateEnv(vm); if (!env) return NULL; // TODO: What if we can't allocate Env? if (!initClasspathEntries(env, options->basePath, options->rawBootclasspath, &options->bootclasspath)) return NULL; if (!initClasspathEntries(env, options->basePath, options->rawClasspath, &options->classpath)) return NULL; // Call init on modules TRACE("Initializing logging"); if (!rvmInitLog(env)) return NULL; TRACE("Initializing classes"); if (!rvmInitClasses(env)) return NULL; TRACE("Initializing memory"); if (!rvmInitMemory(env)) return NULL; TRACE("Initializing methods"); if (!rvmInitMethods(env)) return NULL; TRACE("Initializing strings"); if (!rvmInitStrings(env)) return NULL; TRACE("Initializing monitors"); if (!rvmInitMonitors(env)) return NULL; TRACE("Initializing proxy"); if (!rvmInitProxy(env)) return NULL; TRACE("Initializing threads"); if (!rvmInitThreads(env)) return NULL; TRACE("Initializing attributes"); if (!rvmInitAttributes(env)) return NULL; TRACE("Initializing primitive wrapper classes"); if (!rvmInitPrimitiveWrapperClasses(env)) return NULL; TRACE("Initializing exceptions"); if (!rvmInitExceptions(env)) return NULL; TRACE("Initializing signals"); if (!rvmInitSignals(env)) return NULL; // Initialize the RoboVM rt JNI code // RT_JNI_OnLoad(&vm->javaVM, NULL); // Initialize dalvik's JNIHelp code in libnativehelper TRACE("Initializing dalvik's libnativehelper"); registerJniHelp((JNIEnv*) env); // Initialize the dalvik rt JNI code TRACE("Initializing dalvik's runtime JNI code"); registerCoreLibrariesJni((JNIEnv*) env); TRACE("Creating system ClassLoader"); systemClassLoader = rvmGetSystemClassLoader(env); if (rvmExceptionOccurred(env)) goto error_system_ClassLoader; env->currentThread->threadObj->contextClassLoader = systemClassLoader; TRACE("Initialization done"); env->vm->initialized = TRUE; // Start Daemons TRACE("Starting Daemons"); java_lang_Daemons = rvmFindClassUsingLoader(env, "java/lang/Daemons", NULL); if (!java_lang_Daemons) goto error_daemons; java_lang_Daemons_start = rvmGetClassMethod(env, java_lang_Daemons, "start", "()V"); if (!java_lang_Daemons_start) goto error_daemons; rvmCallVoidClassMethod(env, java_lang_Daemons, java_lang_Daemons_start); if (rvmExceptionCheck(env)) goto error_daemons; TRACE("Daemons started"); return env; error_daemons: error_system_ClassLoader: rvmDetachCurrentThread(env->vm, TRUE); return NULL; }