From 286ade2d17b8e7a0e0072a9685be5eb4ac0ae085 Mon Sep 17 00:00:00 2001 From: Patrick Dehne Date: Thu, 24 Oct 2013 17:31:18 +0200 Subject: [PATCH] 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 --- src/beast/beast/config/CompilerConfig.h | 4 +- src/beast/beast/threads/ServiceQueue.h | 1 + src/beast/beast/threads/impl/ServiceQueue.cpp | 6 + src/beast/beast/threads/impl/Thread.cpp | 6 +- src/beast/beast/utility/impl/LeakChecked.cpp | 4 +- .../xcode/unittests.xcodeproj/project.pbxproj | 30 +- src/beast/demos/unittests/src/AppConfig.h | 94 +++++ .../demos/unittests/src/BeastUnitTests.h | 2 +- .../src/{beast.cpp => beast_modules.cpp} | 4 +- .../src/{beast.h => beast_modules.h} | 4 +- .../demos/unittests/src/beast_modules.mm | 20 + .../demos/unittests/src/juce_modules.cpp | 21 + src/beast/demos/unittests/src/juce_modules.h | 28 ++ .../src/{beast.mm => juce_modules.mm} | 2 +- src/beast/demos/unittests/src/mac.cpp | 30 +- src/beast/demos/unittests/src/win32.cpp | 19 + .../beast_core/containers/PropertySet.cpp | 2 +- .../modules/beast_core/logging/FileLogger.cpp | 2 +- .../modules/beast_core/logging/Logger.cpp | 2 +- .../modules/beast_core/maths/Expression.cpp | 4 +- .../modules/beast_core/system/Functional.h | 4 +- src/beast/modules/beast_core/xml/XmlElement.h | 4 +- src/beast/modules/beast_vflib/beast_vflib.cpp | 8 +- src/beast/modules/beast_vflib/beast_vflib.h | 8 +- .../modules/beast_vflib/functor/BindHelper.h | 41 +- .../threads/BindableServiceQueue.h | 71 ---- .../modules/beast_vflib/threads/CallQueue.h | 382 ++++++++++++++++++ .../beast_vflib/threads/GuiServiceQueue.h | 72 ++++ .../beast_vflib/threads/ManualServiceQueue.h | 165 ++++++++ .../threads/ThreadWithServiceQueue.cpp | 195 +++++---- .../threads/ThreadWithServiceQueue.h | 117 +++--- 31 files changed, 1069 insertions(+), 283 deletions(-) create mode 100644 src/beast/demos/unittests/src/AppConfig.h rename src/beast/demos/unittests/src/{beast.cpp => beast_modules.cpp} (95%) rename src/beast/demos/unittests/src/{beast.h => beast_modules.h} (93%) create mode 100644 src/beast/demos/unittests/src/beast_modules.mm create mode 100644 src/beast/demos/unittests/src/juce_modules.cpp create mode 100644 src/beast/demos/unittests/src/juce_modules.h rename src/beast/demos/unittests/src/{beast.mm => juce_modules.mm} (97%) delete mode 100644 src/beast/modules/beast_vflib/threads/BindableServiceQueue.h create mode 100644 src/beast/modules/beast_vflib/threads/CallQueue.h create mode 100644 src/beast/modules/beast_vflib/threads/GuiServiceQueue.h create mode 100644 src/beast/modules/beast_vflib/threads/ManualServiceQueue.h diff --git a/src/beast/beast/config/CompilerConfig.h b/src/beast/beast/config/CompilerConfig.h index 46e3afbfa5..217df60400 100644 --- a/src/beast/beast/config/CompilerConfig.h +++ b/src/beast/beast/config/CompilerConfig.h @@ -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 diff --git a/src/beast/beast/threads/ServiceQueue.h b/src/beast/beast/threads/ServiceQueue.h index 115737c833..8ccd974cb0 100644 --- a/src/beast/beast/threads/ServiceQueue.h +++ b/src/beast/beast/threads/ServiceQueue.h @@ -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; diff --git a/src/beast/beast/threads/impl/ServiceQueue.cpp b/src/beast/beast/threads/impl/ServiceQueue.cpp index 1facf600b2..16aaddb74d 100644 --- a/src/beast/beast/threads/impl/ServiceQueue.cpp +++ b/src/beast/beast/threads/impl/ServiceQueue.cpp @@ -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. diff --git a/src/beast/beast/threads/impl/Thread.cpp b/src/beast/beast/threads/impl/Thread.cpp index 79369953bf..ebc5a4450a 100644 --- a/src/beast/beast/threads/impl/Thread.cpp +++ b/src/beast/beast/threads/impl/Thread.cpp @@ -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; diff --git a/src/beast/beast/utility/impl/LeakChecked.cpp b/src/beast/beast/utility/impl/LeakChecked.cpp index 2209995e68..df261e4908 100644 --- a/src/beast/beast/utility/impl/LeakChecked.cpp +++ b/src/beast/beast/utility/impl/LeakChecked.cpp @@ -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; } diff --git a/src/beast/demos/unittests/builds/xcode/unittests.xcodeproj/project.pbxproj b/src/beast/demos/unittests/builds/xcode/unittests.xcodeproj/project.pbxproj index 8a75f50998..5aa5935ece 100644 --- a/src/beast/demos/unittests/builds/xcode/unittests.xcodeproj/project.pbxproj +++ b/src/beast/demos/unittests/builds/xcode/unittests.xcodeproj/project.pbxproj @@ -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 = ""; }; CD0A5B401817097800DA0342 /* BeastUnitTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BeastUnitTests.cpp; path = ../../src/BeastUnitTests.cpp; sourceTree = ""; }; CD0A5B411817097800DA0342 /* BeastUnitTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BeastUnitTests.h; path = ../../src/BeastUnitTests.h; sourceTree = ""; }; - CD0A5B4318170A5100DA0342 /* beast.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = beast.cpp; path = ../../src/beast.cpp; sourceTree = ""; }; - CD0A5B4418170A5100DA0342 /* beast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = beast.h; path = ../../src/beast.h; sourceTree = ""; }; - CD0A5B4818170DC300DA0342 /* beast.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = beast.mm; path = ../../src/beast.mm; sourceTree = ""; }; + CD0A5B4318170A5100DA0342 /* beast_modules.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = beast_modules.cpp; path = ../../src/beast_modules.cpp; sourceTree = ""; }; + CD0A5B4418170A5100DA0342 /* beast_modules.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = beast_modules.h; path = ../../src/beast_modules.h; sourceTree = ""; }; + CD0A5B4818170DC300DA0342 /* beast_modules.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = beast_modules.mm; path = ../../src/beast_modules.mm; sourceTree = ""; }; 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 = ""; }; CD0A5B50181714B800DA0342 /* modules */ = {isa = PBXFileReference; lastKnownFileType = folder; name = modules; path = ../../../../modules; sourceTree = ""; }; + CD1CBE62181B2689002CCC0C /* juce_modules.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = juce_modules.cpp; path = ../../src/juce_modules.cpp; sourceTree = ""; }; + CD1CBE63181B2689002CCC0C /* juce_modules.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = juce_modules.h; path = ../../src/juce_modules.h; sourceTree = ""; }; + CD1CBE64181B2689002CCC0C /* juce_modules.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = juce_modules.mm; path = ../../src/juce_modules.mm; sourceTree = ""; }; /* 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; diff --git a/src/beast/demos/unittests/src/AppConfig.h b/src/beast/demos/unittests/src/AppConfig.h new file mode 100644 index 0000000000..df92349a63 --- /dev/null +++ b/src/beast/demos/unittests/src/AppConfig.h @@ -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__ diff --git a/src/beast/demos/unittests/src/BeastUnitTests.h b/src/beast/demos/unittests/src/BeastUnitTests.h index e3b20b0843..f26246eef4 100644 --- a/src/beast/demos/unittests/src/BeastUnitTests.h +++ b/src/beast/demos/unittests/src/BeastUnitTests.h @@ -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); diff --git a/src/beast/demos/unittests/src/beast.cpp b/src/beast/demos/unittests/src/beast_modules.cpp similarity index 95% rename from src/beast/demos/unittests/src/beast.cpp rename to src/beast/demos/unittests/src/beast_modules.cpp index e424d93efc..8d05fc23ba 100644 --- a/src/beast/demos/unittests/src/beast.cpp +++ b/src/beast/demos/unittests/src/beast_modules.cpp @@ -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" diff --git a/src/beast/demos/unittests/src/beast.h b/src/beast/demos/unittests/src/beast_modules.h similarity index 93% rename from src/beast/demos/unittests/src/beast.h rename to src/beast/demos/unittests/src/beast_modules.h index 351fb0a2a4..955aeb456a 100644 --- a/src/beast/demos/unittests/src/beast.h +++ b/src/beast/demos/unittests/src/beast_modules.h @@ -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" diff --git a/src/beast/demos/unittests/src/beast_modules.mm b/src/beast/demos/unittests/src/beast_modules.mm new file mode 100644 index 0000000000..4eebeb14d5 --- /dev/null +++ b/src/beast/demos/unittests/src/beast_modules.mm @@ -0,0 +1,20 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + 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" diff --git a/src/beast/demos/unittests/src/juce_modules.cpp b/src/beast/demos/unittests/src/juce_modules.cpp new file mode 100644 index 0000000000..8fc5db542b --- /dev/null +++ b/src/beast/demos/unittests/src/juce_modules.cpp @@ -0,0 +1,21 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + 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" diff --git a/src/beast/demos/unittests/src/juce_modules.h b/src/beast/demos/unittests/src/juce_modules.h new file mode 100644 index 0000000000..e1af1b0f44 --- /dev/null +++ b/src/beast/demos/unittests/src/juce_modules.h @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + 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 diff --git a/src/beast/demos/unittests/src/beast.mm b/src/beast/demos/unittests/src/juce_modules.mm similarity index 97% rename from src/beast/demos/unittests/src/beast.mm rename to src/beast/demos/unittests/src/juce_modules.mm index 566db5b523..58e56bc68b 100644 --- a/src/beast/demos/unittests/src/beast.mm +++ b/src/beast/demos/unittests/src/juce_modules.mm @@ -17,4 +17,4 @@ */ //============================================================================== -#include "beast.cpp" +#include "juce_modules.cpp" diff --git a/src/beast/demos/unittests/src/mac.cpp b/src/beast/demos/unittests/src/mac.cpp index 2e13ce4792..1d6868f239 100644 --- a/src/beast/demos/unittests/src/mac.cpp +++ b/src/beast/demos/unittests/src/mac.cpp @@ -1,25 +1,29 @@ //------------------------------------------------------------------------------ /* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco - 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"); } diff --git a/src/beast/demos/unittests/src/win32.cpp b/src/beast/demos/unittests/src/win32.cpp index 7fe103a845..35b8f2c4ba 100644 --- a/src/beast/demos/unittests/src/win32.cpp +++ b/src/beast/demos/unittests/src/win32.cpp @@ -1,3 +1,22 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright Patrick Dehne (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 #include diff --git a/src/beast/modules/beast_core/containers/PropertySet.cpp b/src/beast/modules/beast_core/containers/PropertySet.cpp index cf2ff79df2..c87e5cfb1f 100644 --- a/src/beast/modules/beast_core/containers/PropertySet.cpp +++ b/src/beast/modules/beast_core/containers/PropertySet.cpp @@ -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")) diff --git a/src/beast/modules/beast_core/logging/FileLogger.cpp b/src/beast/modules/beast_core/logging/FileLogger.cpp index fa19b3afe8..ad654cdf8f 100644 --- a/src/beast/modules/beast_core/logging/FileLogger.cpp +++ b/src/beast/modules/beast_core/logging/FileLogger.cpp @@ -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; } diff --git a/src/beast/modules/beast_core/logging/Logger.cpp b/src/beast/modules/beast_core/logging/Logger.cpp index 06d252f42a..5a5f073345 100644 --- a/src/beast/modules/beast_core/logging/Logger.cpp +++ b/src/beast/modules/beast_core/logging/Logger.cpp @@ -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 diff --git a/src/beast/modules/beast_core/maths/Expression.cpp b/src/beast/modules/beast_core/maths/Expression.cpp index e47082a301..c8f780754c 100644 --- a/src/beast/modules/beast_core/maths/Expression.cpp +++ b/src/beast/modules/beast_core/maths/Expression.cpp @@ -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::negated() Expression::ParseError::ParseError (const String& message) : description (message) { - DBG ("Expression::ParseError: " + message); + BDBG ("Expression::ParseError: " + message); } //============================================================================== diff --git a/src/beast/modules/beast_core/system/Functional.h b/src/beast/modules/beast_core/system/Functional.h index 173b93519b..9aabe28e95 100644 --- a/src/beast/modules/beast_core/system/Functional.h +++ b/src/beast/modules/beast_core/system/Functional.h @@ -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 //------------------------------------------------------------------------------ diff --git a/src/beast/modules/beast_core/xml/XmlElement.h b/src/beast/modules/beast_core/xml/XmlElement.h index 58c3125ad5..4875d69832 100644 --- a/src/beast/modules/beast_core/xml/XmlElement.h +++ b/src/beast/modules/beast_core/xml/XmlElement.h @@ -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; \ diff --git a/src/beast/modules/beast_vflib/beast_vflib.cpp b/src/beast/modules/beast_vflib/beast_vflib.cpp index 94e2c88a0f..355f19d5d6 100644 --- a/src/beast/modules/beast_vflib/beast_vflib.cpp +++ b/src/beast/modules/beast_vflib/beast_vflib.cpp @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ /* This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco + Copyright Patrick Dehne (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; diff --git a/src/beast/modules/beast_vflib/beast_vflib.h b/src/beast/modules/beast_vflib/beast_vflib.h index 6582169d41..50e2d76a80 100644 --- a/src/beast/modules/beast_vflib/beast_vflib.h +++ b/src/beast/modules/beast_vflib/beast_vflib.h @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ /* - This file is part of BeastUtils: https://github.com/pdehne/BeastUtils - Copyright 2013, Patrick Dehne + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright Patrick Dehne (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 diff --git a/src/beast/modules/beast_vflib/functor/BindHelper.h b/src/beast/modules/beast_vflib/functor/BindHelper.h index 0247592f64..b148fd081a 100644 --- a/src/beast/modules/beast_vflib/functor/BindHelper.h +++ b/src/beast/modules/beast_vflib/functor/BindHelper.h @@ -2,6 +2,7 @@ /* This file is part of Beast: https://github.com/vinniefalco/Beast Copyright 2013, Vinnie Falco + Copyright Patrick Dehne (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 explicit BindHelper (Arg& arg) : m_f (arg) @@ -51,26 +53,61 @@ public: template void operator() (F const& f) const { m_f (f); } +#endif +#if BEAST_VARIADIC_MAX >= 2 template void operator() (F const& f, P1 const& p1) const { m_f (bind (f, p1)); } - +#endif + +#if BEAST_VARIADIC_MAX >= 3 template 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 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 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 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 + 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 + 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 + 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 + 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 }; } diff --git a/src/beast/modules/beast_vflib/threads/BindableServiceQueue.h b/src/beast/modules/beast_vflib/threads/BindableServiceQueue.h deleted file mode 100644 index 42872f2447..0000000000 --- a/src/beast/modules/beast_vflib/threads/BindableServiceQueue.h +++ /dev/null @@ -1,71 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - 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 BindableServiceQueueType - : public ServiceQueueType - { - public: - explicit BindableServiceQueueType (int expectedConcurrency = 1, - Allocator alloc = Allocator()) - : ServiceQueueType(expectedConcurrency, alloc) - , queue(*this) - , call(*this) - { - } - - struct BindHelperPost - { - BindableServiceQueueType& m_queue; - explicit BindHelperPost (BindableServiceQueueType& queue) - : m_queue (queue) - { } - template - void operator() (F const& f) const - { m_queue.post ( F (f) ); } - }; - - struct BindHelperDispatch - { - BindableServiceQueueType& m_queue; - explicit BindHelperDispatch (BindableServiceQueueType& queue) - : m_queue (queue) - { } - template - void operator() (F const& f) const - { m_queue.dispatch ( F (f) ); } - }; - - BindHelper const queue; - BindHelper const call; - }; - - typedef BindableServiceQueueType > BindableServiceQueue; - -} - -#endif diff --git a/src/beast/modules/beast_vflib/threads/CallQueue.h b/src/beast/modules/beast_vflib/threads/CallQueue.h new file mode 100644 index 0000000000..352977de20 --- /dev/null +++ b/src/beast/modules/beast_vflib/threads/CallQueue.h @@ -0,0 +1,382 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + Copyright Patrick Dehne (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 CallQueueType +: public ServiceQueueType +{ +public: + explicit CallQueueType (const String& name, + int expectedConcurrency = 1, + Allocator alloc = Allocator()) + : ServiceQueueType(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 ::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 ::stop (); + } + + struct BindHelperPost + { + CallQueueType& m_queue; + explicit BindHelperPost (CallQueueType& queue) + : m_queue (queue) + { } + template + void operator() (F const& f) const + { m_queue.post ( F (f) ); } + }; + + struct BindHelperDispatch + { + CallQueueType& m_queue; + explicit BindHelperDispatch (CallQueueType& queue) + : m_queue (queue) + { } + template + void operator() (F const& f) const + { m_queue.dispatch ( F (f) ); } + }; + + BindHelper const queue; + BindHelper const call; + +private: + String m_name; + AtomicFlag m_closed; +}; + +typedef CallQueueType > 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 diff --git a/src/beast/modules/beast_vflib/threads/GuiServiceQueue.h b/src/beast/modules/beast_vflib/threads/GuiServiceQueue.h new file mode 100644 index 0000000000..2f8d8750bb --- /dev/null +++ b/src/beast/modules/beast_vflib/threads/GuiServiceQueue.h @@ -0,0 +1,72 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + Copyright Patrick Dehne (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 diff --git a/src/beast/modules/beast_vflib/threads/ManualServiceQueue.h b/src/beast/modules/beast_vflib/threads/ManualServiceQueue.h new file mode 100644 index 0000000000..3ab220e7f0 --- /dev/null +++ b/src/beast/modules/beast_vflib/threads/ManualServiceQueue.h @@ -0,0 +1,165 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright Patrick Dehne (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 0) + { + for(std::size_t y=0; y + Copyright Patrick Dehne (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 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; + +} } diff --git a/src/beast/modules/beast_vflib/threads/ThreadWithServiceQueue.h b/src/beast/modules/beast_vflib/threads/ThreadWithServiceQueue.h index 2e93d5bacf..1c19718b31 100644 --- a/src/beast/modules/beast_vflib/threads/ThreadWithServiceQueue.h +++ b/src/beast/modules/beast_vflib/threads/ThreadWithServiceQueue.h @@ -2,6 +2,7 @@ /* This file is part of Beast: https://github.com/vinniefalco/Beast Copyright 2013, Vinnie Falco + Copyright Patrick Dehne (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