Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
codemercenary committed Feb 25, 2015
2 parents 44f5cff + 800d800 commit e1606cf
Show file tree
Hide file tree
Showing 61 changed files with 1,053 additions and 465 deletions.
3 changes: 3 additions & 0 deletions AutowiringConfig.h.in
Expand Up @@ -8,6 +8,9 @@
// Are we building autonet?
#cmakedefine01 AUTOWIRING_BUILD_AUTONET

// Building for ARM?
#cmakedefine01 autowiring_BUILD_ARM

// Are we linking with C++11 STL?
#cmakedefine01 autowiring_USE_LIBCXX
#if autowiring_USE_LIBCXX
Expand Down
3 changes: 2 additions & 1 deletion Doxyfile
Expand Up @@ -32,7 +32,7 @@ PROJECT_NAME = Autowiring
# This could be handy for archiving the generated documentation or
# if some version control system is used.

PROJECT_NUMBER = "0.4.1"
PROJECT_NUMBER = "0.4.2"

# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer
Expand Down Expand Up @@ -706,6 +706,7 @@ FILE_PATTERNS = "at_exit.h" \
"ContextCreator.h" \
"ContextCreatorBase.h" \
"ContextEnumerator.h" \
ContextMap.h \
"ContextMember.h" \
"CoreContext.h" \
"CoreJob.h" \
Expand Down
72 changes: 33 additions & 39 deletions autowiring/AutoPacket.h
Expand Up @@ -106,9 +106,9 @@ class AutoPacket:
/// <param name="info">The decoration which was just added to this packet</param>
/// <remarks>
/// This method results in a call to the AutoFilter method on any subscribers which are
/// satisfied by this decoration.
/// satisfied by this decoration. This method must be called with m_lock held.
/// </remarks>
void UpdateSatisfaction(const DecorationKey& info);
void UpdateSatisfactionUnsafe(std::unique_lock<std::mutex>&& lk, const DecorationDisposition& disposition);

/// <summary>
/// Performs a "satisfaction pulse", which will avoid notifying any deferred filters
Expand All @@ -126,7 +126,7 @@ class AutoPacket:
/// <summary>
/// Performs a decoration operation but does not attach priors to successors.
/// </summary>
void DecorateUnsafeNoPriors(const AnySharedPointer& ptr, const DecorationKey& key);
void DecorateNoPriors(const AnySharedPointer& ptr, DecorationKey key);

/// <summary>Runtime counterpart to Decorate</summary>
void Decorate(const AnySharedPointer& ptr, DecorationKey key);
Expand Down Expand Up @@ -185,7 +185,7 @@ class AutoPacket:
template<class T>
bool Has(int tshift=0) const {
std::lock_guard<std::mutex> lk(m_lock);
return HasUnsafe(DecorationKey(auto_id<T>::key(), tshift));
return HasUnsafe(DecorationKey(auto_id<T>::key(), true, tshift));
}

/// <summary>
Expand All @@ -197,7 +197,7 @@ class AutoPacket:

const T* retVal;
if (!Get(retVal, tshift))
ThrowNotDecoratedException(DecorationKey(auto_id<T>::key(), tshift));
ThrowNotDecoratedException(DecorationKey(auto_id<T>::key(), false, tshift));
return *retVal;
}

