Beast improvements and vflib compatibility module work

* Add CallQueue vflib compatibility class
* Use run instead of run_one
* Merge BindableServiceQueue into CallQueue
* Take BEAST_VARIADIC_MAX into account
* Fix license headers as suggested by Vinnie
* Remove obsolete comment
* Add ManualServiceQueue
* Add ManualServiceQueue to beast_vflib include
* Move static unit test variables of header only classes to module cpp
* Remove no longer used mutex member
* _VARIADIC_MAX maxes out at 10
* Correctly apply BEAST_VARIADIC_MAX
* Merge BindableServiceQueue into CallQueue
* New GuiServiceQueue and its JUCE dependency
* Fix leftover merge errors
* Fix CallQueue unit test
* Don't use bassert for better CI support
This commit is contained in:
Patrick Dehne
2013-10-24 17:31:18 +02:00
committed by Vinnie Falco
parent bf87614fa6
commit 08aa415c66
31 changed files with 1069 additions and 283 deletions

View File

@@ -107,7 +107,7 @@ extern void beast_reportFatalError (char const* message, char const* fileName, i
This is only compiled in a debug build.
@see Logger::outputDebugString
*/
#define DBG(dbgtext) { beast::String tempDbgBuf; tempDbgBuf << dbgtext; beast::Logger::outputDebugString (tempDbgBuf); }
#define BDBG(dbgtext) { beast::String tempDbgBuf; tempDbgBuf << dbgtext; beast::Logger::outputDebugString (tempDbgBuf); }
/** This will always cause an assertion failure.
It is only compiled in a debug build, (unless BEAST_LOG_ASSERTIONS is enabled for your build).
@@ -127,7 +127,7 @@ extern void beast_reportFatalError (char const* message, char const* fileName, i
// If debugging is disabled, these dummy debug and assertion macros are used..
#define DBG(dbgtext)
#define BDBG(dbgtext)
#define bassertfalse { beast_LogCurrentAssertion }
# if BEAST_LOG_ASSERTIONS

View File

@@ -354,6 +354,7 @@ protected:
void wait();
virtual void enqueue (Item* item);
bool empty();
virtual std::size_t dequeue() = 0;
virtual Waiter* new_waiter() = 0;

View File

@@ -179,6 +179,12 @@ void ServiceQueueBase::enqueue (Item* item)
waiter->signal();
}
bool ServiceQueueBase::empty()
{
SharedState::Access state (m_state);
return state->handlers.empty();
}
// A thread can only be blocked on one ServiceQueue so we store the pointer
// to which ServiceQueue it is blocked on to determine if the thread belongs
// to that queue.

View File

@@ -456,8 +456,8 @@ void BEAST_CALLTYPE Thread::sleep (int millisecs)
void BEAST_API beast_threadEntryPoint (void*);
extern "C" void* threadEntryProc (void*);
extern "C" void* threadEntryProc (void* userData)
extern "C" void* threadEntryProcBeast (void*);
extern "C" void* threadEntryProcBeast (void* userData)
{
BEAST_AUTORELEASEPOOL
{
@@ -482,7 +482,7 @@ void Thread::launchThread()
threadHandle = 0;
pthread_t handle = 0;
if (pthread_create (&handle, 0, threadEntryProc, this) == 0)
if (pthread_create (&handle, 0, threadEntryProcBeast, this) == 0)
{
pthread_detach (handle);
threadHandle = (void*) handle;

View File

@@ -85,7 +85,7 @@ void LeakCheckedBase::LeakCounterBase::checkForLeaks ()
always use ScopedPointers, OwnedArrays, SharedObjects,
etc, and avoid the 'delete' operator at all costs!
*/
DBG ("Leaked objects: " << count << " of " << getClassName ());
BDBG ("Leaked objects: " << count << " of " << getClassName ());
//bassertfalse;
}
@@ -115,7 +115,7 @@ void LeakCheckedBase::reportDanglingPointer (char const*)
SharedObjects, etc, and avoid the 'delete' operator
at all costs!
*/
DBG ("Dangling pointer deletion: " << objectName);
BDBG ("Dangling pointer deletion: " << objectName);
bassertfalse;
}

View File

