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();