template <class LbrStruct> static void fillNfa(NFA *nfa, lbr_common *c, ReportID report, const depth &repeatMin, const depth &repeatMax, u32 minPeriod, enum RepeatType rtype) { assert(nfa); RepeatStateInfo rsi(rtype, repeatMin, repeatMax, minPeriod); DEBUG_PRINTF("selected %s model for {%s,%s} repeat\n", repeatTypeName(rtype), repeatMin.str().c_str(), repeatMax.str().c_str()); // Fill the lbr_common structure first. Note that the RepeatInfo structure // directly follows the LbrStruct. const u32 info_offset = sizeof(LbrStruct); c->repeatInfoOffset = info_offset; c->report = report; RepeatInfo *info = (RepeatInfo *)((char *)c + info_offset); info->type = verify_u8(rtype); info->repeatMin = depth_to_u32(repeatMin); info->repeatMax = depth_to_u32(repeatMax); info->stateSize = rsi.stateSize; info->packedCtrlSize = rsi.packedCtrlSize; info->horizon = rsi.horizon; info->minPeriod = minPeriod; copy_bytes(&info->packedFieldSizes, rsi.packedFieldSizes); info->patchCount = rsi.patchCount; info->patchSize = rsi.patchSize; info->encodingSize = rsi.encodingSize; info->patchesOffset = rsi.patchesOffset; // Fill the NFA structure. nfa->nPositions = repeatMin; nfa->streamStateSize = verify_u32(rsi.packedCtrlSize + rsi.stateSize); nfa->scratchStateSize = (u32)sizeof(lbr_state); nfa->minWidth = verify_u32(repeatMin); nfa->maxWidth = repeatMax.is_finite() ? verify_u32(repeatMax) : 0; // Fill the lbr table for sparse lbr model. if (rtype == REPEAT_SPARSE_OPTIMAL_P) { u64a *table = getTable<LbrStruct>(nfa); // Adjust table length according to the optimal patch length. size_t len = nfa->length; assert((u32)repeatMax >= rsi.patchSize); len -= sizeof(u64a) * ((u32)repeatMax - rsi.patchSize); nfa->length = verify_u32(len); info->length = verify_u32(sizeof(RepeatInfo) + sizeof(u64a) * (rsi.patchSize + 1)); copy_bytes(table, rsi.table); } }
// The 'self' parameter is for keeping the current Group object alive while this thread is running. void Group::finalizeRestart(GroupPtr self, Options options, RestartMethod method, SpawnerFactoryPtr spawnerFactory, unsigned int restartsInitiated, vector<Callback> postLockActions) { TRACE_POINT(); Pool::runAllActions(postLockActions); postLockActions.clear(); this_thread::disable_interruption di; this_thread::disable_syscall_interruption dsi; // Create a new spawner. SpawnerPtr newSpawner = spawnerFactory->create(options); SpawnerPtr oldSpawner; UPDATE_TRACE_POINT(); PoolPtr pool = getPool(); Pool::DebugSupportPtr debug = pool->debugSupport; if (debug != NULL && debug->restarting) { this_thread::restore_interruption ri(di); this_thread::restore_syscall_interruption rsi(dsi); this_thread::interruption_point(); debug->debugger->send("About to end restarting"); debug->messages->recv("Finish restarting"); } ScopedLock l(pool->syncher); if (!isAlive()) { P_DEBUG("Group " << name << " is shutting down, so aborting restart"); return; } if (restartsInitiated != this->restartsInitiated) { // Before this restart could be finalized, another restart command was given. // The spawner we just created might be out of date now so we abort. P_DEBUG("Restart of group " << name << " aborted because a new restart was initiated concurrently"); if (debug != NULL && debug->restarting) { debug->debugger->send("Restarting aborted"); } return; } // Run some sanity checks. pool->fullVerifyInvariants(); assert(m_restarting); UPDATE_TRACE_POINT(); // Atomically swap the new spawner with the old one. resetOptions(options); oldSpawner = spawner; spawner = newSpawner; m_restarting = false; if (shouldSpawn()) { spawn(); } else if (isWaitingForCapacity()) { P_INFO("Group " << name << " is waiting for capacity to become available. " "Trying to shutdown another idle process to free capacity..."); if (pool->forceFreeCapacity(this, postLockActions) != NULL) { spawn(); } else { P_INFO("There are no processes right now that are eligible " "for shutdown. Will try again later."); } } verifyInvariants(); l.unlock(); oldSpawner.reset(); Pool::runAllActions(postLockActions); P_DEBUG("Restart of group " << name << " done"); if (debug != NULL && debug->restarting) { debug->debugger->send("Restarting done"); } }
void Group::spawnThreadRealMain(const SpawnerPtr &spawner, const Options &options, unsigned int restartsInitiated) { TRACE_POINT(); this_thread::disable_interruption di; this_thread::disable_syscall_interruption dsi; PoolPtr pool = getPool(); Pool::DebugSupportPtr debug = pool->debugSupport; bool done = false; while (!done) { bool shouldFail = false; if (debug != NULL && debug->spawning) { UPDATE_TRACE_POINT(); this_thread::restore_interruption ri(di); this_thread::restore_syscall_interruption rsi(dsi); this_thread::interruption_point(); string iteration; { LockGuard g(debug->syncher); debug->spawnLoopIteration++; iteration = toString(debug->spawnLoopIteration); } P_DEBUG("Begin spawn loop iteration " << iteration); debug->debugger->send("Begin spawn loop iteration " + iteration); vector<string> cases; cases.push_back("Proceed with spawn loop iteration " + iteration); cases.push_back("Fail spawn loop iteration " + iteration); MessagePtr message = debug->messages->recvAny(cases); shouldFail = message->name == "Fail spawn loop iteration " + iteration; } ProcessPtr process; ExceptionPtr exception; try { UPDATE_TRACE_POINT(); this_thread::restore_interruption ri(di); this_thread::restore_syscall_interruption rsi(dsi); if (shouldFail) { throw SpawnException("Simulated failure"); } else { process = spawner->spawn(options); process->setGroup(shared_from_this()); } } catch (const thread_interrupted &) { break; } catch (const tracable_exception &e) { exception = copyException(e); // Let other (unexpected) exceptions crash the program so // gdb can generate a backtrace. } UPDATE_TRACE_POINT(); ScopeGuard guard(boost::bind(Process::forceTriggerShutdownAndCleanup, process)); boost::unique_lock<boost::mutex> lock(pool->syncher); if (!isAlive()) { if (process != NULL) { P_DEBUG("Group is being shut down so dropping process " << process->inspect() << " which we just spawned and exiting spawn loop"); } else { P_DEBUG("The group is being shut down. A process failed " "to be spawned anyway, so ignoring this error and exiting " "spawn loop"); } // We stop immediately because any previously assumed invariants // may have been violated. break; } else if (restartsInitiated != this->restartsInitiated) { if (process != NULL) { P_DEBUG("A restart was issued for the group, so dropping process " << process->inspect() << " which we just spawned and exiting spawn loop"); } else { P_DEBUG("A restart was issued for the group. A process failed " "to be spawned anyway, so ignoring this error and exiting " "spawn loop"); } // We stop immediately because any previously assumed invariants // may have been violated. break; } verifyInvariants(); assert(m_spawning); assert(processesBeingSpawned > 0); processesBeingSpawned--; assert(processesBeingSpawned == 0); UPDATE_TRACE_POINT(); vector<Callback> actions; if (process != NULL) { AttachResult result = attach(process, actions); if (result == AR_OK) { guard.clear(); if (getWaitlist.empty()) { pool->assignSessionsToGetWaiters(actions); } else { assignSessionsToGetWaiters(actions); } P_DEBUG("New process count = " << enabledCount << ", remaining get waiters = " << getWaitlist.size()); } else { done = true; P_DEBUG("Unable to attach spawned process " << process->inspect()); if (result == AR_ANOTHER_GROUP_IS_WAITING_FOR_CAPACITY) { pool->possiblySpawnMoreProcessesForExistingGroups(); } } } else { // TODO: sure this is the best thing? if there are // processes currently alive we should just use them. P_ERROR("Could not spawn process for group " << name << ": " << exception->what() << "\n" << exception->backtrace()); if (enabledCount == 0) { enableAllDisablingProcesses(actions); } Pool::assignExceptionToGetWaiters(getWaitlist, exception, actions); pool->assignSessionsToGetWaiters(actions); done = true; } done = done || (processLowerLimitsSatisfied() && getWaitlist.empty()) || processUpperLimitsReached() || pool->atFullCapacity(false); m_spawning = !done; if (done) { P_DEBUG("Spawn loop done"); } else { processesBeingSpawned++; P_DEBUG("Continue spawning"); } UPDATE_TRACE_POINT(); pool->fullVerifyInvariants(); lock.unlock(); UPDATE_TRACE_POINT(); runAllActions(actions); UPDATE_TRACE_POINT(); } if (debug != NULL && debug->spawning) { debug->debugger->send("Spawn loop done"); } }
// The 'self' parameter is for keeping the current Group object alive while this thread is running. void Group::spawnThreadOOBWRequest(GroupPtr self, ProcessPtr process) { TRACE_POINT(); this_thread::disable_interruption di; this_thread::disable_syscall_interruption dsi; Socket *socket; Connection connection; PoolPtr pool = getPool(); Pool::DebugSupportPtr debug = pool->debugSupport; UPDATE_TRACE_POINT(); P_DEBUG("Performing OOBW request for process " << process->inspect()); if (debug != NULL && debug->oobw) { debug->debugger->send("OOBW request about to start"); debug->messages->recv("Proceed with OOBW request"); } UPDATE_TRACE_POINT(); { // Standard resource management boilerplate stuff... boost::unique_lock<boost::mutex> lock(pool->syncher); if (OXT_UNLIKELY(!process->isAlive() || process->enabled == Process::DETACHED || !isAlive())) { return; } if (process->enabled != Process::DISABLED) { UPDATE_TRACE_POINT(); P_INFO("Out-of-Band Work canceled: process " << process->inspect() << " was concurrently re-enabled."); if (debug != NULL && debug->oobw) { debug->debugger->send("OOBW request canceled"); } return; } assert(process->oobwStatus == Process::OOBW_IN_PROGRESS); assert(process->sessions == 0); socket = process->sessionSockets.top(); assert(socket != NULL); } UPDATE_TRACE_POINT(); unsigned long long timeout = 1000 * 1000 * 60; // 1 min try { this_thread::restore_interruption ri(di); this_thread::restore_syscall_interruption rsi(dsi); // Grab a connection. The connection is marked as fail in order to // ensure it is closed / recycled after this request (otherwise we'd // need to completely read the response). connection = socket->checkoutConnection(); connection.fail = true; ScopeGuard guard(boost::bind(&Socket::checkinConnection, socket, connection)); // This is copied from RequestHandler when it is sending data using the // "session" protocol. char sizeField[sizeof(uint32_t)]; SmallVector<StaticString, 10> data; data.push_back(StaticString(sizeField, sizeof(uint32_t))); data.push_back(makeStaticStringWithNull("REQUEST_METHOD")); data.push_back(makeStaticStringWithNull("OOBW")); data.push_back(makeStaticStringWithNull("PASSENGER_CONNECT_PASSWORD")); data.push_back(makeStaticStringWithNull(process->connectPassword)); uint32_t dataSize = 0; for (unsigned int i = 1; i < data.size(); i++) { dataSize += (uint32_t) data[i].size(); } Uint32Message::generate(sizeField, dataSize); gatheredWrite(connection.fd, &data[0], data.size(), &timeout); // We do not care what the actual response is ... just wait for it. UPDATE_TRACE_POINT(); waitUntilReadable(connection.fd, &timeout); } catch (const SystemException &e) { P_ERROR("*** ERROR: " << e.what() << "\n" << e.backtrace()); } catch (const TimeoutException &e) { P_ERROR("*** ERROR: " << e.what() << "\n" << e.backtrace()); } UPDATE_TRACE_POINT(); vector<Callback> actions; { // Standard resource management boilerplate stuff... PoolPtr pool = getPool(); boost::unique_lock<boost::mutex> lock(pool->syncher); if (OXT_UNLIKELY(!process->isAlive() || !isAlive())) { return; } process->oobwStatus = Process::OOBW_NOT_ACTIVE; if (process->enabled == Process::DISABLED) { enable(process, actions); assignSessionsToGetWaiters(actions); } pool->fullVerifyInvariants(); initiateNextOobwRequest(); } UPDATE_TRACE_POINT(); runAllActions(actions); actions.clear(); UPDATE_TRACE_POINT(); P_DEBUG("Finished OOBW request for process " << process->inspect()); if (debug != NULL && debug->oobw) { debug->debugger->send("OOBW request finished"); } }
void threadMain() { while (!boost::this_thread::interruption_requested()) { syscalls::sleep(60 * 60); begin_touch: boost::this_thread::disable_interruption di; boost::this_thread::disable_syscall_interruption dsi; // Fork a process which touches everything in the server instance dir. pid_t pid = syscalls::fork(); if (pid == 0) { // Child int prio, ret, e; closeAllFileDescriptors(2); // Make process nicer. do { prio = getpriority(PRIO_PROCESS, getpid()); } while (prio == -1 && errno == EINTR); if (prio != -1) { prio++; if (prio > 20) { prio = 20; } do { ret = setpriority(PRIO_PROCESS, getpid(), prio); } while (ret == -1 && errno == EINTR); } else { perror("getpriority"); } do { ret = chdir(wo->instanceDir->getPath().c_str()); } while (ret == -1 && errno == EINTR); if (ret == -1) { e = errno; fprintf(stderr, "chdir(\"%s\") failed: %s (%d)\n", wo->instanceDir->getPath().c_str(), strerror(e), e); fflush(stderr); _exit(1); } restoreOomScore(agentsOptions); execlp("/bin/sh", "/bin/sh", "-c", "find . | xargs touch", (char *) 0); e = errno; fprintf(stderr, "Cannot execute 'find . | xargs touch': %s (%d)\n", strerror(e), e); fflush(stderr); _exit(1); } else if (pid == -1) { // Error P_WARN("Could not touch the server instance directory because " "fork() failed. Retrying in 2 minutes..."); boost::this_thread::restore_interruption si(di); boost::this_thread::restore_syscall_interruption rsi(dsi); syscalls::sleep(60 * 2); goto begin_touch; } else { syscalls::waitpid(pid, NULL, 0); } } }
/** * Starts the agent process. May throw arbitrary exceptions. */ virtual pid_t start() { this_thread::disable_interruption di; this_thread::disable_syscall_interruption dsi; string exeFilename = getExeFilename(); SocketPair fds; int e, ret; pid_t pid; /* Create feedback fd for this agent process. We'll send some startup * arguments to this agent process through this fd, and we'll receive * startup information through it as well. */ fds = createUnixSocketPair(); pid = syscalls::fork(); if (pid == 0) { // Child /* Make sure file descriptor FEEDBACK_FD refers to the newly created * feedback fd (fds[1]) and close all other file descriptors. * In this child process we don't care about the original FEEDBACK_FD * (which is the Watchdog's communication channel to the agents starter.) * * fds[1] is guaranteed to be != FEEDBACK_FD because the watchdog * is started with FEEDBACK_FD already assigned. */ syscalls::close(fds[0]); if (syscalls::dup2(fds[1], FEEDBACK_FD) == -1) { /* Something went wrong, report error through feedback fd. */ e = errno; try { writeArrayMessage(fds[1], "system error before exec", "dup2() failed", toString(e).c_str(), NULL); _exit(1); } catch (...) { fprintf(stderr, "Passenger Watchdog: dup2() failed: %s (%d)\n", strerror(e), e); fflush(stderr); _exit(1); } } closeAllFileDescriptors(FEEDBACK_FD); /* Become the process group leader so that the watchdog can kill the * agent as well as all its descendant processes. */ setpgid(getpid(), getpid()); setOomScore(oldOomScore); try { execProgram(); } catch (...) { fprintf(stderr, "PassengerWatchdog: execProgram() threw an exception\n"); fflush(stderr); _exit(1); } e = errno; try { writeArrayMessage(FEEDBACK_FD, "exec error", toString(e).c_str(), NULL); } catch (...) { fprintf(stderr, "Passenger Watchdog: could not execute %s: %s (%d)\n", exeFilename.c_str(), strerror(e), e); fflush(stderr); } _exit(1); } else if (pid == -1) { // Error e = errno; throw SystemException("Cannot fork a new process", e); } else { // Parent FileDescriptor feedbackFd = fds[0]; vector<string> args; fds[1].close(); this_thread::restore_interruption ri(di); this_thread::restore_syscall_interruption rsi(dsi); ScopeGuard failGuard(boost::bind(killAndWait, pid)); /* Send startup arguments. Ignore EPIPE and ECONNRESET here * because the child process might have sent an feedback message * without reading startup arguments. */ try { sendStartupArguments(pid, feedbackFd); } catch (const SystemException &ex) { if (ex.code() != EPIPE && ex.code() != ECONNRESET) { throw SystemException(string("Unable to start the ") + name() + ": an error occurred while sending startup arguments", ex.code()); } } // Now read its feedback. try { ret = readArrayMessage(feedbackFd, args); } catch (const SystemException &e) { if (e.code() == ECONNRESET) { ret = false; } else { throw SystemException(string("Unable to start the ") + name() + ": unable to read its startup information", e.code()); } } if (!ret) { this_thread::disable_interruption di2; this_thread::disable_syscall_interruption dsi2; int status; /* The feedback fd was prematurely closed for an unknown reason. * Did the agent process crash? * * We use timedWaitPid() here because if the process crashed * because of an uncaught exception, the file descriptor * might be closed before the process has printed an error * message, so we give it some time to print the error * before we kill it. */ ret = timedWaitPid(pid, &status, 5000); if (ret == 0) { /* Doesn't look like it; it seems it's still running. * We can't do anything without proper feedback so kill * the agent process and throw an exception. */ failGuard.runNow(); throw RuntimeException(string("Unable to start the ") + name() + ": it froze and reported an unknown error during its startup"); } else if (ret != -1 && WIFSIGNALED(status)) { /* Looks like a crash which caused a signal. */ throw RuntimeException(string("Unable to start the ") + name() + ": it seems to have been killed with signal " + getSignalName(WTERMSIG(status)) + " during startup"); } else if (ret == -1) { /* Looks like it exited after detecting an error. */ throw RuntimeException(string("Unable to start the ") + name() + ": it seems to have crashed during startup for an unknown reason"); } else { /* Looks like it exited after detecting an error, but has an exit code. */ throw RuntimeException(string("Unable to start the ") + name() + ": it seems to have crashed during startup for an unknown reason, " "with exit code " + toString(WEXITSTATUS(status))); } } if (args[0] == "system error before exec") { throw SystemException(string("Unable to start the ") + name() + ": " + args[1], atoi(args[2])); } else if (args[0] == "exec error") { e = atoi(args[1]); if (e == ENOENT) { throw RuntimeException(string("Unable to start the ") + name() + " because its executable (" + getExeFilename() + ") " "doesn't exist. This probably means that your " "Phusion Passenger installation is broken or " "incomplete. Please reinstall Phusion Passenger"); } else { throw SystemException(string("Unable to start the ") + name() + " because exec(\"" + getExeFilename() + "\") failed", atoi(args[1])); } } else if (!processStartupInfo(pid, feedbackFd, args)) { throw RuntimeException(string("The ") + name() + " sent an unknown startup info message '" + args[0] + "'"); } lock_guard<boost::mutex> l(lock); this->feedbackFd = feedbackFd; this->pid = pid; failGuard.clear(); return pid; } }
ErrorCode WriteDamsel::write_file(const char *file_name, const bool /* overwrite */, const FileOptions& opts, const EntityHandle *meshset_list, const int num_sets, const std::vector<std::string>& /* qa_records */, const Tag* /* tag_list */, int /* num_tags */, int /* requested_output_dimension */) { // gather all entities into one big range Range all_ents; ErrorCode rval; damsel_err_t err; dU.dmslLib = DMSLlib_init(); // create a damsel model dU.dmslModel = DMSLmodel_create(sizeof(EntityHandle) == 8 ? DAMSEL_HANDLE_TYPE_HANDLE64 : DAMSEL_HANDLE_TYPE_HANDLE32); // attach to a file, since we need it for creating containers MPI_Comm comm = MPI_COMM_WORLD; unlink(file_name); err = DMSLmodel_attach(dU.dmslModel, file_name, comm, NULL); CHK_DMSL_ERR(err, "DMSLmodel_attach failed."); rval = mWriteIface->gather_entities(all_ents, meshset_list, num_sets); CHK_MB_ERR(rval, "Gather entities failed in WriteDamsel."); if (all_ents.empty()) return MB_SUCCESS; // create damsel tags for MOAB dense, sparse, and conventional tags rval = init_tag_info(); CHK_MB_ERR(rval, NULL); // iterate through the groups of contiguous sequences of handles RangeSeqIntersectIter rsi(sequenceManager); rval = rsi.init(all_ents.begin(), all_ents.end()); while (rval == MB_SUCCESS) { // write subrange of things to damsel: map handles, map entity definition data (connectivity/coords/set contents), // map dense tags rval = write_subrange(rsi); CHK_MB_ERR(rval, "Failed to write subrange."); rval = rsi.step(); while (MB_ENTITY_NOT_FOUND == rval) rval = rsi.step(); } // write sparse tags rval = map_sparse_tags(); CHK_MB_ERR(rval, "Failed to write sparse tags."); //damsel_request_t request; //err = DMSLmodel_transfer_async(dU.dmslModel, DAMSEL_TRANSFER_TYPE_WRITE, &request); err = DMSLmodel_transfer_sync(dU.dmslModel, DAMSEL_TRANSFER_TYPE_WRITE); CHK_DMSL_ERR(err, "DMSLmodel_transfer_asynch failed."); //damsel_status_t status; //err = DMSLmodel_wait(request, &status); CHK_DMSL_ERR(err, "DMSLmodel_wait failed."); DMSLmodel_close(dU.dmslModel); DMSLlib_finalize(dU.dmslLib); // we should be done return MB_SUCCESS; }
/** \brief Returns the stream state size in bytes for a given bounded * repeat. */ static u32 streamStateSize(enum RepeatType type, const depth &repeatMin, const depth &repeatMax, u32 minPeriod) { RepeatStateInfo rsi(type, repeatMin, repeatMax, minPeriod); return rsi.stateSize; }
/** \brief Returns the packed control block size in bytes for a given bounded * repeat. */ static u32 packedSize(enum RepeatType type, const depth &repeatMin, const depth &repeatMax, u32 minPeriod) { RepeatStateInfo rsi(type, repeatMin, repeatMax, minPeriod); return rsi.packedCtrlSize; }