From 1c7fc39b6c7aa89109554c224658426330927a13 Mon Sep 17 00:00:00 2001 From: peri4 Date: Tue, 30 Jul 2024 14:18:02 +0300 Subject: [PATCH] version 4.0.0_alpha in almost all methods removed timeouts in milliseconds, replaced to PISystemTime PITimer rewrite, remove internal impl, now only thread implementation, API similar to PIThread PITimer API no longer pass void* PIPeer, PIConnection improved stability on reinit and exit PISystemTime new methods pisd now exit without hanging --- CMakeLists.txt | 28 +- cmake/FindPIP.cmake | 4 - doc/examples/pitimer.cpp | 34 +- doc/pages/using_basic.md | 2 +- libs/cloud/picloudclient.cpp | 2 +- libs/cloud/picloudserver.cpp | 6 +- libs/console/piscreen.cpp | 11 +- libs/console/piterminal.cpp | 7 +- libs/io_utils/pibroadcast.cpp | 4 +- libs/io_utils/pistreampacker.cpp | 3 +- libs/main/console/pikbdlistener.cpp | 3 +- libs/main/console/piscreen.h | 5 +- libs/main/core/pibase_macros.h | 5 - .../piintrospection_threads_p.cpp | 2 +- libs/main/io_devices/pibinarylog.cpp | 36 +- libs/main/io_devices/piethernet.cpp | 16 +- libs/main/io_devices/piethernet.h | 18 +- libs/main/io_devices/piiodevice.cpp | 46 +- libs/main/io_devices/piiodevice.h | 47 +- libs/main/io_devices/pipeer.cpp | 64 +- libs/main/io_devices/pipeer.h | 2 +- libs/main/io_devices/piserial.cpp | 1 + libs/main/io_utils/pibasetransfer.cpp | 12 +- libs/main/io_utils/pibasetransfer.h | 5 +- libs/main/io_utils/piconnection.cpp | 56 +- libs/main/io_utils/piconnection.h | 6 +- libs/main/io_utils/pidiagnostics.cpp | 39 +- libs/main/io_utils/pidiagnostics.h | 14 +- libs/main/io_utils/pipacketextractor.cpp | 4 +- libs/main/io_utils/pipacketextractor.h | 10 +- libs/main/pip.h | 1 + .../pistatemachine_transition.cpp | 6 +- libs/main/system/piprocess.cpp | 11 +- libs/main/system/piprocess.h | 8 +- libs/main/system/pisingleapplication.cpp | 6 +- libs/main/system/pisystemmonitor.cpp | 27 +- libs/main/system/pisystemmonitor.h | 4 +- libs/main/thread/piblockingqueue.h | 18 +- libs/main/thread/piconditionvar.cpp | 30 +- libs/main/thread/piconditionvar.h | 11 +- libs/main/thread/pigrabberbase.h | 1 + libs/main/thread/pithread.cpp | 112 +-- libs/main/thread/pithread.h | 106 +-- libs/main/thread/pithreadpoolexecutor.cpp | 10 +- libs/main/thread/pithreadpoolexecutor.h | 3 +- libs/main/thread/pithreadpoolloop.cpp | 3 +- libs/main/thread/pitimer.cpp | 677 +++--------------- libs/main/thread/pitimer.h | 238 ++---- libs/main/types/pisystemtime.h | 12 + main_picloud_test.cpp | 6 +- utils/cloud_dispatcher/dispatcherserver.cpp | 3 +- utils/cloud_dispatcher/dispatcherserver.h | 1 + utils/cloud_dispatcher/main.cpp | 15 +- utils/piterminal/main.cpp | 8 +- utils/system_daemon/daemon.cpp | 11 +- utils/system_daemon/daemon.h | 3 +- utils/system_daemon/main.cpp | 37 +- utils/udp_file_transfer/main.cpp | 8 +- 58 files changed, 677 insertions(+), 1191 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e342b7c..0c87ff17 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,10 @@ cmake_minimum_required(VERSION 3.0) cmake_policy(SET CMP0017 NEW) # need include() with .cmake project(PIP) -set(PIP_MAJOR 3) -set(PIP_MINOR 21) +set(PIP_MAJOR 4) +set(PIP_MINOR 0) set(PIP_REVISION 0) -set(PIP_SUFFIX ) +set(PIP_SUFFIX _alpha) set(PIP_COMPANY SHS) set(PIP_DOMAIN org.SHS) @@ -247,18 +247,6 @@ if(PIP_MATH_YN) endif() -# Check if RT timers exists -set(CMAKE_REQUIRED_INCLUDES time.h) -set(CMAKE_REQUIRED_LIBRARIES ) -if((NOT DEFINED ENV{QNX_HOST}) AND (NOT APPLE) AND (NOT WIN32) AND (NOT DEFINED ANDROID_PLATFORM) AND (NOT PIP_FREERTOS)) - list(APPEND LIBS_MAIN rt) - set(CMAKE_REQUIRED_LIBRARIES rt) -endif() -CHECK_FUNCTION_EXISTS(timer_create PIP_TIMER_RT_0) -CHECK_FUNCTION_EXISTS(timer_settime PIP_TIMER_RT_1) -CHECK_FUNCTION_EXISTS(timer_delete PIP_TIMER_RT_2) - - # Check if build debug version if (PIP_BUILD_DEBUG) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3 -Wall") @@ -317,15 +305,6 @@ list(APPEND HDRS ${_PIP_DEFS_FILE}) #message("${_PIP_DEFS_CHANGED}") -# Check if RT timers exists -if(PIP_TIMER_RT_0 AND PIP_TIMER_RT_1 AND PIP_TIMER_RT_2) - set(PIP_TIMERS "Thread, ThreadRT, Pool") - add_definitions(-DPIP_TIMER_RT) -else() - set(PIP_TIMERS "Thread, Pool") -endif() - - # Add main library if(APPLE) @@ -673,7 +652,6 @@ message("") message(" Options:") message(" std::iostream: ${PIP_STD_IOSTREAM}") message(" ICU strings : ${PIP_ICU}") -message(" Timer types : ${PIP_TIMERS}") message(" Introspection: ${PIP_INTROSPECTION}") message(" Coverage : ${PIP_COVERAGE}") if(INTROSPECTION) diff --git a/cmake/FindPIP.cmake b/cmake/FindPIP.cmake index 8d7a295b..4fd88f33 100644 --- a/cmake/FindPIP.cmake +++ b/cmake/FindPIP.cmake @@ -66,10 +66,6 @@ if (NOT BUILDING_PIP) find_library(PTHREAD_LIBRARY pthread) find_library(UTIL_LIBRARY util) set(_PIP_ADD_LIBS_ ${PTHREAD_LIBRARY} ${UTIL_LIBRARY}) - if((NOT DEFINED ENV{QNX_HOST}) AND (NOT APPLE) AND (NOT PIP_FREERTOS)) - find_library(RT_LIBRARY rt) - list(APPEND _PIP_ADD_LIBS_ ${RT_LIBRARY}) - endif() list(APPEND PIP_LIBRARY ${_PIP_ADD_LIBS_}) endif() endif() diff --git a/doc/examples/pitimer.cpp b/doc/examples/pitimer.cpp index 69fc5b4f..18c745a0 100644 --- a/doc/examples/pitimer.cpp +++ b/doc/examples/pitimer.cpp @@ -1,10 +1,10 @@ #include "pip.h" - + //! [delimiter] -void tfunc(void * , int delim) { +void tfunc(int delim) { piCout << "tick with delimiter" << delim; }; -void tfunc4(void * , int delim) { +void tfunc4(int delim) { piCout << "tick4 with delimiter" << delim; }; int main() { @@ -13,8 +13,7 @@ int main() { timer.addDelimiter(4, tfunc4); timer.start(50); piMSleep(200); - timer.stop(); - timer.waitForFinish(); + timer.stopAndWait(); return 0; }; /* Result: @@ -29,14 +28,14 @@ tick4 with delimiter 4 //! [delimiter] //! [elapsed] int main() { - PITimer timer; + PITimeMeasurer tm; piMSleep(100); - piCout << "elapsed" << timer.elapsed_m() << "ms"; + piCout << "elapsed" << tm.elapsed_m() << "ms"; piMSleep(100); - piCout << "elapsed" << timer.elapsed_m() << "ms"; - timer.reset(); + piCout << "elapsed" << tm.elapsed_m() << "ms"; + tm.reset(); piMSleep(150); - piCout << "elapsed" << timer.elapsed_s() << "s"; + piCout << "elapsed" << tm.elapsed_s() << "s"; return 0; }; /* Result: @@ -47,22 +46,21 @@ elapsed 0.15 s //! [elapsed] //! [system_time] int main() { - PISystemTime t0; // s = ns = 0 - t0.addMilliseconds(200); // s = 0, ns = 200000000 - t0.addMilliseconds(900); // s = 1, ns = 100000000 + PISystemTime t0; // s = ns = 0 + t0.addMilliseconds(200); // s = 0, ns = 200000000 + t0.addMilliseconds(900); // s = 1, ns = 100000000 t0 -= PISystemTime::fromSeconds(0.1); // s = 1, ns = 0 - t0.sleep(); // sleep for 1 second + t0.sleep(); // sleep for 1 second PISystemTime t1; - t0 = currentSystemTime(); + t0 = PISystemTime::current(); piMSleep(500); - t1 = currentSystemTime(); + t1 = PISystemTime::current(); (t1 - t0).sleep(); // sleep for 500 milliseconds return 0; }; //! [system_time] -void _() { - +void _(){ }; diff --git a/doc/pages/using_basic.md b/doc/pages/using_basic.md index f19f5f5e..b0f3ee52 100644 --- a/doc/pages/using_basic.md +++ b/doc/pages/using_basic.md @@ -56,7 +56,7 @@ class MainClass: public PITimer { public: MainClass() {} protected: - void tick(void * data, int delimiter) { + void tick(int delimiter) { piCout << "timer tick"; // timer tick } diff --git a/libs/cloud/picloudclient.cpp b/libs/cloud/picloudclient.cpp index b70107ec..30ccab2c 100644 --- a/libs/cloud/picloudclient.cpp +++ b/libs/cloud/picloudclient.cpp @@ -82,7 +82,7 @@ bool PICloudClient::openDevice() { mutex_connect.lock(); eth.startThreadedRead(); // piCoutObj << "connecting..."; - bool conn_ok = cond_connect.waitFor(mutex_connect, (int)eth.readTimeout()); + bool conn_ok = cond_connect.waitFor(mutex_connect, eth.readTimeout()); // piCoutObj << "conn_ok" << conn_ok << is_connected; mutex_connect.unlock(); if (!conn_ok) { diff --git a/libs/cloud/picloudserver.cpp b/libs/cloud/picloudserver.cpp index 97faa9e9..14f519bf 100644 --- a/libs/cloud/picloudserver.cpp +++ b/libs/cloud/picloudserver.cpp @@ -19,6 +19,8 @@ #include "picloudserver.h" +#include "piliterals_time.h" + PICloudServer::PICloudServer(const PIString & path, PIIODevice::DeviceMode mode): PIIODevice(path, mode), PICloudBase() { PIString server_name = "PCS_" + PIString::fromNumber(randomi() % 1000); @@ -94,7 +96,7 @@ bool PICloudServer::openDevice() { bool op = eth.connect(PINetworkAddress::resolve(path()), false); if (op) { eth.startThreadedRead(); - ping_timer.start(5000); + ping_timer.start(5_s); return true; } else { ping_timer.stop(); @@ -169,7 +171,7 @@ PICloudServer::Client::Client(PICloudServer * srv, uint id): server(srv), client PICloudServer::Client::~Client() { // piCoutObj << "~PICloudServer::Client..." << this; close(); - stopAndWait(10000); + stopAndWait(10_s); // piCoutObj << "~PICloudServer::Client done" << this; } diff --git a/libs/console/piscreen.cpp b/libs/console/piscreen.cpp index 1cd0baf7..726b1575 100644 --- a/libs/console/piscreen.cpp +++ b/libs/console/piscreen.cpp @@ -19,6 +19,7 @@ #include "piscreen.h" #include "piincludes_p.h" +#include "piliterals_time.h" #ifndef WINDOWS # include # include @@ -417,8 +418,8 @@ PIScreen::PIScreen(bool startNow, PIKbdListener::KBFunc slot): PIThread(), drawe PIScreen::~PIScreen() { if (isRunning()) stop(); - PIThread::waitForFinish(10); - listener->waitForFinish(10); + PIThread::waitForFinish(100_ms); + listener->waitForFinish(100_ms); delete listener; } @@ -590,6 +591,12 @@ void PIScreen::waitForFinish() { } +void PIScreen::start(bool wait) { + PIThread::start(25_Hz); + if (wait) waitForFinish(); +} + + void PIScreen::stop(bool clear) { PIThread::stopAndWait(); if (clear) console.clearScreen(); diff --git a/libs/console/piterminal.cpp b/libs/console/piterminal.cpp index a3f532dc..ee67b852 100644 --- a/libs/console/piterminal.cpp +++ b/libs/console/piterminal.cpp @@ -19,6 +19,7 @@ #include "piterminal.h" #include "piincludes_p.h" +#include "piliterals_time.h" #include "pisharedmemory.h" #ifndef MICRO_PIP # ifdef WINDOWS @@ -126,7 +127,7 @@ PITerminal::PITerminal(): PIThread() { PITerminal::~PITerminal() { if (isRunning()) stop(); - PIThread::waitForFinish(10); + PIThread::waitForFinish(1_s); destroy(); # ifdef WINDOWS if (PRIVATE->shm) delete PRIVATE->shm; @@ -915,7 +916,7 @@ bool PITerminal::initialize() { # endif cursor_blink = false; cursor_tm.reset(); - start(40); + start(25_Hz); return true; } @@ -923,7 +924,7 @@ bool PITerminal::initialize() { void PITerminal::destroy() { // piCout << "destroy ..."; stop(); - waitForFinish(1000); + waitForFinish(1_s); # ifdef WINDOWS if (PRIVATE->pi.hProcess) { // piCout << "term"; diff --git a/libs/io_utils/pibroadcast.cpp b/libs/io_utils/pibroadcast.cpp index 54e52b64..7dc5a5c6 100644 --- a/libs/io_utils/pibroadcast.cpp +++ b/libs/io_utils/pibroadcast.cpp @@ -19,6 +19,8 @@ #include "pibroadcast.h" +#include "piliterals_time.h" + /** \class PIBroadcast * \brief Broadcast for all interfaces, including loopback * @@ -223,7 +225,7 @@ void PIBroadcast::startRead() { if (!isRunning()) { _started = false; reinit(); - PIThread::start(3000); + PIThread::start(3_s); } if (_send_only) return; PIMutexLocker ml(mcast_mutex); diff --git a/libs/io_utils/pistreampacker.cpp b/libs/io_utils/pistreampacker.cpp index 579718fd..3df49296 100644 --- a/libs/io_utils/pistreampacker.cpp +++ b/libs/io_utils/pistreampacker.cpp @@ -24,6 +24,7 @@ #include "pistreampacker.h" #include "piiodevice.h" +#include "piliterals_bytes.h" #ifdef __GNUC__ # pragma GCC diagnostic pop #endif @@ -52,7 +53,7 @@ PIStreamPacker::PIStreamPacker(PIIODevice * dev): PIObject() { aggressive_optimization = true; packet_size = -1; size_crypted_size = sizeof(int); - crypt_frag_size = 1024 * 1024; + crypt_frag_size = 1_MiB; max_packet_size = 1400; packet_sign = 0xAFBE; assignDevice(dev); diff --git a/libs/main/console/pikbdlistener.cpp b/libs/main/console/pikbdlistener.cpp index 5d0d95aa..e959c52f 100644 --- a/libs/main/console/pikbdlistener.cpp +++ b/libs/main/console/pikbdlistener.cpp @@ -167,7 +167,8 @@ PIKbdListener::PIKbdListener(KBFunc slot, void * _d, bool startNow): PIThread() PIKbdListener::~PIKbdListener() { - terminate(); + stop(); + if (!waitForFinish(100_ms)) terminate(); end(); } diff --git a/libs/main/console/piscreen.h b/libs/main/console/piscreen.h index 67fdf15c..d9d50187 100644 --- a/libs/main/console/piscreen.h +++ b/libs/main/console/piscreen.h @@ -73,10 +73,7 @@ public: EVENT_HANDLER0(void, waitForFinish); EVENT_HANDLER0(void, start) { start(false); } - EVENT_HANDLER1(void, start, bool, wait) { - PIThread::start(40); - if (wait) waitForFinish(); - } + EVENT_HANDLER1(void, start, bool, wait); EVENT_HANDLER0(void, stop) { stop(false); } EVENT_HANDLER1(void, stop, bool, clear); diff --git a/libs/main/core/pibase_macros.h b/libs/main/core/pibase_macros.h index 76f914e6..aa95ed99 100644 --- a/libs/main/core/pibase_macros.h +++ b/libs/main/core/pibase_macros.h @@ -150,11 +150,6 @@ //! \~russian Макрос объявлен когда компилятор неизвестен # define CC_OTHER -//! \~\brief -//! \~english Macro is defined when PIP can use "rt" library for \a PITimer::ThreadRT timers implementation -//! \~russian Макрос объявлен когда PIP может использовать библиотеку "rt" для \a PITimer::ThreadRT реализации таймера -# define PIP_TIMER_RT - //! \~\brief //! \~english Macro to declare private section, "export" is optional //! \~russian Макрос для объявления частной секции, "export" необязателен diff --git a/libs/main/introspection/piintrospection_threads_p.cpp b/libs/main/introspection/piintrospection_threads_p.cpp index 3447ab43..b7b8fbd1 100644 --- a/libs/main/introspection/piintrospection_threads_p.cpp +++ b/libs/main/introspection/piintrospection_threads_p.cpp @@ -48,7 +48,7 @@ void PIIntrospectionThreads::threadStart(PIThread * t) { ThreadInfo & ti(threads[t]); ti.id = t->tid(); ti.priority = t->priority(); - ti.delay = t->delay_; + ti.delay = t->delay_.toMilliseconds(); ti.state = sStarting; } diff --git a/libs/main/io_devices/pibinarylog.cpp b/libs/main/io_devices/pibinarylog.cpp index 9c9eb13a..1cb53796 100644 --- a/libs/main/io_devices/pibinarylog.cpp +++ b/libs/main/io_devices/pibinarylog.cpp @@ -20,8 +20,10 @@ #include "pibinarylog.h" #include "pidir.h" -#include "piliterals.h" +#include "piliterals_bytes.h" +#include "piliterals_time.h" #include "pipropertystorage.h" +#include "pitime.h" #define PIBINARYLOG_VERSION_OLD 0x31 @@ -259,9 +261,9 @@ PIString PIBinaryLog::getLogfilePath(const PIString & log_dir, const PIString & << "Creating directory" << dir.path(); dir.make(true); } - const PIString npath = log_dir + PIDir::separator + prefix + PIDateTime::current().toString("yyyy_MM_dd__hh_mm_ss"); - PIString cnpath = npath + ".binlog"; - int i = 1; + const PIString npath = log_dir + PIDir::separator + prefix + PIDateTime::current().toString("yyyy_MM_dd__hh_mm_ss"); + PIString cnpath = npath + ".binlog"; + int i = 1; while (PIFile::isExists(cnpath)) { cnpath = npath + '_' + PIString::fromNumber(i) + ".binlog"; i++; @@ -644,9 +646,9 @@ void PIBinaryLog::parseLog(PIFile * f, PIBinaryLog::BinLogInfo * info, PIVector< } PIByteArray ba; Record br; - br.id = 0; - br.size = 0; - bool first = true; + br.id = 0; + br.size = 0; + bool first = true; constexpr size_t hdr_size = sizeof(Record) - sizeof(PIByteArray); ba.resize(hdr_size); while (1) { @@ -977,16 +979,16 @@ void PIBinaryLog::configureFromVariantDevice(const PIPropertyStorage & d) { void PIBinaryLog::propertyChanged(const char * s) { - default_id = property("defaultID").toInt(); - rapid_start = property("rapidStart").toBool(); - play_mode = (PlayMode)property("playMode").toInt(); - const double ps = property("playSpeed").toDouble(); - play_speed = ps > 0. ? 1. / ps : 0.; - play_delay = property("playDelay").toSystemTime(); - split_mode = (SplitMode)property("splitMode").toInt(); - split_time = property("splitTime").toSystemTime(); - split_size = property("splitFileSize").toLLong(); - split_count = property("splitRecordCount").toInt(); + default_id = property("defaultID").toInt(); + rapid_start = property("rapidStart").toBool(); + play_mode = (PlayMode)property("playMode").toInt(); + const double ps = property("playSpeed").toDouble(); + play_speed = ps > 0. ? 1. / ps : 0.; + play_delay = property("playDelay").toSystemTime(); + split_mode = (SplitMode)property("splitMode").toInt(); + split_time = property("splitTime").toSystemTime(); + split_size = property("splitFileSize").toLLong(); + split_count = property("splitRecordCount").toInt(); // piCoutObj << "propertyChanged" << s << play_mode; } diff --git a/libs/main/io_devices/piethernet.cpp b/libs/main/io_devices/piethernet.cpp index d9a85094..4aa86b93 100644 --- a/libs/main/io_devices/piethernet.cpp +++ b/libs/main/io_devices/piethernet.cpp @@ -163,8 +163,8 @@ void PIEthernet::construct() { setOption(BlockingWrite); connected_ = connecting_ = listen_threaded = server_bounded = false; sock = sock_s = -1; - setReadTimeout(10000.); - setWriteTimeout(10000.); + setReadTimeout(10_s); + setWriteTimeout(10_s); setTTL(64); setMulticastTTL(1); server_thread_.setData(this); @@ -331,7 +331,7 @@ void PIEthernet::closeSocket(int & sd) { void PIEthernet::applyTimeouts() { if (sock < 0) return; - double rtm = readTimeout(), wtm = writeTimeout(); + PISystemTime rtm = readTimeout(), wtm = writeTimeout(); applyTimeout(sock, SO_RCVTIMEO, rtm); applyTimeout(sock, SO_SNDTIMEO, wtm); if (sock_s != sock && sock_s != -1) { @@ -341,17 +341,15 @@ void PIEthernet::applyTimeouts() { } -void PIEthernet::applyTimeout(int fd, int opt, double ms) { +void PIEthernet::applyTimeout(int fd, int opt, PISystemTime tm) { if (fd == 0) return; // piCoutObj << "setReadIsBlocking" << yes; #ifdef WINDOWS - DWORD _tm = ms; + DWORD _tm = tm.toMilliseconds(); #else - double s = ms / 1000.; timeval _tm; - _tm.tv_sec = piFloord(s); - s -= _tm.tv_sec; - _tm.tv_usec = s * 1000000.; + _tm.tv_sec = tm.seconds; + _tm.tv_usec = tm.nanoseconds / 1000; #endif ethSetsockopt(fd, SOL_SOCKET, opt, &_tm, sizeof(_tm)); } diff --git a/libs/main/io_devices/piethernet.h b/libs/main/io_devices/piethernet.h index ddca15e4..a1c10c3f 100644 --- a/libs/main/io_devices/piethernet.h +++ b/libs/main/io_devices/piethernet.h @@ -174,16 +174,16 @@ public: Type type() const { return eth_type; } //! Returns read timeout - double readTimeout() const { return property("readTimeout").toDouble(); } + PISystemTime readTimeout() const { return property("readTimeout").toSystemTime(); } //! Returns write timeout - double writeTimeout() const { return property("writeTimeout").toDouble(); } + PISystemTime writeTimeout() const { return property("writeTimeout").toSystemTime(); } //! Set timeout for read - void setReadTimeout(double ms) { setProperty("readTimeout", ms); } + void setReadTimeout(PISystemTime tm) { setProperty("readTimeout", tm); } //! Set timeout for write - void setWriteTimeout(double ms) { setProperty("writeTimeout", ms); } + void setWriteTimeout(PISystemTime tm) { setProperty("writeTimeout", tm); } //! Returns TTL (Time To Live) @@ -437,11 +437,11 @@ public: //! \brief ethernet parameters int parameters; - //! \brief read timeout, default 1000 ms - double readTimeout; + //! \brief read timeout, default 10 s + PISystemTime readTimeout; - //! \brief write timeout, default 1000 ms - double writeTimeout; + //! \brief write timeout, default 10 s + PISystemTime writeTimeout; //! \brief time-to-live, default 64 int TTL; @@ -475,7 +475,7 @@ protected: bool closeDevice() override; void closeSocket(int & sd); void applyTimeouts(); - void applyTimeout(int fd, int opt, double ms); + void applyTimeout(int fd, int opt, PISystemTime tm); void applyOptInt(int level, int opt, int val); PRIVATE_DECLARATION(PIP_EXPORT) diff --git a/libs/main/io_devices/piiodevice.cpp b/libs/main/io_devices/piiodevice.cpp index 889b31b1..7c06b4a6 100644 --- a/libs/main/io_devices/piiodevice.cpp +++ b/libs/main/io_devices/piiodevice.cpp @@ -20,9 +20,11 @@ #include "piiodevice.h" #include "piconfig.h" -#include "piconnection.h" -#include "piliterals.h" +#include "piliterals_bytes.h" +#include "piliterals_string.h" +#include "piliterals_time.h" #include "pipropertystorage.h" +#include "pitime.h" //! \class PIIODevice piiodevice.h @@ -158,9 +160,9 @@ void PIIODevice::setReopenEnabled(bool yes) { } -void PIIODevice::setReopenTimeout(int msecs) { - setProperty("reopenTimeout", msecs); - reopen_timeout = msecs; +void PIIODevice::setReopenTimeout(PISystemTime timeout) { + setProperty("reopenTimeout", timeout); + reopen_timeout = timeout; } @@ -231,11 +233,13 @@ void PIIODevice::terminateThreadedRead() { } -bool PIIODevice::waitThreadedReadFinished(int timeout_ms) { +bool PIIODevice::waitThreadedReadFinished(PISystemTime timeout) { PITimeMeasurer tm, tm_intr; while (read_thread.isRunning()) { - if (tm.elapsed_m() > timeout_ms) return false; - if (tm_intr.elapsed_m() > 100.) { + if (timeout.isNotNull()) { + if (tm.elapsed() > timeout) return false; + } + if (tm_intr.elapsed() > 100_ms) { tm_intr.reset(); interrupt(); } @@ -266,8 +270,8 @@ void PIIODevice::terminateThreadedWrite() { } -bool PIIODevice::waitThreadedWriteFinished(int timeout_ms) { - return write_thread.waitForFinish(timeout_ms); +bool PIIODevice::waitThreadedWriteFinished(PISystemTime timeout) { + return write_thread.waitForFinish(timeout); } @@ -290,10 +294,10 @@ void PIIODevice::stop() { } -void PIIODevice::stopAndWait(int timeout_ms) { +void PIIODevice::stopAndWait(PISystemTime timeout) { stop(); - waitThreadedReadFinished(timeout_ms); - waitThreadedWriteFinished(timeout_ms); + waitThreadedReadFinished(timeout); + waitThreadedWriteFinished(timeout); } @@ -327,7 +331,7 @@ void PIIODevice::_init() { opened_ = false; setOptions(0); setReopenEnabled(true); - setReopenTimeout(1000); + setReopenTimeout(1_s); #ifdef MICRO_PIP threaded_read_buffer_size = 512; #else @@ -375,7 +379,7 @@ void PIIODevice::read_func() { piMSleep(10); bool ok = false; if (reopen_enabled) { - if (reopen_tm.elapsed_m() >= reopen_timeout) { + if (reopen_tm.elapsed() >= reopen_timeout) { reopen_tm.reset(); ok = open(); } @@ -394,14 +398,14 @@ void PIIODevice::read_func() { } -PIByteArray PIIODevice::readForTime(double timeout_ms) { +PIByteArray PIIODevice::readForTime(PISystemTime timeout) { PIByteArray str; - if (timeout_ms <= 0.) return str; + if (timeout.isNull()) return str; ssize_t ret; uchar * td = new uchar[threaded_read_buffer_size]; bool was_br = setOption(BlockingRead, false); tm.reset(); - while (tm.elapsed_m() < timeout_ms) { + while (tm.elapsed() < timeout) { ret = read(td, threaded_read_buffer_size); if (ret <= 0) piMinSleep(); @@ -477,13 +481,13 @@ bool PIIODevice::configure(const PIString & config_file, const PIString & sectio if (ep != 0) { setReopenEnabled(ep->getValue("reopenEnabled", isReopenEnabled(), &ex).toBool()); if (!ex) setReopenEnabled(em.getValue("reopenEnabled", isReopenEnabled()).toBool()); - setReopenTimeout(ep->getValue("reopenTimeout", reopenTimeout(), &ex).toInt()); - if (!ex) setReopenTimeout(em.getValue("reopenTimeout", reopenTimeout()).toInt()); + setReopenTimeout(PISystemTime::fromMilliseconds(ep->getValue("reopenTimeout", reopenTimeout().toMilliseconds(), &ex).toInt())); + if (!ex) setReopenTimeout(PISystemTime::fromMilliseconds(em.getValue("reopenTimeout", reopenTimeout().toMilliseconds()).toInt())); setThreadedReadBufferSize(ep->getValue("threadedReadBufferSize", int(threaded_read_buffer_size), &ex).toInt()); if (!ex) setThreadedReadBufferSize(em.getValue("threadedReadBufferSize", int(threaded_read_buffer_size)).toInt()); } else { setReopenEnabled(em.getValue("reopenEnabled", isReopenEnabled()).toBool()); - setReopenTimeout(em.getValue("reopenTimeout", reopenTimeout()).toInt()); + setReopenTimeout(PISystemTime::fromMilliseconds(em.getValue("reopenTimeout", reopenTimeout().toMilliseconds()).toInt())); setThreadedReadBufferSize(em.getValue("threadedReadBufferSize", int(threaded_read_buffer_size)).toInt()); } return configureDevice(&em, ep); diff --git a/libs/main/io_devices/piiodevice.h b/libs/main/io_devices/piiodevice.h index 667a8e62..db7225d7 100644 --- a/libs/main/io_devices/piiodevice.h +++ b/libs/main/io_devices/piiodevice.h @@ -28,7 +28,7 @@ #include "piinit.h" #include "piqueue.h" -#include "pitimer.h" +#include "pithread.h" /// TODO: написать документацию, тут ничего не понятно // function executed from threaded read, pass readedData, sizeOfData, ThreadedReadData @@ -201,21 +201,17 @@ public: //! \~russian Устанавливает возможность вызова \a open() при потоковом чтении на закрытом устройстве void setReopenEnabled(bool yes = true); - //! \~english Set timeout in milliseconds between \a open() tryings if reopen is enabled - //! \~russian Устанавливает задержку в миллисекундах между вызовами \a open() если переоткрытие активно - void setReopenTimeout(int msecs); - //! \~english Set timeout between \a open() tryings if reopen is enabled //! \~russian Устанавливает задержку между вызовами \a open() если переоткрытие активно - void setReopenTimeout(PISystemTime timeout) { setReopenTimeout(timeout.toMilliseconds()); } + void setReopenTimeout(PISystemTime timeout); //! \~english Returns reopen enable //! \~russian Возвращает активно ли переоткрытие bool isReopenEnabled() const { return property("reopenEnabled").toBool(); } - //! \~english Returns reopen timeout in milliseconds - //! \~russian Возвращает задержку переоткрытия в миллисекундах - int reopenTimeout() { return property("reopenTimeout").toInt(); } + //! \~english Returns reopen timeout + //! \~russian Возвращает задержку переоткрытия + PISystemTime reopenTimeout() { return property("reopenTimeout").toSystemTime(); } //! \~english Set threaded read callback @@ -266,13 +262,9 @@ public: //! \~russian Старайтесь не использовать! Этот метод может привести к повреждению памяти! void terminateThreadedRead(); - //! \~english Wait for threaded read finish no longer than "timeout_ms" milliseconds. - //! \~russian Ожидает завершения потокового чтения в течении не более "timeout_ms" миллисекунд. - bool waitThreadedReadFinished(int timeout_ms = -1); - //! \~english Wait for threaded read finish no longer than "timeout". //! \~russian Ожидает завершения потокового чтения в течении не более "timeout". - bool waitThreadedReadFinished(PISystemTime timeout) { return waitThreadedReadFinished(timeout.toMilliseconds()); } + bool waitThreadedReadFinished(PISystemTime timeout = {}); //! \~english Returns if threaded write is started @@ -294,13 +286,9 @@ public: //! \~russian Старайтесь не использовать! Этот метод может привести к повреждению памяти! void terminateThreadedWrite(); - //! \~english Wait for threaded write finish no longer than "timeout_ms" milliseconds. - //! \~russian Ожидает завершения потоковой записи в течении не более "timeout_ms" миллисекунд. - bool waitThreadedWriteFinished(int timeout_ms = -1); - //! \~english Wait for threaded write finish no longer than "timeout". //! \~russian Ожидает завершения потоковой записи в течении не более "timeout". - bool waitThreadedWriteFinished(PISystemTime timeout) { return waitThreadedWriteFinished(timeout.toMilliseconds()); } + bool waitThreadedWriteFinished(PISystemTime timeout = {}); //! \~english Clear threaded write task queue //! \~russian Очищает очередь потоковой записи @@ -317,11 +305,7 @@ public: //! \~english Stop both threaded read and threaded write and wait for finish. //! \~russian Останавливает потоковое чтение и запись и ожидает завершения. - void stopAndWait(int timeout_ms = -1); - - //! \~english Stop both threaded read and threaded write and wait for finish. - //! \~russian Останавливает потоковое чтение и запись и ожидает завершения. - void stopAndWait(PISystemTime timeout) { return stopAndWait(timeout.toMilliseconds()); } + void stopAndWait(PISystemTime timeout = {}); //! \~english Interrupt blocking operation. //! \~russian Прерывает блокирующую операцию. @@ -355,15 +339,9 @@ public: //! \~russian Пишет в устройство не более "max_size" байт из "data" ssize_t write(const void * data, ssize_t max_size); - //! \~english Read from device for "timeout_ms" milliseconds and return readed data as PIByteArray. - //! Timeout should to be greater than 0 - //! \~russian Читает из устройства в течении "timeout_ms" миллисекунд и возвращает данные как PIByteArray. - //! Таймаут должен быть больше 0 - PIByteArray readForTime(double timeout_ms); - //! \~english Read from device for "timeout" and return readed data as PIByteArray. //! \~russian Читает из устройства в течении "timeout" и возвращает данные как PIByteArray. - PIByteArray readForTime(PISystemTime timeout) { return readForTime(timeout.toMilliseconds()); } + PIByteArray readForTime(PISystemTime timeout); //! \~english Add task to threaded write queue and return task ID @@ -506,8 +484,8 @@ public: //! \~russian setReopenEnabled, по умолчанию "true" bool reopenEnabled; - //! \~english setReopenTimeout in milliseconds, default 1000 - //! \~russian setReopenTimeout в миллисекундах, по умолчанию 1000 + //! \~english setReopenTimeout, default 1_s + //! \~russian setReopenTimeout, по умолчанию 1_s int reopenTimeout; //! \~english setThreadedReadBufferSize in bytes, default 4096 @@ -609,8 +587,9 @@ private: PIThread read_thread, write_thread; PIByteArray buffer_in, buffer_tr; PIQueue> write_queue; + PISystemTime reopen_timeout; ullong tri = 0; - uint threaded_read_buffer_size, reopen_timeout = 1000; + uint threaded_read_buffer_size; bool reopen_enabled = true, destroying = false; static PIMutex nfp_mutex; diff --git a/libs/main/io_devices/pipeer.cpp b/libs/main/io_devices/pipeer.cpp index dc035ad2..180ad28e 100644 --- a/libs/main/io_devices/pipeer.cpp +++ b/libs/main/io_devices/pipeer.cpp @@ -21,7 +21,9 @@ #include "piconfig.h" #include "pidatatransfer.h" +#include "piliterals_time.h" #include "pipropertystorage.h" +#include "pitime.h" #define _PIPEER_MSG_SIZE 4000 #define _PIPEER_MSG_TTL 100 @@ -85,7 +87,7 @@ PIPeer::PeerData::~PeerData() { dt_in.stop(); dt_out.stop(); t.stop(); - if (!t.waitForFinish(1000)) t.terminate(); + if (!t.waitForFinish(1_s)) t.terminate(); } @@ -182,12 +184,12 @@ PIPeer::PIPeer(const PIString & n) PIMutexLocker pl(peers_mutex); PIMutexLocker sl(send_mutex); changeName(n); - setReopenTimeout(100); + setReopenTimeout(100_ms); read_buffer_size = 128; self_info.dist = 0; self_info.time = PISystemTime::current(); randomize(); - CONNECT2(void, void *, int, &sync_timer, tickEvent, this, timerEvent); + CONNECT1(void, int, &sync_timer, tickEvent, this, timerEvent); prev_ifaces = PIEthernet::interfaces(); no_timer = false; sync_timer.addDelimiter(5); @@ -199,9 +201,9 @@ PIPeer::~PIPeer() { stop(); if (destroyed) return; destroyed = true; - sync_timer.stop(); - diag_s.stop(); - diag_d.stop(); + sync_timer.stopAndWait(); + diag_s.stopAndWait(); + diag_d.stopAndWait(); PIMutexLocker ml(peers_mutex); piForeach(PeerInfo & p, peers) if (p._data) { @@ -212,15 +214,15 @@ PIPeer::~PIPeer() { destroyEths(); piForeach(PIEthernet * i, eths_mcast) { if (!i) continue; - i->stopThreadedRead(); + i->stopAndWait(); } piForeach(PIEthernet * i, eths_bcast) { if (!i) continue; - i->stopThreadedRead(); + i->stopAndWait(); } - eth_lo.stopThreadedRead(); - eth_tcp_srv.stopThreadedRead(); - eth_tcp_cli.stopThreadedRead(); + eth_lo.stopAndWait(); + eth_tcp_srv.stopAndWait(); + eth_tcp_cli.stopAndWait(); sendSelfRemove(); destroyMBcasts(); eth_send.close(); @@ -229,7 +231,7 @@ PIPeer::~PIPeer() { } -void PIPeer::timerEvent(void * data, int delim) { +void PIPeer::timerEvent(int delim) { // piCoutObj << "timerEvent" << delim; if (no_timer) return; switch (delim) { @@ -362,46 +364,32 @@ void PIPeer::initMBcasts(PIStringList al) { void PIPeer::destroyEths() { - piForeach(PIEthernet * i, eths_traffic) { + for (auto * i: eths_traffic) { if (!i) continue; - ((PIThread *)i)->stop(); - ((PIThread *)i)->waitForFinish(100); - i->stopThreadedRead(); + i->stopAndWait(); i->close(); - delete i; - i = 0; } - eths_traffic.clear(); + piDeleteAllAndClear(eths_traffic); } void PIPeer::destroyMBcasts() { - piForeach(PIEthernet * i, eths_mcast) { + for (auto * i: eths_mcast) { if (!i) continue; - ((PIThread *)i)->stop(); - ((PIThread *)i)->waitForFinish(100); - i->stopThreadedRead(); i->leaveMulticastGroup(_PIPEER_MULTICAST_IP); + i->stopAndWait(); i->close(); - delete i; - i = 0; } - eths_mcast.clear(); - piForeach(PIEthernet * i, eths_bcast) { + for (auto * i: eths_bcast) { if (!i) continue; - ((PIThread *)i)->stop(); - ((PIThread *)i)->waitForFinish(100); - i->stopThreadedRead(); + i->stopAndWait(); i->close(); - delete i; - i = 0; } - eths_bcast.clear(); - ((PIThread *)ð_lo)->stop(); - ((PIThread *)ð_lo)->waitForFinish(100); - eth_lo.stopThreadedRead(); + piDeleteAllAndClear(eths_mcast); + piDeleteAllAndClear(eths_bcast); + eth_lo.stopAndWait(); eth_lo.close(); - eth_tcp_srv.stop(); + eth_tcp_srv.stopAndWait(); } @@ -918,7 +906,7 @@ void PIPeer::reinit() { initNetwork(); sendSelfInfo(); no_timer = false; - if (!sync_timer.isRunning()) sync_timer.start(1000); + if (!sync_timer.isRunning()) sync_timer.start(1_Hz); } diff --git a/libs/main/io_devices/pipeer.h b/libs/main/io_devices/pipeer.h index 224c4711..d69f4da1 100644 --- a/libs/main/io_devices/pipeer.h +++ b/libs/main/io_devices/pipeer.h @@ -172,7 +172,7 @@ protected: EVENT_HANDLER2(bool, mbcastRead, const uchar *, readed, ssize_t, size); private: - EVENT_HANDLER2(void, timerEvent, void *, data, int, delim); + EVENT_HANDLER1(void, timerEvent, int, delim); EVENT_HANDLER2(bool, sendInternal, const PIString &, to, const PIByteArray &, data); EVENT_HANDLER2(void, dtReceived, const PIString &, from, const PIByteArray &, data); EVENT_HANDLER1(void, newTcpClient, PIEthernet *, client); diff --git a/libs/main/io_devices/piserial.cpp b/libs/main/io_devices/piserial.cpp index 694d0649..28a172f8 100644 --- a/libs/main/io_devices/piserial.cpp +++ b/libs/main/io_devices/piserial.cpp @@ -23,6 +23,7 @@ #include "pidir.h" #include "piincludes_p.h" #include "pipropertystorage.h" +#include "pitime.h" #include "piwaitevent_p.h" #include diff --git a/libs/main/io_utils/pibasetransfer.cpp b/libs/main/io_utils/pibasetransfer.cpp index 261d5886..f509a44f 100644 --- a/libs/main/io_utils/pibasetransfer.cpp +++ b/libs/main/io_utils/pibasetransfer.cpp @@ -19,6 +19,8 @@ #include "pibasetransfer.h" +#include "pitime.h" + const uint PIBaseTransfer::signature = 0x54424950; PIBaseTransfer::PIBaseTransfer(): crc(standardCRC_16()), diag(false) { @@ -33,7 +35,7 @@ PIBaseTransfer::PIBaseTransfer(): crc(standardCRC_16()), diag(false) { send_queue = 0; send_up = 0; timeout_ = 10.; - diag.setDisconnectTimeout(timeout_ / 10); + diag.setDisconnectTimeout(PISystemTime::fromSeconds(timeout_ / 10.)); diag.setName("PIBaseTransfer"); diag.start(50); packets_count = 10; @@ -47,7 +49,7 @@ PIBaseTransfer::PIBaseTransfer(): crc(standardCRC_16()), diag(false) { PIBaseTransfer::~PIBaseTransfer() { - diag.stop(); + diag.stopAndWait(); break_ = true; } @@ -77,6 +79,12 @@ void PIBaseTransfer::setPause(bool pause_) { } +void PIBaseTransfer::setTimeout(double sec) { + timeout_ = sec; + diag.setDisconnectTimeout(PISystemTime::fromSeconds(sec)); +} + + void PIBaseTransfer::received(PIByteArray data) { packet_header_size = sizeof(PacketHeader) + customHeader().size(); if (data.size() < sizeof(PacketHeader)) { diff --git a/libs/main/io_utils/pibasetransfer.h b/libs/main/io_utils/pibasetransfer.h index c5cde96b..efbc52d8 100644 --- a/libs/main/io_utils/pibasetransfer.h +++ b/libs/main/io_utils/pibasetransfer.h @@ -65,10 +65,7 @@ public: void setPacketSize(int size) { packet_size = size; } int packetSize() const { return packet_size; } - void setTimeout(double sec) { - timeout_ = sec; - diag.setDisconnectTimeout(sec); - } + void setTimeout(double sec); double timeout() const { return timeout_; } void setCRCEnabled(bool en = true) { crc_enabled = en; } diff --git a/libs/main/io_utils/piconnection.cpp b/libs/main/io_utils/piconnection.cpp index a2ff6877..79758b92 100644 --- a/libs/main/io_utils/piconnection.cpp +++ b/libs/main/io_utils/piconnection.cpp @@ -21,6 +21,8 @@ #include "piconfig.h" #include "piiostream.h" +#include "piliterals_time.h" +#include "pitime.h" /** \class PIConnection * \brief Complex Input/Output point @@ -160,7 +162,9 @@ bool PIConnection::configure(PIConfig & conf, const PIString & name_) { PIConfig::Entry de = ce.getValue("device." + n); dev->setThreadedReadBufferSize(de.getValue("bufferSize", dev->threadedReadBufferSize()).toInt()); PIDiagnostics * diag = diags_.value(dev, nullptr); - if (diag) diag->setDisconnectTimeout(de.getValue("disconnectTimeout", diag->disconnectTimeout()).toFloat()); + if (diag) + diag->setDisconnectTimeout( + PISystemTime::fromSeconds(de.getValue("disconnectTimeout", diag->disconnectTimeout().toSeconds()).toFloat())); } int added(0), padded(-1), tries(0); bool pdebug = debug(); @@ -223,9 +227,11 @@ bool PIConnection::configure(PIConfig & conf, const PIString & name_) { } } PIDiagnostics * diag = diags_.value(pe, nullptr); - if (diag) diag->setDisconnectTimeout(e->getValue("disconnectTimeout", diag->disconnectTimeout()).toFloat()); + if (diag) + diag->setDisconnectTimeout( + PISystemTime::fromSeconds(e->getValue("disconnectTimeout", diag->disconnectTimeout().toSeconds()).toFloat())); pe->setPayloadSize(e->getValue("payloadSize", pe->payloadSize()).toInt()); - pe->setTimeout(e->getValue("timeout", pe->timeout()).toDouble()); + pe->setTimeout(PISystemTime::fromMilliseconds(e->getValue("timeout", pe->timeout().toMilliseconds()).toDouble())); pe->setHeader(PIByteArray::fromUserInput(e->getValue("header", "").toString())); pe->setFooter(PIByteArray::fromUserInput(e->getValue("footer", "").toString())); } @@ -271,7 +277,7 @@ PIString PIConnection::makeConfig() const { ts << "device." << dname << " = " << d->constructFullPath() << " #s\n"; ts << "device." << dname << ".bufferSize = " << d->threadedReadBufferSize() << " #n\n"; PIDiagnostics * diag = diags_.value(const_cast(d), nullptr); - if (diag) ts << "device." << dname << ".disconnectTimeout = " << diag->disconnectTimeout() << " #f\n"; + if (diag) ts << "device." << dname << ".disconnectTimeout = " << diag->disconnectTimeout().toSeconds() << " #f\n"; } } auto ite = extractors.makeIterator(); @@ -285,7 +291,7 @@ PIString PIConnection::makeConfig() const { ts << prefix << ".device." << i << " = " << dname << " #s\n"; } PIDiagnostics * diag = diags_.value(ite.value()->extractor, nullptr); - if (diag) ts << prefix << ".disconnectTimeout = " << diag->disconnectTimeout() << " #f\n"; + if (diag) ts << prefix << ".disconnectTimeout = " << diag->disconnectTimeout().toSeconds() << " #f\n"; ts << prefix << ".splitMode = "; switch (ite.value()->extractor->splitMode()) { case PIPacketExtractor::None: ts << "none"; break; @@ -297,7 +303,7 @@ PIString PIConnection::makeConfig() const { } ts << " #s\n"; ts << prefix << ".payloadSize = " << ite.value()->extractor->payloadSize() << " #n\n"; - ts << prefix << ".timeout = " << ite.value()->extractor->timeout() << " #f\n"; + ts << prefix << ".timeout = " << ite.value()->extractor->timeout().toMilliseconds() << " #f\n"; ts << prefix << ".header = " << ite.value()->extractor->header().toString() << " #s\n"; ts << prefix << ".footer = " << ite.value()->extractor->footer().toString() << " #s\n"; } @@ -324,8 +330,8 @@ PIString PIConnection::makeConfig() const { if (dname.isEmpty()) dname = devPath(its.value()->devices[i]); ts << prefix << ".device." << i << " = " << dname << " #s\n"; } - double int_ = its.value()->int_; - if (int_ > 0.) ts << prefix << ".frequency = " << (1000. / int_) << " #f\n"; + auto int_ = its.value()->int_; + if (!int_.isNull()) ts << prefix << ".frequency = " << (1. / int_.toSeconds()) << " #f\n"; if (!its.value()->sdata.isEmpty()) ts << prefix << ".fixedData = " << its.value()->sdata.toString() << " #s\n"; } ts << "[]\n"; @@ -342,7 +348,7 @@ PIIODevice * PIConnection::addDevice(const PIString & full_path, PIIODevice::Dev __device_pool__->lock(); if (!diags_.value(dev, nullptr)) { PIDiagnostics * d = new PIDiagnostics(false); - d->setInterval(100.); + d->setInterval(10_Hz); diags_[dev] = d; CONNECT2(void, PIDiagnostics::Quality, PIDiagnostics::Quality, d, qualityChanged, this, diagQualityChanged); __device_pool__->init(); @@ -476,7 +482,7 @@ PIPacketExtractor * PIConnection::addFilter(const PIString & name_, const PIStri __device_pool__->lock(); if (!diags_.value(e->extractor, nullptr)) { PIDiagnostics * d = new PIDiagnostics(false); - d->setInterval(100.); + d->setInterval(10_Hz); diags_[e->extractor] = d; CONNECT2(void, PIDiagnostics::Quality, PIDiagnostics::Quality, d, qualityChanged, this, diagQualityChanged); } @@ -514,7 +520,7 @@ PIPacketExtractor * PIConnection::addFilter(PIPacketExtractor * filter, const PI __device_pool__->lock(); if (diags_.value(e->extractor, 0) == 0) { PIDiagnostics * d = new PIDiagnostics(false); - d->setInterval(100.); + d->setInterval(10_Hz); diags_[e->extractor] = d; CONNECT2(void, PIDiagnostics::Quality, PIDiagnostics::Quality, d, qualityChanged, this, diagQualityChanged); } @@ -728,7 +734,7 @@ void PIConnection::addSender(const PIString & name_, const PIString & full_path_ if (!s) { s = new Sender(this); s->setName(fname_); - s->int_ = 1000. / frequency; + s->int_ = PISystemTime::fromSeconds(1. / frequency); senders[fname_] = s; } PIIODevice * dev = devByString(full_path_name); @@ -797,9 +803,9 @@ PIByteArray PIConnection::senderFixedData(const PIString & name) const { float PIConnection::senderFrequency(const PIString & name) const { Sender * s = senders.value(name, nullptr); if (!s) return -1.f; - double i = s->interval(); - if (i == 0.) return 0.f; - return 1000. / s->interval(); + auto i = s->interval(); + if (i.isNull()) return 0.f; + return 1. / s->interval().toSeconds(); } @@ -865,14 +871,14 @@ void PIConnection::stopAllThreadedReads() { void PIConnection::stopSender(const PIString & name) { Sender * s = senders.value(name, nullptr); if (!s) return; - if (s->isRunning()) s->stop(); + if (s->isRunning()) s->stopAndWait(); } void PIConnection::stopAllSenders() { for (auto s = senders.begin(); s != senders.end(); s++) { if (!s.value()) continue; - if (s.value()->isRunning()) s.value()->stop(); + if (s.value()->isRunning()) s.value()->stopAndWait(); } } @@ -949,7 +955,7 @@ bool PIConnection::isFakeMode() { } -PIConnection::DevicePool::DevicePool(): PIThread(false, 10) { +PIConnection::DevicePool::DevicePool(): PIThread(false, 100_Hz) { setName("PIConnection::DevicePool"); needLockRun(true); fake = false; @@ -960,7 +966,7 @@ PIConnection::DevicePool::~DevicePool() {} void PIConnection::DevicePool::init() { - if (!isRunning()) start(100); + if (!isRunning()) start(10_Hz); } @@ -1111,7 +1117,7 @@ PIConnection::DevicePool::DeviceData::~DeviceData() { if (rthread) { rthread->stop(); if (dev) dev->interrupt(); - if (!rthread->waitForFinish(1000)) rthread->terminate(); + if (!rthread->waitForFinish(1_s)) rthread->terminate(); delete rthread; rthread = nullptr; } @@ -1128,7 +1134,7 @@ void PIConnection::DevicePool::run() { for (PIConnection * c: conns) { for (auto d = c->diags_.begin(); d != c->diags_.end(); d++) { if (!d.value()) continue; - d.value()->tick(0, 1); + d.value()->tick(1); } } } @@ -1143,9 +1149,9 @@ void __DevicePool_threadReadDP(void * ddp) { } if (dev->isClosed()) { if (!dev->open()) { + auto timeout = dev->reopenTimeout(); PITimeMeasurer tm; - int timeout = dev->reopenTimeout(); - while (tm.elapsed_m() < timeout) { + while (tm.elapsed() < timeout) { if (dd->rthread->isStopping()) return; piMSleep(50); } @@ -1204,13 +1210,13 @@ PIConnection::Extractor::~Extractor() { } -PIConnection::Sender::Sender(PIConnection * parent_): parent(parent_), int_(0.f) { +PIConnection::Sender::Sender(PIConnection * parent_): parent(parent_) { setName("__S__.PIConnection.Sender"); needLockRun(true); } -void PIConnection::Sender::tick(void *, int) { +void PIConnection::Sender::tick(int) { if (!parent) return; PIByteArray data; if (!sdata.isEmpty()) diff --git a/libs/main/io_utils/piconnection.h b/libs/main/io_utils/piconnection.h index ecb9bf93..cdd39d87 100644 --- a/libs/main/io_utils/piconnection.h +++ b/libs/main/io_utils/piconnection.h @@ -387,12 +387,12 @@ private: public: Sender(PIConnection * parent_ = 0); - ~Sender() { stop(); } + ~Sender() { stopAndWait(); } PIConnection * parent; PIVector devices; PIByteArray sdata; - float int_; - void tick(void *, int) override; + PISystemTime int_; + void tick(int) override; }; PIMap extractors; diff --git a/libs/main/io_utils/pidiagnostics.cpp b/libs/main/io_utils/pidiagnostics.cpp index 21beb7d5..61a38fb6 100644 --- a/libs/main/io_utils/pidiagnostics.cpp +++ b/libs/main/io_utils/pidiagnostics.cpp @@ -19,6 +19,8 @@ #include "pidiagnostics.h" +#include "piliterals_time.h" + /** \class PIDiagnostics * \brief Connection quality diagnostics @@ -42,18 +44,18 @@ PIDiagnostics::State::State() { } -PIDiagnostics::PIDiagnostics(bool start_): PITimer(/*PITimer::Pool*/) { +PIDiagnostics::PIDiagnostics(bool start_): PITimer() { // piCout << "PIDiagnostics construct"; - setInterval(100); + setInterval(10_Hz); reset(); - setDisconnectTimeout(3.); - changeDisconnectTimeout(3.); - if (start_) PITimer::start(100); + setDisconnectTimeout(3_s); + changeDisconnectTimeout(3_s); + if (start_) PITimer::start(10_Hz); // piCout << "PIDiagnostics construct done"; } PIDiagnostics::~PIDiagnostics() { - PITimer::stop(); + PITimer::stopAndWait(); // piCout << "~PIDiagnostics start..."; // piCout << "~PIDiagnostics done!"; } @@ -92,14 +94,14 @@ PIString PIDiagnostics::sendSpeed() const { void PIDiagnostics::start() { - PITimer::start(100.); + PITimer::start(10_Hz); changeDisconnectTimeout(disconn_); } void PIDiagnostics::start(double msecs) { if (msecs > 0.) { - PITimer::start(msecs); + PITimer::start(PISystemTime::fromMilliseconds(msecs)); changeDisconnectTimeout(disconn_); } } @@ -108,7 +110,7 @@ void PIDiagnostics::start(double msecs) { void PIDiagnostics::reset() { mutex_state.lock(); cur_state = State(); - if (disconn_ != 0.) { + if (disconn_.isNotNull()) { int hist_size = history_rec.size(); history_rec.clear(); history_send.clear(); @@ -150,16 +152,16 @@ void PIDiagnostics::sended(int size) { } -void PIDiagnostics::tick(void *, int) { +void PIDiagnostics::tick(int) { mutex_state.lock(); // piCoutObj << "lock"; int tcnt_recv = 0; int tcnt_send = 0; Entry send = calcHistory(history_send, tcnt_send); Entry recv = calcHistory(history_rec, tcnt_recv); - float itr = disconn_ * (float(tcnt_recv) / history_rec.size()); - float its = disconn_ * (float(tcnt_send) / history_send.size()); - float hz = interval() / 1000.f; + float itr = disconn_.toSeconds() * (float(tcnt_recv) / history_rec.size()); + float its = disconn_.toSeconds() * (float(tcnt_send) / history_send.size()); + float hz = 1. / interval().toSeconds(); if (tcnt_recv == 0) { cur_state.integral_freq = cur_state.immediate_freq = 0; cur_state.received_packets_per_sec = cur_state.received_bytes_per_sec = 0; @@ -229,16 +231,15 @@ PIDiagnostics::Entry PIDiagnostics::calcHistory(PIQueue & hist, int & cnt void PIDiagnostics::propertyChanged(const char *) { - float disct = property("disconnectTimeout").toFloat(); - changeDisconnectTimeout(disct); + changeDisconnectTimeout(property("disconnectTimeout").toSystemTime()); } -void PIDiagnostics::changeDisconnectTimeout(float disct) { +void PIDiagnostics::changeDisconnectTimeout(PISystemTime disct) { mutex_state.lock(); - disconn_ = piMaxf(disct, interval() / 1000.f); - if (interval() > 0) { - int hist_size = piClampi(int(disconn_ * 1000.f / float(interval())), 1, 65536); + disconn_ = piMax(disct, interval()); + if (!interval().isNull()) { + int hist_size = piClampi(piRound(disconn_.toSeconds() / interval().toSeconds()), 1, 65536); // piCoutObj << hist_size << interval(); history_rec.resize(hist_size); history_send.resize(hist_size); diff --git a/libs/main/io_utils/pidiagnostics.h b/libs/main/io_utils/pidiagnostics.h index 9140903c..b1a5635d 100644 --- a/libs/main/io_utils/pidiagnostics.h +++ b/libs/main/io_utils/pidiagnostics.h @@ -75,13 +75,15 @@ public: PIDiagnostics::State state() const; //! Returns period of full disconnect in seconds and period of averaging frequency - float disconnectTimeout() const { return disconn_; } + PISystemTime disconnectTimeout() const { return disconn_; } //! Returns period of full disconnect in seconds and period of averaging frequency - void setDisconnectTimeout(float s) { setProperty("disconnectTimeout", s); } + void setDisconnectTimeout(float s) DEPRECATEDM("use setDisconnectTimeout(PISystemTime)") { + setDisconnectTimeout(PISystemTime::fromSeconds(s)); + } //! Returns period of full disconnect and period of averaging frequency - void setDisconnectTimeout(PISystemTime tm) { setProperty("disconnectTimeout", tm.toSeconds()); } + void setDisconnectTimeout(PISystemTime tm) { setProperty("disconnectTimeout", tm); } //! Returns connection quality PIDiagnostics::Quality quality() const; @@ -139,13 +141,13 @@ private: friend bool operator!=(const PIDiagnostics::Entry & f, const PIDiagnostics::Entry & s); friend bool operator<(const PIDiagnostics::Entry & f, const PIDiagnostics::Entry & s); - void tick(void *, int) override; + void tick(int) override; Entry calcHistory(PIQueue & hist, int & cnt); void propertyChanged(const char *) override; - void changeDisconnectTimeout(float disct); + void changeDisconnectTimeout(PISystemTime disct); PIQueue history_rec, history_send; - float disconn_ = 0.f; + PISystemTime disconn_; State cur_state; mutable PIMutex mutex_state; }; diff --git a/libs/main/io_utils/pipacketextractor.cpp b/libs/main/io_utils/pipacketextractor.cpp index feeb1839..ebd549e9 100644 --- a/libs/main/io_utils/pipacketextractor.cpp +++ b/libs/main/io_utils/pipacketextractor.cpp @@ -97,7 +97,7 @@ void PIPacketExtractor::construct() { func_footer = nullptr; func_payload = nullptr; setPayloadSize(0); - setTimeout(100); + setTimeout(100_ms); #ifdef MICRO_PIP setThreadedReadBufferSize(512); #else @@ -115,7 +115,7 @@ void PIPacketExtractor::propertyChanged(const char *) { dataSize = property("payloadSize").toInt(); src_header = property("header").toByteArray(); src_footer = property("footer").toByteArray(); - time_ = property("timeout").toDouble(); + time_ = property("timeout").toSystemTime(); } diff --git a/libs/main/io_utils/pipacketextractor.h b/libs/main/io_utils/pipacketextractor.h index 3b9db272..d36d0331 100644 --- a/libs/main/io_utils/pipacketextractor.h +++ b/libs/main/io_utils/pipacketextractor.h @@ -53,7 +53,7 @@ public: Footer /** Detect packets with \a footer() and leading \a payloadSize() */, HeaderAndFooter /** Detect packets with \a header() and \a footer() without \a payloadSize() */, Size /** Detect packets with \a packetSize() */, - Timeout /** Wait for first read, then read for \a timeout() milliseconds */ + Timeout /** Wait for first read, then read for \a timeout() */ }; //! Contructs extractor with child device "device_" and extract algorithm "mode" @@ -87,8 +87,8 @@ public: //! Set footer data, used for PIPacketExtractor::Footer and PIPacketExtractor::HeaderAndFooter algorithms void setFooter(const PIByteArray & data); - //! Set timeout in milliseconds, used for PIPacketExtractor::Timeout algorithm - void setTimeout(double msecs) { setProperty("timeout", msecs); } + //! Set timeout, used for PIPacketExtractor::Timeout algorithm + void setTimeout(PISystemTime tm) { setProperty("timeout", tm); } //! Returns current extract algorithm @@ -105,7 +105,7 @@ public: PIByteArray footer() const { return src_footer; } //! Returns current timeout in milliseconds, used for PIPacketExtractor::Timeout algorithm - double timeout() const { return time_; } + PISystemTime timeout() const { return time_; } //! Returns missed by validating functions bytes count ullong missedBytes() const { return missed; } @@ -165,7 +165,7 @@ private: PacketExtractorFooterFunc func_footer; SplitMode mode_; int dataSize, packetSize_pending, footerInd; - double time_; + PISystemTime time_; bool header_found; ullong missed; }; diff --git a/libs/main/pip.h b/libs/main/pip.h index 3cbfea91..a5018103 100644 --- a/libs/main/pip.h +++ b/libs/main/pip.h @@ -28,6 +28,7 @@ #include "pigeomodule.h" #include "piiodevicesmodule.h" #include "piioutilsmodule.h" +#include "piliterals.h" #include "pimathmodule.h" #include "pistatemachinemodule.h" #include "pisystemmodule.h" diff --git a/libs/main/state_machine/pistatemachine_transition.cpp b/libs/main/state_machine/pistatemachine_transition.cpp index ca95f1f7..f895d694 100644 --- a/libs/main/state_machine/pistatemachine_transition.cpp +++ b/libs/main/state_machine/pistatemachine_transition.cpp @@ -102,13 +102,13 @@ PITransitionTimeout::PITransitionTimeout(PIStateBase * source, PIStateBase * tar timer.setInterval(timeout); timer.setSlot([this] { trigger(); - timer.stopLater(); + timer.stop(); }); } PITransitionTimeout::~PITransitionTimeout() { - timer.stop(); + timer.stopAndWait(); } @@ -118,5 +118,5 @@ void PITransitionTimeout::enabled() { void PITransitionTimeout::disabled() { - timer.stopLater(); + timer.stop(); } diff --git a/libs/main/system/piprocess.cpp b/libs/main/system/piprocess.cpp index a43311fe..b63a0278 100644 --- a/libs/main/system/piprocess.cpp +++ b/libs/main/system/piprocess.cpp @@ -17,11 +17,12 @@ along with this program. If not, see . */ +#include "piliterals_time.h" +#include "pitime.h" #ifndef MICRO_PIP -# include "piprocess.h" - # include "piincludes_p.h" +# include "piprocess.h" # ifndef WINDOWS # include # include @@ -88,6 +89,7 @@ PIProcess::PIProcess(): PIThread() { PIProcess::~PIProcess() { + PIThread::stopAndWait(); if (t_in) f_in.remove(); if (t_out) f_out.remove(); if (t_err) f_err.remove(); @@ -232,6 +234,11 @@ else { } + bool PIProcess::waitForFinish() { + return PIThread::waitForFinish(1_m); + } + + void PIProcess::execIndependent(const PIString & program, const PIStringList & args_) { PIProcess p; p.args << program << args_; diff --git a/libs/main/system/piprocess.h b/libs/main/system/piprocess.h index b9700f35..c0e3ef90 100644 --- a/libs/main/system/piprocess.h +++ b/libs/main/system/piprocess.h @@ -147,8 +147,8 @@ public: exec_(); } EVENT_HANDLER(void, terminate); - EVENT_HANDLER(bool, waitForFinish) { return waitForFinish(60000); } - EVENT_HANDLER1(bool, waitForFinish, int, timeout_msecs) { return PIThread::waitForFinish(timeout_msecs); } + EVENT_HANDLER(bool, waitForFinish); + EVENT_HANDLER1(bool, waitForFinish, PISystemTime, timeout) { return PIThread::waitForFinish(timeout); } EVENT1(execStarted, PIString, program); EVENT2(execFinished, PIString, program, int, exit_code); @@ -202,9 +202,9 @@ public: //! \~english Wait for attached execution finish maximum for 60 seconds //! \~russian - //! \fn bool waitForFinish(int timeout_msecs) + //! \fn bool waitForFinish(PISystemTime timeout) //! \brief - //! \~english Wait for attached execution finish maximum for "timeout_msecs" milliseconds + //! \~english Wait for attached execution finish maximum for "timeout_" //! \~russian //! \} diff --git a/libs/main/system/pisingleapplication.cpp b/libs/main/system/pisingleapplication.cpp index d0c67af5..0626483b 100644 --- a/libs/main/system/pisingleapplication.cpp +++ b/libs/main/system/pisingleapplication.cpp @@ -19,8 +19,10 @@ #include "pisingleapplication.h" -#include "piliterals.h" +#include "piliterals_bytes.h" +#include "piliterals_time.h" #include "pisharedmemory.h" +#include "pitime.h" //! \class PISingleApplication pisingleapplication.h @@ -70,7 +72,7 @@ PISingleApplication::PISingleApplication(const PIString & app_name): PIThread() started = false; sacnt = 0; shm = new PISharedMemory("sa_" + app_name, SHM_SIZE); - start(100); + start(10_Hz); } diff --git a/libs/main/system/pisystemmonitor.cpp b/libs/main/system/pisystemmonitor.cpp index fc0b24e7..c8e61f11 100644 --- a/libs/main/system/pisystemmonitor.cpp +++ b/libs/main/system/pisystemmonitor.cpp @@ -95,7 +95,7 @@ PISystemMonitor::~PISystemMonitor() { #ifndef MICRO_PIP -bool PISystemMonitor::startOnProcess(int pID, int interval_ms) { +bool PISystemMonitor::startOnProcess(int pID, PISystemTime interval) { stop(); pID_ = pID; Pool::instance()->add(this); @@ -118,17 +118,17 @@ bool PISystemMonitor::startOnProcess(int pID, int interval_ms) { } PRIVATE->tm.reset(); # endif - return start(interval_ms); + return start(interval); } #endif -bool PISystemMonitor::startOnSelf(int interval_ms) { +bool PISystemMonitor::startOnSelf(PISystemTime interval) { #ifndef MICRO_PIP - bool ret = startOnProcess(PIProcess::currentPID(), interval_ms); + bool ret = startOnProcess(PIProcess::currentPID(), interval); cycle = -1; #else - bool ret = start(interval_ms); + bool ret = start(interval); #endif return ret; } @@ -190,7 +190,8 @@ void PISystemMonitor::run() { if (t->isPIObject()) gatherThread(t->tid()); #else # ifndef WINDOWS - tbid[pID_] = "main"; + double delay_ms = delay_.toMilliseconds(); + tbid[pID_] = "main"; # ifdef MAC_OS rusage_info_current ru; proc_pid_rusage(pID_, RUSAGE_INFO_CURRENT, (rusage_info_t *)&ru); @@ -203,10 +204,10 @@ void PISystemMonitor::run() { PRIVATE->cpu_s_prev = PRIVATE->cpu_s_cur; PRIVATE->cpu_u_cur = uint64toST(ru.ri_user_time); PRIVATE->cpu_s_cur = uint64toST(ru.ri_system_time); - tstat.cpu_load_system = 100.f * (PRIVATE->cpu_s_cur - PRIVATE->cpu_s_prev).toMilliseconds() / delay_; - tstat.cpu_load_user = 100.f * (PRIVATE->cpu_u_cur - PRIVATE->cpu_u_prev).toMilliseconds() / delay_; + tstat.cpu_load_system = 100.f * (PRIVATE->cpu_s_cur - PRIVATE->cpu_s_prev).toMilliseconds() / delay_ms; + tstat.cpu_load_user = 100.f * (PRIVATE->cpu_u_cur - PRIVATE->cpu_u_prev).toMilliseconds() / delay_ms; cycle = 0; - // piCout << (PRIVATE->cpu_u_cur - PRIVATE->cpu_u_prev).toMilliseconds() / delay_; + // piCout << (PRIVATE->cpu_u_cur - PRIVATE->cpu_u_prev).toMilliseconds() / delay_ms; # else PRIVATE->file.seekToBegin(); PIString str = PIString::fromAscii(PRIVATE->file.readAll(true)); @@ -236,8 +237,8 @@ void PISystemMonitor::run() { PRIVATE->cpu_s_prev = PRIVATE->cpu_s_cur; PRIVATE->cpu_u_cur = sl[12].toLLong(); PRIVATE->cpu_s_cur = sl[13].toLLong(); - tstat.cpu_load_system = (PRIVATE->cpu_s_cur - PRIVATE->cpu_s_prev) / (delay_ / 1000.); - tstat.cpu_load_user = (PRIVATE->cpu_u_cur - PRIVATE->cpu_u_prev) / (delay_ / 1000.); + tstat.cpu_load_system = (PRIVATE->cpu_s_cur - PRIVATE->cpu_s_prev) / (delay_ms / 1000.); + tstat.cpu_load_user = (PRIVATE->cpu_u_cur - PRIVATE->cpu_u_prev) / (delay_ms / 1000.); tstat.cpu_load_system /= cpu_count; tstat.cpu_load_user /= cpu_count; cycle = 0; @@ -394,8 +395,8 @@ void PISystemMonitor::gatherThread(llong id) { float PISystemMonitor::calcThreadUsage(PISystemTime & t_new, PISystemTime & t_old) { - if (delay_ <= 0) return -1.; - return piClampf(100. * ((t_new - t_old).toMilliseconds() / delay_), 0.f, 100.f); + if (delay_.isNull()) return -1.; + return piClampf(100. * ((t_new - t_old).toMilliseconds() / delay_.toMilliseconds()), 0.f, 100.f); } diff --git a/libs/main/system/pisystemmonitor.h b/libs/main/system/pisystemmonitor.h index c5084e7e..ed005e9b 100644 --- a/libs/main/system/pisystemmonitor.h +++ b/libs/main/system/pisystemmonitor.h @@ -203,12 +203,12 @@ public: //! \~english Starts monitoring of process with PID "pID" and update interval "interval_ms" milliseconds //! \~russian Начинает мониторинг процесса с PID "pID" и интервалом обновления "interval_ms" миллисекунд - bool startOnProcess(int pID, int interval_ms = 1000); + bool startOnProcess(int pID, PISystemTime interval = PISystemTime::fromSeconds(1.)); #endif //! \~english Starts monitoring of application process with update interval "interval_ms" milliseconds //! \~russian Начинает мониторинг процесса приложения с интервалом обновления "interval_ms" миллисекунд - bool startOnSelf(int interval_ms = 1000); + bool startOnSelf(PISystemTime interval = PISystemTime::fromSeconds(1.)); //! \~english Stop monitoring //! \~russian Останавливает мониторинг diff --git a/libs/main/thread/piblockingqueue.h b/libs/main/thread/piblockingqueue.h index a99268f2..378b9068 100644 --- a/libs/main/thread/piblockingqueue.h +++ b/libs/main/thread/piblockingqueue.h @@ -27,7 +27,7 @@ #define PIBLOCKINGQUEUE_H #include "piconditionvar.h" -#include "pideque.h" +#include "piqueue.h" /** * \brief A Queue that supports operations that wait for the queue to become non-empty when retrieving an element, and @@ -96,16 +96,16 @@ public: * exceeding the queue's capacity, returning true upon success and false if this queue is full. * * @param v the element to add - * @param timeoutMs the timeout waiting for inserting if que is full, if timeout = 0, then returns immediately + * @param timeout the timeout waiting for inserting if que is full, if timeout is null, then returns immediately * @return true if the element was added to this queue, else false */ - bool offer(const T & v, int timeoutMs = 0) { + bool offer(const T & v, PISystemTime timeout = {}) { bool isOk; mutex.lock(); - if (timeoutMs == 0) + if (timeout.isNull()) isOk = PIDeque::size() < max_size; else - isOk = cond_var_rem->waitFor(mutex, timeoutMs, [&]() { return PIDeque::size() < max_size; }); + isOk = cond_var_rem->waitFor(mutex, timeout, [&]() { return PIDeque::size() < max_size; }); if (isOk) PIDeque::push_back(v); mutex.unlock(); if (isOk) cond_var_add->notifyOne(); @@ -133,20 +133,20 @@ public: * \brief Retrieves and removes the head of this queue, waiting up to the specified wait time if necessary for an * element to become available. * - * @param timeoutMs how long to wait before giving up, in milliseconds + * @param timeout how long to wait before giving up * @param defaultVal value, which returns if the specified waiting time elapses before an element is available * @param isOk flag, which indicates result of method execution. It will be set to false if timeout, or true if * return value is retrieved value * @return the head of this queue, or defaultVal if the specified waiting time elapses before an element is available */ - T poll(int timeoutMs = 0, const T & defaultVal = T(), bool * isOk = nullptr) { + T poll(PISystemTime timeout = {}, const T & defaultVal = T(), bool * isOk = nullptr) { T t = defaultVal; bool isNotEmpty; mutex.lock(); - if (timeoutMs == 0) + if (timeout.isNull()) isNotEmpty = !PIDeque::isEmpty(); else - isNotEmpty = cond_var_add->waitFor(mutex, timeoutMs, [&]() { return !PIDeque::isEmpty(); }); + isNotEmpty = cond_var_add->waitFor(mutex, timeout, [&]() { return !PIDeque::isEmpty(); }); if (isNotEmpty) t = PIDeque::take_front(); mutex.unlock(); if (isNotEmpty) cond_var_rem->notifyOne(); diff --git a/libs/main/thread/piconditionvar.cpp b/libs/main/thread/piconditionvar.cpp index f9d12c40..4aa3995d 100644 --- a/libs/main/thread/piconditionvar.cpp +++ b/libs/main/thread/piconditionvar.cpp @@ -25,8 +25,6 @@ #include "piconditionvar.h" #include "piincludes_p.h" -#include "pithread.h" -#include "pitime.h" #ifdef WINDOWS # include # include @@ -105,19 +103,18 @@ void PIConditionVariable::wait(PIMutex & lk, const std::function & condi } -bool PIConditionVariable::waitFor(PIMutex & lk, int timeoutMs) { +bool PIConditionVariable::waitFor(PIMutex & lk, PISystemTime timeout) { bool isNotTimeout; #if defined(WINDOWS) - isNotTimeout = SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), timeoutMs) != 0; + isNotTimeout = SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), timeout.toMilliseconds()) != 0; #elif defined(FREERTOS) xEventGroupClearBits(PRIVATE->nativeHandle, 1); EventBits_t uxBits; - uxBits = xEventGroupWaitBits(PRIVATE->nativeHandle, 1, pdTRUE, pdTRUE, timeoutMs / portTICK_PERIOD_MS); - isNotTimeout = (uxBits & 1) != 0; + uxBits = xEventGroupWaitBits(PRIVATE->nativeHandle, 1, pdTRUE, pdTRUE, timeout.toMilliseconds() / portTICK_PERIOD_MS); + isNotTimeout = (uxBits & 1) != 0; #else + PISystemTime st = PISystemTime::current(true) + timeout; timespec expire_ts; - PISystemTime st = PISystemTime::current(true); - st.addMilliseconds(timeoutMs); st.toTimespec(&expire_ts); isNotTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t *)lk.handle(), &expire_ts) == 0; #endif @@ -125,14 +122,13 @@ bool PIConditionVariable::waitFor(PIMutex & lk, int timeoutMs) { } -bool PIConditionVariable::waitFor(PIMutex & lk, int timeoutMs, const std::function & condition) { +bool PIConditionVariable::waitFor(PIMutex & lk, PISystemTime timeout, const std::function & condition) { bool isCondition; #if defined(WINDOWS) || defined(FREERTOS) PITimeMeasurer measurer; #else + PISystemTime st = PISystemTime::current(true) + timeout; timespec expire_ts; - PISystemTime st = PISystemTime::current(true); - st.addMilliseconds(timeoutMs); st.toTimespec(&expire_ts); #endif #ifdef FREERTOS @@ -143,12 +139,16 @@ bool PIConditionVariable::waitFor(PIMutex & lk, int timeoutMs, const std::functi if (isCondition) break; bool isTimeout; #if defined(WINDOWS) - isTimeout = - SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), timeoutMs - (int)measurer.elapsed_m()) == 0; + isTimeout = SleepConditionVariableCS(&PRIVATE->nativeHandle, + (PCRITICAL_SECTION)lk.handle(), + timeout.toMilliseconds() - (int)measurer.elapsed_m()) == 0; #elif defined(FREERTOS) EventBits_t uxBits; - uxBits = - xEventGroupWaitBits(PRIVATE->nativeHandle, 1, pdTRUE, pdTRUE, (timeoutMs - (int)measurer.elapsed_m()) / portTICK_PERIOD_MS); + uxBits = xEventGroupWaitBits(PRIVATE->nativeHandle, + 1, + pdTRUE, + pdTRUE, + (timeout.toMilliseconds() - (int)measurer.elapsed_m()) / portTICK_PERIOD_MS); isTimeout = (uxBits & 1) == 0; #else isTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t *)lk.handle(), &expire_ts) != 0; diff --git a/libs/main/thread/piconditionvar.h b/libs/main/thread/piconditionvar.h index 86e0237e..ee11ac78 100644 --- a/libs/main/thread/piconditionvar.h +++ b/libs/main/thread/piconditionvar.h @@ -26,7 +26,8 @@ #ifndef PICONDITIONVAR_H #define PICONDITIONVAR_H -#include "pithread.h" +#include "pimutex.h" +#include "pisystemtime.h" /** @@ -87,18 +88,18 @@ public: /** * \brief see waitFor(PIMutex &, int, const std::function&) */ - virtual bool waitFor(PIMutex & lk, int timeoutMs); + virtual bool waitFor(PIMutex & lk, PISystemTime timeout); /** * \brief Wait for timeout or until notified * * The execution of the current thread (which shall have locked with lk method PIMutex::lock()) is blocked - * during timeoutMs, or until notified (if the latter happens first). + * during timeout, or until notified (if the latter happens first). * * At the moment of blocking the thread, the function automatically calls lk.lock() (PIMutex::lock()), allowing * other locked threads to continue. * - * Once notified or once timeoutMs has passed, the function unblocks and calls lk.unlock() (PIMutex::unlock()), + * Once notified or once timeout has passed, the function unblocks and calls lk.unlock() (PIMutex::unlock()), * leaving lk in the same state as when the function was called. Then the function returns (notice that this last * mutex locking may block again the thread before returning). * @@ -114,7 +115,7 @@ public: * as a bool. This is called repeatedly until it evaluates to true. * @return false if timeout reached or true if wakeup condition is true */ - virtual bool waitFor(PIMutex & lk, int timeoutMs, const std::function & condition); + virtual bool waitFor(PIMutex & lk, PISystemTime timeout, const std::function & condition); private: PRIVATE_DECLARATION(PIP_EXPORT) diff --git a/libs/main/thread/pigrabberbase.h b/libs/main/thread/pigrabberbase.h index 59be1cb0..feabbc62 100644 --- a/libs/main/thread/pigrabberbase.h +++ b/libs/main/thread/pigrabberbase.h @@ -28,6 +28,7 @@ #include "pidiagnostics.h" #include "pithread.h" +#include "pitime.h" template diff --git a/libs/main/thread/pithread.cpp b/libs/main/thread/pithread.cpp index 093934f9..c75776a3 100644 --- a/libs/main/thread/pithread.cpp +++ b/libs/main/thread/pithread.cpp @@ -535,33 +535,33 @@ PRIVATE_DEFINITION_START(PIThread) PRIVATE_DEFINITION_END(PIThread) -PIThread::PIThread(void * data, ThreadFunc func, bool startNow, int loop_delay): PIObject() { +PIThread::PIThread(void * data, ThreadFunc func, bool startNow, PISystemTime loop_delay): PIObject() { PIINTROSPECTION_THREAD_NEW(this); data_ = data; ret_func = func; terminating = running_ = lockRun = false; priority_ = piNormal; delay_ = loop_delay; - if (startNow) start(loop_delay); + if (startNow) start(); } -PIThread::PIThread(std::function func, bool startNow, int loop_delay) { +PIThread::PIThread(std::function func, bool startNow, PISystemTime loop_delay) { PIINTROSPECTION_THREAD_NEW(this); ret_func = [func](void *) { func(); }; terminating = running_ = lockRun = false; priority_ = piNormal; delay_ = loop_delay; - if (startNow) start(loop_delay); + if (startNow) start(); } -PIThread::PIThread(bool startNow, int loop_delay): PIObject() { +PIThread::PIThread(bool startNow, PISystemTime loop_delay): PIObject() { PIINTROSPECTION_THREAD_NEW(this); terminating = running_ = lockRun = false; priority_ = piNormal; delay_ = loop_delay; - if (startNow) start(loop_delay); + if (startNow) start(); } @@ -573,7 +573,7 @@ PIThread::~PIThread() { // PICout(PICoutManipulators::DefaultControls) << "~PIThread" << PRIVATE->thread; // PICout(PICoutManipulators::DefaultControls) << pthread_join(PRIVATE->thread, 0); PICout(PICoutManipulators::DefaultControls) << "FreeRTOS can't terminate pthreads! waiting for stop"; - stop(true); + stopAndWait(); // PICout(PICoutManipulators::DefaultControls) << "stopped!"; #else # ifndef WINDOWS @@ -591,15 +591,47 @@ PIThread::~PIThread() { } -bool PIThread::start(ThreadFunc func, int loop_delay) { - ret_func = func; - return start(loop_delay); +bool PIThread::start() { + if (running_) return false; + return _startThread((void *)thread_function); } -bool PIThread::start(std::function func, int loop_delay) { +bool PIThread::start(PISystemTime loop_delay) { + delay_ = loop_delay; + return start(); +} + + +bool PIThread::start(ThreadFunc func) { + ret_func = func; + return start(); +} + + +bool PIThread::start(ThreadFunc func, PISystemTime loop_delay) { + ret_func = func; + delay_ = loop_delay; + return start(); +} + + +bool PIThread::start(std::function func) { ret_func = [func](void *) { func(); }; - return start(loop_delay); + return start(); +} + + +bool PIThread::start(std::function func, PISystemTime loop_delay) { + ret_func = [func](void *) { func(); }; + delay_ = loop_delay; + return start(); +} + + +bool PIThread::startOnce() { + if (running_) return false; + return _startThread((void *)thread_function_once); } @@ -609,9 +641,15 @@ bool PIThread::startOnce(ThreadFunc func) { } -void PIThread::stopAndWait(int timeout_ms) { +bool PIThread::startOnce(std::function func) { + ret_func = [func](void *) { func(); }; + return startOnce(); +} + + +void PIThread::stopAndWait(PISystemTime timeout) { stop(); - waitForFinish(timeout_ms); + waitForFinish(timeout); } @@ -621,19 +659,6 @@ void PIThread::stop() { } -bool PIThread::start(int loop_delay) { - if (running_) return false; - delay_ = loop_delay; - return _startThread((void *)thread_function); -} - - -bool PIThread::startOnce() { - if (running_) return false; - return _startThread((void *)thread_function_once); -} - - void PIThread::terminate() { piCoutObj << "Warning, terminate!"; // PICout(PICoutManipulators::DefaultControls) << "thread" << this << "terminate ..." << running_; @@ -766,7 +791,7 @@ void PIThread::setPriority(PIThread::Priority prior) { #else # ifndef WINDOWS // PICout(PICoutManipulators::DefaultControls) << "setPriority" << PRIVATE->thread; - policy_ = 0; + int policy_ = 0; memset(&(PRIVATE->sparam), 0, sizeof(PRIVATE->sparam)); pthread_getschedparam(PRIVATE->thread, &policy_, &(PRIVATE->sparam)); PRIVATE->sparam. @@ -785,16 +810,6 @@ void PIThread::setPriority(PIThread::Priority prior) { } -bool PIThread::waitForStart(PISystemTime timeout) { - return waitForStart(timeout.toMilliseconds()); -} - - -bool PIThread::waitForFinish(PISystemTime timeout) { - return waitForFinish(timeout.toMilliseconds()); -} - - #ifdef WINDOWS bool isExists(HANDLE hThread) { // errorClear(); @@ -808,11 +823,12 @@ bool isExists(HANDLE hThread) { } #endif -bool PIThread::waitForFinish(int timeout_msecs) { + +bool PIThread::waitForFinish(PISystemTime timeout) { // PICout(PICoutManipulators::DefaultControls) << "thread" << this << "PIThread::waitForFinish" << running_ << terminating << // timeout_msecs; if (!running_) return true; - if (timeout_msecs < 0) { + if (timeout.isNull()) { while (running_) { piMinSleep(); #ifdef WINDOWS @@ -825,7 +841,7 @@ bool PIThread::waitForFinish(int timeout_msecs) { return true; } tmf_.reset(); - while (running_ && tmf_.elapsed_m() < timeout_msecs) { + while (running_ && tmf_.elapsed() < timeout) { piMinSleep(); #ifdef WINDOWS if (!isExists(PRIVATE->thread)) { @@ -834,21 +850,21 @@ bool PIThread::waitForFinish(int timeout_msecs) { } #endif } - return tmf_.elapsed_m() < timeout_msecs; + return tmf_.elapsed() < timeout; } -bool PIThread::waitForStart(int timeout_msecs) { +bool PIThread::waitForStart(PISystemTime timeout) { if (running_) return true; - if (timeout_msecs < 0) { + if (timeout.isNull()) { while (!running_) piMinSleep(); return true; } tms_.reset(); - while (!running_ && tms_.elapsed_m() < timeout_msecs) + while (!running_ && tms_.elapsed() < timeout) piMinSleep(); - return tms_.elapsed_m() < timeout_msecs; + return tms_.elapsed() < timeout; } @@ -940,11 +956,11 @@ void PIThread::__thread_func__() { _runThread(); // PICout(PICoutManipulators::DefaultControls) << "thread" << this << "wait" << "..."; PIINTROSPECTION_THREAD_WAIT(this); - if (delay_ > 0) { + if (delay_.isNotNull()) { tmr_.reset(); double sl(0.); while (1) { - sl = piMind(delay_ - tmr_.elapsed_m(), PIP_MIN_MSLEEP); + sl = piMind(delay_.toMilliseconds() - tmr_.elapsed_m(), PIP_MIN_MSLEEP); if (terminating) break; if (sl <= 0.) break; piMSleep(sl); diff --git a/libs/main/thread/pithread.h b/libs/main/thread/pithread.h index 078d569b..bb47db84 100644 --- a/libs/main/thread/pithread.h +++ b/libs/main/thread/pithread.h @@ -79,15 +79,15 @@ public: //! \~english Contructs thread with custom data "data", external function "func" and main loop delay "loop_delay" //! \~russian Создает поток с данными "data", функцией "func" и задержкой цикла "loop_delay" - PIThread(void * data, ThreadFunc func, bool startNow = false, int loop_delay = -1); + PIThread(void * data, ThreadFunc func, bool startNow = false, PISystemTime loop_delay = {}); //! \~english Contructs thread with external function "func" and main loop delay "loop_delay" //! \~russian Создает поток с функцией "func" и задержкой цикла "loop_delay" - PIThread(std::function func, bool startNow = false, int loop_delay = -1); + PIThread(std::function func, bool startNow = false, PISystemTime loop_delay = {}); //! \~english Contructs thread with main loop delay "loop_delay" //! \~russian Создает поток с задержкой цикла "loop_delay" - PIThread(bool startNow = false, int loop_delay = -1); + PIThread(bool startNow = false, PISystemTime loop_delay = {}); virtual ~PIThread(); @@ -103,27 +103,55 @@ public: piHighest /** \~english Highest \~russian Высший */ }; - EVENT_HANDLER0(bool, start) { return start(-1); } - EVENT_HANDLER1(bool, start, int, loop_delay); - bool start(PISystemTime loop_delay) { return start(loop_delay.toMilliseconds()); } - bool start(ThreadFunc func) { return start(func, -1); } - bool start(ThreadFunc func, int loop_delay); - bool start(ThreadFunc func, PISystemTime loop_delay) { return start(func, loop_delay.toMilliseconds()); } - bool start(std::function func) { return start(func, -1); } - bool start(std::function func, int loop_delay); - bool start(std::function func, PISystemTime loop_delay) { return start(func, loop_delay.toMilliseconds()); } - EVENT_HANDLER0(bool, startOnce); - EVENT_HANDLER1(bool, startOnce, ThreadFunc, func); + + //! \~english Start thread + //! \~russian Запускает поток + bool start(); + + //! \~english Start thread + //! \~russian Запускает поток + bool start(PISystemTime loop_delay); + + //! \~english Start thread + //! \~russian Запускает поток + bool start(ThreadFunc func); + + //! \~english Start thread + //! \~russian Запускает поток + bool start(ThreadFunc func, PISystemTime loop_delay); + + //! \~english Start thread + //! \~russian Запускает поток + bool start(std::function func); + + //! \~english Start thread + //! \~russian Запускает поток + bool start(std::function func, PISystemTime loop_delay); + + //! \~english Start thread without internal loop + //! \~russian Запускает поток без внутреннего цикла + bool startOnce(); + + //! \~english Start thread without internal loop + //! \~russian Запускает поток без внутреннего цикла + bool startOnce(ThreadFunc func); + + //! \~english Start thread without internal loop + //! \~russian Запускает поток без внутреннего цикла + bool startOnce(std::function func); + EVENT_HANDLER0(void, stop); EVENT_HANDLER0(void, terminate); //! \~english Stop thread and wait for finish. //! \~russian Останавливает поток и ожидает завершения. - void stopAndWait(int timeout_ms = -1); + void stopAndWait(int timeout_ms) DEPRECATEDM("use waitForStart(PISystemTime)") { + stopAndWait(PISystemTime::fromMilliseconds(timeout_ms)); + } //! \~english Stop thread and wait for finish. //! \~russian Останавливает поток и ожидает завершения. - void stopAndWait(PISystemTime timeout) { stopAndWait(timeout.toMilliseconds()); } + void stopAndWait(PISystemTime timeout = {}); //! \~english Set common data passed to external function //! \~russian Устанавливает данные, передаваемые в функцию потока @@ -159,12 +187,19 @@ public: //! \~russian Возвращает останавливается ли поток bool isStopping() const { return running_ && terminating; } - EVENT_HANDLER0(bool, waitForStart) { return waitForStart(-1); } - EVENT_HANDLER1(bool, waitForStart, int, timeout_msecs); - bool waitForStart(PISystemTime timeout); - EVENT_HANDLER0(bool, waitForFinish) { return waitForFinish(-1); } - EVENT_HANDLER1(bool, waitForFinish, int, timeout_msecs); - bool waitForFinish(PISystemTime timeout); + //! \~english Wait for thread start + //! \~russian Ожидает старта потока + bool waitForStart(PISystemTime timeout = {}); + bool waitForStart(int timeout_msecs) DEPRECATEDM("use waitForStart(PISystemTime)") { + return waitForStart(PISystemTime::fromMilliseconds(timeout_msecs)); + } + + //! \~english Wait for thread finish + //! \~russian Ожидает завершения потока + bool waitForFinish(PISystemTime timeout = {}); + bool waitForFinish(int timeout_msecs) DEPRECATEDM("use waitForFinish(PISystemTime)") { + return waitForFinish(PISystemTime::fromMilliseconds(timeout_msecs)); + } //! \~english Set necessity of lock every \a run() with internal mutex //! \~russian Устанавливает необходимость блокировки внутреннего мьютекса каждый \a run() @@ -198,21 +233,6 @@ public: //! \handlers //! \{ - //! \fn bool start(int loop_delay = -1) - //! \brief - //! \~english Start thread - //! \~russian Запускает поток - - //! \fn bool startOnce() - //! \brief - //! \~english Start thread without internal loop - //! \~russian Запускает поток без внутреннего цикла - - //! \fn bool startOnce(ThreadFunc func) - //! \brief - //! \~english Start thread without internal loop - //! \~russian Запускает поток без внутреннего цикла - //! \fn void stop() //! \brief //! \~english Stop thread @@ -223,16 +243,6 @@ public: //! \~english Strongly stop thread //! \~russian Жёстко прерывает поток - //! \fn bool waitForStart(int timeout_msecs = -1) - //! \brief - //! \~english Wait for thread start - //! \~russian Ожидает старта потока - - //! \fn bool waitForFinish(int timeout_msecs = -1) - //! \brief - //! \~english Wait for thread finish - //! \~russian Ожидает завершения потока - //! \fn void lock() //! \brief //! \~english Lock internal mutex @@ -275,7 +285,7 @@ protected: virtual void end() { ; } std::atomic_bool terminating, running_, lockRun; - int delay_, policy_; + PISystemTime delay_; llong tid_ = -1; void * data_ = nullptr; mutable PIMutex thread_mutex; diff --git a/libs/main/thread/pithreadpoolexecutor.cpp b/libs/main/thread/pithreadpoolexecutor.cpp index bd7043fc..55d3ae29 100644 --- a/libs/main/thread/pithreadpoolexecutor.cpp +++ b/libs/main/thread/pithreadpoolexecutor.cpp @@ -19,6 +19,8 @@ #include "pithreadpoolexecutor.h" +#include "piliterals_time.h" + /*! \class PIThreadPoolExecutor * \brief Thread pools address two different problems: they usually provide improved performance when executing large * numbers of asynchronous tasks, due to reduced per-task invocation overhead, and they provide a means of bounding and @@ -29,7 +31,7 @@ PIThreadPoolExecutor::PIThreadPoolExecutor(int corePoolSize): isShutdown_(false) { for (int i = 0; i < corePoolSize; ++i) { PIThread * thread = new PIThread([&, i]() { - auto runnable = taskQueue.poll(100, std::function()); + auto runnable = taskQueue.poll(100_ms, std::function()); if (runnable) { runnable(); } @@ -41,11 +43,11 @@ PIThreadPoolExecutor::PIThreadPoolExecutor(int corePoolSize): isShutdown_(false) } -bool PIThreadPoolExecutor::awaitTermination(int timeoutMs) { +bool PIThreadPoolExecutor::awaitTermination(PISystemTime timeout) { PITimeMeasurer measurer; for (size_t i = 0; i < threadPool.size(); ++i) { - int dif = timeoutMs - (int)measurer.elapsed_m(); - if (dif < 0) return false; + auto dif = timeout - measurer.elapsed(); + if (dif.isNegative()) return false; if (!threadPool[i]->waitForFinish(dif)) return false; } return true; diff --git a/libs/main/thread/pithreadpoolexecutor.h b/libs/main/thread/pithreadpoolexecutor.h index ac8f4a3d..cc43f6f5 100644 --- a/libs/main/thread/pithreadpoolexecutor.h +++ b/libs/main/thread/pithreadpoolexecutor.h @@ -21,6 +21,7 @@ #define PITHREADPOOLEXECUTOR_H #include "piblockingqueue.h" +#include "pithread.h" #include @@ -47,7 +48,7 @@ public: bool isShutdown() const; - bool awaitTermination(int timeoutMs); + bool awaitTermination(PISystemTime timeout); private: std::atomic_bool isShutdown_; diff --git a/libs/main/thread/pithreadpoolloop.cpp b/libs/main/thread/pithreadpoolloop.cpp index 9815ae74..1e364e4a 100644 --- a/libs/main/thread/pithreadpoolloop.cpp +++ b/libs/main/thread/pithreadpoolloop.cpp @@ -19,6 +19,7 @@ #include "pithreadpoolloop.h" +#include "piliterals_time.h" #include "pisysteminfo.h" #include "pithread.h" @@ -115,7 +116,7 @@ PIThreadPoolLoop::PIThreadPoolLoop(int thread_cnt) { PIThreadPoolLoop::~PIThreadPoolLoop() { for (auto * t: threads) { t->stop(); - if (!t->waitForFinish(100)) t->terminate(); + if (!t->waitForFinish(100_ms)) t->terminate(); delete t; } } diff --git a/libs/main/thread/pitimer.cpp b/libs/main/thread/pitimer.cpp index f43714ff..114e900e 100644 --- a/libs/main/thread/pitimer.cpp +++ b/libs/main/thread/pitimer.cpp @@ -20,11 +20,8 @@ #include "pitimer.h" #include "piconditionvar.h" -#include "piincludes_p.h" -#include "piliterals.h" -#ifdef PIP_TIMER_RT -# include -#endif +#include "piliterals_time.h" +#include "pithread.h" //! \addtogroup Thread @@ -52,22 +49,22 @@ //! \~russian \section PITimer_sec1 Варианты уведомления //! \~english //! Notify variants: -//! * "slot" - static function with format void func(void * data, int delimiter) or [lambda +//! * "slot" - static function with format void func(int delimiter) or [lambda //! expression](https://en.cppreference.com/w/cpp/language/lambda); //! * event - \a tickEvent(); //! * virtual function - \a tick(). //! -//! Lambda should be [ ]( ){ } or [ ](void*){ } format. +//! Lambda should be [ ]( ){ } or [ ](int){ } format. //! //! All these variants are equivalent, use most applicable. //! \~russian //! Варианты уведомления: -//! * "slot" - статический метод в формате void func(void * data, int delimiter) или +//! * "slot" - статический метод в формате void func(int delimiter) или //! [лямбда-выражение](https://ru.cppreference.com/w/cpp/language/lambda); //! * event - \a tickEvent(); //! * виртуальный метод - \a tick(). //! -//! Лямбда-функция должна быть в формате [ ]( ){ } или [ ](void*){ }. +//! Лямбда-функция должна быть в формате [ ]( ){ } или [ ](int){ }. //! //! Все варианты аналогичны друг другу, используйте самый удобный. //! @@ -89,10 +86,10 @@ //! Пример: //! //! \~\code -//! void tfunc(void * , int delim) { +//! void tfunc(int delim) { //! piCout << "tick with delimiter" << delim; //! }; -//! void tfunc4(void * , int delim) { +//! void tfunc4(int delim) { //! piCout << "tick4 with delimiter" << delim; //! }; //! int main() { @@ -101,8 +98,7 @@ //! timer.addDelimiter(4, tfunc4); //! timer.start(50); //! piMSleep(200); -//! timer.stop(); -//! timer.waitForFinish(); +//! timer.stopAndWait(); //! return 0; //! }; //! /* Result: @@ -119,596 +115,163 @@ //! \} -_PITimerBase::_PITimerBase() { - running_ = false; +PITimer::PITimer(): PIObject() { + initFirst(); } -void _PITimerBase::setInterval(double i) { - interval_ = i; +PITimer::PITimer(std::function func) { + initFirst(); + ret_func = func; +} + + +PITimer::PITimer(std::function func) { + initFirst(); + ret_func = [func](int) { func(); }; +} + + +PITimer::~PITimer() { + stopAndWait(); + piDeleteSafety(thread); +} + + +PISystemTime PITimer::interval() const { + return m_interval; +} + + +void PITimer::setInterval(PISystemTime interval) { + if (m_interval == interval) return; + m_interval = interval; if (isRunning()) { // piCout << "change interval runtime"; - stop(); + stopAndWait(); start(); } } -bool _PITimerBase::start(double interval_ms) { - if (isRunning()) stop(); - deferred_ = false; - setInterval(interval_ms); - // piCout << "_PITimerBase::startTimer"<threadFunc(); } - void adjustTimes(); - bool smallWait(int ms); - - PIThread thread_; - PISystemTime st_time, st_inc, st_wait, st_odt; - PIConditionVariable event; -}; - - -#ifdef PIP_TIMER_RT -struct _PITimerImp_RT_Private_; -class _PITimerImp_RT: public _PITimerBase { -public: - _PITimerImp_RT(); - virtual ~_PITimerImp_RT(); - -protected: - -private: - bool startTimer(double interval_ms) override; - bool stopTimer() override; - - int ti; - _PITimerImp_RT_Private_ * priv; -}; -#endif - - -class _PITimerImp_Pool: public _PITimerImp_Thread { -public: - _PITimerImp_Pool(); - virtual ~_PITimerImp_Pool() { stop(); } - -private: - class Pool: public PIThread { - public: - static Pool * instance(); - void add(_PITimerImp_Pool * t); - void remove(_PITimerImp_Pool * t); - void run() override; - PIVector<_PITimerImp_Pool *> timers, to_remove; - - private: - explicit Pool(); - virtual ~Pool(); - }; - bool startTimer(double interval_ms) override; - bool stopTimer() override; -}; - - -_PITimerImp_Thread::_PITimerImp_Thread() { - thread_.setName("__S__PITimerImp_Thread::thread"_a); - wait_dt = 1000; - wait_dd = 2000; - wait_tick = 1000; - // piCout << "_PITimerImp_Thread" << this << ", thread& =" << &thread_; - // piCout << "new _PITimerImp_Thread"; -} - - -void _PITimerImp_Thread::prepareStart(double interval_ms) { - if (interval_ms <= 0.) { - piCout << "Achtung! Start PITimer with interval <= 0!"; - piCout << "Achtung! Parent" << parent; - assert(interval_ms > 0.); - } - st_inc = PISystemTime::fromMilliseconds(interval_ms); - st_odt = st_inc * 5; - if (st_odt.toSeconds() < 1.) st_odt = 1_s; - if (deferred_) { - if (!deferred_mode) st_time = PISystemTime::current(true) + PISystemTime::fromMilliseconds(deferred_delay); - st_time -= st_inc; - } else - st_time = PISystemTime::current(true) + st_inc; -} - - -bool _PITimerImp_Thread::startTimer(double interval_ms) { - prepareStart(interval_ms); - thread_.setData(this); - return thread_.start(threadFuncS); -} - - -bool _PITimerImp_Thread::stopTimer() { - thread_.stop(); - event.notifyAll(); - thread_.waitForFinish(); - // if (wait) - // if (!thread_.waitForFinish(10)) - // if (thread_.isRunning()) - // thread_.terminate(); - return true; -} - - -bool _PITimerImp_Thread::threadFunc() { - if (!running_) return false; - if (deferred_) { - PISystemTime dwt; - int wth(wait_dt); - if (deferred_mode) { - dwt = deferred_datetime.toSystemTime() - PISystemTime::current(); - wth = wait_dd; - } else - dwt = st_time - PISystemTime::current(true); - if (wth > 0) { - if (dwt.toMilliseconds() > wth + 1.) { - smallWait(wth); - return false; - } else { - if (!smallWait(dwt.toMilliseconds())) return false; - deferred_ = false; - st_time = PISystemTime::current(true); - } - } else { - if (dwt.toMilliseconds() > 0.1) return false; - } - } - st_wait = st_time - PISystemTime::current(true); - // piCout << "wait" << this << st_wait; - if (st_wait.abs() > st_odt || st_wait.seconds <= -5) { - // piCout << &thread_ << "adjust" << "..."; - adjustTimes(); - // piCout << &thread_ << "adjust" << "ok"; - return true; - } - if (wait_tick > 0) { - if (st_wait.toMilliseconds() > wait_tick + 1.) { - smallWait(wait_tick); - return false; - } else { - // piCout << &thread_ << "sleep for" << st_wait; - if (!smallWait(st_wait.toMilliseconds())) return false; - } - } else { - if (st_wait.toMilliseconds() > 0.1) return false; - } - st_time += st_inc; - if (!parent->isPIObject()) { - piCout << "Achtung! PITimer \"parent\" is not PIObject!"; - return false; - } - // piCout << &thread_ << "tfunc" << "..."; - tfunc(parent); - // piCout << &thread_ << "tfunc" << "ok"; - return true; -} - - -void _PITimerImp_Thread::adjustTimes() { - PISystemTime cst = PISystemTime::current(true); - if (st_time < cst) { - int rs = (cst - st_time).toSeconds() / st_inc.toSeconds(); - if (rs >= 100) - st_time = cst + st_inc; - else { - while (st_time < cst) - st_time += st_inc; - } - } else { - int rs = (st_time - cst).toSeconds() / st_inc.toSeconds(); - if (rs >= 100) - st_time = cst - st_inc; - else { - cst += st_inc; - while (st_time > cst) - st_time -= st_inc; - } - } -} - - -bool _PITimerImp_Thread::smallWait(int ms) { - if (thread_.isStopping()) return false; - if (ms > 0) { - thread_.mutex().lock(); - event.waitFor(thread_.mutex(), ms); - thread_.mutex().unlock(); - } - return !thread_.isStopping(); -} - - -#ifdef PIP_TIMER_RT - -void threadFuncS(sigval sv) { - ((_PITimerImp_RT *)sv.sival_ptr)->tfunc(((_PITimerImp_RT *)sv.sival_ptr)->parent); -} - -struct _PITimerImp_RT_Private_ { - itimerspec spec; - timer_t tt; - sigevent se; -}; - -_PITimerImp_RT::_PITimerImp_RT() { - // piCout << "new _PITimerImp_RT"; - priv = new _PITimerImp_RT_Private_(); - priv->tt = 0; - ti = -1; - memset(&(priv->se), 0, sizeof(priv->se)); - priv->se.sigev_notify = SIGEV_THREAD; - priv->se.sigev_value.sival_ptr = this; - priv->se.sigev_notify_function = threadFuncS; - priv->se.sigev_notify_attributes = 0; -} - - -_PITimerImp_RT::~_PITimerImp_RT() { - stop(); - delete priv; -} - - -bool _PITimerImp_RT::startTimer(double interval_ms) { - int flags(0); - priv->spec.it_interval.tv_nsec = ((int)(interval_ms * 1000) % 1000000) * 1000; - priv->spec.it_interval.tv_sec = (time_t)(interval_ms / 1000); - if (deferred_) { - if (deferred_mode) { - PISystemTime dtm = deferred_datetime.toSystemTime(); - priv->spec.it_value.tv_nsec = dtm.nanoseconds; - priv->spec.it_value.tv_sec = dtm.seconds; - flags = TIMER_ABSTIME; - } else { - priv->spec.it_value.tv_nsec = ((int)(deferred_delay * 1000) % 1000000) * 1000; - priv->spec.it_value.tv_sec = (time_t)(deferred_delay / 1000); - } - } else { - priv->spec.it_value = priv->spec.it_interval; - } - ti = timer_create(CLOCK_REALTIME, &(priv->se), &(priv->tt)); - // cout << "***create timer " << msecs << " msecs\n"; - if (ti == -1) { - piCout << "Can`t create RT timer for " << interval_ms << " msecs: " << errorString(); - return false; - } - timer_settime(priv->tt, flags, &(priv->spec), 0); - return true; -} - - -bool _PITimerImp_RT::stopTimer() { - if (ti < 0) return true; - timer_delete(priv->tt); - ti = -1; - priv->tt = 0; - return true; -} - -#endif - - -_PITimerImp_Pool::_PITimerImp_Pool(): _PITimerImp_Thread() { - wait_dt = wait_dd = wait_tick = 0; - // piCout << "new _PITimerImp_Pool"; -} - - -_PITimerImp_Pool::Pool::Pool(): PIThread() { - setName("__S__PITimerImp_Pool::Pool"_a); - needLockRun(true); -#ifndef FREERTOS - timers.reserve(64); - start(PIP_MIN_MSLEEP * 5); -#else - start(PIP_MIN_MSLEEP); -#endif -} - - -_PITimerImp_Pool::Pool::~Pool() { - stop(); - if (!waitForFinish(500)) terminate(); - unlock(); - timers.clear(); -} - - -_PITimerImp_Pool::Pool * _PITimerImp_Pool::Pool::instance() { - static Pool pool; - return &pool; -} - - -void _PITimerImp_Pool::Pool::add(_PITimerImp_Pool * t) { - // piCout << "add ..."; - lock(); - to_remove.removeAll(t); - if (!timers.contains(t)) timers << t; - unlock(); - // piCout << "add done"; -} - - -void _PITimerImp_Pool::Pool::remove(_PITimerImp_Pool * t) { - // piCout << "remove ..."; - lock(); - to_remove << t; - unlock(); - // piCout << "remove done"; -} - - -void _PITimerImp_Pool::Pool::run() { - if (!to_remove.isEmpty()) { - piForeach(_PITimerImp_Pool * t, to_remove) - timers.removeAll(t); - to_remove.clear(); - } - piForeach(_PITimerImp_Pool * t, timers) - t->threadFunc(); -} - - -bool _PITimerImp_Pool::startTimer(double interval_ms) { - prepareStart(interval_ms); - Pool::instance()->add(this); - return true; -} - - -bool _PITimerImp_Pool::stopTimer() { - Pool::instance()->remove(this); - return true; -} - - -PITimer::PITimer(): PIObject() { -#ifdef FREERTOS - imp_mode = PITimer::Thread; -#else - imp_mode = PITimer::Thread; -#endif - initFirst(); -} - - -PITimer::PITimer(PITimer::TimerImplementation ti): PIObject() { - imp_mode = ti; - initFirst(); -} - - -PITimer::PITimer(TimerEvent slot, void * data, PITimer::TimerImplementation ti): PIObject() { - imp_mode = ti; - initFirst(); - data_t = data; - ret_func = slot; -} - - -PITimer::PITimer(std::function slot, PITimer::TimerImplementation ti) { - imp_mode = ti; - initFirst(); - ret_func = [slot](void *, int) { slot(); }; -} - - -PITimer::PITimer(std::function slot, void * data, PITimer::TimerImplementation ti) { - imp_mode = ti; - initFirst(); - data_t = data; - ret_func = [slot](void * d, int) { slot(d); }; -} - - -PITimer::~PITimer() { - destroy(); -} - - -double PITimer::interval() const { - init(); - return imp->interval_; -} - - -void PITimer::setInterval(double ms) { - init(); - setProperty("interval", ms); - imp->setInterval(ms); -} - - bool PITimer::isRunning() const { - init(); - return imp->running_; + return thread->isRunning(); } -bool PITimer::isStopped() const { - init(); - return !imp->running_; +bool PITimer::isStopping() const { + return thread->isStopping(); +} + + +bool PITimer::waitForFinish(PISystemTime timeout) { + return thread->waitForFinish(timeout); } void PITimer::initFirst() { - lockRun = false; - callEvents = true; - setProperty("interval", 0.); + thread = new PIThread([this] { threadFunc(); }); + thread->setName("__S__.PITimer.thread"); + setProperty("interval", PISystemTime()); } -void PITimer::init() const { - if (imp) return; - switch (imp_mode) { - case PITimer::Pool: imp = new _PITimerImp_Pool(); break; - case PITimer::ThreadRT: -#ifdef PIP_TIMER_RT - imp = new _PITimerImp_RT(); - break; -#else - piCoutObj << "Warning: \"ThreadRT\" is not available at this system! Using \"Thread\"."; -#endif - case PITimer::Thread: imp = new _PITimerImp_Thread(); break; - default: piCout << "Fatal: invalid implementation() of" << this << "!"; assert(0); +void PITimer::threadFunc() { + PISystemTime st_wait = m_time_next - PISystemTime::current(true); + // piCout << "wait" << this << st_wait; + if (st_wait.abs() > m_interval_x5 || st_wait.seconds <= -5) { + // piCout << &thread_ << "adjust" << "..."; + adjustTimes(); + // piCout << &thread_ << "adjust" << "ok"; + return; } - if (!imp) return; - // piCout << this << "init" << imp; - imp->tfunc = tickImpS; - imp->parent = const_cast(this); + if (thread->isStopping()) return; + if (st_wait.isPositive()) { + thread->mutex().lock(); + event.waitFor(thread->mutex(), st_wait); + thread->mutex().unlock(); + } + if (thread->isStopping()) return; + m_time_next += m_interval; + // piCout << &thread_ << "tfunc" << "..."; + execTick(); } -void PITimer::destroy() { - if (!imp) return; - // piCout << this << "destroy" << imp; - imp->stop(); - delete imp; - imp = 0; +void PITimer::adjustTimes() { + PISystemTime cst = PISystemTime::current(true); + if (m_time_next < cst) { + int rs = (cst - m_time_next).toSeconds() / m_interval.toSeconds(); + if (rs >= 100) + m_time_next = cst + m_interval; + else { + while (m_time_next < cst) + m_time_next += m_interval; + } + } else { + int rs = (m_time_next - cst).toSeconds() / m_interval.toSeconds(); + if (rs >= 100) + m_time_next = cst - m_interval; + else { + cst += m_interval; + while (m_time_next > cst) + m_time_next -= m_interval; + } + } } -void PITimer::tickImp() { +void PITimer::execTick() { if (!isRunning()) return; if (lockRun) lock(); - if (ret_func) ret_func(data_t, 1); - tick(data_t, 1); - tickEvent(data_t, 1); + if (ret_func) ret_func(1); + tick(1); + tickEvent(1); if (callEvents) maybeCallQueuedEvents(); - piForeach(Delimiter & i, delims) { + for (Delimiter & i: delims) { if (i.delim > ++(i.tick)) continue; i.tick = 0; - if (i.slot) - i.slot(data_t, i.delim); + if (i.func) + i.func(i.delim); else if (ret_func) - ret_func(data_t, i.delim); - tick(data_t, i.delim); - tickEvent(data_t, i.delim); + ret_func(i.delim); + tick(i.delim); + tickEvent(i.delim); } if (lockRun) unlock(); } bool PITimer::start() { - init(); - // piCout << this << "start" << imp; - return imp->start(); + if (isRunning()) return true; + m_interval_x5 = m_interval * 5; + if (m_interval_x5.toSeconds() < 1.) m_interval_x5 = 1_s; + m_time_next = PISystemTime::current(true) + m_interval; + if (!thread->start()) return false; + return thread->waitForStart(); } -bool PITimer::start(double interval_ms_d) { - init(); - // piCout << this << "start" << imp << interval_ms_d; - setProperty("interval", interval_ms_d); - return imp->start(interval_ms_d); +bool PITimer::start(PISystemTime interval) { + if (isRunning()) stopAndWait(); + setInterval(interval); + return start(); } -bool PITimer::start(int interval_ms_i) { - return start((double)interval_ms_i); +void PITimer::stopAndWait(PISystemTime timeout) { + stop(); + thread->waitForFinish(timeout); } -//! \~\details -//! \~english -//! Timer wait "delay_msecs" milliseconds and then normally starts with \a interval() loop delay -//! \~russian -//! Таймер ожидает "delay_msecs" миллисекунд, а затем стартует с интервалом \a interval() -void PITimer::startDeferred(double delay_ms) { - init(); - imp->startDeferred(delay_ms); +void PITimer::addDelimiter(int delim, std::function func) { + delims << Delimiter(func, delim); } -//! \~\details -//! \~english -//! Timer wait "delay_msecs" milliseconds and then normally starts with "interval_msecs" loop delay -//! \~russian -//! Таймер ожидает "delay_msecs" миллисекунд, а затем стартует с интервалом "interval_msecs" -void PITimer::startDeferred(double interval_ms, double delay_ms) { - init(); - imp->startDeferred(interval_ms, delay_ms); -} - - -//! \~\details -//! \~english -//! Timer wait until "start_datetime" and then normally starts with \a interval() loop delay -//! \~russian -//! Таймер ожидает наступления "start_datetime", а затем стартует с интервалом \a interval() -void PITimer::startDeferred(PIDateTime start_datetime) { - startDeferred(imp->interval_, start_datetime); -} - - -//! \~\details -//! \~english -//! Timer wait until "start_datetime" and then normally starts with "interval_msecs" loop delay -//! \~russian -//! Таймер ожидает наступления "start_datetime", а затем стартует с интервалом "interval_msecs" -void PITimer::startDeferred(double interval_ms, PIDateTime start_datetime) { - init(); - imp->startDeferred(interval_ms, start_datetime); -} - - -void PITimer::addDelimiter(int delim, std::function slot) { - delims << Delimiter([slot](void * d, int) { slot(d); }, delim); +void PITimer::addDelimiter(int delim, std::function func) { + delims << Delimiter([func](int) { func(); }, delim); } @@ -722,14 +285,12 @@ void PITimer::removeDelimiter(int delim) { bool PITimer::restart() { - init(); - imp->stop(); - return imp->start(); + stopAndWait(); + return start(); } -bool PITimer::stop() { - init(); - // piCout << this << "stop" << imp << wait; - return imp->stop(); +void PITimer::stop() { + thread->stop(); + event.notifyAll(); } diff --git a/libs/main/thread/pitimer.h b/libs/main/thread/pitimer.h index 89daf598..73ef373c 100644 --- a/libs/main/thread/pitimer.h +++ b/libs/main/thread/pitimer.h @@ -26,50 +26,12 @@ #ifndef PITIMER_H #define PITIMER_H -#include "pithread.h" -#include "pitime.h" +#include "piconditionvar.h" +#include "piobject.h" +#include "pisystemtime.h" -typedef std::function TimerEvent; - -class PITimer; - -class PIP_EXPORT _PITimerBase { - friend class PITimer; - -public: - _PITimerBase(); - virtual ~_PITimerBase() {} - - double interval() const { return interval_; } - void setInterval(double i); - - bool isRunning() const { return running_; } - - bool isStopped() const { return !running_; } - - bool start() { return start(interval_); } - bool start(double interval_ms); - void startDeferred(double delay_ms) { startDeferred(interval_, delay_ms); } - void startDeferred(double interval_ms, double delay_ms); - void startDeferred(PIDateTime start_datetime) { startDeferred(interval_, start_datetime); } - void startDeferred(double interval_ms, PIDateTime start_datetime); - - bool stop(); - - typedef void (*TickFunc)(PITimer *); - TickFunc tfunc = nullptr; - PITimer * parent = nullptr; - -protected: - virtual bool startTimer(double interval_ms) = 0; - virtual bool stopTimer() = 0; - - double interval_ = 1000., deferred_delay = 0.; - bool deferred_ = false, deferred_mode = false; // mode: true - date, false - delay - std::atomic_bool running_; - PIDateTime deferred_datetime; -}; +class PIThread; class PIP_EXPORT PITimer: public PIObject { PIOBJECT_SUBCLASS(PITimer, PIObject); @@ -77,118 +39,70 @@ class PIP_EXPORT PITimer: public PIObject { public: NO_COPY_CLASS(PITimer); - //! \~english Constructs timer with PITimer::Thread implementation - //! \~russian Создает таймер с реализацией PITimer::Thread + //! \~english Constructs timer + //! \~russian Создает таймер explicit PITimer(); - //! \~english Timer implementations - //! \~russian Реализация таймера - enum TimerImplementation { - Thread /*! - \~english Timer works in his own thread. Intervals are measured by the system time - \~russian Таймер работает в собственном потоке. Интервалы измеряются с помощью системного времени - */ - = 0x01, - ThreadRT /*! - \~english Using POSIX timer with SIGEV_THREAD notification. \attention Doesn`t support on Windows and Mac OS! - \~russian Использовать таймер POSIX с SIGEV_THREAD уведомлением. \attention Не поддерживается на Windows и Mac OS! - */ - = 0x02, - Pool /*! - \~english Using single TimerPool for all timers with this implementation. TimerPool works as Thread implementation and - sequentially executes all timers. \attention Use this implementation with care! - \~russian Использовать единый TimerPool для всех таймеров с этой реализацией. TimerPool реализован через Thread и - последовательно исполняет все таймеры. \attention Осторожнее с этой реализацией! - */ - = 0x04 - }; + //! \~english Constructs timer with method void(int) + //! \~russian Создает таймер с функцией void(int) + explicit PITimer(std::function func); - //! \~english Constructs timer with "ti" implementation - //! \~russian Создает таймер с реализацией "ti" - explicit PITimer(TimerImplementation ti); - - //! \~english Constructs timer with "slot" slot void(void *,int), "data" data and "ti" implementation - //! \~russian Создает таймер со слотом "slot", данными "data" и реализацией "ti" - explicit PITimer(TimerEvent slot, void * data = 0, TimerImplementation ti = Thread); - - //! \~english Constructs timer with "slot" slot void(), and "ti" implementation - //! \~russian Создает таймер со слотом "slot" и реализацией "ti" - explicit PITimer(std::function slot, TimerImplementation ti = Thread); - - //! \~english Constructs timer with "slot" slot void(void *), "data" data and "ti" implementation - //! \~russian Создает таймер со слотом "slot", данными "data" и реализацией "ti" - explicit PITimer(std::function slot, void * data, TimerImplementation ti = Thread); + //! \~english Constructs timer with method void() + //! \~russian Создает таймер с функцией void() + explicit PITimer(std::function func); virtual ~PITimer(); + //! \~english Returns timer loop delay + //! \~russian Возвращает задержку цикла таймера + PISystemTime interval() const; - //! \~english Returns timer implementation - //! \~russian Возвращает реализацию таймера - PITimer::TimerImplementation implementation() const { return imp_mode; } - - //! \~english Returns timer loop delay in milliseconds - //! \~russian Возвращает задержку цикла таймера в миллисекундах - double interval() const; - - EVENT_HANDLER1(void, setInterval, double, ms); - void setInterval(PISystemTime interval) { setInterval(interval.toMilliseconds()); } + //! \~english Set timer loop delay + //! \~russian Установить интервал таймера + void setInterval(PISystemTime interval); //! \~english Returns if timer is started //! \~russian Возвращает работает ли таймер bool isRunning() const; - //! \~english Returns if timer is not started - //! \~russian Возвращает остановлен ли таймер - bool isStopped() const; + //! \~english Return if timer is stopping + //! \~russian Возвращает останавливается ли таймер + bool isStopping() const; + //! \~english Wait for timer stop + //! \~russian Ожидает остановки таймера + bool waitForFinish(PISystemTime timeout = {}); + + //! \fn bool start(PISystemTime interval) + //! \brief + //! \~english Start timer with "interval" loop delay + //! \~russian Запустить таймер с интервалом "interval" + bool start(PISystemTime interval); + + bool start(double interval_ms) DEPRECATEDM("use start(PISystemTime)") { return start(PISystemTime::fromMilliseconds(interval_ms)); } EVENT_HANDLER0(bool, start); - EVENT_HANDLER1(bool, start, double, interval_ms_d); - bool start(int interval_ms_i); - bool start(PISystemTime interval) { return start(interval.toMilliseconds()); } + EVENT_HANDLER0(bool, restart); + EVENT_HANDLER0(void, stop); - //! \~english Start timer with \a interval() loop delay after "delay_msecs" delay - //! \~russian Запускает таймер с интервалом \a interval() после ожидания "delay_msecs" - void startDeferred(double delay_ms); + //! \~english Stop timer and wait for finish. + //! \~russian Останавливает таймер и ожидает завершения. + void stopAndWait(int timeout_ms) { stopAndWait(PISystemTime::fromMilliseconds(timeout_ms)); } - //! \~english Start timer with "interval_msecs" loop delay after "delay_msecs" delay - //! \~russian Запускает таймер с интервалом "interval_msecs" после ожидания "delay_msecs" - void startDeferred(double interval_ms, double delay_ms); - - //! \~english Start timer with \a interval() loop delay after "start_datetime" date and time - //! \~russian Запускает таймер с интервалом \a interval() после наступления "start_datetime" - void startDeferred(PIDateTime start_datetime); - - //! \~english Start timer with "interval_msecs" loop delay after "start_datetime" date and time - //! \~russian Запускает таймер с интервалом "interval_msecs" после наступления "start_datetime" - void startDeferred(double interval_ms, PIDateTime start_datetime); - - EVENT_HANDLER0(bool, stop); - - //! \~english Set custom data - //! \~russian Установить данные, передаваемые в метод таймера - void setData(void * data_) { data_t = data_; } - - //! \~english Returns common data passed to tick functions - //! \~russian Возвращает данные, передаваемые в метод таймера - void * data() const { return data_t; } + //! \~english Stop timer and wait for finish. + //! \~russian Останавливает таймер и ожидает завершения. + void stopAndWait(PISystemTime timeout = {}); //! \~english Set timer tick function //! \~russian Установить вызываемый метод - void setSlot(TimerEvent slot) { ret_func = slot; } - - //! \~english Set timer tick function - //! \~russian Установить вызываемый метод - void setSlot(std::function slot) { - ret_func = [slot](void *, int) { slot(); }; + void setSlot(std::function func) { + ret_func = [func](int) { func(); }; } //! \~english Set timer tick function //! \~russian Установить вызываемый метод - void setSlot(std::function slot) { - ret_func = [slot](void * d, int) { slot(d); }; - } + void setSlot(std::function func) { ret_func = func; } void needLockRun(bool need) { lockRun = need; } EVENT_HANDLER0(void, lock) { mutex_.lock(); } @@ -204,13 +118,11 @@ public: //! \~english Add frequency delimiter "delim" with optional delimiter slot "slot" //! \~russian Добавляет делитель частоты "delim" с необязательным методом "slot" - void addDelimiter(int delim, TimerEvent slot = 0) { delims << Delimiter(slot, delim); } + void addDelimiter(int delim, std::function func = nullptr); //! \~english Add frequency delimiter "delim" with optional delimiter slot "slot" //! \~russian Добавляет делитель частоты "delim" с необязательным методом "slot" - void addDelimiter(int delim, std::function slot) { - delims << Delimiter([slot](void *, int) { slot(); }, delim); - } + void addDelimiter(int delim, std::function func); //! \~english Add frequency delimiter "delim" with optional delimiter slot "slot" //! \~russian Добавляет делитель частоты "delim" с необязательным методом "slot" @@ -222,39 +134,15 @@ public: EVENT_HANDLER0(void, clearDelimiters) { delims.clear(); } - EVENT2(tickEvent, void *, data_, int, delimiter); + EVENT1(tickEvent, int, delimiter); //! \handlers //! \{ - //! \fn void setInterval(double ms) - //! \brief - //! \~english Set timer loop delay in milliseconds - //! \~russian Установить интервал таймера "ms" миллисекунд - //! \fn bool start() //! \brief //! \~english Start timer with \a interval() loop delay //! \~russian Запустить таймер с интервалом \a interval() - //! \~\details - //! \~english - //! Start execution of timer functions with frequency = 1 / msecs Hz - //! \~russian - //! Запускает таймер с частотой = 1 / msecs Гц - - //! \fn bool start(double msecs) - //! \brief - //! \~english Start timer with "msecs" loop delay - //! \~russian Запустить таймер с интервалом "msecs" - //! \~\details - //! \~english - //! Start execution of timer functions with frequency = 1. / msecs Hz. - //! Instead of \a start(int msecs) this function allow start timer - //! with frequencies more than 1 kHz - //! \~russian - //! Запускает таймер с частотой = 1 / msecs Гц. В отличии от - //! \a start(int msecs) этот метод позволяет запустить таймер с частотой - //! более 1 кГц //! \fn bool restart() //! \brief @@ -263,8 +151,8 @@ public: //! \fn bool stop() //! \brief - //! \~english Stop timer and wait for it finish - //! \~russian Остановить таймер и дождаться остановки + //! \~english Stop timer (don`t wait for finish) + //! \~russian Остановить таймер (не дожидается остановки) //! \fn void clearDelimiters() //! \brief @@ -275,16 +163,14 @@ public: //! \events //! \{ - //! \fn void tickEvent(void * data, int delimiter) + //! \fn void tickEvent(int delimiter) //! \brief //! \~english Raise on timer tick //! \~russian Вызывается каждый тик таймера //! \~\details //! \~english - //! "data" can be set with function \a setData() or from constructor. //! "delimiter" is frequency delimiter, 1 for main loop. //! \~russian - //! "data" устанавливается методом \a setData() или в конструкторе. //! "delimiter" - делитель частоты, 1 для основного цикла @@ -292,33 +178,33 @@ public: protected: struct PIP_EXPORT Delimiter { - Delimiter(TimerEvent slot_ = 0, int delim_ = 1) { - slot = slot_; + Delimiter(std::function func_ = nullptr, int delim_ = 1) { + func = func_; delim = delim_; } - TimerEvent slot; + std::function func; int delim = 0; int tick = 0; }; void initFirst(); void init() const; - void destroy(); - static void tickImpS(PITimer * t) { t->tickImp(); } - void tickImp(); + void threadFunc(); + void adjustTimes(); + void execTick(); //! Timer execution function, similar to "slot" or event \a timeout(). By default does nothing - virtual void tick(void * data_, int delimiter) {} + virtual void tick(int delimiter) {} - void * data_t = nullptr; - std::atomic_bool lockRun, callEvents; + PIThread * thread = nullptr; + std::atomic_bool lockRun = {false}, callEvents = {true}; PIMutex mutex_; - TimerEvent ret_func = nullptr; - TimerImplementation imp_mode = Thread; + PISystemTime m_interval, m_interval_x5; + PISystemTime m_time_next; + std::function ret_func = nullptr; PIVector delims; - - mutable _PITimerBase * imp = nullptr; + PIConditionVariable event; }; diff --git a/libs/main/types/pisystemtime.h b/libs/main/types/pisystemtime.h index a427b2ef..0fc0d7d2 100644 --- a/libs/main/types/pisystemtime.h +++ b/libs/main/types/pisystemtime.h @@ -194,6 +194,18 @@ public: //! \~russian Возвращает нулевое ли время bool isNull() const { return (seconds == 0) && (nanoseconds == 0); } + //! \~english Returns if time is not null + //! \~russian Возвращает не нулевое ли время + bool isNotNull() const { return !isNull(); } + + //! \~english Returns if time is greater than 0 + //! \~russian Возвращает больше ли 0 время + bool isPositive() const { return (seconds >= 0) && (nanoseconds >= 0); } + + //! \~english Returns if time is lesser than 0 + //! \~russian Возвращает меньше ли 0 время + bool isNegative() const { return (seconds < 0) || (nanoseconds < 0); } + //! \~english Returns time value in seconds //! \~russian Возвращает значение времени в секундах double toSeconds() const { return double(seconds) + nanoseconds / 1.e+9; } diff --git a/main_picloud_test.cpp b/main_picloud_test.cpp index 35dedfe0..797dc648 100644 --- a/main_picloud_test.cpp +++ b/main_picloud_test.cpp @@ -1,6 +1,6 @@ +#include "piliterals_time.h" #include "pip.h" - int main(int argc, char * argv[]) { PIByteArray rnd; rnd.resize(1024 * 1024, 'x'); @@ -12,7 +12,7 @@ int main(int argc, char * argv[]) { // c.setReopenEnabled(true); PICloudServer s("127.0.0.1:10101"); auto clients = new PIVector(); - CONNECTL(&tm, tickEvent, ([&](void *, int) { + CONNECTL(&tm, tickEvent, ([&](int) { if (c.isConnected()) { PIString str = "ping"; piCout << "[Client] send:" << str; @@ -67,7 +67,7 @@ int main(int argc, char * argv[]) { } else { s.startThreadedRead(); } - tm.start(1000); + tm.start(1_Hz); PIKbdListener ls; ls.enableExitCapture(PIKbdListener::F10); ls.start(); diff --git a/utils/cloud_dispatcher/dispatcherserver.cpp b/utils/cloud_dispatcher/dispatcherserver.cpp index ea9933bc..910c2715 100644 --- a/utils/cloud_dispatcher/dispatcherserver.cpp +++ b/utils/cloud_dispatcher/dispatcherserver.cpp @@ -1,5 +1,6 @@ #include "dispatcherserver.h" +#include "piliterals_time.h" #include "piscreentiles.h" @@ -22,7 +23,7 @@ DispatcherServer::~DispatcherServer() { void DispatcherServer::start() { eth.listen(true); - timeout_timer.start(2000); + timeout_timer.start(0.5_Hz); piCoutObj << "server started" << eth.readAddress(); } diff --git a/utils/cloud_dispatcher/dispatcherserver.h b/utils/cloud_dispatcher/dispatcherserver.h index a9b01c10..28611525 100644 --- a/utils/cloud_dispatcher/dispatcherserver.h +++ b/utils/cloud_dispatcher/dispatcherserver.h @@ -2,6 +2,7 @@ #define DISPATCHERSERVER_H #include "cloudserver.h" +#include "pitimer.h" class TileList; diff --git a/utils/cloud_dispatcher/main.cpp b/utils/cloud_dispatcher/main.cpp index 61ab83e7..273e1893 100644 --- a/utils/cloud_dispatcher/main.cpp +++ b/utils/cloud_dispatcher/main.cpp @@ -18,9 +18,14 @@ */ #include "dispatcherserver.h" -#include "picrypt.h" +#include "picli.h" +#include "piconfig.h" +#include "pidir.h" #include "piiostream.h" -#include "pip.h" +#include "piliterals_time.h" +#include "piscreen.h" +#include "piscreentiles.h" +#include "piscreentypes.h" using namespace PICoutManipulators; @@ -127,7 +132,7 @@ int main(int argc, char * argv[]) { a.children()[0]->size_policy = PIScreenTypes::Fixed; maintile.addTile(&a); } - CONNECTL(&status_timer, tickEvent, [&](void *, int) { + CONNECTL(&status_timer, tickEvent, [&](int) { screen.lock(); server.updateConnectionsTile(&conn_tl); server.updateServersTile(&server_tl, sel_servers); @@ -142,7 +147,7 @@ int main(int argc, char * argv[]) { screen.rootTile()->addTile(new TilePICout()); screen.start(); server.start(); - status_timer.start(100); + status_timer.start(10_Hz); screen.waitForFinish(); } else { PIKbdListener ls; @@ -151,7 +156,7 @@ int main(int argc, char * argv[]) { server.start(); if (cli.hasArgument("verbose")) { CONNECTU(&status_timer, tickEvent, &server, picoutStatus); - status_timer.start(1000); + status_timer.start(1_Hz); } WAIT_FOR_EXIT } diff --git a/utils/piterminal/main.cpp b/utils/piterminal/main.cpp index 73164a56..cc33f83a 100644 --- a/utils/piterminal/main.cpp +++ b/utils/piterminal/main.cpp @@ -26,6 +26,7 @@ int main(int argc, char * argv[]) { # define PIP_CONSOLE_STATIC_DEFINE # include "../../libs/console/piterminal.cpp" # include "pifile.h" +# include "piliterals_time.h" # include "pip_console_export.h" # include "piscreentypes.h" # include "pisharedmemory.h" @@ -164,9 +165,12 @@ public: PipeReader(): PIThread() { wrote = readed = 0; msg_size = 0; - start(1); + start(1_ms); + } + ~PipeReader() { + stop(); + if (!waitForFinish(100_ms)) terminate(); } - ~PipeReader() { stop(); } void run() { in.resize(PIPE_BUFFER_SIZE); ReadFile(pipe, in.data(), in.size_s(), &readed, 0); diff --git a/utils/system_daemon/daemon.cpp b/utils/system_daemon/daemon.cpp index e1680aba..4abe8e3b 100644 --- a/utils/system_daemon/daemon.cpp +++ b/utils/system_daemon/daemon.cpp @@ -1,6 +1,7 @@ #include "daemon.h" #include "picrypt.h" +#include "piliterals_time.h" #include "pisysteminfo.h" #include "shared.h" @@ -23,6 +24,7 @@ Daemon::Remote::Remote(const PIString & n): PIThread() { Daemon::Remote::~Remote() { + term_timer.stopAndWait(); shellClose(); ft.stop(); stopAndWait(); @@ -34,14 +36,14 @@ void Daemon::Remote::shellOpen() { piCoutObj << "shell open"; term = new PITerminal(); term->initialize(); - term_timer.start(50); + term_timer.start(20_Hz); } void Daemon::Remote::shellClose() { if (!term) return; piCoutObj << "shell close"; - term_timer.stop(); + term_timer.stopAndWait(); term->destroy(); delete term; term = 0; @@ -272,7 +274,7 @@ Daemon::Daemon(): PIPeer(pisd_prefix + PISystemInfo::instance()->hostname + "_" localft.setCRCEnabled(false); CONNECTU(&localft, sendRequest, _self, received) dtimer.addDelimiter(5); - dtimer.start(200); + dtimer.start(5_Hz); tile_root = new PIScreenTile(); tile_root->direction = Vertical; @@ -320,6 +322,7 @@ Daemon::Daemon(): PIPeer(pisd_prefix + PISystemInfo::instance()->hostname + "_" Daemon::~Daemon() { + dtimer.stopAndWait(); requestCloseShell(); PIVector rl = remotes.values(); piForeach(Remote * r, rl) { @@ -547,7 +550,7 @@ void Daemon::fmActionRequest(bool remote_tile, FileManager::Action type, PIVaria } -void Daemon::timerEvent(void * _d, int delim) { +void Daemon::timerEvent(int delim) { screen->lock(); list_daemons->content.clear(); availableDaemons(); diff --git a/utils/system_daemon/daemon.h b/utils/system_daemon/daemon.h index 72ba6d64..6344ad47 100644 --- a/utils/system_daemon/daemon.h +++ b/utils/system_daemon/daemon.h @@ -2,7 +2,6 @@ #define DAEMON_H #include "file_manager.h" -#include "pidatatransfer.h" #include "pifiletransfer.h" #include "pipeer.h" #include "piscreentiles.h" @@ -165,7 +164,7 @@ private: EVENT_HANDLER3(void, fmActionRequest, bool, remote_tile, FileManager::Action, type, PIVariant, data); EVENT_HANDLER(void, shResizeRequest); EVENT_HANDLER1(void, shKeyEvent, PIKbdListener::KeyEvent, k); - EVENT_HANDLER2(void, timerEvent, void *, _d, int, delim); + EVENT_HANDLER1(void, timerEvent, int, delim); EVENT_HANDLER2(void, filesReceived, const PIString &, p_name, bool, ok); EVENT_HANDLER2(void, filesSended, const PIString &, p_name, bool, ok); EVENT_HANDLER2(void, dirChanged, const PIString &, p_name, const PIString &, dir); diff --git a/utils/system_daemon/main.cpp b/utils/system_daemon/main.cpp index 7dd4a54e..899f8379 100755 --- a/utils/system_daemon/main.cpp +++ b/utils/system_daemon/main.cpp @@ -21,20 +21,19 @@ #include "file_manager.h" #include "picli.h" #include "piintrospection_server.h" +#include "piliterals_time.h" #include "piprocess.h" #include "pisingleapplication.h" #include "pisysteminfo.h" #include "pisystemmonitor.h" #include "shared.h" -class _Init { -public: - _Init() { randomize(); } -}; -_Init _pisd_init; +STATIC_INITIALIZER_BEGIN + randomize(); +STATIC_INITIALIZER_END PISystemMonitor sys_mon; -PIScreen * screen = 0; +PIScreen * screen = nullptr; class MainMenu: public PITimer { @@ -93,7 +92,7 @@ public: CONNECTU(screen, tileEvent, this, tileEvent) CONNECTU(screen, keyPressed, this, keyEvent) CONNECTU(&daemon_, menuRequest, this, menuRequest) - start(25); + start(40_Hz); } PIScreenTile * menuTile() { TileList * ret = new TileList(); @@ -185,13 +184,19 @@ public: addrs_tl->content.clear(); peerinfo_tl->content.clear(); peermap_tl->content.clear(); - peers_tl->content << TileList::Row("this | 0 | 0 | " + PIString::fromNumber(daemon_.allPeers().size_s()) - // + " [em = " + PIString::fromBool(daemon_.lockedEth()) + ", - //" "mm = " + PIString::fromBool(daemon_.lockedMBcasts()) + ", " "sm = " + - //PIString::fromBool(daemon_.lockedSends()) + ", " "ms = " + - //PIString::fromBool(daemon_.lockedMCSends()) + ", " "pm = " + PIString::fromBool(pm) + "]" - , - CellFormat()); + peers_tl->content << TileList::Row( + "this | 0 | 0 | " + PIString::fromNumber(daemon_.allPeers().size_s()) + // + " [em = " + PIString::fromBool(daemon_.lockedEth()) + ", + //" "mm = " + PIString::fromBool(daemon_.lockedMBcasts()) + ", " + //"sm + //= + //" + //+ PIString::fromBool(daemon_.lockedSends()) + ", " "ms = " + + // PIString::fromBool(daemon_.lockedMCSends()) + ", " "pm = " + PIString::fromBool(pm) + // + + // "]" + , + CellFormat()); piForeachC(PIPeer::PeerInfo & p, daemon_.allPeers()) peers_tl->content << TileList::Row(p.name + " | d = " + PIString::fromNumber(p.dist) + " | p = " + PIString::fromNumber(p.ping()) + " | n = " + PIString::fromBool(p.isNeighbour()), @@ -246,7 +251,7 @@ public: } screen->unlock(); } - void tick(void * data_, int delimiter) override { + void tick(int delimiter) override { if (tpeerdiag->visible || tpeer->visible) updatePeerInfo(); if (tinfo->visible) updateSysMon(); } @@ -420,7 +425,7 @@ int main(int argc, char * argv[]) { ls.enableExitCapture(PIKbdListener::F10); ls.start(); WAIT_FOR_EXIT - ls.stop(); + ls.stopAndWait(); } else { screen->start(); screen->waitForFinish(); diff --git a/utils/udp_file_transfer/main.cpp b/utils/udp_file_transfer/main.cpp index 778bfbfb..c0218e1b 100644 --- a/utils/udp_file_transfer/main.cpp +++ b/utils/udp_file_transfer/main.cpp @@ -17,9 +17,11 @@ along with this program. If not, see . */ +#include "picli.h" #include "pidatatransfer.h" +#include "piethernet.h" #include "pifiletransfer.h" -#include "pip.h" +#include "piliterals_time.h" #include "piscreen.h" #include "piscreentiles.h" @@ -52,7 +54,7 @@ public: CONNECTU(&ft, receiveFilesFinished, this, ftevent); } CONNECT2(void, const uchar *, ssize_t, ð, threadedReadEvent, this, received); - start(50); + start(20_Hz); eth.setParameter(PIEthernet::SeparateSockets); eth.startThreadedRead(); } @@ -74,7 +76,7 @@ private: PIEthernet eth; bool quet_; - void tick(void *, int) override { + void tick(int) override { if (ft.isStarted()) { ftevent(); updatePMT();