Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add signals for CoreContext operations #713

Merged
merged 1 commit into from
Aug 7, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 33 additions & 9 deletions autowiring/CoreContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
#include "MemoEntry.h"
#include "CoreObjectDescriptor.h"
#include "result_or_default.h"
#include "TeardownNotifier.h"
#include "ThreadPool.h"
#include "TypeRegistry.h"
#include "TypeUnifier.h"
Expand Down Expand Up @@ -144,14 +143,26 @@ class AutoSearchLambdaDefault:
/// Events, threads, and filter graphs require that the context's Initiate() function is called.
/// </remarks>
class CoreContext:
public TeardownNotifier,
public std::enable_shared_from_this<CoreContext>
{
protected:
typedef std::list<std::weak_ptr<CoreContext>> t_childList;
CoreContext(const std::shared_ptr<CoreContext>& pParent, t_childList::iterator backReference);

public:
// Asserted when the context is initiated
autowiring::signal<void()> onInitiated;

// Asserted when the context is actually running
autowiring::signal<void()> onRunning;

// Asserted when the context is being shut down
autowiring::signal<void()> onShutdown;

// Asserted when the context is tearing down but before members objects are destroyed or
// any contained AutoWired fields are unlinked
autowiring::signal<void(const CoreContext&)> onTeardown;

virtual ~CoreContext(void);

/// <summary>
Expand Down Expand Up @@ -486,18 +497,27 @@ class CoreContext:
// Internal resolvers, used to determine which teardown style the user would like to use
/// \internal
template<class Fx>
void AddTeardownListener2(Fx&& fx, void (Fx::*)(void)) { TeardownNotifier::AddTeardownListener(fx); }
void AddTeardownListener2(Fx&& fx, void (Fx::*)(void)) {
onTeardown += [fx](const CoreContext&) { fx(); };
}

/// \internal
template<class Fx>
void AddTeardownListener2(Fx&& fx, void (Fx::*)(const CoreContext&)) { TeardownNotifier::AddTeardownListener([fx, this] () mutable { fx(*this); }); }
void AddTeardownListener2(Fx&& fx, void (Fx::*)(const CoreContext&)) {
onTeardown += std::move(fx);
}

/// \internal
template<class Fx>
void AddTeardownListener2(Fx&& fx, void (Fx::*)(void) const) { TeardownNotifier::AddTeardownListener(std::forward<Fx&&>(fx)); }
void AddTeardownListener2(Fx&& fx, void (Fx::*)(void) const) {
onTeardown += [fx](const CoreContext&) { fx(); };
}

/// \internal
template<class Fx>
void AddTeardownListener2(Fx&& fx, void (Fx::*)(const CoreContext&) const) { TeardownNotifier::AddTeardownListener([fx, this] () mutable { fx(*this); }); }
void AddTeardownListener2(Fx&& fx, void (Fx::*)(const CoreContext&) const) {
onTeardown += std::move(fx);
}

public:
// Accessor methods:
Expand Down Expand Up @@ -1267,9 +1287,7 @@ class CoreContext:
/// Adds a teardown notifier which receives a pointer to this context on destruction
/// </summary>
template<class Fx>
void AddTeardownListener(Fx&& fx) {
AddTeardownListener2<Fx>(std::forward<Fx&&>(fx), &Fx::operator());
}
void DEPRECATED(AddTeardownListener(Fx&& fx), "Superceded by onTeardown");

/// <summary>
/// Unregisters a slot as a recipient of potential autowiring
Expand All @@ -1282,6 +1300,12 @@ class CoreContext:
void Dump(std::ostream& os) const;
};


template<class Fx>
void CoreContext::AddTeardownListener(Fx&& fx) {
AddTeardownListener2<Fx>(std::forward<Fx&&>(fx), &Fx::operator());
}