Expand All @@ -210,7 +210,7 @@ class AutoPacket:
/// </remarks>
template<class T>
bool Get(const T*& out, int tshift=0) const {
const DecorationDisposition* pDisposition = GetDisposition(DecorationKey(auto_id<T>::key(), tshift));
const DecorationDisposition* pDisposition = GetDisposition(DecorationKey(auto_id<T>::key(), false, tshift));
if (pDisposition) {
if (pDisposition->m_decorations.size() == 1) {
out = static_cast<const T*>(pDisposition->m_decorations[0]->ptr());
Expand Down Expand Up @@ -242,7 +242,7 @@ class AutoPacket:
template<class T>
bool Get(const std::shared_ptr<const T>*& out, int tshift=0) const {
// Decoration must be present and the shared pointer itself must also be present
const DecorationDisposition* pDisposition = GetDisposition(DecorationKey(auto_id<T>::key(), tshift));
const DecorationDisposition* pDisposition = GetDisposition(DecorationKey(auto_id<T>::key(), true, tshift));
if (!pDisposition || pDisposition->m_decorations.size() != 1) {
out = nullptr;
return false;
Expand All @@ -262,7 +262,7 @@ class AutoPacket:
template<class T>
bool Get(std::shared_ptr<const T>& out, int tshift = 0) const {
std::lock_guard<std::mutex> lk(m_lock);
auto deco = m_decorations.find(DecorationKey(auto_id<T>::key(), tshift));
auto deco = m_decorations.find(DecorationKey(auto_id<T>::key(), true, tshift));
if(deco != m_decorations.end() && deco->second.m_state == DispositionState::Satisfied) {
auto& disposition = deco->second;
if(disposition.m_decorations.size() == 1) {
Expand All @@ -274,11 +274,14 @@ class AutoPacket:
return false;
}

/// <returns>
/// The shared pointer decoration for the specified type and time shift, or nullptr if no such decoration exists
/// </returns>
template<class T>
const std::shared_ptr<const T>& GetShared(int tshift = 0) const {
const std::shared_ptr<const T>* GetShared(int tshift = 0) const {
const std::shared_ptr<const T>* retVal;
Get(retVal, tshift);
return *retVal;
return retVal;
}

/// <summary>
Expand All @@ -291,7 +294,7 @@ class AutoPacket:
template<class T>
const T** GetAll(int tshift = 0) const {
std::lock_guard<std::mutex> lk(m_lock);
auto q = m_decorations.find(DecorationKey(auto_id<T>::key(), tshift));
auto q = m_decorations.find(DecorationKey(auto_id<T>::key(), true, tshift));

// If decoration doesn't exist, return empty null-terminated buffer
if (q == m_decorations.end()) {
Expand Down Expand Up @@ -328,22 +331,8 @@ class AutoPacket:
/// </remarks>
template<class T>
void Unsatisfiable(void) {
DecorationKey key(auto_id<T>::key());
{
// Insert a null entry at this location:
std::lock_guard<std::mutex> lk(m_lock);
auto& entry = m_decorations[key];
entry.SetKey(key); // Ensure correct type if instantiated here
if(entry.m_state == DispositionState::PartlySatisfied ||
entry.m_state == DispositionState::Satisfied)
throw std::runtime_error("Cannot mark a decoration as unsatisfiable when that decoration is already present on this packet");

// Mark the entry as permanently checked-out
entry.m_state = DispositionState::Unsatisfiable;
}

// Now trigger a rescan:
MarkUnsatisfiable(key);
MarkUnsatisfiable(DecorationKey(auto_id<T>::key(), false, 0));
MarkUnsatisfiable(DecorationKey(auto_id<T>::key(), true, 0));
}

/// <summary>
Expand All @@ -356,11 +345,12 @@ class AutoPacket:
/// </remarks>
template<class T>
const T& Decorate(T t) {
DecorationKey key(auto_id<T>::key());

// Create a copy of the input, put the copy in a shared pointer
auto ptr = std::make_shared<T>(std::forward<T&&>(t));
Decorate(AnySharedPointer(ptr), key);
Decorate(
AnySharedPointer(ptr),
DecorationKey(auto_id<T>::key(), true, 0)
);
return *ptr;
}

Expand All @@ -375,7 +365,7 @@ class AutoPacket:
/// </remarks>
template<class T>
void Decorate(std::shared_ptr<T> ptr) {
DecorationKey key(auto_id<T>::key());
DecorationKey key(auto_id<T>::key(), true, 0);

// We don't want to see this overload used on a const T
static_assert(!std::is_const<T>::value, "Cannot decorate a shared pointer to const T with this overload");
Expand Down Expand Up @@ -425,8 +415,8 @@ class AutoPacket:
// Perform standard decoration with a short initialization:
std::unique_lock<std::mutex> lk(m_lock);
DecorationDisposition* pTypeSubs[1 + sizeof...(Ts)] = {
&DecorateImmediateUnsafe(DecorationKey(auto_id<T>::key()), &immed),
&DecorateImmediateUnsafe(DecorationKey(auto_id<Ts>::key()), &immeds)...
&DecorateImmediateUnsafe(DecorationKey(auto_id<T>::key(), false, 0), &immed),
&DecorateImmediateUnsafe(DecorationKey(auto_id<Ts>::key(), false, 0), &immeds)...
};
lk.unlock();

Expand All @@ -442,12 +432,14 @@ class AutoPacket:

// Now trigger a rescan to hit any deferred, unsatisfiable entries:
#if autowiring_USE_LIBCXX
for (const std::type_info* ti : {&auto_id<T>::key(), &auto_id<Ts>::key()...})
MarkUnsatisfiable(DecorationKey(*ti));
for (const std::type_info* ti : {&auto_id<T>::key(), &auto_id<Ts>::key()...}) {
MarkUnsatisfiable(DecorationKey(*ti, true, 0));
MarkUnsatisfiable(DecorationKey(*ti, false, 0));
}
#else
bool dummy[] = {
(MarkUnsatisfiable(DecorationKey(auto_id<T>::key())), false),
(MarkUnsatisfiable(DecorationKey(auto_id<Ts>::key())), false)...
(MarkUnsatisfiable(DecorationKey(auto_id<T>::key(), false, 0)), false),
(MarkUnsatisfiable(DecorationKey(auto_id<Ts>::key(), false, 0)), false)...
};
(void)dummy;
#endif
Expand Down Expand Up @@ -505,7 +497,9 @@ class AutoPacket:
/// <returns>True if the indicated type has been requested for use by some consumer</returns>
template<class T>
bool HasSubscribers(void) const {
return HasSubscribers(DecorationKey(auto_id<T>::key()));
return
HasSubscribers(DecorationKey(auto_id<T>::key(), false, 0)) ||
HasSubscribers(DecorationKey(auto_id<T>::key(), true, 0));
}

struct SignalStub {
Expand Down Expand Up @@ -597,7 +591,7 @@ template<class T>
bool AutoPacket::Get(const std::shared_ptr<T>*& out) const {
static_assert(!std::is_const<T>::value, "Overload resolution selected an incorrect version of Get");

const DecorationDisposition* pDisposition = GetDisposition(DecorationKey(auto_id<T>::key()));
const DecorationDisposition* pDisposition = GetDisposition(DecorationKey(auto_id<T>::key(), true, 0));
if (!pDisposition || pDisposition->m_decorations.size() != 1) {
out = nullptr;
return false;
Expand Down
1 change: 1 addition & 0 deletions autowiring/AutoPacketFactory.h
Expand Up @@ -75,6 +75,7 @@ class AutoPacketFactory:
bool OnStart(void) override;
void OnStop(bool graceful) override;
void DoAdditionalWait(void) override;
bool DoAdditionalWait(std::chrono::nanoseconds timeout) override;

/// <summary>
/// Causes this AutoPacketFactory to release all of its packet subscribers
Expand Down
2 changes: 1 addition & 1 deletion autowiring/AutoPacketGraph.h
Expand Up @@ -98,7 +98,7 @@ class AutoPacketGraph:
/// AutowiringEvents overrides
virtual void NewContext(CoreContext&) override {}
virtual void ExpiredContext(CoreContext&) override {}
virtual void NewObject(CoreContext&, const ObjectTraits&) override;
virtual void NewObject(CoreContext&, const CoreObjectDescriptor&) override;

/// CoreRunnable overrides
virtual bool OnStart(void) override;
Expand Down
49 changes: 17 additions & 32 deletions autowiring/AutowirableSlot.h
Expand Up @@ -11,25 +11,24 @@ class DeferrableAutowiring;
class GlobalCoreContext;
class CoreObject;

// Utility routine, for users who need a function that does nothing
template<class T>
void NullOp(T) {}

/// <summary>
/// Strategy class for performing unsynchronized operations on an autowirable slot
/// </summary>
/// <remarks>
/// The DeferrableAutowiring base class' SatisfyAutowiring routine is guaranteed to be run in a
/// synchronized context--IE, a call to CancelAutowiringNotification will block until the above
/// routines return. Unfortunately, this lock also excludes many other types of operations, such
/// as type search operations, which means that some of the work associated with cleaning up after
/// an autowiring has been satisfied will take place in an unsynchronized context. This means
/// that virtual function calls are generally unsafe on the member being autowired when they are
/// made without a lock being held.
/// routine returns. Unfortunately, this lock also excludes many other types of operations, such
/// as CoreContext::Inject and CoreContext::FindByType, which means that handing control to a user
/// specified callback is unsafe.
///
/// To mitigate this problem, instead of performing a virtual call through the original object, a
/// strategy type is provided by the DeferrableAutowiring while the lock is held, and then later the
/// strategy is employed to clean up the object, if necessary.
/// Exacerbating the problem is the fact that the original DeferrableAutowiring may refer to an
/// object on the stack or whose destruction cannot otherwise be delayed. As soon as the synchronized
/// context is exited, the object could already be in a teardown pathway, which means we can't invoke
/// any kind of virtual function call on the object.
///
/// Thus, the Finalize operation is only supported on objects whose lifetimes can be externally
/// guaranteed. Currently, only AutowirableSlotFn supports this behavior, and it is accessable via
/// CoreContext::NotifyWhenAutowired and Autowired::NotifyWhenAutowired.
/// </remarks>
class DeferrableUnsynchronizedStrategy {
public:
Expand All @@ -43,7 +42,7 @@ class DeferrableUnsynchronizedStrategy {
/// outside of the context of a lock. Once this method returns, this object is guaranteed never
/// to be referred to again by CoreContext.
/// </remarks>
virtual void Finalize(DeferrableAutowiring* pSlot) const = 0;
virtual void Finalize(void) = 0;
};

/// <summary>
Expand Down Expand Up @@ -103,7 +102,7 @@ class DeferrableAutowiring:
/// <remarks>
/// If no custom strategy is required, this method may return null
/// </remarks>
virtual const DeferrableUnsynchronizedStrategy* GetStrategy(void) { return nullptr; }
virtual DeferrableUnsynchronizedStrategy* GetStrategy(void) { return nullptr; }

/// <summary>
/// </summary>
Expand Down Expand Up @@ -204,24 +203,12 @@ class AutowirableSlot:
/// </summary>
template<class T, class Fn>
class AutowirableSlotFn:
public AutowirableSlot<T>
public AutowirableSlot<T>,
public DeferrableUnsynchronizedStrategy
{
static_assert(!std::is_same<CoreContext, T>::value, "Do not attempt to autowire CoreContext. Instead, use AutoCurrentContext or AutoCreateContext");
static_assert(!std::is_same<GlobalCoreContext, T>::value, "Do not attempt to autowire GlobalCoreContext. Instead, use AutoGlobalContext");

class Strategy:
public DeferrableUnsynchronizedStrategy
{
public:
Strategy(void) {}

void Finalize(DeferrableAutowiring* pfn) const override {
((AutowirableSlotFn*) pfn)->Finalize();
}
};

static const Strategy s_strategy;

public:
AutowirableSlotFn(const std::shared_ptr<CoreContext>& ctxt, Fn&& fn) :
AutowirableSlot<T>(ctxt),
Expand All @@ -239,7 +226,7 @@ class AutowirableSlotFn:
/// <summary>
/// Finalization routine, called by our strategy
/// </summary>
void Finalize(void) {
void Finalize(void) override {
// Let the lambda execute as it sees fit:
CallThroughObj(fn, &Fn::operator());

Expand All @@ -255,8 +242,6 @@ class AutowirableSlotFn:
);
}

const DeferrableUnsynchronizedStrategy* GetStrategy(void) override { return &s_strategy; }
DeferrableUnsynchronizedStrategy* GetStrategy(void) override { return this; }
};

template<class T, class Fn>
const typename AutowirableSlotFn<T, Fn>::Strategy AutowirableSlotFn<T, Fn>::s_strategy;
3 changes: 2 additions & 1 deletion autowiring/Autowired.h
Expand Up @@ -338,7 +338,8 @@ class AutowiredFast:
/// Enables the specified type to be "bolted" to the current context.
/// </summary>
/// <remarks>
///
/// Used to enable a boltable class in a context and can be used even if the context has not been created yet. In
/// this case, the class will be constructed and enabled when the context is created
/// </remarks>
template<class T>
class AutoEnable
Expand Down
4 changes: 2 additions & 2 deletions autowiring/AutowiringEvents.h
Expand Up @@ -3,7 +3,7 @@
#include "EventRegistry.h"
#include TYPE_INDEX_HEADER

struct ObjectTraits;
struct CoreObjectDescriptor;
class CoreContext;

/// <summary>
Expand All @@ -17,7 +17,7 @@ class AutowiringEvents {

virtual void NewContext(CoreContext&)=0;
virtual void ExpiredContext(CoreContext&)=0;
virtual void NewObject(CoreContext&, const ObjectTraits&)=0;
virtual void NewObject(CoreContext&, const CoreObjectDescriptor&)=0;
};

// Extern explicit template instantiation declarations added to prevent
Expand Down

0 comments on commit e1606cf

Please sign in to comment.