@@ -9,9 +9,10 @@
/* Begin PBXBuildFile section */
CD0A5B3F181707F700DA0342 /* mac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD0A5B3E181707F700DA0342 /* mac.cpp */; };
CD0A5B421817097800DA0342 /* BeastUnitTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD0A5B401817097800DA0342 /* BeastUnitTests.cpp */; };
CD0A5B4918170DC300DA0342 /* beast.mm in Sources */ = {isa = PBXBuildFile; fileRef = CD0A5B4818170DC300DA0342 /* beast.mm */; };
CD0A5B4918170DC300DA0342 /* beast_modules.mm in Sources */ = {isa = PBXBuildFile; fileRef = CD0A5B4818170DC300DA0342 /* beast_modules.mm */; };
CD0A5B4B18170EBC00DA0342 /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD0A5B4A18170EBC00DA0342 /* CoreServices.framework */; };
CD0A5B4E18170F0D00DA0342 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD0A5B4D18170F0D00DA0342 /* AppKit.framework */; };
CD1CBE68181B2D99002CCC0C /* juce_modules.mm in Sources */ = {isa = PBXBuildFile; fileRef = CD1CBE64181B2689002CCC0C /* juce_modules.mm */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -31,13 +32,16 @@
CD0A5B3E181707F700DA0342 /* mac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = mac.cpp; path = ../../src/mac.cpp; sourceTree = "<group>"; };
CD0A5B401817097800DA0342 /* BeastUnitTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BeastUnitTests.cpp; path = ../../src/BeastUnitTests.cpp; sourceTree = "<group>"; };
CD0A5B411817097800DA0342 /* BeastUnitTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BeastUnitTests.h; path = ../../src/BeastUnitTests.h; sourceTree = "<group>"; };
CD0A5B4318170A5100DA0342 /* beast.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = beast.cpp; path = ../../src/beast.cpp; sourceTree = "<group>"; };
CD0A5B4418170A5100DA0342 /* beast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = beast.h; path = ../../src/beast.h; sourceTree = "<group>"; };
CD0A5B4818170DC300DA0342 /* beast.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = beast.mm; path = ../../src/beast.mm; sourceTree = "<group>"; };
CD0A5B4318170A5100DA0342 /* beast_modules.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = beast_modules.cpp; path = ../../src/beast_modules.cpp; sourceTree = "<group>"; };
CD0A5B4418170A5100DA0342 /* beast_modules.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = beast_modules.h; path = ../../src/beast_modules.h; sourceTree = "<group>"; };
CD0A5B4818170DC300DA0342 /* beast_modules.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = beast_modules.mm; path = ../../src/beast_modules.mm; sourceTree = "<group>"; };
CD0A5B4A18170EBC00DA0342 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; };
CD0A5B4D18170F0D00DA0342 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
CD0A5B4F181714A000DA0342 /* beast */ = {isa = PBXFileReference; lastKnownFileType = folder; name = beast; path = ../../../../beast; sourceTree = "<group>"; };
CD0A5B50181714B800DA0342 /* modules */ = {isa = PBXFileReference; lastKnownFileType = folder; name = modules; path = ../../../../modules; sourceTree = "<group>"; };
CD1CBE62181B2689002CCC0C /* juce_modules.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = juce_modules.cpp; path = ../../src/juce_modules.cpp; sourceTree = "<group>"; };
CD1CBE63181B2689002CCC0C /* juce_modules.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = juce_modules.h; path = ../../src/juce_modules.h; sourceTree = "<group>"; };
CD1CBE64181B2689002CCC0C /* juce_modules.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = juce_modules.mm; path = ../../src/juce_modules.mm; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -58,11 +62,14 @@
children = (
CD0A5B50181714B800DA0342 /* modules */,
CD0A5B4F181714A000DA0342 /* beast */,
CD0A5B4818170DC300DA0342 /* beast.mm */,
CD0A5B4318170A5100DA0342 /* beast.cpp */,
CD0A5B4418170A5100DA0342 /* beast.h */,
CD0A5B4318170A5100DA0342 /* beast_modules.cpp */,
CD0A5B4418170A5100DA0342 /* beast_modules.h */,
CD0A5B4818170DC300DA0342 /* beast_modules.mm */,
CD0A5B401817097800DA0342 /* BeastUnitTests.cpp */,
CD0A5B411817097800DA0342 /* BeastUnitTests.h */,
CD1CBE62181B2689002CCC0C /* juce_modules.cpp */,
CD1CBE63181B2689002CCC0C /* juce_modules.h */,
CD1CBE64181B2689002CCC0C /* juce_modules.mm */,
CD0A5B3E181707F700DA0342 /* mac.cpp */,
CD0A5B4C18170EC600DA0342 /* Frameworks */,
CD0A5B331817074500DA0342 /* Products */,
@@ -139,7 +146,8 @@
files = (
CD0A5B3F181707F700DA0342 /* mac.cpp in Sources */,
CD0A5B421817097800DA0342 /* BeastUnitTests.cpp in Sources */,
CD0A5B4918170DC300DA0342 /* beast.mm in Sources */,
CD1CBE68181B2D99002CCC0C /* juce_modules.mm in Sources */,
CD0A5B4918170DC300DA0342 /* beast_modules.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -180,9 +188,10 @@
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../../src",
"$(SRCROOT)/../../../../../../../JUCE",
"$(SRCROOT)/../../../../config",
"$(SRCROOT)/../../../..",
"$(SRCROOT)/../../../../beast",
);
MACOSX_DEPLOYMENT_TARGET = 10.8;
ONLY_ACTIVE_ARCH = YES;
@@ -219,9 +228,10 @@
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../../src",
"$(SRCROOT)/../../../../../../../JUCE",
"$(SRCROOT)/../../../../config",
"$(SRCROOT)/../../../..",
"$(SRCROOT)/../../../../beast",
);
MACOSX_DEPLOYMENT_TARGET = 10.8;
SDKROOT = macosx;

View File

@@ -0,0 +1,94 @@
/*
IMPORTANT! This file is auto-generated each time you save your
project - if you alter its contents, your changes may be overwritten!
There's a section below where you can add your own custom code safely, and the
Introjucer will preserve the contents of that block, but the best way to change
any of these definitions is by using the Introjucer's project settings.
Any commented-out settings will assume their default values.
*/
#ifndef __JUCE_APPCONFIG_M70QFTRRK__
#define __JUCE_APPCONFIG_M70QFTRRK__
//==============================================================================
// [BEGIN_USER_CODE_SECTION]
// (You can add your own code in this section, and the Introjucer will not overwrite it)
// [END_USER_CODE_SECTION]
//==============================================================================
#define JUCE_MODULE_AVAILABLE_juce_core 1
//#define JUCE_MODULE_AVAILABLE_juce_cryptography 1
//#define JUCE_MODULE_AVAILABLE_juce_data_structures 1
#define JUCE_MODULE_AVAILABLE_juce_events 1
//#define JUCE_MODULE_AVAILABLE_juce_graphics 1
//#define JUCE_MODULE_AVAILABLE_juce_gui_basics 1
//#define JUCE_MODULE_AVAILABLE_juce_gui_extra 1
//==============================================================================
// juce_core flags:
#ifndef JUCE_FORCE_DEBUG
//#define JUCE_FORCE_DEBUG
#endif
#ifndef JUCE_LOG_ASSERTIONS
#define JUCE_LOG_ASSERTIONS 1
#endif
#ifndef JUCE_CHECK_MEMORY_LEAKS
//#define JUCE_CHECK_MEMORY_LEAKS
#endif
#ifndef JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
//#define JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
#endif
#ifndef JUCE_INCLUDE_ZLIB_CODE
//#define JUCE_INCLUDE_ZLIB_CODE
#endif
//==============================================================================
// juce_graphics flags:
#ifndef JUCE_USE_COREIMAGE_LOADER
#define JUCE_USE_COREIMAGE_LOADER 0
#endif
#ifndef JUCE_USE_DIRECTWRITE
//#define JUCE_USE_DIRECTWRITE
#endif
//==============================================================================
// juce_gui_basics flags:
#ifndef JUCE_ENABLE_REPAINT_DEBUGGING
//#define JUCE_ENABLE_REPAINT_DEBUGGING
#endif
#ifndef JUCE_USE_XSHM
//#define JUCE_USE_XSHM
#endif
#ifndef JUCE_USE_XRENDER
//#define JUCE_USE_XRENDER
#endif
#ifndef JUCE_USE_XCURSOR
//#define JUCE_USE_XCURSOR
#endif
//==============================================================================
// juce_gui_extra flags:
#ifndef JUCE_WEB_BROWSER
//#define JUCE_WEB_BROWSER
#endif
#endif // __JUCE_APPCONFIG_M70QFTRRK__

View File

@@ -20,7 +20,7 @@
#ifndef UNITTESTS_BEASTUNITTESTS_H_INCLUDED
#define UNITTESTS_BEASTUNITTESTS_H_INCLUDED
#include "beast.h"
#include "beast_modules.h"
int runUnitTests (beast::String const& match, beast::String const& format);

View File

@@ -17,7 +17,7 @@
*/
//==============================================================================
#include "beast.h"
#include "beast_modules.h"
#include "modules/beast_core/beast_core.cpp"
#include "modules/beast_vflib/beast_vflib.cpp"
@@ -26,6 +26,6 @@
#include "beast/crypto/Crypto.cpp"
#include "beast/strings/Strings.cpp"
#include "beast/threads/Threads.cpp"
// #include "beast/http/HTTP.cpp"
//#include "beast/http/HTTP.cpp"
#include "beast/net/Net.cpp"
#include "beast/utility/Utility.cpp"

View File

@@ -17,8 +17,8 @@
*/
//==============================================================================
#ifndef UNITTESTS_BEAST_H_INCLUDED
#define UNITTESTS_BEAST_H_INCLUDED
#ifndef UNITTESTS_BEASTMODULES_H_INCLUDED
#define UNITTESTS_BEASTMODULES_H_INCLUDED
#include "BeastConfig.h"

View File

@@ -0,0 +1,20 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include "beast_modules.cpp"

View File

@@ -0,0 +1,21 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include "modules/juce_core/juce_core.cpp"
#include "modules/juce_events/juce_events.cpp"

View File

@@ -0,0 +1,28 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef UNITTESTS_JUCEMODULES_H_INCLUDED
#define UNITTESTS_JUCEMODULES_H_INCLUDED
#include "AppConfig.h"
#include "modules/juce_core/juce_core.h"
#include "modules/juce_events/juce_events.h"
#endif

View File

@@ -17,4 +17,4 @@
*/
//==============================================================================
#include "beast.cpp"
#include "juce_modules.cpp"

View File

@@ -1,25 +1,29 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include "juce_modules.h"
#include "beast_modules.h"
#include "BeastUnitTests.h"
int main(int argc, const char * argv[])
{
return runUnitTests("", "text");
juce::ScopedJuceInitialiser_GUI juce;
return runUnitTests("", "text");
}

View File

@@ -1,3 +1,22 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright Patrick Dehne <patrick@mysonicweb.de> (www.sonicweb-radio.de)
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <stdio.h>
#include <tchar.h>

View File

@@ -199,7 +199,7 @@ void PropertySet::restoreFromXml (const XmlElement& xml)
const ScopedLock sl (lock);
clear();
forEachXmlChildElementWithTagName (xml, e, "VALUE")
beast_forEachXmlChildElementWithTagName (xml, e, "VALUE")
{
if (e->hasAttribute ("name")
&& e->hasAttribute ("val"))

View File

@@ -47,7 +47,7 @@ FileLogger::~FileLogger() {}
void FileLogger::logMessage (const String& message)
{
const ScopedLock sl (logLock);
DBG (message);
BDBG (message);
FileOutputStream out (logFile, 256);
out << message << newLine;
}

View File

@@ -52,7 +52,7 @@ void logAssertion (const char* const filename, const int lineNum) noexcept
#if BEAST_LOG_ASSERTIONS
Logger::writeToLog (m);
#else
DBG (m);
BDBG (m);
#endif
}
#endif

View File

@@ -93,7 +93,7 @@ struct Expression::Helpers
public:
EvaluationError (const String& desc) : description (desc)
{
DBG ("Expression::EvaluationError: " + description);
BDBG ("Expression::EvaluationError: " + description);
}
String description;
@@ -1086,7 +1086,7 @@ SharedPtr<Expression::Term> Expression::Term::negated()
Expression::ParseError::ParseError (const String& message)
: description (message)
{
DBG ("Expression::ParseError: " + message);
BDBG ("Expression::ParseError: " + message);
}
//==============================================================================

View File

@@ -47,10 +47,10 @@
# ifdef _VARIADIC_MAX
# define BEAST_VARIADIC_MAX _VARIADIC_MAX
# else
# define BEAST_VARIADIC_MAX 9
# define BEAST_VARIADIC_MAX 10
# endif
#else
# define BEAST_VARIADIC_MAX 9
# define BEAST_VARIADIC_MAX 10
#endif
//------------------------------------------------------------------------------

View File

@@ -43,7 +43,7 @@
@see forEachXmlChildElementWithTagName
*/
#define forEachXmlChildElement(parentXmlElement, childElementVariableName) \
#define beast_forEachXmlChildElement(parentXmlElement, childElementVariableName) \
\
for (beast::XmlElement* childElementVariableName = (parentXmlElement).getFirstChildElement(); \
childElementVariableName != nullptr; \
@@ -72,7 +72,7 @@
@see forEachXmlChildElement
*/
#define forEachXmlChildElementWithTagName(parentXmlElement, childElementVariableName, requiredTagName) \
#define beast_forEachXmlChildElementWithTagName(parentXmlElement, childElementVariableName, requiredTagName) \
\
for (beast::XmlElement* childElementVariableName = (parentXmlElement).getChildByName (requiredTagName); \
childElementVariableName != nullptr; \

View File

@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Copyright Patrick Dehne <patrick@mysonicweb.de> (www.sonicweb-radio.de)
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
@@ -20,3 +20,9 @@
#include "beast_vflib.h"
#include "threads/ThreadWithServiceQueue.cpp"
/** Unit tests for header only classes
*/
static beast::detail::CallQueueTests callQueueTests;
static beast::detail::ManualServiceQueueTests manualServiceQueueTests;

View File

@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
/*
This file is part of BeastUtils: https://github.com/pdehne/BeastUtils
Copyright 2013, Patrick Dehne <patrick@sonicweb.de>
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright Patrick Dehne <patrick@mysonicweb.de> (www.sonicweb-radio.de)
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
@@ -21,7 +21,9 @@
#define BEAST_VFLIB_H_INCLUDED
#include "functor/BindHelper.h"
#include "threads/BindableServiceQueue.h"
#include "threads/CallQueue.h"
#include "threads/ThreadWithServiceQueue.h"
#include "threads/ManualServiceQueue.h"
#include "threads/GuiServiceQueue.h"
#endif

View File

@@ -2,6 +2,7 @@
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Copyright Patrick Dehne <patrick@mysonicweb.de> (www.sonicweb-radio.de)
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
@@ -38,6 +39,7 @@ private:
UnaryFunction m_f;
public:
#if BEAST_VARIADIC_MAX >= 1
template <typename Arg>
explicit BindHelper (Arg& arg)
: m_f (arg)
@@ -51,26 +53,61 @@ public:
template <typename F>
void operator() (F const& f) const
{ m_f (f); }
#endif
#if BEAST_VARIADIC_MAX >= 2
template <typename F, class P1>
void operator() (F const& f, P1 const& p1) const
{ m_f (bind (f, p1)); }
#endif
#if BEAST_VARIADIC_MAX >= 3
template <typename F, class P1, class P2>
void operator() (F const& f, P1 const& p1, P2 const& p2) const
{ m_f (bind (f, p1, p2)); }
#endif
#if BEAST_VARIADIC_MAX >= 4
template <typename F, class P1, class P2, class P3>
void operator() (F const& f, P1 const& p1, P2 const& p2, P3 const& p3) const
{ m_f (bind (f, p1, p2, p3)); }
#endif
#if BEAST_VARIADIC_MAX >= 5
template <typename F, class P1, class P2, class P3, class P4>
void operator() (F const& f, P1 const& p1, P2 const& p2, P3 const& p3, P4 const& p4) const
{ m_f (bind (f, p1, p2, p3, p4)); }
#endif
#if BEAST_VARIADIC_MAX >= 6
template <typename F, class P1, class P2, class P3, class P4, class P5>
void operator() (F const& f, P1 const& p1, P2 const& p2, P3 const& p3, P4 const& p4, P5 const& p5) const
{ m_f (bind (f, p1, p2, p3, p4, p5)); }
#endif
#if BEAST_VARIADIC_MAX >= 7
template <typename F, class P1, class P2, class P3, class P4, class P5, class P6>
void operator() (F const& f, P1 const& p1, P2 const& p2, P3 const& p3, P4 const& p4, P5 const& p5, P6 const& p6) const
{ m_f (bind (f, p1, p2, p3, p4, p5, p6)); }
#endif
#if BEAST_VARIADIC_MAX >= 8
template <typename F, class P1, class P2, class P3, class P4, class P5, class P6, class P7>
void operator() (F const& f, P1 const& p1, P2 const& p2, P3 const& p3, P4 const& p4, P5 const& p5, P6 const& p6, P7 const& p7) const
{ m_f (bind (f, p1, p2, p3, p4, p5, p6, p7)); }
#endif
#if BEAST_VARIADIC_MAX >= 9
template <typename F, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8>
void operator() (F const& f, P1 const& p1, P2 const& p2, P3 const& p3, P4 const& p4, P5 const& p5, P6 const& p6, P7 const& p7, P8 const& p8) const
{ m_f (bind (f, p1, p2, p3, p4, p5, p6, p7, p8)); }
#endif
#if BEAST_VARIADIC_MAX >= 10
template <typename F, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9>
void operator() (F const& f, P1 const& p1, P2 const& p2, P3 const& p3, P4 const& p4, P5 const& p5, P6 const& p6, P7 const& p7, P8 const& p8, P9 const& p9) const
{ m_f (bind (f, p1, p2, p3, p4, p5, p6, p7, p8, p9)); }
#endif
};
}

View File

@@ -1,71 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_VFLIB_BINDABLESERVICEQUEUETYPE_H_INCLUDED
#define BEAST_VFLIB_BINDABLESERVICEQUEUETYPE_H_INCLUDED
#include "beast/Threads.h"
#include "../functor/BindHelper.h"
namespace beast {
template <class Allocator = std::allocator <char> >
class BindableServiceQueueType
: public ServiceQueueType <Allocator>
{
public:
explicit BindableServiceQueueType (int expectedConcurrency = 1,
Allocator alloc = Allocator())
: ServiceQueueType<Allocator>(expectedConcurrency, alloc)
, queue(*this)
, call(*this)
{
}
struct BindHelperPost
{
BindableServiceQueueType<Allocator>& m_queue;
explicit BindHelperPost (BindableServiceQueueType<Allocator>& queue)
: m_queue (queue)
{ }
template <typename F>
void operator() (F const& f) const
{ m_queue.post ( F (f) ); }
};
struct BindHelperDispatch
{
BindableServiceQueueType<Allocator>& m_queue;
explicit BindHelperDispatch (BindableServiceQueueType<Allocator>& queue)
: m_queue (queue)
{ }
template <typename F>
void operator() (F const& f) const
{ m_queue.dispatch ( F (f) ); }
};
BindHelper <BindHelperPost> const queue;
BindHelper <BindHelperDispatch> const call;
};
typedef BindableServiceQueueType <std::allocator <char> > BindableServiceQueue;
}
#endif

View File

@@ -0,0 +1,382 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Copyright Patrick Dehne <patrick@mysonicweb.de> (www.sonicweb-radio.de)
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_VFLIB_CALLQUEUE_H_INCLUDED
#define BEAST_VFLIB_CALLQUEUE_H_INCLUDED
#include "beast/Threads.h"
#include "../functor/BindHelper.h"
namespace beast {
template <class Allocator = std::allocator <char> >
class CallQueueType
: public ServiceQueueType <Allocator>
{
public:
explicit CallQueueType (const String& name,
int expectedConcurrency = 1,
Allocator alloc = Allocator())
: ServiceQueueType<Allocator>(expectedConcurrency, alloc)
, m_name (name)
, queue(*this)
, call(*this)
{
}
~CallQueueType ()
{
// Someone forget to close the queue.
bassert (m_closed.isSignaled ());
// Can't destroy queue with unprocessed calls.
bassert (ServiceQueueBase::empty ());
}
void enqueue (ServiceQueueBase::Item* item)
{
// If this goes off someone added calls
// after the queue has been closed.
bassert (!m_closed.isSignaled ());
ServiceQueueType <Allocator>::enqueue (item);
}
/** Close the queue.
Functors may not be added after this routine is called. This is used for
diagnostics, to track down spurious calls during application shutdown
or exit. Derived classes may call this if the appropriate time is known.
The queue is synchronized after it is closed.
Can still have pending calls, just can't put new ones in.
*/
virtual void close ()
{
m_closed.signal ();
ServiceQueueType <Allocator>::stop ();
}
struct BindHelperPost
{
CallQueueType<Allocator>& m_queue;
explicit BindHelperPost (CallQueueType<Allocator>& queue)
: m_queue (queue)
{ }
template <typename F>
void operator() (F const& f) const
{ m_queue.post ( F (f) ); }
};
struct BindHelperDispatch
{
CallQueueType<Allocator>& m_queue;
explicit BindHelperDispatch (CallQueueType<Allocator>& queue)
: m_queue (queue)
{ }
template <typename F>
void operator() (F const& f) const
{ m_queue.dispatch ( F (f) ); }
};
BindHelper <BindHelperPost> const queue;
BindHelper <BindHelperDispatch> const call;
private:
String m_name;
AtomicFlag m_closed;
};
typedef CallQueueType <std::allocator <char> > CallQueue;
namespace detail
{
//------------------------------------------------------------------------------
class CallQueueTests
: public UnitTest
{
public:
struct CallTracker
{
CallQueueTests *unitTest;
int c0, c1, c2, c3, c4, c5, c6, c7, c8;
int q0, q1, q2, q3, q4, q5, q6, q7, q8;
CallTracker(CallQueueTests *parent)
: unitTest(parent)
, c0(0), c1(0), c2(0), c3(0), c4(0), c5(0), c6(0), c7(0), c8(0)
, q0(0), q1(0), q2(0), q3(0), q4(0), q5(0), q6(0), q7(0), q8(0)
{
}
void doQ0() { q0++; }
void doQ1(const String& p1)
{
unitTest->expect(p1 == "p1");
q1++;
}
void doQ2(const String& p1, const String& p2)
{
unitTest->expect(p1 == "p1");
unitTest->expect(p2 == "p2");
q2++;
}
void doQ3(const String& p1, const String& p2, const String& p3)
{
unitTest->expect(p1 == "p1");
unitTest->expect(p2 == "p2");
unitTest->expect(p3 == "p3");
q3++;
}
void doQ4(const String& p1, const String& p2, const String& p3, const String& p4)
{
unitTest->expect(p1 == "p1");
unitTest->expect(p2 == "p2");
unitTest->expect(p3 == "p3");
unitTest->expect(p4 == "p4");
q4++;
}
void doQ5(const String& p1, const String& p2, const String& p3, const String& p4, const String& p5)
{
unitTest->expect(p1 == "p1");
unitTest->expect(p2 == "p2");
unitTest->expect(p3 == "p3");
unitTest->expect(p4 == "p4");
unitTest->expect(p5 == "p5");
q5++;
}
void doQ6(const String& p1, const String& p2, const String& p3, const String& p4, const String& p5, const String& p6)
{
unitTest->expect(p1 == "p1");
unitTest->expect(p2 == "p2");
unitTest->expect(p3 == "p3");
unitTest->expect(p4 == "p4");
unitTest->expect(p5 == "p5");
unitTest->expect(p6 == "p6");
q6++;
}
void doQ7(const String& p1, const String& p2, const String& p3, const String& p4, const String& p5, const String& p6, const String& p7)
{
unitTest->expect(p1 == "p1");
unitTest->expect(p2 == "p2");
unitTest->expect(p3 == "p3");
unitTest->expect(p4 == "p4");
unitTest->expect(p5 == "p5");
unitTest->expect(p6 == "p6");
unitTest->expect(p7 == "p7");
q7++;
}
void doQ8(const String& p1, const String& p2, const String& p3, const String& p4, const String& p5, const String& p6, const String& p7, const String& p8)
{
unitTest->expect(p1 == "p1");
unitTest->expect(p2 == "p2");
unitTest->expect(p3 == "p3");
unitTest->expect(p4 == "p4");
unitTest->expect(p5 == "p5");
unitTest->expect(p6 == "p6");
unitTest->expect(p7 == "p7");
unitTest->expect(p8 == "p8");
q8++;
}
void doC0() { c0++; }
void doC1(const String& p1)
{
unitTest->expect(p1 == "p1");
c1++;
}
void doC2(const String& p1, const String& p2)
{
unitTest->expect(p1 == "p1");
unitTest->expect(p2 == "p2");
c2++;
}
void doC3(const String& p1, const String& p2, const String& p3)
{
unitTest->expect(p1 == "p1");
unitTest->expect(p2 == "p2");
unitTest->expect(p3 == "p3");
c3++;
}
void doC4(const String& p1, const String& p2, const String& p3, const String& p4)
{
unitTest->expect(p1 == "p1");
unitTest->expect(p2 == "p2");
unitTest->expect(p3 == "p3");
unitTest->expect(p4 == "p4");
c4++;
}
void doC5(const String& p1, const String& p2, const String& p3, const String& p4, const String& p5)
{
unitTest->expect(p1 == "p1");
unitTest->expect(p2 == "p2");
unitTest->expect(p3 == "p3");
unitTest->expect(p4 == "p4");
unitTest->expect(p5 == "p5");
c5++;
}
void doC6(const String& p1, const String& p2, const String& p3, const String& p4, const String& p5, const String& p6)
{
unitTest->expect(p1 == "p1");
unitTest->expect(p2 == "p2");
unitTest->expect(p3 == "p3");
unitTest->expect(p4 == "p4");
unitTest->expect(p5 == "p5");
unitTest->expect(p6 == "p6");
c6++;
}
void doC7(const String& p1, const String& p2, const String& p3, const String& p4, const String& p5, const String& p6, const String& p7)
{
unitTest->expect(p1 == "p1");
unitTest->expect(p2 == "p2");
unitTest->expect(p3 == "p3");
unitTest->expect(p4 == "p4");
unitTest->expect(p5 == "p5");
unitTest->expect(p6 == "p6");
unitTest->expect(p7 == "p7");
c7++;
}
void doC8(const String& p1, const String& p2, const String& p3, const String& p4, const String& p5, const String& p6, const String& p7, const String& p8)
{
unitTest->expect(p1 == "p1");
unitTest->expect(p2 == "p2");
unitTest->expect(p3 == "p3");
unitTest->expect(p4 == "p4");
unitTest->expect(p5 == "p5");
unitTest->expect(p6 == "p6");
unitTest->expect(p7 == "p7");
unitTest->expect(p8 == "p8");
c8++;
}
};
CallTracker m_callTracker;
void testArities ()
{
beginTestCase("Arities");
int calls = 0;
#if BEAST_VARIADIC_MAX >= 2
m_queue.queue(&CallTracker::doQ0, &m_callTracker); calls++;
m_queue.queue(&CallTracker::doC0, &m_callTracker); calls++;
#endif
#if BEAST_VARIADIC_MAX >= 3
m_queue.queue(&CallTracker::doQ1, &m_callTracker, "p1"); calls++;
m_queue.queue(&CallTracker::doC1, &m_callTracker, "p1"); calls++;
#endif
#if BEAST_VARIADIC_MAX >= 4
m_queue.queue(&CallTracker::doQ2, &m_callTracker, "p1", "p2"); calls++;
m_queue.queue(&CallTracker::doC2, &m_callTracker, "p1", "p2"); calls++;
#endif
#if BEAST_VARIADIC_MAX >= 5
m_queue.queue(&CallTracker::doQ3, &m_callTracker, "p1", "p2", "p3"); calls++;
m_queue.queue(&CallTracker::doC3, &m_callTracker, "p1", "p2", "p3"); calls++;
#endif
#if BEAST_VARIADIC_MAX >= 6
m_queue.queue(&CallTracker::doQ4, &m_callTracker, "p1", "p2", "p3", "p4"); calls++;
m_queue.queue(&CallTracker::doC4, &m_callTracker, "p1", "p2", "p3", "p4"); calls++;
#endif
#if BEAST_VARIADIC_MAX >= 7
m_queue.queue(&CallTracker::doQ5, &m_callTracker, "p1", "p2", "p3", "p4", "p5"); calls++;
m_queue.queue(&CallTracker::doC5, &m_callTracker, "p1", "p2", "p3", "p4", "p5"); calls++;
#endif
#if BEAST_VARIADIC_MAX >= 8
m_queue.queue(&CallTracker::doQ6, &m_callTracker, "p1", "p2", "p3", "p4", "p5", "p6"); calls++;
m_queue.queue(&CallTracker::doC6, &m_callTracker, "p1", "p2", "p3", "p4", "p5", "p6"); calls++;
#endif
#if BEAST_VARIADIC_MAX >= 9
m_queue.queue(&CallTracker::doQ7, &m_callTracker, "p1", "p2", "p3", "p4", "p5", "p6", "p7"); calls++;
m_queue.queue(&CallTracker::doC7, &m_callTracker, "p1", "p2", "p3", "p4", "p5", "p6", "p7"); calls++;
#endif
#if BEAST_VARIADIC_MAX >= 10
m_queue.queue(&CallTracker::doQ8, &m_callTracker, "p1", "p2", "p3", "p4", "p5", "p6", "p7", "p8"); calls++;
m_queue.queue(&CallTracker::doC8, &m_callTracker, "p1", "p2", "p3", "p4", "p5", "p6", "p7", "p8"); calls++;
#endif
std::size_t performedCalls = m_queue.poll();
m_queue.close();
expect (performedCalls == calls);
expect (m_callTracker.c0 == 1);
expect (m_callTracker.c1 == 1);
expect (m_callTracker.c2 == 1);
expect (m_callTracker.c3 == 1);
expect (m_callTracker.c4 == 1);
expect (m_callTracker.c5 == 1);
expect (m_callTracker.q0 == 1);
expect (m_callTracker.q1 == 1);
expect (m_callTracker.q2 == 1);
expect (m_callTracker.q3 == 1);
expect (m_callTracker.q4 == 1);
expect (m_callTracker.q5 == 1);
}
void runTest()
{
testArities();
}
CallQueueTests ()
: UnitTest ("CallQueue", "beast")
, m_queue("CallQueue Test Queue")
, m_callTracker(this)
{
}
CallQueue m_queue;
};
}
}
#endif

View File

@@ -0,0 +1,72 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Copyright Patrick Dehne <patrick@mysonicweb.de> (www.sonicweb-radio.de)
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_VFLIB_GUISERVICEQUEUE_H_INCLUDED
#define BEAST_VFLIB_GUISERVICEQUEUE_H_INCLUDED
#include "AppConfig.h"
#include "modules/juce_core/juce_core.h"
#include "modules/juce_events/juce_events.h"
#include "CallQueue.h"
namespace beast {
class GuiServiceQueue
: public CallQueue
, private juce::AsyncUpdater
, private ThreadWithServiceQueue::EntryPoints
{
public:
explicit GuiServiceQueue (const String& name)
: CallQueue(name)
, m_thread(name)
{
bassert (juce::MessageManager::getInstance()->isThisTheMessageThread());
m_thread.start (this);
}
void close ()
{
m_thread.stop (true);
CallQueue::close ();
}
void enqueue (ServiceQueueBase::Item* item)
{
CallQueue::enqueue (item);
m_thread.call (&juce::AsyncUpdater::triggerAsyncUpdate, (AsyncUpdater*)this);
}
void handleAsyncUpdate()
{
poll();
}
private:
ThreadWithServiceQueue m_thread;
};
}
#endif

View File

@@ -0,0 +1,165 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright Patrick Dehne <patrick@mysonicweb.de> (www.sonicweb-radio.de)
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_VFLIB_MANUALSERVICEQUEUE_H_INCLUDED
#define BEAST_VFLIB_MANUALSERVICEQUEUE_H_INCLUDED
#include "CallQueue.h"
namespace beast {
class ManualServiceQueue
: public CallQueue
{
public:
explicit ManualServiceQueue (const String& name)
: CallQueue(name)
{
}
/** Calls all functors in the queue. Returns if there are no
more functors available to run
*/
bool synchronize ()
{
if(poll() > 0)
return true;
return false;
}
};
//------------------------------------------------------------------------------
namespace detail
{
//------------------------------------------------------------------------------
class ManualServiceQueueTests
: public UnitTest
{
public:
struct CallTracker
{
ManualServiceQueueTests *unitTest;
int c0, c1;
int q0, q1;
CallTracker(ManualServiceQueueTests *parent)
: unitTest(parent)
, c0(0), c1(0)
, q0(0), q1(0)
{
}
void doQ0() { q0++; }
void doQ1(const String& p1)
{
unitTest->expect(p1 == "p1");
q1++;
}
void doC0() { c0++; }
void doC1(const String& p1)
{
unitTest->expect(p1 == "p1");
c1++;
}
};
void performEmptyQueue()
{
beginTestCase("Empty queue");
ManualServiceQueue queue("ManualServiceQueueTests");
bool doneSomething = queue.synchronize();
expect(!doneSomething);
queue.close();
}
void performCalls()
{
beginTestCase("Calls");
Random r;
r.setSeedRandomly();
ManualServiceQueue queue("ManualServiceQueueTests");
static int const batches = 1000;
for(std::size_t i=0; i<batches; i++)
{
CallTracker ct(this);
std::size_t batchSize = r.nextLargeNumber(10).toInteger();
if(batchSize > 0)
{
for(std::size_t y=0; y<batchSize; y++)
{
int callType = r.nextLargeNumber(10).toInteger();
if(callType % 2)
{
queue.queue(&CallTracker::doQ0, &ct);
queue.call(&CallTracker::doC0, &ct);
}
else
{
queue.queue(&CallTracker::doQ1, &ct, "p1");
queue.call(&CallTracker::doC1, &ct, "p1");
}
}
bool doneSomething = queue.synchronize();
expect(doneSomething);
expect ((ct.q0 + ct.q1) == batchSize);
expect ((ct.c0 + ct.c1) == batchSize);
doneSomething = queue.synchronize();
expect(!doneSomething);
}
}
queue.close ();
}
void runTest()
{
performEmptyQueue ();
performCalls ();
}
ManualServiceQueueTests () : UnitTest ("ManualServiceQueue", "beast")
{
}
};
}
}
#endif

View File

@@ -2,6 +2,7 @@
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Copyright Patrick Dehne <patrick@mysonicweb.de> (www.sonicweb-radio.de)
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
@@ -22,106 +23,65 @@
namespace beast {
ThreadWithServiceQueue::ThreadWithServiceQueue (const String& name)
: Thread (name)
: CallQueue(name)
, m_thread(name, this)
, m_entryPoints(nullptr)
, m_calledStart(false)
, m_calledStop(false)
, m_interrupted(false)
{
}
ThreadWithServiceQueue::~ThreadWithServiceQueue()
ThreadWithServiceQueue::~ThreadWithServiceQueue ()
{
stop(true);
}
void ThreadWithServiceQueue::start (EntryPoints* const entryPoints)
{
{
CriticalSection::ScopedLockType lock (m_mutex);
// start() MUST be called.
bassert (!m_calledStart);
m_calledStart = true;
}
// start() MUST be called.
bassert (!m_calledStart);
m_calledStart = true;
m_entryPoints = entryPoints;
startThread();
m_thread.startThread ();
}
void ThreadWithServiceQueue::stop (bool const wait)
{
// start() MUST be called.
bassert (m_calledStart);
if (!m_calledStop)
{
CriticalSection::ScopedLockType lock (m_mutex);
m_calledStop = true;
// start() MUST be called.
bassert (m_calledStart);
m_thread.signalThreadShouldExit();
if (!m_calledStop)
{
m_calledStop = true;
{
CriticalSection::ScopedUnlockType unlock (m_mutex);
call (&Thread::signalThreadShouldExit, this);
// something could slip in here
// m_queue.close();
}
}
// something could slip in here
close ();
}
if (wait)
waitForThreadToExit();
}
void ThreadWithServiceQueue::interrupt ()
{
call (&ThreadWithServiceQueue::doInterrupt, this);
m_thread.waitForThreadToExit ();
}
bool ThreadWithServiceQueue::interruptionPoint ()
void ThreadWithServiceQueue::runThread ()
{
return m_interrupted;
}
void ThreadWithServiceQueue::run ()
{
m_entryPoints->threadInit();
m_entryPoints->threadInit ();
while (! this->threadShouldExit())
{
run_one();
bool isInterrupted = m_entryPoints->threadIdle();
isInterrupted |= interruptionPoint();
if(isInterrupted)
{
// We put this call into the service queue to make
// sure we get through to threadIdle without
// waiting
call (&ThreadWithServiceQueue::doWakeUp, this);
}
}
while (! m_thread.threadShouldExit ())
run ();
// Perform the remaining calls in the queue
reset ();
poll ();
m_entryPoints->threadExit();
}
void ThreadWithServiceQueue::doInterrupt ()
{
m_interrupted = true;
}
void ThreadWithServiceQueue::doWakeUp ()
{
m_interrupted = false;
}
//------------------------------------------------------------------------------
namespace detail
@@ -129,22 +89,27 @@ namespace detail
//------------------------------------------------------------------------------
class BindableServiceQueueTests
class ThreadWithServiceQueueTests
: public UnitTest
{
public:
struct BindableServiceQueueRunner
struct ThreadWithServiceQueueRunner
: public ThreadWithServiceQueue::EntryPoints
{
ThreadWithServiceQueue m_worker;
int cCallCount, c1CallCount, idleInterruptedCount;
int cCallCount, c1CallCount;
int qCallCount, q1CallCount;
int initCalled, exitCalled;
BindableServiceQueueRunner()
: m_worker("BindableServiceQueueRunner")
ThreadWithServiceQueueRunner()
: m_worker("ThreadWithServiceQueueRunner")
, cCallCount(0)
, c1CallCount(0)
, idleInterruptedCount(0)
, qCallCount(0)
, q1CallCount(0)
, initCalled(0)
, exitCalled(0)
{
}
@@ -158,14 +123,9 @@ public:
m_worker.stop(true);
}
void interrupt()
{
m_worker.interrupt();
}
void c()
{
m_worker.queue(&BindableServiceQueueRunner::cImpl, this);
m_worker.call(&ThreadWithServiceQueueRunner::cImpl, this);
}
void cImpl()
@@ -175,38 +135,66 @@ public:
void c1(int p1)
{
m_worker.queue(&BindableServiceQueueRunner::c1Impl, this, p1);
m_worker.call(&ThreadWithServiceQueueRunner::c1Impl, this, p1);
}
void c1Impl(int p1)
{
c1CallCount++;
}
bool threadIdle ()
void q()
{
bool interrupted = m_worker.interruptionPoint ();
if(interrupted)
idleInterruptedCount++;
return interrupted;
m_worker.queue(&ThreadWithServiceQueueRunner::qImpl, this);
}
void qImpl()
{
qCallCount++;
}
void q1(int p1)
{
m_worker.queue(&ThreadWithServiceQueueRunner::q1Impl, this, p1);
}
void q1Impl(int p1)
{
q1CallCount++;
}
void threadInit ()
{
initCalled++;
}
void threadExit ()
{
exitCalled++;
}
};
static int const calls = 10000;
static int const calls = 1000;
void performCalls()
{
Random r;
r.setSeedRandomly();
BindableServiceQueueRunner runner;
beginTestCase("Calls and interruptions");
ThreadWithServiceQueueRunner runner;
runner.start();
for(std::size_t i=0; i<calls; i++)
{
int wait = r.nextLargeNumber(10).toInteger();
if(wait % 2)
runner.q();
else
runner.q1Impl(wait);
}
for(std::size_t i=0; i<calls; i++)
{
int wait = r.nextLargeNumber(10).toInteger();
@@ -216,31 +204,32 @@ public:
else
runner.c1Impl(wait);
}
for(std::size_t i=0; i<calls; i++)
runner.interrupt();
runner.stop();
// We can only reason that the idle method must have been interrupted
// at least once
expect ((runner.cCallCount + runner.c1CallCount) == calls);
expect (runner.idleInterruptedCount > 0);
expect ((runner.qCallCount + runner.q1CallCount) == calls);
expect (runner.initCalled == 1);
expect (runner.exitCalled == 1);
}
void runTest()
{
performCalls ();
beginTestCase("Calls");
for(int i=0; i<100; i++)
performCalls ();
}
BindableServiceQueueTests () : UnitTest ("BindableServiceQueue", "beast")
ThreadWithServiceQueueTests () : UnitTest ("ThreadWithServiceQueue", "beast")
{
}
};
static BindableServiceQueueTests bindableServiceQueueTests;
}
static CallQueueTests callQueueTests;
static ThreadWithServiceQueueTests bindableServiceQueueTests;
}
}

