version 4.0.0_alpha
in almost all methods removed timeouts in milliseconds, replaced to PISystemTime PITimer rewrite, remove internal impl, now only thread implementation, API similar to PIThread PITimer API no longer pass void* PIPeer, PIConnection improved stability on reinit and exit PISystemTime new methods pisd now exit without hanging
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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:
|
||||
@@ -53,16 +52,15 @@ int main() {
|
||||
t0 -= PISystemTime::fromSeconds(0.1); // s = 1, ns = 0
|
||||
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 _(){
|
||||
|
||||
|
||||
};
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "piscreen.h"
|
||||
|
||||
#include "piincludes_p.h"
|
||||
#include "piliterals_time.h"
|
||||
#ifndef WINDOWS
|
||||
# include <fcntl.h>
|
||||
# include <sys/ioctl.h>
|
||||
@@ -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();
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -167,7 +167,8 @@ PIKbdListener::PIKbdListener(KBFunc slot, void * _d, bool startNow): PIThread()
|
||||
|
||||
|
||||
PIKbdListener::~PIKbdListener() {
|
||||
terminate();
|
||||
stop();
|
||||
if (!waitForFinish(100_ms)) terminate();
|
||||
end();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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" необязателен
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<PIPair<PIByteArray, ullong>> 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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "pidir.h"
|
||||
#include "piincludes_p.h"
|
||||
#include "pipropertystorage.h"
|
||||
#include "pitime.h"
|
||||
#include "piwaitevent_p.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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<PIIODevice *>(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())
|
||||
|
||||
@@ -387,12 +387,12 @@ private:
|
||||
|
||||
public:
|
||||
Sender(PIConnection * parent_ = 0);
|
||||
~Sender() { stop(); }
|
||||
~Sender() { stopAndWait(); }
|
||||
PIConnection * parent;
|
||||
PIVector<PIIODevice *> devices;
|
||||
PIByteArray sdata;
|
||||
float int_;
|
||||
void tick(void *, int) override;
|
||||
PISystemTime int_;
|
||||
void tick(int) override;
|
||||
};
|
||||
|
||||
PIMap<PIString, Extractor *> extractors;
|
||||
|
||||
@@ -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<Entry> & 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);
|
||||
|
||||
@@ -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<Entry> & hist, int & cnt);
|
||||
void propertyChanged(const char *) override;
|
||||
void changeDisconnectTimeout(float disct);
|
||||
void changeDisconnectTimeout(PISystemTime disct);
|
||||
|
||||
PIQueue<Entry> history_rec, history_send;
|
||||
float disconn_ = 0.f;
|
||||
PISystemTime disconn_;
|
||||
State cur_state;
|
||||
mutable PIMutex mutex_state;
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -17,11 +17,12 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "piliterals_time.h"
|
||||
#include "pitime.h"
|
||||
#ifndef MICRO_PIP
|
||||
|
||||
# include "piprocess.h"
|
||||
|
||||
# include "piincludes_p.h"
|
||||
# include "piprocess.h"
|
||||
# ifndef WINDOWS
|
||||
# include <csignal>
|
||||
# include <sys/wait.h>
|
||||
@@ -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_;
|
||||
|
||||
@@ -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
|
||||
|
||||
//! \}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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,6 +190,7 @@ void PISystemMonitor::run() {
|
||||
if (t->isPIObject()) gatherThread(t->tid());
|
||||
#else
|
||||
# ifndef WINDOWS
|
||||
double delay_ms = delay_.toMilliseconds();
|
||||
tbid[pID_] = "main";
|
||||
# ifdef MAC_OS
|
||||
rusage_info_current 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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 Останавливает мониторинг
|
||||
|
||||
@@ -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<T>::size() < max_size;
|
||||
else
|
||||
isOk = cond_var_rem->waitFor(mutex, timeoutMs, [&]() { return PIDeque<T>::size() < max_size; });
|
||||
isOk = cond_var_rem->waitFor(mutex, timeout, [&]() { return PIDeque<T>::size() < max_size; });
|
||||
if (isOk) PIDeque<T>::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<T>::isEmpty();
|
||||
else
|
||||
isNotEmpty = cond_var_add->waitFor(mutex, timeoutMs, [&]() { return !PIDeque<T>::isEmpty(); });
|
||||
isNotEmpty = cond_var_add->waitFor(mutex, timeout, [&]() { return !PIDeque<T>::isEmpty(); });
|
||||
if (isNotEmpty) t = PIDeque<T>::take_front();
|
||||
mutex.unlock();
|
||||
if (isNotEmpty) cond_var_rem->notifyOne();
|
||||
|
||||
@@ -25,8 +25,6 @@
|
||||
|
||||
#include "piconditionvar.h"
|
||||
#include "piincludes_p.h"
|
||||
#include "pithread.h"
|
||||
#include "pitime.h"
|
||||
#ifdef WINDOWS
|
||||
# include <synchapi.h>
|
||||
# include <winbase.h>
|
||||
@@ -105,19 +103,18 @@ void PIConditionVariable::wait(PIMutex & lk, const std::function<bool()> & 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);
|
||||
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<bool()> & condition) {
|
||||
bool PIConditionVariable::waitFor(PIMutex & lk, PISystemTime timeout, const std::function<bool()> & 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;
|
||||
|
||||
@@ -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<bool()>&)
|
||||
*/
|
||||
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<bool()> & condition);
|
||||
virtual bool waitFor(PIMutex & lk, PISystemTime timeout, const std::function<bool()> & condition);
|
||||
|
||||
private:
|
||||
PRIVATE_DECLARATION(PIP_EXPORT)
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include "pidiagnostics.h"
|
||||
#include "pithread.h"
|
||||
#include "pitime.h"
|
||||
|
||||
|
||||
template<typename T = PIByteArray>
|
||||
|
||||
@@ -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<void()> func, bool startNow, int loop_delay) {
|
||||
PIThread::PIThread(std::function<void()> 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<void()> 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<void()> func) {
|
||||
ret_func = [func](void *) { func(); };
|
||||
return start(loop_delay);
|
||||
return start();
|
||||
}
|
||||
|
||||
|
||||
bool PIThread::start(std::function<void()> 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<void()> 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);
|
||||
|
||||
@@ -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<void()> func, bool startNow = false, int loop_delay = -1);
|
||||
PIThread(std::function<void()> 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<void()> func) { return start(func, -1); }
|
||||
bool start(std::function<void()> func, int loop_delay);
|
||||
bool start(std::function<void()> 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<void()> func);
|
||||
|
||||
//! \~english Start thread
|
||||
//! \~russian Запускает поток
|
||||
bool start(std::function<void()> 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<void()> 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;
|
||||
|
||||
@@ -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<void()>());
|
||||
auto runnable = taskQueue.poll(100_ms, std::function<void()>());
|
||||
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;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#define PITHREADPOOLEXECUTOR_H
|
||||
|
||||
#include "piblockingqueue.h"
|
||||
#include "pithread.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
@@ -47,7 +48,7 @@ public:
|
||||
|
||||
bool isShutdown() const;
|
||||
|
||||
bool awaitTermination(int timeoutMs);
|
||||
bool awaitTermination(PISystemTime timeout);
|
||||
|
||||
private:
|
||||
std::atomic_bool isShutdown_;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,8 @@
|
||||
#include "pitimer.h"
|
||||
|
||||
#include "piconditionvar.h"
|
||||
#include "piincludes_p.h"
|
||||
#include "piliterals.h"
|
||||
#ifdef PIP_TIMER_RT
|
||||
# include <csignal>
|
||||
#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<void(int)> func) {
|
||||
initFirst();
|
||||
ret_func = func;
|
||||
}
|
||||
|
||||
|
||||
PITimer::PITimer(std::function<void()> 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"<<interval_ms<<"...";
|
||||
running_ = startTimer(interval_ms);
|
||||
return running_;
|
||||
}
|
||||
|
||||
|
||||
void _PITimerBase::startDeferred(double interval_ms, PIDateTime start_datetime) {
|
||||
if (isRunning()) stop();
|
||||
deferred_ = true;
|
||||
deferred_mode = true;
|
||||
deferred_datetime = start_datetime;
|
||||
setInterval(interval_ms);
|
||||
running_ = startTimer(interval_ms);
|
||||
}
|
||||
|
||||
|
||||
void _PITimerBase::startDeferred(double interval_ms, double delay_ms) {
|
||||
if (isRunning()) stop();
|
||||
deferred_ = true;
|
||||
deferred_mode = false;
|
||||
deferred_delay = delay_ms;
|
||||
setInterval(interval_ms);
|
||||
running_ = startTimer(interval_ms);
|
||||
}
|
||||
|
||||
|
||||
bool _PITimerBase::stop() {
|
||||
// piCout << GetCurrentThreadId() << "_PITimerBase::stop" << wait << isRunning();
|
||||
if (!isRunning()) return true;
|
||||
// piCout << "_PITimerBase::stopTimer ...";
|
||||
running_ = !stopTimer();
|
||||
return !running_;
|
||||
}
|
||||
|
||||
|
||||
class _PITimerImp_Thread: public _PITimerBase {
|
||||
public:
|
||||
_PITimerImp_Thread();
|
||||
virtual ~_PITimerImp_Thread() { stop(); }
|
||||
|
||||
protected:
|
||||
void prepareStart(double interval_ms);
|
||||
bool threadFunc(); // returns true if repeat is needed
|
||||
int wait_dt, wait_dd, wait_tick;
|
||||
|
||||
private:
|
||||
bool startTimer(double interval_ms) override;
|
||||
bool stopTimer() override;
|
||||
static void threadFuncS(void * d) { ((_PITimerImp_Thread *)d)->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<void()> slot, PITimer::TimerImplementation ti) {
|
||||
imp_mode = ti;
|
||||
initFirst();
|
||||
ret_func = [slot](void *, int) { slot(); };
|
||||
}
|
||||
|
||||
|
||||
PITimer::PITimer(std::function<void(void *)> 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<PITimer *>(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<void(int)> 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<void(void *)> slot) {
|
||||
delims << Delimiter([slot](void * d, int) { slot(d); }, delim);
|
||||
void PITimer::addDelimiter(int delim, std::function<void()> 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();
|
||||
}
|
||||
|
||||
@@ -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<void(void *, int)> 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<void(int)> 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<void()> 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<void(void *)> slot, void * data, TimerImplementation ti = Thread);
|
||||
//! \~english Constructs timer with method void()
|
||||
//! \~russian Создает таймер с функцией void()
|
||||
explicit PITimer(std::function<void()> 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<void()> slot) {
|
||||
ret_func = [slot](void *, int) { slot(); };
|
||||
void setSlot(std::function<void()> func) {
|
||||
ret_func = [func](int) { func(); };
|
||||
}
|
||||
|
||||
//! \~english Set timer tick function
|
||||
//! \~russian Установить вызываемый метод
|
||||
void setSlot(std::function<void(void *)> slot) {
|
||||
ret_func = [slot](void * d, int) { slot(d); };
|
||||
}
|
||||
void setSlot(std::function<void(int)> 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<void(int)> func = nullptr);
|
||||
|
||||
//! \~english Add frequency delimiter "delim" with optional delimiter slot "slot"
|
||||
//! \~russian Добавляет делитель частоты "delim" с необязательным методом "slot"
|
||||
void addDelimiter(int delim, std::function<void()> slot) {
|
||||
delims << Delimiter([slot](void *, int) { slot(); }, delim);
|
||||
}
|
||||
void addDelimiter(int delim, std::function<void()> 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<void(int)> func_ = nullptr, int delim_ = 1) {
|
||||
func = func_;
|
||||
delim = delim_;
|
||||
}
|
||||
TimerEvent slot;
|
||||
std::function<void(int)> 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<void(int)> ret_func = nullptr;
|
||||
PIVector<Delimiter> delims;
|
||||
|
||||
mutable _PITimerBase * imp = nullptr;
|
||||
PIConditionVariable event;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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<PICloudServer::Client *>();
|
||||
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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define DISPATCHERSERVER_H
|
||||
|
||||
#include "cloudserver.h"
|
||||
#include "pitimer.h"
|
||||
|
||||
class TileList;
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<Remote *> 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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,11 +184,17 @@ 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())
|
||||
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) + "]"
|
||||
//" "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())
|
||||
@@ -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();
|
||||
|
||||
@@ -17,9 +17,11 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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();
|
||||
|
||||
Reference in New Issue
Block a user