bool ThreadPool::init() { #ifdef JS_THREADSAFE // Compute desired number of workers based on env var or # of CPUs. size_t numWorkers = 0; char *pathreads = getenv("PATHREADS"); if (pathreads != NULL) numWorkers = strtol(pathreads, NULL, 10); else numWorkers = GetCPUCount() - 1; // Allocate workers array and then start the worker threads. // Ensure that the field numWorkers_ always tracks the number of // *successfully initialized* workers. for (size_t workerId = 0; workerId < numWorkers; workerId++) { ThreadPoolWorker *worker = js_new<ThreadPoolWorker>(workerId, this); if (!worker->init()) { js_delete(worker); return false; } if (!workers_.append(worker)) { js_delete(worker); return false; } if (!worker->start()) return false; } #endif return true; }
bool ThreadPool::lazyStartWorkers(JSContext *cx) { // Starts the workers if they have not already been started. If // something goes wrong, reports an error and ensures that all // partially started threads are terminated. Therefore, upon exit // from this function, the workers array is either full (upon // success) or empty (upon failure). #ifndef JS_THREADSAFE return true; #else if (!workers_.empty()) { JS_ASSERT(workers_.length() == numWorkers()); return true; } // Allocate workers array and then start the worker threads. // Note that numWorkers() is the number of *desired* workers, // but workers_.length() is the number of *successfully // initialized* workers. for (size_t workerId = 0; workerId < numWorkers(); workerId++) { ThreadPoolWorker *worker = js_new<ThreadPoolWorker>(workerId); if (!worker) { terminateWorkersAndReportOOM(cx); return false; } if (!worker->init() || !workers_.append(worker)) { js_delete(worker); terminateWorkersAndReportOOM(cx); return false; } if (!worker->start()) { // Note: do not delete worker here because it has been // added to the array and hence will be deleted by // |terminateWorkersAndReportOOM()|. terminateWorkersAndReportOOM(cx); return false; } } return true; #endif }