namespace autowiring {
/// <summary>
/// Forward-declarable version of CoreContext::InjectCurrent
Expand Down
11 changes: 10 additions & 1 deletion src/autowiring/CoreContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ CoreContext::~CoreContext(void) {
);

// Notify all ContextMember instances that their parent is going away
NotifyTeardownListeners();
onTeardown(*this);

// Make sure events aren't happening anymore:
UnregisterEventReceiversUnsafe();
Expand Down Expand Up @@ -435,6 +435,7 @@ void CoreContext::Initiate(void) {
// Notify all child contexts that they can start if they want
if (!IsRunning()) {
lk.unlock();
onInitiated();

// Need to inject a delayed context type so that this context will not be destroyed until
// it has an opportunity to start.
Expand Down Expand Up @@ -464,6 +465,7 @@ void CoreContext::Initiate(void) {
// call to Start that follows the unlock.
threadPool = m_threadPool;
lk.unlock();
onInitiated();

// Start the thread pool out of the lock, and then update our start token if our thread pool
// reference has not changed. The next pool could potentially be nullptr if the parent is going
Expand All @@ -490,6 +492,9 @@ void CoreContext::Initiate(void) {
(*q)->Start(outstanding);
}

// We assert this condition only after all threads have been at least notified that they can start
onRunning();

// Update state of children now that we are initated
TryTransitionChildrenState();
}
Expand Down Expand Up @@ -532,6 +537,7 @@ void CoreContext::SignalShutdown(bool wait, ShutdownMode shutdownMode) {

m_stateBlock->m_stateChanged.notify_all();
}
onShutdown();

// Teardown interleave assurance--all of these contexts will generally be destroyed
// at the exit of this block, due to the behavior of SignalTerminate, unless exterior
Expand Down Expand Up @@ -1208,7 +1214,10 @@ void CoreContext::TryTransitionChildrenState(void) {
// Child had it's state changed
child->m_stateBlock->m_stateChanged.notify_all();

// Raise the run condition in the child
childLk.unlock();
child->onRunning();

auto outstanding = child->m_stateBlock->IncrementOutstandingThreadCount(child);

while (q != child->m_threads.end()) {
Expand Down
43 changes: 43 additions & 0 deletions src/autowiring/test/CoreContextTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -522,3 +522,46 @@ TEST_F(CoreContextTest, UnlinkOnTeardown) {
ASSERT_TRUE(strongB->v.IsAutowired()) << "An Autowired field pointing to a foreign context was incorrectly unlinked";
ASSERT_EQ(so.get(), strongB->so.get()) << "An Autowired field was unlinked on teardown even though it pointed outside of a context";
}

TEST_F(CoreContextTest, InitiateAssertsSignals) {
AutoCurrentContext outer;

auto teardown = std::make_shared<bool>(false);
{
AutoCreateContext ctxt;
auto initiated = std::make_shared<bool>(false);
auto running = std::make_shared<bool>(false);
auto shutdown = std::make_shared<bool>(false);

ctxt->onInitiated += [initiated] { *initiated = true; };
ctxt->onRunning += [running] { *running = true; };
ctxt->onShutdown += [shutdown] { *shutdown = true; };
ctxt->onTeardown += [teardown] (const CoreContext&) { *teardown = true; };

ctxt->Initiate();
ASSERT_TRUE(*initiated) << "Initiation signal not asserted on context startup";
ASSERT_FALSE(*running) << "Running signal asserted before the outer context was started";
ASSERT_FALSE(*shutdown) << "Termination signal asserted prematurely";
*initiated = false;

outer->Initiate();
ASSERT_FALSE(*initiated) << "Initiation signal was redundantly asserted";
ASSERT_TRUE(*running) << "Running signal not asserted when the outer context was started";
ASSERT_FALSE(*shutdown) << "Termination signal asserted prematurely";

*running = false;

ctxt->Initiate();
ASSERT_FALSE(*initiated) << "Initiation signal redundantly asserted";
ASSERT_FALSE(*running) << "Running signal redundantly asserted";
ASSERT_FALSE(*shutdown) << "Termination signal asserted unexpectedly";

ctxt->SignalShutdown();
ASSERT_FALSE(*initiated) << "Initiation signal not asserted during teardown";
ASSERT_FALSE(*running) << "Running signal asserted improperly on teardown";
ASSERT_TRUE(*shutdown) << "Termination signal not asserted as expected";

ASSERT_FALSE(*teardown) << "Teardown handler notified prematurely";
}
ASSERT_TRUE(*teardown) << "Teardown handler not correctly notified on context teardown";
}