// Thread-safe, but only call outside the pool lock! void Group::requestOOBW(const ProcessPtr &process) { // Standard resource management boilerplate stuff... Pool *pool = getPool(); boost::unique_lock<boost::mutex> lock(pool->syncher); if (isAlive() && process->isAlive() && process->oobwStatus == Process::OOBW_NOT_ACTIVE) { process->oobwStatus = Process::OOBW_REQUESTED; } }
void Process::sendAbortLongRunningConnectionsMessage(const string &address) { boost::function<void ()> func = boost::bind( realSendAbortLongRunningConnectionsMessage, address); return getPool()->nonInterruptableThreads.create_thread( boost::bind(runAndPrintExceptions, func, false), "Sending detached message to process " + toString(pid), 256 * 1024); }
ConfigStorage::ConfigStorage() : m_timer(new TouchFile), m_sharedMemory(NULL), m_recursive(0), m_mutexTID(0) { m_cfg_file = -1; m_dirty = false; PathName filename; #ifdef WIN_NT DWORD sesID = 0; typedef BOOL (WINAPI *PFnProcessIdToSessionId) (DWORD, DWORD *); HMODULE hmodKernel32 = GetModuleHandle("kernel32.dll"); PFnProcessIdToSessionId pfnProcessIdToSessionId = (PFnProcessIdToSessionId) GetProcAddress(hmodKernel32, "ProcessIdToSessionId"); if (fb_utils::isGlobalKernelPrefix() || !pfnProcessIdToSessionId || pfnProcessIdToSessionId(GetCurrentProcessId(), &sesID) == 0 || sesID == 0) { filename.printf(TRACE_FILE); // TODO: it must be per engine instance } else { filename.printf("%s.%u", TRACE_FILE, sesID); } #else filename.printf(TRACE_FILE); // TODO: it must be per engine instance #endif try { m_sharedMemory.reset(FB_NEW(getPool()) SharedMemory<TraceCSHeader>(filename.c_str(), sizeof(TraceCSHeader), this)); } catch (const Exception& ex) { iscLogException("ConfigStorage: Cannot initialize the shared memory region", ex); throw; } fb_assert(m_sharedMemory->getHeader()); fb_assert(m_sharedMemory->getHeader()->mhb_version == 1); StorageGuard guard(this); checkFile(); m_timer->start(m_sharedMemory->getHeader()->cfg_file_name); ++(m_sharedMemory->getHeader()->cnt_uses); }
/* * Execute an extrinsic method */ wbem::framework::UINT32 wbem::pmem_config::PersistentMemoryCapabilitiesFactory::executeMethod( wbem::framework::UINT32 &wbemRc, const std::string method, wbem::framework::ObjectPath &object, wbem::framework::attributes_t &inParms, wbem::framework::attributes_t &outParms) { framework::UINT32 httpRc = framework::MOF_ERR_SUCCESS; wbemRc = framework::MOF_ERR_SUCCESS; struct pool *pPool = NULL; COMMON_LOG_ENTRY_PARAMS("methodName: %s, number of in params: %d", method.c_str(), (int)(inParms.size())); try { if (method == PMCAP_GETBLOCKSIZES) { // get the supported block sizes for this pool wbem::framework::UINT64_LIST blockSizes; pPool = getPool(object); // if pool is block capable, then retrieve supported block sizes, else empty if (pPool->type == POOL_TYPE_PERSISTENT) { // get system supported block sizes getSupportedBlockSizes(blockSizes); } // return in outParams outParms[PMCAP_BLOCKSIZES_PARAMNAME] = framework::Attribute(blockSizes, false); } else { httpRc = framework::CIM_ERR_METHOD_NOT_AVAILABLE; } } catch (framework::ExceptionBadParameter &) { wbemRc = PMCAP_ERR_INVALID_PARAMETER; } catch(exception::NvmExceptionLibError &e) { wbemRc = getReturnCodeFromLibException(e); } catch(framework::Exception &) { wbemRc = PMCAP_ERR_UNKNOWN; } if (pPool) { delete pPool; } COMMON_LOG_EXIT_RETURN("httpRc: %u, wbemRc: %u", httpRc, wbemRc); return httpRc; }
bool Group::testOverflowRequestQueue() const { // This has a performance penalty, although I'm not sure whether the penalty is // any greater than a hash table lookup if I were to implement it in Options. Pool::DebugSupportPtr debug = getPool()->debugSupport; if (debug) { return debug->testOverflowRequestQueue; } else { return false; } }
HRESULT IDirect3DDevice9New::CreateCubeTexture(UINT EdgeLength,UINT Levels,DWORD Usage,D3DFORMAT Format,D3DPOOL Pool,IDirect3DCubeTexture9** ppCubeTexture,HANDLE* pSharedHandle) { dbgf("dev: CreateCubeTexture: %d %d levels %s %s %s", EdgeLength, Levels, getPool(Pool), getUsage(Usage), getMode(Format)); if(Pool == D3DPOOL_MANAGED) { dbg("WARNING: Emulating managed cube texture with D3DUSAGE_DYNAMIC"); Pool = D3DPOOL_DEFAULT; Usage |= D3DUSAGE_DYNAMIC; } HRESULT ret = dev->CreateCubeTexture(EdgeLength, Levels, Usage, Format, Pool, ppCubeTexture, pSharedHandle); return ret; }
/* Given a hook name like "queue_full_error", we return HookScriptOptions filled in with this name and a spec * (user settings that can be queried from agentsOptions using the external hook name that is prefixed with "hook_") * * @return false if the user parameters (agentsOptions) are not available (e.g. during ApplicationPool2_PoolTest) */ bool Group::prepareHookScriptOptions(HookScriptOptions &hsOptions, const char *name) { SpawningKit::ConfigPtr config = getPool()->getSpawningKitConfig(); if (config->agentsOptions == NULL) { return false; } hsOptions.name = name; string hookName = string("hook_") + name; hsOptions.spec = config->agentsOptions->get(hookName, false); return true; }
void Group::restart(const Options &options, RestartMethod method) { vector<Callback> actions; assert(isAlive()); P_DEBUG("Restarting group " << name); // If there is currently a restarter thread or a spawner thread active, // the following tells them to abort their current work as soon as possible. restartsInitiated++; processesBeingSpawned = 0; m_spawning = false; m_restarting = true; detachAll(actions); getPool()->interruptableThreads.create_thread( boost::bind(&Group::finalizeRestart, this, shared_from_this(), options.copyAndPersist().clearPerRequestFields(), method, getPool()->spawnerFactory, restartsInitiated, actions), "Group restarter: " + name, POOL_HELPER_THREAD_STACK_SIZE ); }
// 命令格式 void GameFactory::createCommandRequestAndSend( int command, int type, int id, property_list propertyList ) { GameFactory::GameCommandRequest request; request.command = command; request.type = type; request.id = id; request.propertyList = propertyList; getPool()->processRequest(request); }
/** * The `immediately` parameter only has effect if the detached processes checker * thread is active. It means that, if the thread is currently sleeping, it should * wake up immediately and perform work. */ void Group::startCheckingDetachedProcesses(bool immediately) { if (!detachedProcessesCheckerActive) { P_DEBUG("Starting detached processes checker"); getPool()->nonInterruptableThreads.create_thread( boost::bind(&Group::detachedProcessesCheckerMain, this, shared_from_this()), "Detached processes checker: " + name, POOL_HELPER_THREAD_STACK_SIZE ); detachedProcessesCheckerActive = true; } else if (detachedProcessesCheckerActive && immediately) { detachedProcessesCheckerCond.notify_all(); } }
boost::shared_ptr<Group> Group::findOtherGroupWaitingForCapacity() const { PoolPtr pool = getPool(); StringMap<SuperGroupPtr>::const_iterator sg_it, sg_end = pool->superGroups.end(); for (sg_it = pool->superGroups.begin(); sg_it != sg_end; sg_it++) { pair<StaticString, SuperGroupPtr> p = *sg_it; vector<GroupPtr>::const_iterator g_it, g_end = p.second->groups.end(); for (g_it = p.second->groups.begin(); g_it != g_end; g_it++) { if (g_it->get() != this && (*g_it)->isWaitingForCapacity()) { return *g_it; } } } return GroupPtr(); }
int MTGPack::assemblePack(MTGDeck *to) { int carryover = 0; WSrcCards * p = getPool(pool); if (!p) return -1; p->Shuffle(); for (size_t i = 0; i < slotss.size(); i++) { carryover = slotss[i]->add(p, to, carryover); } SAFE_DELETE(p); return carryover; }
Group * Group::findOtherGroupWaitingForCapacity() const { Pool *pool = getPool(); if (pool->groups.size() == 1) { return NULL; } GroupMap::ConstIterator g_it(pool->groups); while (*g_it != NULL) { const GroupPtr &group = g_it.getValue(); if (group.get() != this && group->isWaitingForCapacity()) { return group.get(); } g_it.next(); } return NULL; }
bool MTGPack::meetsRequirements() { bool unlocked = true; WCFilterFactory * ff = WCFilterFactory::GetInstance(); WSrcCards * myC = getPool(pool); if (!myC || myC->Size() < maxCards) unlocked = false; //Top pool lacks cards. SAFE_DELETE(myC); if (!check.size() || !unlocked) return unlocked; myC = NEW WSrcUnlockedCards(); //Requirements are independent of pool; WCardFilter * cf = ff->Construct(check); unlocked = !myC->isEmptySet(cf); //Quick check for empty set status. SAFE_DELETE(cf); //delete requirement filter SAFE_DELETE(myC); //delete pool. return unlocked; }
GlobalRWLock::GlobalRWLock(thread_db* tdbb, MemoryPool& p, locktype_t lckType, lck_owner_t lock_owner, bool lock_caching, size_t lockLen, const UCHAR* lockStr) : PermanentStorage(p), pendingLock(0), readers(0), pendingWriters(0), currentWriter(false), lockCaching(lock_caching), blocking(false) { SET_TDBB(tdbb); cachedLock = FB_NEW_RPT(getPool(), lockLen) Lock(); cachedLock->lck_type = static_cast<lck_t>(lckType); cachedLock->lck_owner_handle = LCK_get_owner_handle_by_type(tdbb, lock_owner); cachedLock->lck_length = lockLen; Database* dbb = tdbb->getDatabase(); cachedLock->lck_dbb = dbb; cachedLock->lck_parent = dbb->dbb_lock; cachedLock->lck_object = this; cachedLock->lck_ast = lockCaching ? blocking_ast_cached_lock : NULL; memcpy(&cachedLock->lck_key, lockStr, lockLen); }
void Group::onSessionInitiateFailure(const ProcessPtr &process, Session *session) { vector<Callback> actions; TRACE_POINT(); // Standard resource management boilerplate stuff... PoolPtr pool = getPool(); boost::unique_lock<boost::mutex> lock(pool->syncher); assert(process->isAlive()); assert(isAlive() || getLifeStatus() == SHUTTING_DOWN); UPDATE_TRACE_POINT(); P_DEBUG("Could not initiate a session with process " << process->inspect() << ", detaching from pool if possible"); if (!pool->detachProcessUnlocked(process, actions)) { P_DEBUG("Process was already detached"); } pool->fullVerifyInvariants(); lock.unlock(); runAllActions(actions); }
// The 'self' parameter is for keeping the current Group object alive void Group::lockAndMaybeInitiateOobw(const ProcessPtr &process, DisableResult result, GroupPtr self) { TRACE_POINT(); // Standard resource management boilerplate stuff... PoolPtr pool = getPool(); boost::unique_lock<boost::mutex> lock(pool->syncher); if (OXT_UNLIKELY(!process->isAlive() || !isAlive())) { return; } assert(process->oobwStatus == Process::OOBW_IN_PROGRESS); if (result == DR_SUCCESS) { if (process->enabled == Process::DISABLED) { P_DEBUG("Process " << process->inspect() << " disabled; proceeding " << "with out-of-band work"); process->oobwStatus = Process::OOBW_REQUESTED; if (shouldInitiateOobw(process)) { initiateOobw(process); } else { // We do not re-enable the process because it's likely that the // administrator has explicitly changed the state. P_DEBUG("Out-of-band work for process " << process->inspect() << " aborted " "because the process no longer requests out-of-band work"); process->oobwStatus = Process::OOBW_NOT_ACTIVE; } } else { // We do not re-enable the process because it's likely that the // administrator has explicitly changed the state. P_DEBUG("Out-of-band work for process " << process->inspect() << " aborted " "because the process was reenabled after disabling"); process->oobwStatus = Process::OOBW_NOT_ACTIVE; } } else { P_DEBUG("Out-of-band work for process " << process->inspect() << " aborted " "because the process could not be disabled"); process->oobwStatus = Process::OOBW_NOT_ACTIVE; } }
gl::Error TextureStorage9_2D::getBaseTexture(IDirect3DBaseTexture9 **outTexture) { // if the width or height is not positive this should be treated as an incomplete texture // we handle that here by skipping the d3d texture creation if (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0) { ASSERT(mMipLevels > 0); IDirect3DDevice9 *device = mRenderer->getDevice(); HRESULT result = device->CreateTexture(mTextureWidth, mTextureHeight, mMipLevels, getUsage(), mTextureFormat, getPool(), &mTexture, NULL); if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 2D storage texture, result: 0x%X.", result); } } *outTexture = mTexture; return gl::Error(GL_NO_ERROR); }
Config::Config(const ConfigFile& file) { // Array to save string temporarily // Will be finally saved by loadValues() in the end of ctor Firebird::ObjectsArray<ConfigFile::String> tempStrings(getPool()); // Iterate through the known configuration entries for (unsigned int i = 0; i < MAX_CONFIG_KEY; i++) { values[i] = entries[i].default_value; if (entries[i].data_type == TYPE_STRING && values[i]) { ConfigFile::String expand((const char*)values[i]); if (file.macroParse(expand, NULL) && expand != (const char*) values[i]) { ConfigFile::String& saved(tempStrings.add()); saved = expand; values[i] = (ConfigValue) saved.c_str(); } } } loadValues(file); }
HRESULT IDirect3DDevice9New::CreateVertexBuffer(UINT Length,DWORD Usage,DWORD FVF,D3DPOOL Pool,IDirect3DVertexBuffer9** ppVertexBuffer,HANDLE* pSharedHandle) { dbgf("dev: CreateVertexBuffer %s %s fvf%d length%d %d", getUsage(Usage), getPool(Pool), FVF, Length, pSharedHandle); /*CHECKPOOL(Pool);*/ #if USE_D3DEX || MANAGE_DEBUG_VB if(config.debug.compatibleVB || config.debug.enableVBQuirk) { if(config.debug.enableVBQuirk) ONCE dbg("DEBUG: Vertex buffer quirk mode enabled: Using compatibleVB"); // Not so good performance but works ok if(Pool == D3DPOOL_MANAGED) Pool = D3DPOOL_DEFAULT; } else { if(config.debug.enableVBQuirk) dbg("ERROR: enableVBQuirk with manage-emulation!"); if(Pool == D3DPOOL_MANAGED) { // Emulate manage-vertexbuffer *ppVertexBuffer = new IDirect3DVertexBuffer9Managed((IDirect3DDevice9Ex*)dev, this, Length, Usage, FVF, Pool, pSharedHandle); return ((IDirect3DVertexBuffer9Managed*)*ppVertexBuffer)->GetResult(); } } #endif HRESULT ret = dev->CreateVertexBuffer(Length, Usage, FVF, Pool, ppVertexBuffer, pSharedHandle); if(ret == D3D_OK && !(Usage&D3DUSAGE_SOFTWAREPROCESSING)) // TODO: Why does Trackmania crash with D3DUSAGE_SOFTWAREPROCESSING here? { if(config.debug.enableVBQuirk) { // Vertex buffer quirk mode for old DCS-10C version (emulate D3D behaviour with illegal functionality) ONCE dbg("DEBUG: using vertex buffer quirk mode"); *ppVertexBuffer = new IDirect3DVertexBuffer9Quirk(*ppVertexBuffer, Length); } } return ret; }
// 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"); } }
string SuperGroup::generateSecret() const { return getPool()->randomGenerator->generateAsciiString(43); }
void Group::onSessionClose(const ProcessPtr &process, Session *session) { TRACE_POINT(); // Standard resource management boilerplate stuff... PoolPtr pool = getPool(); boost::unique_lock<boost::mutex> lock(pool->syncher); assert(process->isAlive()); assert(isAlive() || getLifeStatus() == SHUTTING_DOWN); P_TRACE(2, "Session closed for process " << process->inspect()); verifyInvariants(); UPDATE_TRACE_POINT(); /* Update statistics. */ process->sessionClosed(session); assert(process->getLifeStatus() == Process::ALIVE); assert(process->enabled == Process::ENABLED || process->enabled == Process::DISABLING || process->enabled == Process::DETACHED); if (process->enabled == Process::ENABLED) { pqueue.decrease(process->pqHandle, process->busyness()); } /* This group now has a process that's guaranteed to be not * totally busy. */ assert(!process->isTotallyBusy()); bool detachingBecauseOfMaxRequests = false; bool detachingBecauseCapacityNeeded = false; bool shouldDetach = ( detachingBecauseOfMaxRequests = ( options.maxRequests > 0 && process->processed >= options.maxRequests )) || ( detachingBecauseCapacityNeeded = ( process->sessions == 0 && getWaitlist.empty() && ( !pool->getWaitlist.empty() || anotherGroupIsWaitingForCapacity() ) ) ); bool shouldDisable = process->enabled == Process::DISABLING && process->sessions == 0 && enabledCount > 0; if (shouldDetach || shouldDisable) { vector<Callback> actions; if (shouldDetach) { if (detachingBecauseCapacityNeeded) { /* Someone might be trying to get() a session for a different * group that couldn't be spawned because of lack of pool capacity. * If this group isn't under sufficiently load (as apparent by the * checked conditions) then now's a good time to detach * this process or group in order to free capacity. */ P_DEBUG("Process " << process->inspect() << " is no longer totally " "busy; detaching it in order to make room in the pool"); } else { /* This process has processed its maximum number of requests, * so we detach it. */ P_DEBUG("Process " << process->inspect() << " has reached its maximum number of requests (" << options.maxRequests << "); detaching it"); } pool->detachProcessUnlocked(process, actions); } else { removeProcessFromList(process, disablingProcesses); addProcessToList(process, disabledProcesses); removeFromDisableWaitlist(process, DR_SUCCESS, actions); maybeInitiateOobw(process); } pool->fullVerifyInvariants(); lock.unlock(); runAllActions(actions); } else { // This could change process->enabled. maybeInitiateOobw(process); if (!getWaitlist.empty() && process->enabled == Process::ENABLED) { /* If there are clients on this group waiting for a process to * become available then call them now. */ UPDATE_TRACE_POINT(); // Already calls verifyInvariants(). assignSessionsToGetWaitersQuickly(lock); } } }
void SuperGroup::realDoRestart(const Options &options, unsigned int generation) { TRACE_POINT(); vector<ComponentInfo> componentInfos = loadComponentInfos(options); vector<ComponentInfo>::const_iterator it; PoolPtr pool = getPool(); Pool::DebugSupportPtr debug = pool->debugSupport; if (debug != NULL && debug->superGroup) { debug->debugger->send("About to finish SuperGroup restart"); debug->messages->recv("Proceed with restarting SuperGroup"); } boost::unique_lock<boost::mutex> lock(getPoolSyncher(pool)); if (OXT_UNLIKELY(this->generation != generation)) { return; } assert(state == RESTARTING); verifyInvariants(); vector<GroupPtr> allGroups; vector<GroupPtr> updatedGroups; vector<GroupPtr> newGroups; vector<GroupPtr>::const_iterator g_it; vector<Callback> actions; this->options = options; // Update the component information for existing groups. UPDATE_TRACE_POINT(); for (it = componentInfos.begin(); it != componentInfos.end(); it++) { const ComponentInfo &info = *it; pair<GroupPtr, unsigned int> result = findGroupCorrespondingToComponent(groups, info); GroupPtr group = result.first; if (group != NULL) { unsigned int index = result.second; group->componentInfo = info; updatedGroups.push_back(group); groups[index].reset(); } else { // This is not an existing group but a new one, // so create it. group = boost::make_shared<Group>(shared_from_this(), options, info); newGroups.push_back(group); } // allGroups must be in the same order as componentInfos. allGroups.push_back(group); } // Some components might have been deleted, so delete the // corresponding groups. detachAllGroups(groups, actions); // Tell all previous existing groups to restart. for (g_it = updatedGroups.begin(); g_it != updatedGroups.end(); g_it++) { GroupPtr group = *g_it; group->restart(options); } groups = allGroups; defaultGroup = findDefaultGroup(allGroups); setState(READY); assignGetWaitlistToGroups(actions); UPDATE_TRACE_POINT(); verifyInvariants(); lock.unlock(); runAllActions(actions); }
void SuperGroup::realDoInitialize(const Options &options, unsigned int generation) { vector<ComponentInfo> componentInfos; vector<ComponentInfo>::const_iterator it; ExceptionPtr exception; P_TRACE(2, "Initializing SuperGroup " << inspect() << " in the background..."); try { componentInfos = loadComponentInfos(options); } catch (const tracable_exception &e) { exception = copyException(e); } if (componentInfos.empty() && exception == NULL) { string message = "The directory " + options.appRoot + " does not seem to contain a web application."; exception = boost::make_shared<SpawnException>( message, message, false); } PoolPtr pool = getPool(); Pool::DebugSupportPtr debug = pool->debugSupport; vector<Callback> actions; { if (debug != NULL && debug->superGroup) { debug->debugger->send("About to finish SuperGroup initialization"); debug->messages->recv("Proceed with initializing SuperGroup"); } boost::unique_lock<boost::mutex> lock(getPoolSyncher(pool)); this_thread::disable_interruption di; this_thread::disable_syscall_interruption dsi; NOT_EXPECTING_EXCEPTIONS(); if (OXT_UNLIKELY(getPool() == NULL || generation != this->generation)) { return; } P_TRACE(2, "Initialization of SuperGroup " << inspect() << " almost done; grabbed lock"); assert(state == INITIALIZING); verifyInvariants(); if (componentInfos.empty()) { /* Somehow initialization failed. Maybe something has deleted * the supergroup files while we're working. */ assert(exception != NULL); setState(DESTROYED); actions.reserve(getWaitlist.size()); while (!getWaitlist.empty()) { const GetWaiter &waiter = getWaitlist.front(); actions.push_back(boost::bind(waiter.callback, SessionPtr(), exception)); getWaitlist.pop_front(); } } else { for (it = componentInfos.begin(); it != componentInfos.end(); it++) { const ComponentInfo &info = *it; GroupPtr group = boost::make_shared<Group>(shared_from_this(), options, info); groups.push_back(group); if (info.isDefault) { defaultGroup = group.get(); } } setState(READY); assignGetWaitlistToGroups(actions); } verifyInvariants(); P_TRACE(2, "Done initializing SuperGroup " << inspect()); } this_thread::disable_interruption di; this_thread::disable_syscall_interruption dsi; runAllActions(actions); runInitializationHooks(); }
void SuperGroup::createInterruptableThread(const boost::function<void ()> &func, const string &name, unsigned int stackSize) { getPool()->interruptableThreads.create_thread(func, name, stackSize); }
void SuperGroup::runDestructionHooks() const { getPool()->runHookScripts("before_destroy_supergroup", boost::bind(&SuperGroup::setupInitializationOrDestructionHook, this, _1)); }
void SuperGroup::runInitializationHooks() const { getPool()->runHookScripts("after_initialize_supergroup", boost::bind(&SuperGroup::setupInitializationOrDestructionHook, this, _1)); }