View File

@@ -2,6 +2,7 @@
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Copyright Patrick Dehne <patrick@mysonicweb.de> (www.sonicweb-radio.de)
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
@@ -20,72 +21,72 @@
#ifndef BEAST_VFLIB_THREADWITHSERVICEQUEUE_H_INCLUDED
#define BEAST_VFLIB_THREADWITHSERVICEQUEUE_H_INCLUDED
#include "BindableServiceQueue.h"
#include "CallQueue.h"
namespace beast {
/** TODO: Queued calls no longer interrupt the idle method at the moment
use an explicit call to interrupt() if you want to also interrupt the
idle method when queuing calls
*/
class ThreadWithServiceQueue
: public BindableServiceQueue
, public Thread
class ThreadWithServiceQueue
: public CallQueue
{
public:
/** Entry points for a ThreadWithCallQueue.
*/
class EntryPoints
{
public:
/** Entry points for a ThreadWithCallQueue.
*/
class EntryPoints
{
public:
virtual ~EntryPoints () { }
virtual ~EntryPoints () { }
virtual void threadInit () { }
virtual void threadInit () { }
virtual void threadExit () { }
virtual bool threadIdle ()
{
bool interrupted = false;
return interrupted;
}
};
explicit ThreadWithServiceQueue (const String& name);
~ThreadWithServiceQueue();
void start (EntryPoints* const entryPoints);
void stop (bool const wait);
// Should be called periodically by the idle function.
// There are two possible results:
//
// #1 Returns false. The idle function may continue or return.
// #2 Returns true. The idle function should return as soon as possible.
//
// May only be called on the service queue thead
bool interruptionPoint ();
/* Interrupts the idle function.
*/
void interrupt ();
private:
void run ();
void doInterrupt ();
void doWakeUp ();
private:
EntryPoints* m_entryPoints;
bool m_calledStart;
bool m_calledStop;
bool m_interrupted;
CriticalSection m_mutex;
virtual void threadExit () { }
};
explicit ThreadWithServiceQueue (const String& name);
~ThreadWithServiceQueue();
void start (EntryPoints* const entryPoints);
void stop (bool const wait);
/** Calls all functors in the queue. Blocks if there are no
functors available to run until more functors become
available or the queue is stopped
*/
bool synchronize ();
/** Helper class to work around ThreadWithServiceQueue and Thread both
having a run member
*/
class Worker
: public Thread
{
public:
Worker(const String& name, ThreadWithServiceQueue *parent)
: Thread(name)
, m_parent(parent)
{
}
void run()
{
m_parent->runThread();
}
private:
ThreadWithServiceQueue *m_parent;
};
void runThread ();
private:
EntryPoints* m_entryPoints;
bool m_calledStart;
bool m_calledStop;
Worker m_thread;
};
}
#endif