Mercurial > hg > orthanc-stone
changeset 2281:2329f970cde7 refactoring tip
native oracle: sleep
| author | Sebastien Jodogne <s.jodogne@gmail.com> |
|---|---|
| date | Sat, 19 Sep 2026 01:24:20 +0200 |
| parents | 7a169e34a033 |
| children | |
| files | Applications/Samples/Sdl/SingleFrameViewer/SdlSimpleViewer.cpp Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp OrthancStone/Resources/CMake/OrthancStoneConfiguration.cmake OrthancStone/Sources/Oracle/IOracle.h OrthancStone/Sources/Oracle/OracleCallback.cpp OrthancStone/Sources/Oracle/OracleCallback.h OrthancStone/Sources/Oracle/ThreadedOracle.cpp OrthancStone/Sources/Oracle/ThreadedOracle.h OrthancStone/Sources/Platforms/Native/NativeEnvironment.h OrthancStone/Sources/Platforms/Native/RunnableThread.h OrthancStone/Sources/Platforms/WebAssembly/WebAssemblyOracle.cpp OrthancStone/Sources/Platforms/WebAssembly/WebAssemblyOracle.h |
| diffstat | 12 files changed, 259 insertions(+), 81 deletions(-) [+] |
line wrap: on
line diff
--- a/Applications/Samples/Sdl/SingleFrameViewer/SdlSimpleViewer.cpp Thu Sep 17 20:17:50 2026 +0200 +++ b/Applications/Samples/Sdl/SingleFrameViewer/SdlSimpleViewer.cpp Sat Sep 19 01:24:20 2026 +0200 @@ -61,7 +61,7 @@ #include "../../../../OrthancStone/Sources/Oracle/ThreadedOracle.h" static OrthancStone::NativeEnvironment environment_; -static OrthancStone::New::ThreadedOracle oracle_(environment_, 4 /* threads */); +static OrthancStone::New::ThreadedOracle oracle_(4 /* threads */); class Toto : public OrthancStone::IOracleClient @@ -215,6 +215,7 @@ context.StartOracle(); environment_.Start(); + oracle_.Start(); { { @@ -298,7 +299,7 @@ { case SDLK_b: // TODO Refactoring - oracle_.Submit(toto_, new OrthancStone::SleepOracleCommand(1000)); + oracle_.Submit(environment_, toto_, new OrthancStone::SleepOracleCommand(1000)); break; case SDLK_f: @@ -560,6 +561,7 @@ } context.StopOracle(); + oracle_.Stop(); environment_.Stop(); } }
--- a/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp Thu Sep 17 20:17:50 2026 +0200 +++ b/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp Sat Sep 19 01:24:20 2026 +0200 @@ -4878,7 +4878,7 @@ #include "../../../OrthancStone/Sources/Oracle/SleepOracleCommand.h" static OrthancStone::WebAssemblyEnvironment environment_; -static OrthancStone::New::WebAssemblyOracle oracle_(environment_); +static OrthancStone::New::WebAssemblyOracle oracle_; class Toto : public OrthancStone::IOracleClient { @@ -4937,7 +4937,7 @@ // TODO Refactoring - oracle_.Submit(toto_, new OrthancStone::SleepOracleCommand(2000)); + oracle_.Submit(environment_, toto_, new OrthancStone::SleepOracleCommand(2000)); }
--- a/OrthancStone/Resources/CMake/OrthancStoneConfiguration.cmake Thu Sep 17 20:17:50 2026 +0200 +++ b/OrthancStone/Resources/CMake/OrthancStoneConfiguration.cmake Sat Sep 19 01:24:20 2026 +0200 @@ -266,6 +266,7 @@ ${ORTHANC_STONE_ROOT}/Oracle/GetOrthancImageCommand.cpp ${ORTHANC_STONE_ROOT}/Oracle/GetOrthancWebViewerJpegCommand.cpp ${ORTHANC_STONE_ROOT}/Oracle/HttpCommand.cpp + ${ORTHANC_STONE_ROOT}/Oracle/OracleCallback.cpp ${ORTHANC_STONE_ROOT}/Oracle/OracleCommandBase.cpp ${ORTHANC_STONE_ROOT}/Oracle/OrthancRestApiCommand.cpp ${ORTHANC_STONE_ROOT}/Oracle/ParseDicomFromFileCommand.cpp
--- a/OrthancStone/Sources/Oracle/IOracle.h Thu Sep 17 20:17:50 2026 +0200 +++ b/OrthancStone/Sources/Oracle/IOracle.h Sat Sep 19 01:24:20 2026 +0200 @@ -24,8 +24,9 @@ #pragma once #include "../Messages/IObserver.h" +#include "IEnvironment.h" +#include "IOracleClient.h" #include "IOracleCommand.h" -#include "IOracleClient.h" #include <OrthancException.h> @@ -59,7 +60,8 @@ { } - virtual void Submit(const boost::shared_ptr<IOracleClient>& client, + virtual void Submit(IEnvironment& environment, + const boost::shared_ptr<IOracleClient>& client, IOracleCommand* command /* takes ownership */) = 0; }; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancStone/Sources/Oracle/OracleCallback.cpp Sat Sep 19 01:24:20 2026 +0200 @@ -0,0 +1,70 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2021-2026 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/>. + **/ + + +#include "OracleCallback.h" + + +namespace OrthancStone +{ + OracleCallback::OracleCallback(IEnvironment& environment, + const boost::shared_ptr<IOracleClient>& client, + IOracleCommand* command /* takes ownership */) : + environment_(environment), + client_(client), + command_(command) + { + if (!client || + command == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); + } + } + + + void OracleCallback::NotifySuccess(Orthanc::IDynamicObject* result) + { + std::unique_ptr<Orthanc::IDynamicObject> protection(result); + + if (command_.get() == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + else + { + environment_.NotifyOracleSuccess(client_, command_.release(), protection.release()); + } + } + + + void OracleCallback::NotifyError(const Orthanc::OrthancException& error) + { + if (command_.get() == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + else + { + environment_.NotifyOracleError(client_, command_.release(), error); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancStone/Sources/Oracle/OracleCallback.h Sat Sep 19 01:24:20 2026 +0200 @@ -0,0 +1,46 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2021-2026 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "IEnvironment.h" + +namespace OrthancStone +{ + class OracleCallback : public boost::noncopyable + { + private: + IEnvironment& environment_; + boost::weak_ptr<IOracleClient> client_; + std::unique_ptr<IOracleCommand> command_; + + public: + OracleCallback(IEnvironment& environment, + const boost::shared_ptr<IOracleClient>& client, + IOracleCommand* command /* takes ownership */); + + void NotifySuccess(Orthanc::IDynamicObject* result); + + void NotifyError(const Orthanc::OrthancException& error); + }; +}
--- a/OrthancStone/Sources/Oracle/ThreadedOracle.cpp Thu Sep 17 20:17:50 2026 +0200 +++ b/OrthancStone/Sources/Oracle/ThreadedOracle.cpp Sat Sep 19 01:24:20 2026 +0200 @@ -23,6 +23,7 @@ #include "ThreadedOracle.h" +#include "OracleCallback.h" #include "SleepOracleCommand.h" #include <Logging.h> @@ -132,7 +133,7 @@ const boost::posix_time::ptime now = boost::posix_time::microsec_clock::local_time(); Content stillSleeping; - + for (Content::iterator it = content_.begin(); it != content_.end(); ++it) { if (*it != NULL && @@ -440,18 +441,91 @@ class ThreadedOracle::SleepRunnable : public Orthanc::IRunnable { private: + class Item : public boost::noncopyable + { + private: + OracleCallback callback_; + boost::posix_time::ptime expiration_; + public: + Item(IEnvironment& environment, + const boost::shared_ptr<IOracleClient>& client, + SleepOracleCommand* command) : + callback_(environment, client, command) + { + expiration_ = (boost::posix_time::microsec_clock::local_time() + + boost::posix_time::milliseconds(command->GetDelay())); + } + + const boost::posix_time::ptime& GetExpirationTime() const + { + return expiration_; + } + + OracleCallback& GetCallback() + { + return callback_; + } + }; + + typedef std::list<Item*> Content; + + boost::mutex mutex_; + Content content_; public: + ~SleepRunnable() + { + for (Content::iterator it = content_.begin(); it != content_.end(); ++it) + { + if (*it != NULL) + { + delete *it; + } + } + } + + + void Add(IEnvironment& environment, + const boost::shared_ptr<IOracleClient>& client, + SleepOracleCommand* command /* takes ownership */) + { + boost::mutex::scoped_lock lock(mutex_); + content_.push_back(new Item(environment, client, command)); + } + + + // Awakes expired sleeps virtual void Run() ORTHANC_OVERRIDE { + boost::mutex::scoped_lock lock(mutex_); + + const boost::posix_time::ptime now = boost::posix_time::microsec_clock::local_time(); + + Content stillSleeping; + + for (Content::iterator it = content_.begin(); it != content_.end(); ++it) + { + if (*it != NULL && + (*it)->GetExpirationTime() <= now) + { + (*it)->GetCallback().NotifySuccess(new Orthanc::IDynamicObject); + delete *it; + *it = NULL; + } + else + { + stillSleeping.push_back(*it); + } + } + + // Compact the still-sleeping commands + content_ = stillSleeping; } }; - ThreadedOracle::ThreadedOracle(IEnvironment& environment, - unsigned int countWorkers) : - environment_(environment), + ThreadedOracle::ThreadedOracle(unsigned int countWorkers) : sleepingThread_(new SleepRunnable, 50 /* milliseconds */) { threadPool_.SetThreadsCount(countWorkers); @@ -459,12 +533,28 @@ } - void ThreadedOracle::Submit(const boost::shared_ptr<IOracleClient>& client, + void ThreadedOracle::Start() + { + sleepingThread_.Start(); + threadPool_.Start(); + } + + + void ThreadedOracle::Stop() + { + threadPool_.Stop(); + sleepingThread_.Stop(); + } + + + void ThreadedOracle::Submit(IEnvironment& environment, + const boost::shared_ptr<IOracleClient>& client, IOracleCommand* command /* takes ownership */) { std::unique_ptr<IOracleCommand> protection(command); - if (command == NULL) + if (!client || + command == NULL) { throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); } @@ -473,6 +563,13 @@ { switch (command->GetType()) { + case IOracleCommand::Type_Sleep: + { + SleepRunnable& runnable = dynamic_cast<SleepRunnable&>(sleepingThread_.GetRunnable()); + runnable.Add(environment, client, dynamic_cast<SleepOracleCommand*>(protection.release())); + break; + } + default: throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented, "Command type not implemented by the Threaded Oracle: " + @@ -481,11 +578,11 @@ } catch (Orthanc::OrthancException& e) { - environment_.NotifyOracleError(client, protection.release(), e); + environment.NotifyOracleError(client, protection.release(), e); } catch (...) { - environment_.NotifyOracleError(client, protection.release(), Orthanc::OrthancException(Orthanc::ErrorCode_InternalError)); + environment.NotifyOracleError(client, protection.release(), Orthanc::OrthancException(Orthanc::ErrorCode_InternalError)); } } }
--- a/OrthancStone/Sources/Oracle/ThreadedOracle.h Thu Sep 17 20:17:50 2026 +0200 +++ b/OrthancStone/Sources/Oracle/ThreadedOracle.h Sat Sep 19 01:24:20 2026 +0200 @@ -122,30 +122,20 @@ class ThreadedOracle : public IOracle { private: - class SleepCommands; class SleepRunnable; - IEnvironment& environment_; RunnableThread sleepingThread_; Orthanc::ThreadPool threadPool_; public: - ThreadedOracle(IEnvironment& environment, - unsigned int countWorkers); + ThreadedOracle(unsigned int countWorkers); + + void Start(); - void Start() - { - sleepingThread_.Start(); - threadPool_.Start(); - } + void Stop(); - void Stop() - { - threadPool_.Stop(); - sleepingThread_.Stop(); - } - - virtual void Submit(const boost::shared_ptr<IOracleClient>& client, + virtual void Submit(IEnvironment& environment, + const boost::shared_ptr<IOracleClient>& client, IOracleCommand* command /* takes ownership */) ORTHANC_OVERRIDE; }; }
--- a/OrthancStone/Sources/Platforms/Native/NativeEnvironment.h Thu Sep 17 20:17:50 2026 +0200 +++ b/OrthancStone/Sources/Platforms/Native/NativeEnvironment.h Sat Sep 19 01:24:20 2026 +0200 @@ -39,7 +39,7 @@ class SuccessCompletion; class ErrorCompletion; - boost::mutex mutex_; // Main mutex of the application, to go single-threaded + boost::recursive_mutex mutex_; // Main mutex of the application, to go single-threaded Orthanc::SharedMessageQueue oracleQueue_; RunnableThread oracleThread_;
--- a/OrthancStone/Sources/Platforms/Native/RunnableThread.h Thu Sep 17 20:17:50 2026 +0200 +++ b/OrthancStone/Sources/Platforms/Native/RunnableThread.h Sat Sep 19 01:24:20 2026 +0200 @@ -69,5 +69,10 @@ { StopInternal(true); } + + Orthanc::IRunnable& GetRunnable() const + { + return *runnable_; + } }; }
--- a/OrthancStone/Sources/Platforms/WebAssembly/WebAssemblyOracle.cpp Thu Sep 17 20:17:50 2026 +0200 +++ b/OrthancStone/Sources/Platforms/WebAssembly/WebAssemblyOracle.cpp Sat Sep 19 01:24:20 2026 +0200 @@ -29,6 +29,7 @@ # include <Oracle/WebAssemblyOracle_Includes.h> #endif +#include "../../Oracle/OracleCallback.h" #include "../../Toolbox/StoneToolbox.h" #include <OrthancException.h> @@ -880,43 +881,15 @@ namespace New { - class WebAssemblyOracle::TimeoutCallback + static void TimeoutCallback(void *userData) { - private: - IEnvironment& environment_; - boost::weak_ptr<IOracleClient> client_; - std::unique_ptr<SleepOracleCommand> command_; - - public: - TimeoutCallback(IEnvironment& environment, - const boost::weak_ptr<IOracleClient>& client, - SleepOracleCommand* command) : - environment_(environment), - client_(client), - command_(command) - { - if (command == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); - } - } - - void Notify() - { - assert(environment_.get() != NULL); - assert(command_.get() != NULL); - environment_.NotifyOracleSuccess(client_, command_.release(), new Orthanc::IDynamicObject); - } - - static void Callback(void *userData) - { - std::unique_ptr<TimeoutCallback> callback(reinterpret_cast<TimeoutCallback*>(userData)); - callback->Notify(); - } - }; + std::unique_ptr<OracleCallback> callback(reinterpret_cast<OracleCallback*>(userData)); + callback->NotifySuccess(new Orthanc::IDynamicObject); + } - void WebAssemblyOracle::Submit(const boost::shared_ptr<IOracleClient>& client, + void WebAssemblyOracle::Submit(IEnvironment& environment, + const boost::shared_ptr<IOracleClient>& client, IOracleCommand* command /* takes ownership */) { // TODO Refactoring - Use "priority" @@ -935,23 +908,24 @@ case IOracleCommand::Type_Sleep: { unsigned int timeoutMS = dynamic_cast<SleepOracleCommand*>(command)->GetDelay(); - emscripten_set_timeout(TimeoutCallback::Callback, timeoutMS, - new TimeoutCallback(environment_, client, dynamic_cast<SleepOracleCommand*>(protection.release()))); + emscripten_set_timeout(TimeoutCallback, timeoutMS, + new OracleCallback(environment, client, dynamic_cast<SleepOracleCommand*>(protection.release()))); break; } default: throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented, - "Command type not implemented by the WebAssembly Oracle: " + command->GetType()); + "Command type not implemented by the WebAssembly Oracle: " + + boost::lexical_cast<std::string>(command->GetType())); } } catch (Orthanc::OrthancException& e) { - environment_.NotifyOracleError(client, protection.release(), e); + environment.NotifyOracleError(client, protection.release(), e); } catch (...) { - environment_.NotifyOracleError(client, protection.release(), Orthanc::OrthancException(Orthanc::ErrorCode_InternalError)); + environment.NotifyOracleError(client, protection.release(), Orthanc::OrthancException(Orthanc::ErrorCode_InternalError)); } } }
--- a/OrthancStone/Sources/Platforms/WebAssembly/WebAssemblyOracle.h Thu Sep 17 20:17:50 2026 +0200 +++ b/OrthancStone/Sources/Platforms/WebAssembly/WebAssemblyOracle.h Sat Sep 19 01:24:20 2026 +0200 @@ -160,18 +160,9 @@ { class WebAssemblyOracle : public IOracle { - private: - class TimeoutCallback; - - IEnvironment& environment_; - public: - WebAssemblyOracle(IEnvironment& environment) : - environment_(environment) - { - } - - virtual void Submit(const boost::shared_ptr<IOracleClient>& client, + virtual void Submit(IEnvironment& environment, + const boost::shared_ptr<IOracleClient>& client, IOracleCommand* command /* takes ownership */) ORTHANC_OVERRIDE; }; }
