Browse files

Merge commit '44c89d6565bacc0f990d7fa85347ba32b31a18e8'

  • Loading branch information...
2 parents 77662e1 + 44c89d6 commit d35b78f20aea8a94fdbd94363a70c5531bca95c7 @vinniefalco committed Nov 7, 2012
View
5 VFLib/Builds/VisualStudio2010/VFLib.vcxproj
@@ -109,6 +109,10 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
+ <ClCompile Include="..\..\modules\vf_concurrent\threads\vf_SharedObject.cpp">
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+ </ClCompile>
<ClCompile Include="..\..\modules\vf_concurrent\threads\vf_ThreadGroup.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
@@ -513,6 +517,7 @@
<ClInclude Include="..\..\modules\vf_concurrent\threads\vf_ReadWriteMutex.h" />
<ClInclude Include="..\..\modules\vf_concurrent\threads\vf_ConcurrentObject.h" />
<ClInclude Include="..\..\modules\vf_concurrent\threads\vf_ConcurrentState.h" />
+ <ClInclude Include="..\..\modules\vf_concurrent\threads\vf_SharedObject.h" />
<ClInclude Include="..\..\modules\vf_concurrent\threads\vf_ThreadGroup.h" />
<ClInclude Include="..\..\modules\vf_concurrent\threads\vf_ThreadWithCallQueue.h" />
<ClInclude Include="..\..\modules\vf_concurrent\vf_concurrent.h" />
View
6 VFLib/Builds/VisualStudio2010/VFLib.vcxproj.filters
@@ -516,6 +516,9 @@
<ClCompile Include="..\..\modules\vf_unfinished\graphics\vf_PatternOverlayStyle.cpp">
<Filter>VF Modules\vf_unfinished\graphics</Filter>
</ClCompile>
+ <ClCompile Include="..\..\modules\vf_concurrent\threads\vf_SharedObject.cpp">
+ <Filter>VF Modules\vf_concurrent\threads</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\modules\vf_db\api\backend.h">
@@ -1007,6 +1010,9 @@
<ClInclude Include="..\..\modules\vf_unfinished\graphics\vf_PatternFill.h">
<Filter>VF Modules\vf_unfinished\graphics</Filter>
</ClInclude>
+ <ClInclude Include="..\..\modules\vf_concurrent\threads\vf_SharedObject.h">
+ <Filter>VF Modules\vf_concurrent\threads</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\..\README.md" />
View
4 VFLib/modules/vf_concurrent/threads/vf_ConcurrentObject.cpp
@@ -30,12 +30,12 @@
*/
/*============================================================================*/
-class ConcurrentObject::Deleter
+class ConcurrentObject::Deleter : private ThreadWithCallQueue::EntryPoints
{
private:
Deleter () : m_thread ("AsyncDeleter")
{
- m_thread.start ();
+ m_thread.start (this);
}
~Deleter ()
View
5 VFLib/modules/vf_concurrent/threads/vf_GuiCallQueue.cpp
@@ -30,6 +30,9 @@
*/
/*============================================================================*/
+// This thread is used so that we don't call triggerAsyncUpdate() from any
+// audio device I/O callback or other performance-sensitive threads.
+//
GuiCallQueue::GuiCallQueue ()
: CallQueue ("GuiCallQueue")
, m_thread ("GuiCallQueue")
@@ -42,7 +45,7 @@ GuiCallQueue::GuiCallQueue ()
//
synchronize ();
- m_thread.start ();
+ m_thread.start (this);
}
void GuiCallQueue::close ()
View
1 VFLib/modules/vf_concurrent/threads/vf_GuiCallQueue.h
@@ -53,6 +53,7 @@
class GuiCallQueue
: public CallQueue
, private AsyncUpdater
+ , private ThreadWithCallQueue::EntryPoints
{
public:
/** Create a GuiCallQueue.
View
49 VFLib/modules/vf_concurrent/threads/vf_SharedObject.cpp
@@ -0,0 +1,49 @@
+/*============================================================================*/
+/*
+ VFLib: https://github.com/vinniefalco/VFLib
+
+ Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
+
+ This library contains portions of other open source products covered by
+ separate licenses. Please see the corresponding source files for specific
+ terms.
+
+ VFLib is provided under the terms of The MIT License (MIT):
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+*/
+/*============================================================================*/
+
+SharedObject::ThreadedScope::ThreadedScope (char const* name)
+ : m_thread (name)
+{
+ m_thread.start (this);
+}
+
+void SharedObject::ThreadedScope::destroySharedObject (SharedObject* const object)
+{
+ deleteAsync (object);
+}
+
+//------------------------------------------------------------------------------
+
+void SharedObject::destroySharedObject ()
+{
+ delete this;
+}
View
318 VFLib/modules/vf_concurrent/threads/vf_SharedObject.h
@@ -0,0 +1,318 @@
+/*============================================================================*/
+/*
+ VFLib: https://github.com/vinniefalco/VFLib
+
+ Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
+
+ This library contains portions of other open source products covered by
+ separate licenses. Please see the corresponding source files for specific
+ terms.
+
+ VFLib is provided under the terms of The MIT License (MIT):
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+*/
+/*============================================================================*/
+
+#ifndef VF_SHAREDOBJECT_VFHEADER
+#define VF_SHAREDOBJECT_VFHEADER
+
+//==============================================================================
+/**
+ A reference counted object with overridable destroy behavior.
+
+ This is a reference counted object compatible with SharedObjectPtr or
+ ReferenceCountedObjectPtr. When the last reference is removed, an
+ overridable virtual function is called to destroy the object. The default
+ behavior simply calls operator delete. Overrides can perform more complex
+ dispose actions, typically to destroy the object on a separate thread.
+
+ @ingroup vf_concurrent
+*/
+class SharedObject : Uncopyable
+{
+public:
+ /** Abstract SharedObject scope.
+
+ The scope is invoked to destroy the object.
+ */
+ class Scope
+ {
+ public:
+ virtual ~Scope () { }
+
+ virtual void destroySharedObject (SharedObject* const object) = 0;
+ };
+
+public:
+ /** Separate thread for a SharedObject scope.
+
+ This Scope deletes the shared object on a separate provided thread.
+ */
+ class ThreadedScope
+ : public Scope
+ , private ThreadWithCallQueue::EntryPoints
+ {
+ public:
+ /** Create a ThreadedScope.
+
+ @param name The name of the provided thread, for diagnostics.
+ */
+ explicit ThreadedScope (char const* name);
+
+ void destroySharedObject (SharedObject* const object);
+
+ /** Delete a dynamic object asynchronously.
+
+ This convenient template will delete a dynamically allocated
+ object on the provided thread.
+ */
+ template <class Object>
+ void deleteAsync (Object* const object)
+ {
+ // If an object being deleted recursively triggers async deletes,
+ // it is possible that the call queue has already been closed.
+ // We detect this condition by checking the associated thread and
+ // doing the delete directly.
+ //
+ if (m_thread.isAssociatedWithCurrentThread ())
+ delete object;
+ else
+ m_thread.callf (Delete <Object> (object));
+ }
+
+ private:
+ // Simple functor to delete an object.
+ //
+ template <class Object>
+ struct Delete
+ {
+ Delete (Object* const object) : m_object (object)
+ {
+ }
+
+ void operator() ()
+ {
+ delete m_object;
+ }
+
+ private:
+ Delete& operator= (Delete const&);
+
+ Object* const m_object;
+ };
+
+ private:
+ ThreadWithCallQueue m_thread;
+ };
+
+protected:
+ /** Construct a SharedObject.
+
+ The constructor is protected to require subclassing.
+ */
+ SharedObject () { }
+
+ virtual ~SharedObject () { }
+
+ /** Delete the object.
+
+ The default behavior calls operator delete.
+ */
+ virtual void destroySharedObject ();
+
+public:
+ /** Increment the reference count.
+
+ It should not be necessary to call this function directly. Use one of
+ the RAII containers that manages the reference count to hold the
+ object instead.
+ */
+ inline void incReferenceCount() noexcept
+ {
+ m_refs.addref ();
+ }
+
+ /** Decrement the reference count.
+
+ It should not be necessary to call this function directly. Use one of
+ the RAII containers that manages the reference count to hold the
+ object instead.
+ */
+ inline void decReferenceCount() noexcept
+ {
+ if (m_refs.release ())
+ destroySharedObject ();
+ }
+
+private:
+ AtomicCounter m_refs;
+};
+
+//------------------------------------------------------------------------------
+
+/** RAII container for SharedObject.
+
+ This container is used to hold a pointer to a SharedObject and manage the
+ reference counts for you.
+*/
+template <class Object>
+class SharedObjectPtr
+{
+public:
+ typedef Object ReferencedType;
+
+ inline SharedObjectPtr() noexcept
+ : m_object (nullptr)
+ {
+ }
+
+ inline SharedObjectPtr (Object* const refCountedObject) noexcept
+ : m_object (refCountedObject)
+ {
+ if (refCountedObject != nullptr)
+ refCountedObject->incReferenceCount();
+ }
+
+ inline SharedObjectPtr (const SharedObjectPtr& other) noexcept
+ : m_object (other.m_object)
+ {
+ if (m_object != nullptr)
+ m_object->incReferenceCount();
+ }
+
+#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+ inline SharedObjectPtr (SharedObjectPtr&& other) noexcept
+ : m_object (other.m_object)
+ {
+ other.m_object = nullptr;
+ }
+#endif
+
+ template <class DerivedClass>
+ inline SharedObjectPtr (const SharedObjectPtr <DerivedClass>& other) noexcept
+ : m_object (static_cast <Object*> (other.get()))
+ {
+ if (m_object != nullptr)
+ m_object->incReferenceCount();
+ }
+
+ SharedObjectPtr& operator= (const SharedObjectPtr& other)
+ {
+ return operator= (other.m_object);
+ }
+
+ template <class DerivedClass>
+ SharedObjectPtr& operator= (const SharedObjectPtr <DerivedClass>& other)
+ {
+ return operator= (static_cast <Object*> (other.get()));
+ }
+
+#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
+ SharedObjectPtr& operator= (SharedObjectPtr&& other)
+ {
+ std::swap (m_object, other.m_object);
+ return *this;
+ }
+#endif
+
+ SharedObjectPtr& operator= (Object* const newObject)
+ {
+ if (m_object != newObject)
+ {
+ if (newObject != nullptr)
+ newObject->incReferenceCount();
+
+ Object* const oldObject = m_object;
+ m_object = newObject;
+
+ if (oldObject != nullptr)
+ oldObject->decReferenceCount();
+ }
+
+ return *this;
+ }
+
+ inline ~SharedObjectPtr()
+ {
+ if (m_object != nullptr)
+ m_object->decReferenceCount();
+ }
+
+ inline operator Object*() const noexcept
+ {
+ return m_object;
+ }
+
+ inline Object* operator->() const noexcept
+ {
+ return m_object;
+ }
+
+ inline Object* get() const noexcept
+ {
+ return m_object;
+ }
+
+ inline Object* getObject() const noexcept
+ {
+ return m_object;
+ }
+
+private:
+ Object* m_object;
+};
+
+template <class Object>
+bool operator== (const SharedObjectPtr <Object>& object1, Object* const object2) noexcept
+{
+ return object1.get() == object2;
+}
+
+template <class Object>
+bool operator== (const SharedObjectPtr <Object>& object1, const SharedObjectPtr <Object>& object2) noexcept
+{
+ return object1.get() == object2.get();
+}
+
+template <class Object>
+bool operator== (Object* object1, SharedObjectPtr <Object>& object2) noexcept
+{
+ return object1 == object2.get();
+}
+
+template <class Object>
+bool operator!= (const SharedObjectPtr <Object>& object1, const Object* object2) noexcept
+{
+ return object1.get() != object2;
+}
+
+template <class Object>
+bool operator!= (const SharedObjectPtr <Object>& object1, SharedObjectPtr <Object>& object2) noexcept
+{
+ return object1.get() != object2.get();
+}
+
+template <class Object>
+bool operator!= (Object* object1, SharedObjectPtr <Object>& object2) noexcept
+{
+ return object1 != object2.get();
+}
+
+#endif
View
34 VFLib/modules/vf_concurrent/threads/vf_ThreadWithCallQueue.cpp
@@ -33,6 +33,7 @@
ThreadWithCallQueue::ThreadWithCallQueue (String name)
: CallQueue (name)
, m_thread (name)
+ , m_entryPoints (nullptr)
, m_calledStart (false)
, m_calledStop (false)
, m_shouldStop (false)
@@ -44,24 +45,21 @@ ThreadWithCallQueue::~ThreadWithCallQueue ()
stop (true);
}
-void ThreadWithCallQueue::start (idle_t worker_idle,
- init_t worker_init,
- exit_t worker_exit)
+void ThreadWithCallQueue::start (EntryPoints* const entryPoints)
{
{
- // TODO: Atomic for this
+ // This is mostly for diagnostics
+ // TODO: Atomic flag for this whole thing
CriticalSection::ScopedLockType lock (m_mutex);
// start() MUST be called.
jassert (!m_calledStart);
m_calledStart = true;
}
- m_init = worker_init;
- m_idle = worker_idle;
- m_exit = worker_exit;
+ m_entryPoints = entryPoints;
- m_thread.start (vf::bind (&ThreadWithCallQueue::run, this));
+ m_thread.start (this);
}
void ThreadWithCallQueue::stop (bool const wait)
@@ -83,7 +81,7 @@ void ThreadWithCallQueue::stop (bool const wait)
{
CriticalSection::ScopedUnlockType unlock (m_mutex); // getting fancy
- call (&ThreadWithCallQueue::do_stop, this);
+ call (&ThreadWithCallQueue::doStop, this);
// in theory something could slip in here
@@ -114,7 +112,12 @@ bool ThreadWithCallQueue::interruptionPoint ()
// Interrupts the idle function by queueing a call that does nothing.
void ThreadWithCallQueue::interrupt ()
{
- call (Function <void (void)>::None ());
+ call (&ThreadWithCallQueue::doNothing);
+}
+
+void ThreadWithCallQueue::doNothing ()
+{
+ // Intentionally empty
}
void ThreadWithCallQueue::signal ()
@@ -126,14 +129,14 @@ void ThreadWithCallQueue::reset ()
{
}
-void ThreadWithCallQueue::do_stop ()
+void ThreadWithCallQueue::doStop ()
{
m_shouldStop = true;
}
-void ThreadWithCallQueue::run ()
+void ThreadWithCallQueue::threadRun ()
{
- m_init ();
+ m_entryPoints->threadInit ();
for (;;)
{
@@ -142,8 +145,7 @@ void ThreadWithCallQueue::run ()
if (m_shouldStop)
break;
- // idle_t::None() must return false for this to work.
- bool interrupted = m_idle ();
+ bool interrupted = m_entryPoints->threadIdle ();
if (!interrupted)
interrupted = interruptionPoint ();
@@ -152,5 +154,5 @@ void ThreadWithCallQueue::run ()
m_thread.wait ();
}
- m_exit ();
+ m_entryPoints->threadExit ();
}
View
49 VFLib/modules/vf_concurrent/threads/vf_ThreadWithCallQueue.h
@@ -53,12 +53,29 @@
@ingroup vf_concurrent
*/
-class ThreadWithCallQueue : public CallQueue
+class ThreadWithCallQueue
+ : public CallQueue
+ , private InterruptibleThread::EntryPoint
{
public:
- typedef Function <bool (void)> idle_t;
- typedef Function <void (void)> init_t;
- typedef Function <void (void)> exit_t;
+ /** Entry points for a ThreadWithCallQueue.
+ */
+ class EntryPoints
+ {
+ public:
+ virtual ~EntryPoints () { }
+
+ virtual void threadInit () { }
+
+ virtual void threadExit () { }
+
+ virtual bool threadIdle ()
+ {
+ bool interrupted = false;
+
+ return interrupted;
+ }
+ };
/** Create a thread.
@@ -75,18 +92,8 @@ class ThreadWithCallQueue : public CallQueue
~ThreadWithCallQueue ();
/** Start the thread.
-
- All thread functions are invoked from the thread:
-
- @param thread_idle The function to call when the thread is idle.
-
- @param thread_init The function to call when the thread starts.
-
- @param thread_exit The function to call when the thread stops.
*/
- void start (idle_t thread_idle = idle_t::None(),
- init_t thread_init = init_t::None(),
- exit_t thread_exit = exit_t::None());
+ void start (EntryPoints* const entryPoints);
/* Stop the thread.
@@ -128,21 +135,23 @@ class ThreadWithCallQueue : public CallQueue
void interrupt ();
private:
+ static void doNothing ();
+
void signal ();
+
void reset ();
- void do_stop ();
- void run ();
+ void doStop ();
+
+ void threadRun ();
private:
InterruptibleThread m_thread;
+ EntryPoints* m_entryPoints;
bool m_calledStart;
bool m_calledStop;
bool m_shouldStop;
CriticalSection m_mutex;
- idle_t m_idle;
- init_t m_init;
- exit_t m_exit;
};
#endif
View
1 VFLib/modules/vf_concurrent/vf_concurrent.cpp
@@ -62,6 +62,7 @@ namespace vf
#include "threads/vf_MessageThread.cpp"
#include "threads/vf_ParallelFor.cpp"
#include "threads/vf_ReadWriteMutex.cpp"
+#include "threads/vf_SharedObject.cpp"
#include "threads/vf_ThreadGroup.cpp"
#include "threads/vf_ThreadWithCallQueue.cpp"
View
2 VFLib/modules/vf_concurrent/vf_concurrent.h
@@ -171,8 +171,8 @@ namespace vf
#include "threads/vf_ThreadWithCallQueue.h"
#include "threads/vf_GuiCallQueue.h"
-
#include "threads/vf_MessageThread.h"
+#include "threads/vf_SharedObject.h"
}
#endif
View
27 VFLib/modules/vf_core/diagnostic/vf_LeakChecked.cpp
@@ -44,13 +44,14 @@ class LeakCheckedBase::CounterBase::Singleton
void detectAllLeaks ()
{
- CounterBase* counter = m_list.pop_front ();
-
- while (counter != nullptr)
+ for (;;)
{
+ CounterBase* counter = m_list.pop_front ();
+
+ if (!counter)
+ break;
+
counter->detectLeaks ();
-
- counter = m_list.pop_front ();
}
}
@@ -77,6 +78,22 @@ void LeakCheckedBase::CounterBase::detectAllLeaks ()
Singleton::getInstance().detectAllLeaks ();
}
+void LeakCheckedBase::CounterBase::detectLeaks ()
+{
+ // If there's a runtime error from this line, it means there's
+ // an order of destruction problem between different translation units!
+ //
+ this->checkPureVirtual ();
+
+ int const count = m_count.get ();
+
+ if (count > 0)
+ {
+ jassertfalse;
+ DBG ("[LEAK] " << count << " of " << getClassName ());
+ }
+}
+
//------------------------------------------------------------------------------
void LeakCheckedBase::detectAllLeaks ()
View
59 VFLib/modules/vf_core/diagnostic/vf_LeakChecked.h
@@ -56,19 +56,40 @@ class LeakCheckedBase
CounterBase ();
virtual ~CounterBase () { }
-
+
+ inline int increment ()
+ {
+ return ++m_count;
+ }
+
+ inline int decrement ()
+ {
+ return --m_count;
+ }
+
+ virtual char const* getClassName () const = 0;
+
static void detectAllLeaks ();
private:
- virtual void detectLeaks () = 0;
+ void detectLeaks ();
- private:
+ virtual void checkPureVirtual () const = 0;
+
+ protected:
class Singleton;
+
+ Atomic <int> m_count;
};
};
//------------------------------------------------------------------------------
+/** Detects leaks at program exit.
+
+ To use this, derive your class from this template using CRTP (curiously
+ recurring template pattern).
+*/
template <class Object>
class LeakChecked : private LeakCheckedBase
{
@@ -104,44 +125,38 @@ class LeakChecked : private LeakCheckedBase
class Counter : public CounterBase
{
public:
- inline int increment ()
+ Counter () noexcept
{
- return ++m_count;
- }
-
- inline int decrement ()
- {
- return --m_count;
}
- void detectLeaks ()
+ char const* getClassName () const
{
- const int count = m_count.get ();
-
- if (count > 0)
- {
- DBG ("[LEAK] " << count << " of " << getLeakCheckedName());
- }
+ return getLeakCheckedName ();
}
- private:
- Atomic <int> m_count;
+ void checkPureVirtual () const { }
};
+private:
+ /* Due to a bug in Visual Studio 10 and earlier, the string returned by
+ typeid().name() will appear to leak on exit. Therefore, we should
+ only call this function when there's an actual leak, or else there
+ will be spurious leak notices at exit.
+ */
static const char* getLeakCheckedName ()
{
return typeid (Object).name ();
}
- static Counter& getLeakCheckedCounter() noexcept
+ static Counter& getLeakCheckedCounter () noexcept
{
static Counter* volatile s_instance;
static Static::Initializer s_initializer;
if (s_initializer.begin ())
{
- static Counter s_object;
- s_instance = &s_object;
+ static char s_storage [sizeof (Counter)];
+ s_instance = new (s_storage) Counter;
s_initializer.end ();
}
View
5 VFLib/modules/vf_core/events/vf_OncePerSecond.cpp
@@ -32,14 +32,15 @@
class OncePerSecond::TimerSingleton
: public RefCountedSingleton <OncePerSecond::TimerSingleton>
+ , private InterruptibleThread::EntryPoint
{
private:
TimerSingleton ()
: RefCountedSingleton <OncePerSecond::TimerSingleton> (
SingletonLifetime::persistAfterCreation)
, m_thread ("Once Per Second")
{
- m_thread.start (vf::bind (&TimerSingleton::run, this));
+ m_thread.start (this);
}
~TimerSingleton ()
@@ -49,7 +50,7 @@ class OncePerSecond::TimerSingleton
jassert (m_list.empty ());
}
- void run ()
+ void threadRun ()
{
for(;;)
{
View
82 VFLib/modules/vf_core/threads/vf_InterruptibleThread.cpp
@@ -51,6 +51,7 @@ void InterruptibleThread::ThreadHelper::run ()
InterruptibleThread::InterruptibleThread (String name)
: m_thread (name, this)
+ , m_entryPoint (nullptr)
, m_state (stateRun)
{
}
@@ -62,13 +63,14 @@ InterruptibleThread::~InterruptibleThread ()
join ();
}
-void InterruptibleThread::start (const Function <void (void)>& f)
+void InterruptibleThread::start (EntryPoint* const entryPoint)
{
- m_function = f;
+ m_entryPoint = entryPoint;
m_thread.startThread ();
- // prevents data race with member variables
+ // Prevent data race with member variables
+ //
m_runEvent.signal ();
}
@@ -79,7 +81,8 @@ void InterruptibleThread::join ()
bool InterruptibleThread::wait (int milliSeconds)
{
- // Can only be called from the current thread
+ // Can only be called from the corresponding thread of execution.
+ //
jassert (isTheCurrentThread ());
bool interrupted = false;
@@ -89,18 +92,19 @@ bool InterruptibleThread::wait (int milliSeconds)
jassert (m_state != stateWait);
// See if we are interrupted
+ //
if (m_state.tryChangeState (stateInterrupt, stateRun))
{
- // We were interrupted, state is changed to Run.
- // Caller must run now.
+ // We were interrupted, state is changed to Run. Caller must run now.
+ //
interrupted = true;
break;
}
else if (m_state.tryChangeState (stateRun, stateWait) ||
m_state.tryChangeState (stateReturn, stateWait))
{
- // Transitioned to wait.
- // Caller must wait now.
+ // Transitioned to wait. Caller must wait now.
+ //
interrupted = false;
break;
}
@@ -135,10 +139,11 @@ void InterruptibleThread::interrupt ()
int const state = m_state;
if (state == stateInterrupt ||
- state == stateReturn ||
- m_state.tryChangeState (stateRun, stateInterrupt))
+ state == stateReturn ||
+ m_state.tryChangeState (stateRun, stateInterrupt))
{
// Thread will see this at next interruption point.
+ //
break;
}
else if (m_state.tryChangeState (stateWait, stateRun))
@@ -151,24 +156,24 @@ void InterruptibleThread::interrupt ()
bool InterruptibleThread::interruptionPoint ()
{
- // Can only be called from the current thread
+ // Can only be called from the thread of execution.
+ //
jassert (isTheCurrentThread ());
if (m_state == stateWait)
{
- // It is impossible for this function
- // to be called while in the wait state.
+ // It is impossible for this function to be called while in the wait state.
+ //
Throw (Error().fail (__FILE__, __LINE__));
}
else if (m_state == stateReturn)
{
// If this goes off it means the thread called the
// interruption a second time after already getting interrupted.
+ //
Throw (Error().fail (__FILE__, __LINE__));
}
- // Switch to Return state if we are interrupted
- //bool const interrupted = m_state.tryChangeState (stateInterrupt, stateReturn);
bool const interrupted = m_state.tryChangeState (stateInterrupt, stateRun);
return interrupted;
@@ -191,16 +196,20 @@ void InterruptibleThread::setPriority (int priority)
InterruptibleThread* InterruptibleThread::getCurrentThread ()
{
+ InterruptibleThread* result = nullptr;
+
Thread* const thread = Thread::getCurrentThread();
- // This doesn't work for the message thread!
- jassert (thread != nullptr);
+ if (thread != nullptr)
+ {
+ ThreadHelper* const helper = dynamic_cast <ThreadHelper*> (thread);
- ThreadHelper* const helper = dynamic_cast <ThreadHelper*> (thread);
+ jassert (helper != nullptr);
- jassert (helper != nullptr);
+ result = helper->getOwner ();
+ }
- return helper->getOwner ();
+ return result;
}
void InterruptibleThread::run ()
@@ -209,7 +218,8 @@ void InterruptibleThread::run ()
m_runEvent.wait ();
- CatchAny (m_function);
+ //CatchAny (m_function);
+ m_entryPoint->threadRun ();
}
//------------------------------------------------------------------------------
@@ -218,35 +228,11 @@ bool CurrentInterruptibleThread::interruptionPoint ()
{
bool interrupted = false;
-#if 1
- interrupted = InterruptibleThread::getCurrentThread ()->interruptionPoint ();
-
-#else
- Thread* const thread = Thread::getCurrentThread();
-
- // Can't use interruption points on the message thread
- jassert (thread != nullptr);
-
- if (thread)
- {
- InterruptibleThread* const interruptibleThread = dynamic_cast <InterruptibleThread*> (thread);
+ InterruptibleThread* const interruptibleThread (InterruptibleThread::getCurrentThread ());
- jassert (interruptibleThread != nullptr);
+ jassert (interruptibleThread != nullptr);
- if (interruptibleThread != nullptr)
- {
- interrupted = interruptibleThread->interruptionPoint ();
- }
- else
- {
- interrupted = false;
- }
- }
- else
- {
- interrupted = false;
- }
-#endif
+ interrupted = interruptibleThread->interruptionPoint ();
return interrupted;
}
View
40 VFLib/modules/vf_core/threads/vf_InterruptibleThread.h
@@ -36,19 +36,33 @@
#include "../diagnostic/vf_SafeBool.h"
#include "../functor/vf_Function.h"
-/*============================================================================*/
+//==============================================================================
/**
- A thread with soft interruption support.
+ A thread with soft interruption support.
+
+ The thread must periodically call interruptionPoint(), which returns `true`
+ the first time an interruption has occurred since the last call to
+ interruptionPoint().
- The thread must periodically call interruptionPoint(), which returns
- true the first time an interruption has occurred since the last call to
- interruptionPoint().
+ To create a thread, derive your class from InterruptibleThread::EntryPoint
+ and implement the threadRun() function. Then, call run() with your object.
- @ingroup vf_core
+ @ingroup vf_core
*/
class InterruptibleThread
{
public:
+ /** InterruptibleThread entry point.
+ */
+ class EntryPoint
+ {
+ public:
+ virtual ~EntryPoint () { }
+
+ virtual void threadRun () = 0;
+ };
+
+public:
typedef Thread::ThreadID id;
/** Construct an interruptible thread.
@@ -67,7 +81,7 @@ class InterruptibleThread
/** Start the thread.
*/
- void start (Function <void (void)> const& f);
+ void start (EntryPoint* const entryPoint);
/** Wait for the thread to exit.
*/
@@ -97,13 +111,13 @@ class InterruptibleThread
/** Determine if an interruption is requested.
After the function returns `true`, the interrupt status is cleared.
- Subsequent calls will return `false` until another interrupt is requested.
+ Subsequent calls will return `false` until another interrupt is requested.
- May only be called by the thread of execution.
+ May only be called by the thread of execution.
- @see CurrentInterruptibleThread::interruptionPoint
+ @see CurrentInterruptibleThread::interruptionPoint
- @return `true` if an interrupt was requested.
+ @return `true` if an interrupt was requested.
*/
bool interruptionPoint ();
@@ -130,6 +144,9 @@ class InterruptibleThread
void setPriority (int priority);
/** Get the InterruptibleThread for the thread of execution.
+
+ This will return `nullptr` when called from the message thread, or from
+ a thread of execution that is not an InterruptibleThread.
*/
static InterruptibleThread* getCurrentThread ();
@@ -150,6 +167,7 @@ class InterruptibleThread
void run ();
ThreadHelper m_thread;
+ EntryPoint* m_entryPoint;
Function <void (void)> m_function;
WaitableEvent m_runEvent;
id m_threadId;
View
4 VFLib/modules/vf_gui/mouse/vf_MouseEnterEditable.cpp
@@ -96,12 +96,12 @@ void MouseEnterEditable::Container::exitCurrentEditMode ()
{
if (m_currentEdit != nullptr)
{
- stopTimer ();
-
MouseEnterEditable* editable = m_currentEdit;
m_currentEdit = nullptr;
editable->onMouseEnterEditMode (false);
}
+
+ stopTimer ();
}
void MouseEnterEditable::Container::mouseEnterEditableActivity (
View
6,853 VFLib/modules/vf_sqlite/sqlite/sqlite3.c
3,244 additions, 3,609 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
157 VFLib/modules/vf_sqlite/sqlite/sqlite3.h
@@ -107,9 +107,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.7.12.1"
-#define SQLITE_VERSION_NUMBER 3007012
-#define SQLITE_SOURCE_ID "2012-05-22 02:45:53 6d326d44fd1d626aae0e8456e5fa2049f1ce0789"
+#define SQLITE_VERSION "3.7.14"
+#define SQLITE_VERSION_NUMBER 3007014
+#define SQLITE_SOURCE_ID "2012-09-03 15:42:36 c0d89d4a9752922f9e367362366efde4f1b06f2a"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -219,7 +219,8 @@ SQLITE_API int sqlite3_threadsafe(void);
** the opaque structure named "sqlite3". It is useful to think of an sqlite3
** pointer as an object. The [sqlite3_open()], [sqlite3_open16()], and
** [sqlite3_open_v2()] interfaces are its constructors, and [sqlite3_close()]
-** is its destructor. There are many other interfaces (such as
+** and [sqlite3_close_v2()] are its destructors. There are many other
+** interfaces (such as
** [sqlite3_prepare_v2()], [sqlite3_create_function()], and
** [sqlite3_busy_timeout()] to name but three) that are methods on an
** sqlite3 object.
@@ -266,28 +267,46 @@ typedef sqlite_uint64 sqlite3_uint64;
/*
** CAPI3REF: Closing A Database Connection
**
-** ^The sqlite3_close() routine is the destructor for the [sqlite3] object.
-** ^Calls to sqlite3_close() return SQLITE_OK if the [sqlite3] object is
-** successfully destroyed and all associated resources are deallocated.
-**
-** Applications must [sqlite3_finalize | finalize] all [prepared statements]
-** and [sqlite3_blob_close | close] all [BLOB handles] associated with
-** the [sqlite3] object prior to attempting to close the object. ^If
+** ^The sqlite3_close() and sqlite3_close_v2() routines are destructors
+** for the [sqlite3] object.
+** ^Calls to sqlite3_close() and sqlite3_close_v2() return SQLITE_OK if
+** the [sqlite3] object is successfully destroyed and all associated
+** resources are deallocated.
+**
+** ^If the database connection is associated with unfinalized prepared
+** statements or unfinished sqlite3_backup objects then sqlite3_close()
+** will leave the database connection open and return [SQLITE_BUSY].
+** ^If sqlite3_close_v2() is called with unfinalized prepared statements
+** and unfinished sqlite3_backups, then the database connection becomes
+** an unusable "zombie" which will automatically be deallocated when the
+** last prepared statement is finalized or the last sqlite3_backup is
+** finished. The sqlite3_close_v2() interface is intended for use with
+** host languages that are garbage collected, and where the order in which
+** destructors are called is arbitrary.
+**
+** Applications should [sqlite3_finalize | finalize] all [prepared statements],
+** [sqlite3_blob_close | close] all [BLOB handles], and
+** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated
+** with the [sqlite3] object prior to attempting to close the object. ^If
** sqlite3_close() is called on a [database connection] that still has
-** outstanding [prepared statements] or [BLOB handles], then it returns
-** SQLITE_BUSY.
+** outstanding [prepared statements], [BLOB handles], and/or
+** [sqlite3_backup] objects then it returns SQLITE_OK but the deallocation
+** of resources is deferred until all [prepared statements], [BLOB handles],
+** and [sqlite3_backup] objects are also destroyed.
**
-** ^If [sqlite3_close()] is invoked while a transaction is open,
+** ^If an [sqlite3] object is destroyed while a transaction is open,
** the transaction is automatically rolled back.
**
-** The C parameter to [sqlite3_close(C)] must be either a NULL
+** The C parameter to [sqlite3_close(C)] and [sqlite3_close_v2(C)]
+** must be either a NULL
** pointer or an [sqlite3] object pointer obtained
** from [sqlite3_open()], [sqlite3_open16()], or
** [sqlite3_open_v2()], and not previously closed.
-** ^Calling sqlite3_close() with a NULL pointer argument is a
-** harmless no-op.
+** ^Calling sqlite3_close() or sqlite3_close_v2() with a NULL pointer
+** argument is a harmless no-op.
*/
-SQLITE_API int sqlite3_close(sqlite3 *);
+SQLITE_API int sqlite3_close(sqlite3*);
+SQLITE_API int sqlite3_close_v2(sqlite3*);
/*
** The type for a callback function.
@@ -478,6 +497,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_OPEN_EXCLUSIVE 0x00000010 /* VFS only */
#define SQLITE_OPEN_AUTOPROXY 0x00000020 /* VFS only */
#define SQLITE_OPEN_URI 0x00000040 /* Ok for sqlite3_open_v2() */
+#define SQLITE_OPEN_MEMORY 0x00000080 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_MAIN_DB 0x00000100 /* VFS only */
#define SQLITE_OPEN_TEMP_DB 0x00000200 /* VFS only */
#define SQLITE_OPEN_TRANSIENT_DB 0x00000400 /* VFS only */
@@ -497,7 +517,7 @@ SQLITE_API int sqlite3_exec(
** CAPI3REF: Device Characteristics
**
** The xDeviceCharacteristics method of the [sqlite3_io_methods]
-** object returns an integer which is a vector of the these
+** object returns an integer which is a vector of these
** bit values expressing I/O characteristics of the mass storage
** device that holds the file that the [sqlite3_io_methods]
** refers to.
@@ -2169,12 +2189,12 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
** implementation of these routines to be omitted. That capability
** is no longer provided. Only built-in memory allocators can be used.
**
-** The Windows OS interface layer calls
+** Prior to SQLite version 3.7.10, the Windows OS interface layer called
** the system malloc() and free() directly when converting
** filenames between the UTF-8 encoding used by SQLite
** and whatever filename encoding is used by the particular Windows
-** installation. Memory allocation errors are detected, but
-** they are reported back as [SQLITE_CANTOPEN] or
+** installation. Memory allocation errors were detected, but
+** they were reported back as [SQLITE_CANTOPEN] or
** [SQLITE_IOERR] rather than [SQLITE_NOMEM].
**
** The pointer arguments to [sqlite3_free()] and [sqlite3_realloc()]
@@ -2575,18 +2595,20 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** present, then the VFS specified by the option takes precedence over
** the value passed as the fourth parameter to sqlite3_open_v2().
**
-** <li> <b>mode</b>: ^(The mode parameter may be set to either "ro", "rw" or
-** "rwc". Attempting to set it to any other value is an error)^.
+** <li> <b>mode</b>: ^(The mode parameter may be set to either "ro", "rw",
+** "rwc", or "memory". Attempting to set it to any other value is
+** an error)^.
** ^If "ro" is specified, then the database is opened for read-only
** access, just as if the [SQLITE_OPEN_READONLY] flag had been set in the
** third argument to sqlite3_prepare_v2(). ^If the mode option is set to
** "rw", then the database is opened for read-write (but not create)
** access, as if SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had
** been set. ^Value "rwc" is equivalent to setting both
-** SQLITE_OPEN_READWRITE and SQLITE_OPEN_CREATE. ^If sqlite3_open_v2() is
-** used, it is an error to specify a value for the mode parameter that is
-** less restrictive than that specified by the flags passed as the third
-** parameter.
+** SQLITE_OPEN_READWRITE and SQLITE_OPEN_CREATE. ^If the mode option is
+** set to "memory" then a pure [in-memory database] that never reads
+** or writes from disk is used. ^It is an error to specify a value for
+** the mode parameter that is less restrictive than that specified by
+** the flags passed in the third parameter to sqlite3_open_v2().
**
** <li> <b>cache</b>: ^The cache parameter may be set to either "shared" or
** "private". ^Setting it to "shared" is equivalent to setting the
@@ -2645,6 +2667,12 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** codepage is currently defined. Filenames containing international
** characters must be converted to UTF-8 prior to passing them into
** sqlite3_open() or sqlite3_open_v2().
+**
+** <b>Note to Windows Runtime users:</b> The temporary directory must be set
+** prior to calling sqlite3_open() or sqlite3_open_v2(). Otherwise, various
+** features that require the use of temporary files may fail.
+**
+** See also: [sqlite3_temp_directory]
*/
SQLITE_API int sqlite3_open(
const char *filename, /* Database filename (UTF-8) */
@@ -3137,8 +3165,11 @@ typedef struct sqlite3_context sqlite3_context;
** ^(In those routines that have a fourth argument, its value is the
** number of bytes in the parameter. To be clear: the value is the
** number of <u>bytes</u> in the value, not the number of characters.)^
-** ^If the fourth parameter is negative, the length of the string is
+** ^If the fourth parameter to sqlite3_bind_text() or sqlite3_bind_text16()
+** is negative, then the length of the string is
** the number of bytes up to the first zero terminator.
+** If the fourth parameter to sqlite3_bind_blob() is negative, then
+** the behavior is undefined.
** If a non-negative fourth parameter is provided to sqlite3_bind_text()
** or sqlite3_bind_text16() then that parameter must be the byte offset
** where the NUL terminator would occur assuming the string were NUL
@@ -4135,11 +4166,11 @@ typedef void (*sqlite3_destructor_type)(void*);
** the error code is SQLITE_ERROR. ^A subsequent call to sqlite3_result_error()
** or sqlite3_result_error16() resets the error code to SQLITE_ERROR.
**
-** ^The sqlite3_result_toobig() interface causes SQLite to throw an error
-** indicating that a string or BLOB is too long to represent.
+** ^The sqlite3_result_error_toobig() interface causes SQLite to throw an
+** error indicating that a string or BLOB is too long to represent.
**
-** ^The sqlite3_result_nomem() interface causes SQLite to throw an error
-** indicating that a memory allocation failed.
+** ^The sqlite3_result_error_nomem() interface causes SQLite to throw an
+** error indicating that a memory allocation failed.
**
** ^The sqlite3_result_int() interface sets the return value
** of the application-defined function to be the 32-bit signed integer
@@ -4446,10 +4477,62 @@ SQLITE_API int sqlite3_sleep(int);
** Hence, if this variable is modified directly, either it should be
** made NULL or made to point to memory obtained from [sqlite3_malloc]
** or else the use of the [temp_store_directory pragma] should be avoided.
+**
+** <b>Note to Windows Runtime users:</b> The temporary directory must be set
+** prior to calling [sqlite3_open] or [sqlite3_open_v2]. Otherwise, various
+** features that require the use of temporary files may fail. Here is an
+** example of how to do this using C++ with the Windows Runtime:
+**
+** <blockquote><pre>
+** LPCWSTR zPath = Windows::Storage::ApplicationData::Current->
+** &nbsp; TemporaryFolder->Path->Data();
+** char zPathBuf&#91;MAX_PATH + 1&#93;;
+** memset(zPathBuf, 0, sizeof(zPathBuf));
+** WideCharToMultiByte(CP_UTF8, 0, zPath, -1, zPathBuf, sizeof(zPathBuf),
+** &nbsp; NULL, NULL);
+** sqlite3_temp_directory = sqlite3_mprintf("%s", zPathBuf);
+** </pre></blockquote>
*/
SQLITE_API SQLITE_EXTERN char *sqlite3_temp_directory;
/*
+** CAPI3REF: Name Of The Folder Holding Database Files
+**
+** ^(If this global variable is made to point to a string which is
+** the name of a folder (a.k.a. directory), then all database files
+** specified with a relative pathname and created or accessed by
+** SQLite when using a built-in windows [sqlite3_vfs | VFS] will be assumed
+** to be relative to that directory.)^ ^If this variable is a NULL
+** pointer, then SQLite assumes that all database files specified
+** with a relative pathname are relative to the current directory
+** for the process. Only the windows VFS makes use of this global
+** variable; it is ignored by the unix VFS.
+**
+** Changing the value of this variable while a database connection is
+** open can result in a corrupt database.
+**
+** It is not safe to read or modify this variable in more than one
+** thread at a time. It is not safe to read or modify this variable
+** if a [database connection] is being used at the same time in a separate
+** thread.
+** It is intended that this variable be set once
+** as part of process initialization and before any SQLite interface
+** routines have been called and that this variable remain unchanged
+** thereafter.
+**
+** ^The [data_store_directory pragma] may modify this variable and cause
+** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore,
+** the [data_store_directory pragma] always assumes that any string
+** that this variable points to is held in memory obtained from
+** [sqlite3_malloc] and the pragma may attempt to free that memory
+** using [sqlite3_free].
+** Hence, if this variable is modified directly, either it should be
+** made NULL or made to point to memory obtained from [sqlite3_malloc]
+** or else the use of the [data_store_directory pragma] should be avoided.
+*/
+SQLITE_API SQLITE_EXTERN char *sqlite3_data_directory;
+
+/*
** CAPI3REF: Test For Auto-Commit Mode
** KEYWORDS: {autocommit mode}
**
@@ -4627,7 +4710,6 @@ SQLITE_API void *sqlite3_update_hook(
/*
** CAPI3REF: Enable Or Disable Shared Pager Cache
-** KEYWORDS: {shared cache}
**
** ^(This routine enables or disables the sharing of the database cache
** and schema data structures between [database connection | connections]
@@ -5455,17 +5537,16 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
** implementations are available in the SQLite core:
**
** <ul>
-** <li> SQLITE_MUTEX_OS2
** <li> SQLITE_MUTEX_PTHREADS
** <li> SQLITE_MUTEX_W32
** <li> SQLITE_MUTEX_NOOP
** </ul>)^
**
** ^The SQLITE_MUTEX_NOOP implementation is a set of routines
** that does no real locking and is appropriate for use in
-** a single-threaded application. ^The SQLITE_MUTEX_OS2,
-** SQLITE_MUTEX_PTHREADS, and SQLITE_MUTEX_W32 implementations
-** are appropriate for use on OS/2, Unix, and Windows.
+** a single-threaded application. ^The SQLITE_MUTEX_PTHREADS and
+** SQLITE_MUTEX_W32 implementations are appropriate for use on Unix
+** and Windows.
**
** ^(If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor
** macro defined (with "-DSQLITE_MUTEX_APPDEF=1"), then no mutex

0 comments on commit d35b78f

Please sign in to comment.