virtual ~CollapsedForwardingRr();
protected:
- virtual void create(const RunnerRegistry &);
- virtual void open(const RunnerRegistry &);
+ virtual void create();
+ virtual void open();
private:
Ipc::MultiQueue::Owner *owner;
};
-RunnerRegistrationEntry(rrAfterConfig, CollapsedForwardingRr);
+RunnerRegistrationEntry(CollapsedForwardingRr);
-void CollapsedForwardingRr::create(const RunnerRegistry &)
+void CollapsedForwardingRr::create()
{
Must(!owner);
owner = Ipc::MultiQueue::Init(ShmLabel, Config.workers, 1,
QueueCapacity);
}
-void CollapsedForwardingRr::open(const RunnerRegistry &)
+void CollapsedForwardingRr::open()
{
CollapsedForwarding::Init();
}
}
/// reports our needs for shared memory pages to Ipc::Mem::Pages
-class IpcIoClaimMemoryNeedsRr: public RegisteredRunner
+/// and initializes shared memory segments used by IpcIoFile
+class IpcIoRr: public Ipc::Mem::RegisteredRunner
{
public:
/* RegisteredRunner API */
- virtual void run(const RunnerRegistry &r);
+ IpcIoRr(): owner(NULL) {}
+ virtual ~IpcIoRr();
+ virtual void claimMemoryNeeds();
+
+protected:
+ /* Ipc::Mem::RegisteredRunner API */
+ virtual void create();
+
+private:
+ Ipc::FewToFewBiQueue::Owner *owner;
};
-RunnerRegistrationEntry(rrClaimMemoryNeeds, IpcIoClaimMemoryNeedsRr);
+RunnerRegistrationEntry(IpcIoRr);
void
-IpcIoClaimMemoryNeedsRr::run(const RunnerRegistry &)
+IpcIoRr::claimMemoryNeeds()
{
const int itemsCount = Ipc::FewToFewBiQueue::MaxItemsCount(
::Config.workers, ::Config.cacheSwap.n_strands, QueueCapacity);
static_cast<int>(itemsCount * 1.1));
}
-/// initializes shared memory segments used by IpcIoFile
-class IpcIoRr: public Ipc::Mem::RegisteredRunner
-{
-public:
- /* RegisteredRunner API */
- IpcIoRr(): owner(NULL) {}
- virtual ~IpcIoRr();
-
-protected:
- virtual void create(const RunnerRegistry &);
-
-private:
- Ipc::FewToFewBiQueue::Owner *owner;
-};
-
-RunnerRegistrationEntry(rrAfterConfig, IpcIoRr);
-
-void IpcIoRr::create(const RunnerRegistry &)
+void
+IpcIoRr::create()
{
if (Config.cacheSwap.n_strands <= 0)
return;
return entryLimit;
}
-/// reports our needs for shared memory pages to Ipc::Mem::Pages
-class MemStoreClaimMemoryNeedsRr: public RegisteredRunner
+/// reports our needs for shared memory pages to Ipc::Mem::Pages;
+/// decides whether to use a shared memory cache or checks its configuration;
+/// and initializes shared memory segments used by MemStore
+class MemStoreRr: public Ipc::Mem::RegisteredRunner
{
public:
/* RegisteredRunner API */
- virtual void run(const RunnerRegistry &r);
+ MemStoreRr(): spaceOwner(NULL), mapOwner(NULL) {}
+ virtual void finalizeConfig();
+ virtual void claimMemoryNeeds();
+ virtual void useConfig();
+ virtual ~MemStoreRr();
+
+protected:
+ /* Ipc::Mem::RegisteredRunner API */
+ virtual void create();
+
+private:
+ Ipc::Mem::Owner<Ipc::Mem::PageStack> *spaceOwner; ///< free slices Owner
+ MemStoreMap::Owner *mapOwner; ///< primary map Owner
};
-RunnerRegistrationEntry(rrClaimMemoryNeeds, MemStoreClaimMemoryNeedsRr);
+RunnerRegistrationEntry(MemStoreRr);
void
-MemStoreClaimMemoryNeedsRr::run(const RunnerRegistry &)
+MemStoreRr::claimMemoryNeeds()
{
Ipc::Mem::NotePageNeed(Ipc::Mem::PageId::cachePage, MemStore::EntryLimit());
}
-/// decides whether to use a shared memory cache or checks its configuration
-class MemStoreCfgRr: public ::RegisteredRunner
-{
-public:
- /* RegisteredRunner API */
- virtual void run(const RunnerRegistry &);
-};
-
-RunnerRegistrationEntry(rrFinalizeConfig, MemStoreCfgRr);
-
-void MemStoreCfgRr::run(const RunnerRegistry &r)
+void
+MemStoreRr::finalizeConfig()
{
// decide whether to use a shared memory cache if the user did not specify
if (!Config.memShared.configured()) {
}
}
-/// initializes shared memory segments used by MemStore
-class MemStoreRr: public Ipc::Mem::RegisteredRunner
-{
-public:
- /* RegisteredRunner API */
- MemStoreRr(): spaceOwner(NULL), mapOwner(NULL) {}
- virtual void run(const RunnerRegistry &);
- virtual ~MemStoreRr();
-
-protected:
- virtual void create(const RunnerRegistry &);
-
-private:
- Ipc::Mem::Owner<Ipc::Mem::PageStack> *spaceOwner; ///< free slices Owner
- MemStoreMap::Owner *mapOwner; ///< primary map Owner
-};
-
-RunnerRegistrationEntry(rrAfterConfig, MemStoreRr);
-
-void MemStoreRr::run(const RunnerRegistry &r)
+void
+MemStoreRr::useConfig()
{
assert(Config.memShared.configured());
- Ipc::Mem::RegisteredRunner::run(r);
+ Ipc::Mem::RegisteredRunner::useConfig();
}
-void MemStoreRr::create(const RunnerRegistry &)
+void
+MemStoreRr::create()
{
if (!Config.memShared)
return;
public:
/* RegisteredRunner API */
TransientsRr(): mapOwner(NULL) {}
- virtual void run(const RunnerRegistry &);
+ virtual void useConfig();
virtual ~TransientsRr();
protected:
- virtual void create(const RunnerRegistry &);
+ virtual void create();
private:
TransientsMap::Owner *mapOwner;
};
-RunnerRegistrationEntry(rrAfterConfig, TransientsRr);
+RunnerRegistrationEntry(TransientsRr);
void
-TransientsRr::run(const RunnerRegistry &r)
+TransientsRr::useConfig()
{
assert(Config.memShared.configured());
- Ipc::Mem::RegisteredRunner::run(r);
+ Ipc::Mem::RegisteredRunner::useConfig();
}
void
-TransientsRr::create(const RunnerRegistry &)
+TransientsRr::create()
{
if (!Config.onoff.collapsed_forwarding)
return;
#include "squid.h"
#include "base/RunnersRegistry.h"
-#include <list>
-#include <map>
+#include <set>
-typedef std::list<RegisteredRunner*> Runners;
-typedef std::map<RunnerRegistry, Runners*> Registries;
+/// a collection of unique runners, in no particular order
+typedef std::set<RegisteredRunner*> Runners;
+/// all known runners
+static Runners *TheRunners = NULL;
-/// all known registries
-static Registries *TheRegistries = NULL;
-
-/// returns the requested runners list, initializing structures as needed
+/// safely returns registered runners, initializing structures as needed
static Runners &
-GetRunners(const RunnerRegistry ®istryId)
+GetRunners()
{
- if (!TheRegistries)
- TheRegistries = new Registries;
-
- if (TheRegistries->find(registryId) == TheRegistries->end())
- (*TheRegistries)[registryId] = new Runners;
-
- return *(*TheRegistries)[registryId];
+ if (!TheRunners)
+ TheRunners = new Runners;
+ return *TheRunners;
}
int
-RegisterRunner(const RunnerRegistry ®istryId, RegisteredRunner *rr)
+RegisterRunner(RegisteredRunner *rr)
{
- Runners &runners = GetRunners(registryId);
- runners.push_back(rr);
+ Runners &runners = GetRunners();
+ runners.insert(rr);
return runners.size();
}
-int
-ActivateRegistered(const RunnerRegistry ®istryId)
+void
+RunRegistered(const RegisteredRunner::Method &m)
{
- Runners &runners = GetRunners(registryId);
+ Runners &runners = GetRunners();
typedef Runners::iterator RRI;
for (RRI i = runners.begin(); i != runners.end(); ++i)
- (*i)->run(registryId);
- return runners.size();
-}
+ ((*i)->*m)();
-void
-DeactivateRegistered(const RunnerRegistry ®istryId)
-{
- Runners &runners = GetRunners(registryId);
- while (!runners.empty()) {
- delete runners.back();
- runners.pop_back();
+ if (m == &RegisteredRunner::finishShutdown) {
+ delete TheRunners;
+ TheRunners = NULL;
}
}
#define SQUID_BASE_RUNNERSREGISTRY_H
/**
- * This API allows virtually any module to register with a well-known registry,
- * be activated by some central processor at some registry-specific time, and
- * be deactiveated by some central processor at some registry-specific time.
+ * This API allows virtually any module to register its interest in receiving
+ * notification about initial configuration availability, configuration changes
+ * and other critical events in Squid lifetime without exposing the notifier
+ * to the details of the module.
*
* For example, main.cc may activate registered I/O modules after parsing
- * squid.conf and deactivate them before exiting.
+ * squid.conf and deactivate them before exiting, all without knowing what
+ * those I/O modules really are.
*
* A module in this context is code providing a functionality or service to the
- * rest of Squid, such as src/DiskIO/Blocking, src/fs/ufs, or Cache Manager. A
- * module must declare a RegisteredRunner child class to implement activation and
- * deactivation logic using the run() method and destructor, respectively.
+ * rest of Squid, such as src/DiskIO/Blocking, src/fs/ufs, or Cache Manager. To
+ * receive notifications, a module must declare a RegisteredRunner child class
+ * and implement the methods corresponding to the events the module is
+ * interested in.
*
- * This API allows the registry to determine the right [de]activation time for
- * each group of similar modules, without knowing any module specifics.
+ * The order of events is documented in this header (where applicable), but
+ * the order in which runners are notified about a given event is undefined.
+ * If a specific notification order is required, split the event into two or
+ * more related event(s), documenting their relative order here.
*
*/
-/// well-known registries
-typedef enum {
- /// Managed by main.cc. Activated after parsing squid.conf and
- /// deactivated before freeing configuration-related memory or exit()-ing.
+/// a runnable registrant API
+/// kids must override [only] the methods they are interested in
+class RegisteredRunner
+{
+public:
+ /* Related methods below are declared in their calling order */
+
+ /* Configuration events */
+
+ /// Called after parsing squid.conf.
/// Meant for setting configuration options that depend on other
/// configuration options and were not explicitly configured.
- rrFinalizeConfig,
+ virtual void finalizeConfig() {}
- /// Managed by main.cc. Activated after rrFinalizeConfig and
- /// deactivated before rrFinalizeConfig. Meant for announcing
- /// memory reservations before memory is allocated.
- rrClaimMemoryNeeds,
+ /// Called after finalizeConfig().
+ /// Meant for announcing memory reservations before memory is allocated.
+ virtual void claimMemoryNeeds() {}
- /// Managed by main.cc. Activated after rrClaimMemoryNeeds and
- /// deactivated before rrClaimMemoryNeeds. Meant for activating
- /// modules and features based on the finalized configuration.
- rrAfterConfig,
+ /// Called after claimMemoryNeeds().
+ /// Meant for activating modules and features using a finalized
+ /// configuration with known memory requirements.
+ virtual void useConfig() {}
- rrEnd ///< not a real registry, just a label to mark the end of enum
-} RunnerRegistry;
+ /* Reconfiguration events */
-/// a runnable registrant API
-class RegisteredRunner
-{
-public:
- // called when this runner's registry is deactivated
+ /// Called after parsing squid.conf during reconfiguration.
+ /// Meant for adjusting the module state based on configuration changes.
+ virtual void syncConfig() {}
+
+ /* Shutdown events */
+
+ /// Called after receiving a shutdown request and before stopping the main
+ /// loop. At least one main loop iteration is guaranteed after this call.
+ /// Meant for cleanup and state saving that may require other modules.
+ virtual void startShutdown() {}
+
+ /// Called after stopping the main loop.
+ /// Meant for quick/basic cleanup that does not require any other modules.
virtual ~RegisteredRunner() {}
+ /// exists to simplify caller interface; override the destructor instead
+ void finishShutdown() { delete this; }
+
+ /// a pointer to one of the above notification methods
+ typedef void (RegisteredRunner::*Method)();
- // called when this runner's registry is activated
- virtual void run(const RunnerRegistry &r) = 0;
};
/// registers a given runner with the given registry and returns registry count
-int RegisterRunner(const RunnerRegistry ®istry, RegisteredRunner *rr);
+int RegisterRunner(RegisteredRunner *rr);
+
+/// Calls a given method of all runners.
+/// All runners are destroyed after the finishShutdown() call.
+void RunRegistered(const RegisteredRunner::Method &m);
-/// calls run() methods of all runners in the given registry
-int ActivateRegistered(const RunnerRegistry ®istry);
-/// deletes all runners in the given registry
-void DeactivateRegistered(const RunnerRegistry ®istry);
+/// convenience macro to describe/debug the caller and the method being called
+#define RunRegisteredHere(m) \
+ debugs(1, 2, "running " # m); \
+ RunRegistered(&m)
/// convenience function to "use" an otherwise unreferenced static variable
bool UseThisStatic(const void *);
/// convenience macro: register one RegisteredRunner kid as early as possible
-#define RunnerRegistrationEntry(Registry, Who) \
- static const bool Who ## _RegisteredWith_ ## Registry = \
- RegisterRunner(Registry, new Who) > 0 && \
- UseThisStatic(& Who ## _RegisteredWith_ ## Registry);
+#define RunnerRegistrationEntry(Who) \
+ static const bool Who ## _Registered_ = \
+ RegisterRunner(new Who) > 0 && \
+ UseThisStatic(& Who ## _Registered_);
#endif /* SQUID_BASE_RUNNERSREGISTRY_H */
public:
static Ssl::BumpMode lastDeprecatedRule;
/* RegisteredRunner API */
- virtual void run(const RunnerRegistry &);
+ virtual void finalizeConfig();
};
Ssl::BumpMode sslBumpCfgRr::lastDeprecatedRule = Ssl::bumpEnd;
-RunnerRegistrationEntry(rrFinalizeConfig, sslBumpCfgRr);
+RunnerRegistrationEntry(sslBumpCfgRr);
-void sslBumpCfgRr::run(const RunnerRegistry &r)
+void
+sslBumpCfgRr::finalizeConfig()
{
if (lastDeprecatedRule != Ssl::bumpEnd) {
assert( lastDeprecatedRule == Ssl::bumpClientFirst || lastDeprecatedRule == Ssl::bumpNone);
class ClientDbRr: public RegisteredRunner
{
public:
- virtual void run(const RunnerRegistry &);
+ /* RegisteredRunner API */
+ virtual void useConfig();
};
-RunnerRegistrationEntry(rrAfterConfig, ClientDbRr);
+RunnerRegistrationEntry(ClientDbRr);
void
-ClientDbRr::run(const RunnerRegistry &r)
+ClientDbRr::useConfig()
{
clientdbInit();
Mgr::RegisterAction("client_list", "Cache Client List", clientdbDump, 0, 1);
namespace Rock
{
-RunnerRegistrationEntry(rrAfterConfig, SwapDirRr);
+RunnerRegistrationEntry(SwapDirRr);
}
-void Rock::SwapDirRr::create(const RunnerRegistry &)
+void Rock::SwapDirRr::create()
{
Must(mapOwners.empty() && freeSlotsOwners.empty());
for (int i = 0; i < Config.cacheSwap.n_configured; ++i) {
protected:
/* Ipc::Mem::RegisteredRunner API */
- virtual void create(const RunnerRegistry &);
+ virtual void create();
private:
std::vector<SwapDir::DirMap::Owner *> mapOwners;
public:
/* RegisteredRunner API */
SharedMemPagesRr(): owner(NULL) {}
- virtual void run(const RunnerRegistry &);
- virtual void create(const RunnerRegistry &);
- virtual void open(const RunnerRegistry &);
+ virtual void useConfig();
+ virtual void create();
+ virtual void open();
virtual ~SharedMemPagesRr();
private:
Ipc::Mem::PagePool::Owner *owner;
};
-RunnerRegistrationEntry(rrAfterConfig, SharedMemPagesRr);
+RunnerRegistrationEntry(SharedMemPagesRr);
void
-SharedMemPagesRr::run(const RunnerRegistry &r)
+SharedMemPagesRr::useConfig()
{
if (Ipc::Mem::PageLimit() <= 0)
return;
- Ipc::Mem::RegisteredRunner::run(r);
+ Ipc::Mem::RegisteredRunner::useConfig();
}
void
-SharedMemPagesRr::create(const RunnerRegistry &)
+SharedMemPagesRr::create()
{
Must(!owner);
owner = Ipc::Mem::PagePool::Init(PagePoolId, Ipc::Mem::PageLimit(),
}
void
-SharedMemPagesRr::open(const RunnerRegistry &)
+SharedMemPagesRr::open()
{
Must(!ThePagePool);
ThePagePool = new Ipc::Mem::PagePool(PagePoolId);
#endif // HAVE_SHM
void
-Ipc::Mem::RegisteredRunner::run(const RunnerRegistry &r)
+Ipc::Mem::RegisteredRunner::useConfig()
{
// If Squid is built with real segments, we create() real segments
// in the master process only. Otherwise, we create() fake
#else
if (IamWorkerProcess())
#endif
- create(r);
+ create();
// we assume that master process does not need shared segments
// unless it is also a worker
if (!InDaemonMode() || !IamMasterProcess())
- open(r);
+ open();
}
{
public:
/* RegisteredRunner API */
- virtual void run(const RunnerRegistry &r);
+ virtual void useConfig();
protected:
/// called when the runner should create a new memory segment
- virtual void create(const RunnerRegistry &) = 0;
+ virtual void create() = 0;
/// called when the runner should open a previously created segment,
/// not needed if segments are opened in constructor or init methods
- virtual void open(const RunnerRegistry &) {}
+ virtual void open() {}
};
} // namespace Mem
/* detach the auth components (only do this on full shutdown) */
Auth::Scheme::FreeAll();
#endif
+
+ RunRegisteredHere(RegisteredRunner::startShutdown);
eventAdd("SquidShutdown", &StopEventLoop, this, (double) (wait + 1), 1, false);
}
Config.workers = oldWorkers;
}
+ RunRegisteredHere(RegisteredRunner::syncConfig);
+
if (IamPrimaryProcess())
CpuAffinityCheck();
CpuAffinityReconfigure();
debugs(1,2, HERE << "Doing post-config initialization\n");
leave_suid();
- ActivateRegistered(rrFinalizeConfig);
- ActivateRegistered(rrClaimMemoryNeeds);
- ActivateRegistered(rrAfterConfig);
+ RunRegisteredHere(RegisteredRunner::finalizeConfig);
+ RunRegisteredHere(RegisteredRunner::claimMemoryNeeds);
+ RunRegisteredHere(RegisteredRunner::useConfig);
enter_suid();
if (!opt_no_daemon && Config.workers > 0)
if (!TheKids.someRunning() && !TheKids.shouldRestartSome()) {
leave_suid();
- DeactivateRegistered(rrAfterConfig);
- DeactivateRegistered(rrClaimMemoryNeeds);
- DeactivateRegistered(rrFinalizeConfig);
+ // XXX: Master process has no main loop and, hence, should not call
+ // RegisteredRunner::startShutdown which promises a loop iteration.
+ RunRegisteredHere(RegisteredRunner::finishShutdown);
enter_suid();
if (TheKids.someSignaled(SIGINT) || TheKids.someSignaled(SIGTERM)) {
Store::Root().sync(); /* Flush log close */
StoreFileSystem::FreeAllFs();
DiskIOModule::FreeAllModules();
- DeactivateRegistered(rrAfterConfig);
- DeactivateRegistered(rrClaimMemoryNeeds);
- DeactivateRegistered(rrFinalizeConfig);
#if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
configFreeMemory();
memClean();
+ RunRegisteredHere(RegisteredRunner::finishShutdown);
+
#if XMALLOC_TRACE
xmalloc_find_leaks();
public:
/* RegisteredRunner API */
SharedSessionCacheRr(): owner(NULL) {}
- virtual void run(const RunnerRegistry &);
+ virtual void useConfig();
virtual ~SharedSessionCacheRr();
protected:
- virtual void create(const RunnerRegistry &);
+ virtual void create();
private:
Ipc::MemMap::Owner *owner;
};
-RunnerRegistrationEntry(rrAfterConfig, SharedSessionCacheRr);
+RunnerRegistrationEntry(SharedSessionCacheRr);
void
-SharedSessionCacheRr::run(const RunnerRegistry &r)
+SharedSessionCacheRr::useConfig()
{
- Ipc::Mem::RegisteredRunner::run(r);
+ Ipc::Mem::RegisteredRunner::useConfig();
}
void
-SharedSessionCacheRr::create(const RunnerRegistry &)
+SharedSessionCacheRr::create()
{
if (!isSslServer()) //no need to configure ssl session cache.
return;
store->create();
rr = new Rock::SwapDirRr;
- rr->run(rrAfterConfig);
+ rr->useConfig();
}
void
free_cachedir(&Config.cacheSwap);
- delete rr;
+ rr->finishShutdown(); // deletes rr
+ rr = NULL;
// TODO: do this once, or each time.
// safe_free(Config.replPolicy->type);