From 6e81a419fba6d8c6bb3ff1ee838eb3b5663b6813 Mon Sep 17 00:00:00 2001 From: peri4 Date: Tue, 1 Nov 2022 00:02:44 +0300 Subject: [PATCH 01/23] start move to interruption of blocking calls, PIThread and PIEthernet --- libs/main/core/piincludes_p.h | 4 + libs/main/core/piinit.cpp | 26 +++-- libs/main/io_devices/piethernet.cpp | 142 +++++++++++++++++++++--- libs/main/io_devices/piethernet.h | 4 + libs/main/piplatform.h | 4 + libs/main/thread/pithread.cpp | 23 ++++ libs/main/thread/pithread.h | 2 + main.cpp | 163 ++++++++++++++++++++++------ 8 files changed, 311 insertions(+), 57 deletions(-) diff --git a/libs/main/core/piincludes_p.h b/libs/main/core/piincludes_p.h index e3c622ca..d35baa6e 100644 --- a/libs/main/core/piincludes_p.h +++ b/libs/main/core/piincludes_p.h @@ -22,6 +22,10 @@ #include "picout.h" #ifdef WINDOWS +# ifdef _WIN32_WINNT +# undef _WIN32_WINNT +# define _WIN32_WINNT 0x0600 +# endif # include # include # include diff --git a/libs/main/core/piinit.cpp b/libs/main/core/piinit.cpp index c8354cfb..6d29486f 100644 --- a/libs/main/core/piinit.cpp +++ b/libs/main/core/piinit.cpp @@ -92,9 +92,19 @@ void __sighandler__(PISignals::Signal s) { } -#ifdef ANDROID -void android_thread_exit_handler(int sig) { - pthread_exit(0); +#ifdef POSIX_SIGNALS +void pipThreadSignalHandler(int sig) { +//# ifdef ANDROID +// pthread_exit(0); +//# endif +} +void pipInitThreadSignals() { + struct sigaction actions; + memset(&actions, 0, sizeof(actions)); + sigemptyset(&actions.sa_mask); + actions.sa_flags = 0; + actions.sa_handler = pipThreadSignalHandler; + sigaction(SIGUSR2, &actions, 0); } #endif @@ -166,14 +176,10 @@ PIInit::PIInit() { setlocale(LC_ALL, ""); setlocale(LC_NUMERIC, "C"); # endif //HAS_LOCALE -#else //ANDROID - struct sigaction actions; - memset(&actions, 0, sizeof(actions)); - sigemptyset(&actions.sa_mask); - actions.sa_flags = 0; - actions.sa_handler = android_thread_exit_handler; - sigaction(SIGTERM, &actions, 0); #endif //ANDROID +#ifdef POSIX_SIGNALS + pipInitThreadSignals(); +#endif PRIVATE->delete_locs = false; __syslocname__ = __sysoemname__ = 0; __utf8name__ = const_cast("UTF-8"); diff --git a/libs/main/io_devices/piethernet.cpp b/libs/main/io_devices/piethernet.cpp index 3ad67450..7f459ef9 100644 --- a/libs/main/io_devices/piethernet.cpp +++ b/libs/main/io_devices/piethernet.cpp @@ -212,6 +212,18 @@ PRIVATE_DEFINITION_START(PIEthernet) sockaddr_in addr_; sockaddr_in saddr_; sockaddr_in raddr_; +#ifdef WINDOWS + WSAEVENT read_event = nullptr; + void createEvent() { + closeEvent(); + read_event = WSACreateEvent(); + } + void closeEvent() { + if (!read_event) return; + WSACloseEvent(read_event); + read_event = nullptr; + } +#endif PRIVATE_DEFINITION_END(PIEthernet) @@ -240,6 +252,11 @@ PIEthernet::PIEthernet(int sock_, PIString ip_port): PIIODevice("", ReadWrite) { setParameters(PIEthernet::ReuseAddress | PIEthernet::MulticastLoop); setType(TCP_Client, false); setPath(ip_port); +#ifdef WINDOWS + u_long mode = 1; + ioctlsocket(sock, FIONBIO, &mode); + PRIVATE->createEvent(); +#endif //piCoutObj << "new tcp client" << sock_; } @@ -248,6 +265,9 @@ PIEthernet::~PIEthernet() { //piCout << "~PIEthernet" << uint(this); stop(); close(); +#ifdef WINDOWS + PRIVATE->closeEvent(); +#endif //piCoutObj << "~PIEthernet done"; } @@ -277,6 +297,9 @@ bool PIEthernet::init() { //cout << "init " << type_ << endl; if (sock_s == sock) sock_s = -1; +#ifdef WINDOWS + PRIVATE->closeEvent(); +#endif closeSocket(sock); closeSocket(sock_s); int st = 0, pr = 0; @@ -289,6 +312,14 @@ bool PIEthernet::init() { } PIFlags params = parameters(); sock = ::socket(AF_INET, st, pr); +#ifdef WINDOWS + if (type() != TCP_Server) { + // non-blocking socket + u_long mode = 1; + ioctlsocket(sock, FIONBIO, &mode); + } + PRIVATE->createEvent(); +#endif if (params[SeparateSockets]) sock_s = ::socket(AF_INET, st, pr); else @@ -395,13 +426,17 @@ bool PIEthernet::closeDevice() { //cout << "close\n"; if (server_thread_.isRunning()) { server_thread_.stop(); - if (!server_thread_.waitForFinish(100)) + server_thread_.interrupt(); + if (!server_thread_.waitForFinish(1000)) server_thread_.terminate(); } if (sock_s == sock) sock_s = -1; closeSocket(sock); closeSocket(sock_s); +#ifdef WINDOWS + if (PRIVATE->read_event) WSASetEvent(PRIVATE->read_event); +#endif while (!clients_.isEmpty()) delete clients_.back(); bool ned = connected_; @@ -566,7 +601,7 @@ bool PIEthernet::connect(bool threaded) { #ifdef QNX PRIVATE->addr_.sin_len = sizeof(PRIVATE->addr_); #endif - connected_ = (::connect(sock, (sockaddr * )&PRIVATE->addr_, sizeof(PRIVATE->addr_)) == 0); + connected_ = connectTCP(); if (!connected_) { piCoutObj << "Can`t connect to" << addr_r << "," << ethErrorString(); } @@ -618,7 +653,7 @@ bool PIEthernet::listen(bool threaded) { return false; } opened_ = server_bounded = true; - //piCoutObj << "listen on " << ip_ << ":" << port_; + piCoutObj << "listen on" << path(); server_thread_.start(server_func); return true; } @@ -718,9 +753,7 @@ ssize_t PIEthernet::readDevice(void * read_to, ssize_t max_size) { PRIVATE->addr_.sin_len = sizeof(PRIVATE->addr_); #endif //piCout << "connect to " << path() << "..."; - reading_now = true; - connected_ = (::connect(sock, (sockaddr * )&(PRIVATE->addr_), sizeof(PRIVATE->addr_)) == 0); - reading_now = false; + connected_ = connectTCP(); //piCout << "connect to " << path() << connected_; if (!connected_) piCoutObj << "Can`t connect to" << addr_r << "," << ethErrorString(); @@ -734,9 +767,24 @@ ssize_t PIEthernet::readDevice(void * read_to, ssize_t max_size) { } if (!connected_) return -1; errorClear(); - reading_now = true; +#ifdef WINDOWS + { + long wr = waitForEvent(FD_READ | FD_CLOSE); + switch (wr) { + case FD_READ: + piCout << "fd_read ..."; + rs = ethRecv(sock, read_to, max_size); + break; + case FD_CLOSE: + piCout << "fd_close ..."; + rs = -1; + break; + default: break; + } + } +#else rs = ethRecv(sock, read_to, max_size); - reading_now = false; +#endif //piCoutObj << "readed" << rs; if (rs <= 0) { lerr = ethErrorCore(); @@ -763,11 +811,26 @@ ssize_t PIEthernet::readDevice(void * read_to, ssize_t max_size) { } if (rs > 0) received(read_to, rs); return rs; - case UDP: + case UDP: { memset(&PRIVATE->raddr_, 0, sizeof(PRIVATE->raddr_)); - reading_now = true; + piCoutObj << "read from" << path() << "..."; +#ifdef WINDOWS + long wr = waitForEvent(FD_READ | FD_CLOSE); + switch (wr) { + case FD_READ: + piCout << "fd_read ..."; + rs = ethRecvfrom(sock, read_to, max_size, 0, (sockaddr*)&PRIVATE->raddr_); + break; + case FD_CLOSE: + piCout << "fd_close ..."; + rs = -1; + break; + default: break; + } +#else rs = ethRecvfrom(sock, read_to, max_size, 0, (sockaddr*)&PRIVATE->raddr_); - reading_now = false; +#endif + piCoutObj << "read from" << path() << rs << "bytes"; if (rs > 0) { addr_lr.set(uint(PRIVATE->raddr_.sin_addr.s_addr), ntohs(PRIVATE->raddr_.sin_port)); //piCoutObj << "read from" << ip_r << ":" << port_r << rs << "bytes"; @@ -775,6 +838,7 @@ ssize_t PIEthernet::readDevice(void * read_to, ssize_t max_size) { } //else piCoutObj << "read returt" << rs << ", error" << ethErrorString(); return rs; + } default: break; } return -1; @@ -799,7 +863,7 @@ ssize_t PIEthernet::writeDevice(const void * data, ssize_t max_size) { PRIVATE->addr_.sin_len = sizeof(PRIVATE->addr_); #endif //piCoutObj << "connect SingleTCP" << ip_s << ":" << port_s << "..."; - if (::connect(sock, (sockaddr * )&PRIVATE->addr_, sizeof(PRIVATE->addr_)) != 0) { + if (!connectTCP()) { //piCoutObj << "Can`t connect to " << ip_s << ":" << port_s << ", " << ethErrorString(); piMinSleep(); return -1; @@ -834,7 +898,7 @@ ssize_t PIEthernet::writeDevice(const void * data, ssize_t max_size) { PRIVATE->addr_.sin_len = sizeof(PRIVATE->addr_); #endif //piCoutObj << "connect to " << ip << ":" << port_; - connected_ = (::connect(sock, (sockaddr * )&PRIVATE->addr_, sizeof(PRIVATE->addr_)) == 0); + connected_ = connectTCP(); if (!connected_) piCoutObj << "Can`t connect to" << addr_r << "," << ethErrorString(); opened_ = connected_; @@ -890,7 +954,15 @@ void PIEthernet::server_func(void * eth) { } sockaddr_in client_addr; socklen_t slen = sizeof(client_addr); +#ifdef WINDOWS + long wr = ce->waitForEvent(FD_ACCEPT | FD_CLOSE); + if (wr != FD_ACCEPT) { + piMSleep(10); + return; + } +#endif int s = accept(ce->sock, (sockaddr * )&client_addr, &slen); + piCout << ethErrorString(); if (s == -1) { int lerr = ethErrorCore(); #ifdef WINDOWS @@ -930,6 +1002,50 @@ void PIEthernet::setType(Type t, bool reopen) { } +bool PIEthernet::connectTCP() { +#ifdef WINDOWS + ::connect(sock, (sockaddr * )&(PRIVATE->addr_), sizeof(PRIVATE->addr_)); + long wr = waitForEvent(FD_CONNECT | FD_CLOSE); + switch (wr) { + case FD_CONNECT: { + //piCout << "fd_connect ..."; + timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 0; + fd_set fd_test; + FD_ZERO(&fd_test); + FD_SET(sock, &fd_test); + ::select(0, nullptr, &fd_test, nullptr, &timeout); + return FD_ISSET(sock, &fd_test); + } break; + default: break; + } + return false; +#else + return ::connect(sock, (sockaddr * )&(PRIVATE->addr_), sizeof(PRIVATE->addr_)) == 0; +#endif +} + + +#ifdef WINDOWS +long PIEthernet::waitForEvent(long mask) { + if (!PRIVATE->read_event || sock < 0) return 0; + WSAEventSelect(sock, PRIVATE->read_event, mask); + DWORD wr = WSAWaitForMultipleEvents(1, &(PRIVATE->read_event), FALSE, WSA_INFINITE, TRUE); + piCout << "wait result" << wr; + if (wr == WSA_WAIT_EVENT_0) { + WSANETWORKEVENTS events; + memset(&events, 0, sizeof(events)); + WSAEnumNetworkEvents(sock, PRIVATE->read_event, &events); + WSAResetEvent(PRIVATE->read_event); + return events.lNetworkEvents; + } + WSAResetEvent(PRIVATE->read_event); + return 0; +} +#endif + + bool PIEthernet::configureDevice(const void * e_main, const void * e_parent) { PIConfig::Entry * em = (PIConfig::Entry * )e_main; PIConfig::Entry * ep = (PIConfig::Entry * )e_parent; diff --git a/libs/main/io_devices/piethernet.h b/libs/main/io_devices/piethernet.h index 95f350bc..de8c5987 100644 --- a/libs/main/io_devices/piethernet.h +++ b/libs/main/io_devices/piethernet.h @@ -500,6 +500,10 @@ private: EVENT_HANDLER1(void, clientDeleted, PIObject *, o); static void server_func(void * eth); void setType(Type t, bool reopen = true); + bool connectTCP(); +#ifdef WINDOWS + long waitForEvent(long mask); +#endif static int ethErrorCore(); static PIString ethErrorString(); diff --git a/libs/main/piplatform.h b/libs/main/piplatform.h index 548cbe29..d5125e07 100644 --- a/libs/main/piplatform.h +++ b/libs/main/piplatform.h @@ -100,4 +100,8 @@ #endif +#if defined(LINUX) || defined(MAC_OS) || defined(ANDROID) +# define POSIX_SIGNALS +#endif + #endif // PIPLATFORM_H diff --git a/libs/main/thread/pithread.cpp b/libs/main/thread/pithread.cpp index 1f4e3d2b..dccba139 100644 --- a/libs/main/thread/pithread.cpp +++ b/libs/main/thread/pithread.cpp @@ -23,6 +23,9 @@ #ifndef MICRO_PIP # include "pisystemtests.h" #endif +#ifdef WINDOWS +# include +#endif #include #if defined(WINDOWS) # define __THREAD_FUNC_RET__ uint __stdcall @@ -591,6 +594,26 @@ PIThread::~PIThread() { } +#ifdef WINDOWS +NTAPI void winThreadAPC(ULONG_PTR) { + //piCout << "APC"; +} +#endif + +void PIThread::interrupt() { + if (PRIVATE->thread == 0) return; + piCout << "PIThread::interrupt"; +#ifdef WINDOWS + CancelSynchronousIo(PRIVATE->thread); + QueueUserAPC(winThreadAPC, PRIVATE->thread, 0); +#else +# ifdef POSIX_SIGNALS + pthread_kill(PRIVATE->thread, SIGUSR2); +# endif +#endif +} + + void PIThread::stop(bool wait) { //PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop ..." << running_ << wait; terminating = true; diff --git a/libs/main/thread/pithread.h b/libs/main/thread/pithread.h index 01c9ab05..61b90e59 100644 --- a/libs/main/thread/pithread.h +++ b/libs/main/thread/pithread.h @@ -110,6 +110,8 @@ public: EVENT_HANDLER0(void, stop) {stop(false);} EVENT_HANDLER1(void, stop, bool, wait); EVENT_HANDLER0(void, terminate); + + void interrupt(); //! \~english Set common data passed to external function //! \~russian Устанавливает данные, передаваемые в функцию потока diff --git a/main.cpp b/main.cpp index b5e9a8d1..78b276d7 100644 --- a/main.cpp +++ b/main.cpp @@ -12,43 +12,138 @@ typedef PIVector PIVariantVector; REGISTER_VARIANT(PIVariantMap); REGISTER_VARIANT(PIVariantVector); -const char J[] = - "[ \n" - "{ \n" - " \"idFligth\":\"456123\", \n" - " \"FligthPath\": \"d:/orders/nicirt/BSK-52(BBR)/219031.001/EBN-NM-BBR.IMG\",\n" - " \"FligthDataPath\": \"\", \n" - " \"Passport\": \n" - " { \n" - " \"id\": \"\", \n" - " \"TypePlane\": \"\", \n" - " \"FA_PLANEBORT\": \"Ka52-10\" \n" - " } \n" - " }, [1.1,2,3,4,{\"a\":null},{\"bool\":true,\"bool2\":false}] \n" - "] \n" -; +#ifdef WINDOWS +# include +# include +# include +# include +typedef HANDLE pipe_type; +#else +# include +typedef int pipe_type; +#endif +struct Pipe { + pipe_type fd_read = 0; + pipe_type fd_write = 0; + void create() { +#ifdef WINDOWS + CreatePipe(&fd_read, &fd_write, NULL, 0); +#else + pipe((int*)this); +#endif + } + void destoy() { +#ifdef WINDOWS + CloseHandle(fd_read); + CloseHandle(fd_write); +#else + close(fd_read); + close(fd_write); +#endif + } + int read(void * d, int s) { +#ifdef WINDOWS + DWORD ret(0); + ReadFile(fd_read, d, s, &ret, NULL); + return ret; +#else + return ::read(fd_read, d, s); +#endif + } + int write(void * d, int s) { +#ifdef WINDOWS + DWORD ret(0); + WriteFile(fd_write, d, s, &ret, NULL); + return ret; +#else + return ::write(fd_write, d, s); +#endif + } +}; + +constexpr int count = 4; +Pipe pipes[count]; + +class T: public PIThread { +public: + T(int index): PIThread() {ind = index; pipe = pipes[index];} + void run() { + PIByteArray data(1024); + piCout << "[T"< threads; + piCout << "main start"; + for (int i = 0; i < count; ++i) { + T * t = new T(i); + threads << t; + t->startOnce(); } - piCout << json; + piMSleep(100); + for (int i = 0; i < count; ++i) { + //pipes[i].write((void*)"string", 7); + piMSleep(500); + } + piCout << "main wait"; + for (int i = 0; i < count; ++i) { + threads[i]->interrupt(); + threads[i]->waitForFinish(); + piCout << "main T" << i << "done"; + } + piCout << "main end"; + for (int i = 0; i < count; ++i) { + pipes[i].destoy(); + delete threads[i]; + }*/ + + PIEthernet eth(PIEthernet::TCP_Server), seth(PIEthernet::TCP_Client); + //eth.setReadAddress("127.0.0.1", 50000); + //piCout << eth.open(); + + //PISerial ser; + //ser.setSpeed(PISerial::S9600); + //ser.setOption(PIIODevice::BlockingRead); + //piCout << ser.open("COM3"); + + /* + PIThread thread; + thread.start([&](void*){ + piCout << "[T] start" << GetCurrentThreadId(); + //PIByteArray data = ((PIIODevice*)ð)->read(1024); + eth.connect("192.168.1.13", 23, false); + piCout << "[T] connected" << eth.isConnected() << errorString(); + //piCout << "[T] readed" << data.size() << errorString(); + piCout << "[T] end"; + }); + piMSleep(500); + eth.close(); + //piMSleep(500); + //thread.stop(); + //thread.interrupt(); + //seth.send("127.0.0.1", 50000, "string", 7); + //thread.interrupt(); + thread.waitForFinish();*/ + eth.listen("127.0.0.1", 50000); + piMSleep(500); + seth.connect("127.0.0.1", 50001, false); + piMSleep(500); + piCout << "connected" << seth.isConnected(); + //eth.close(); + piCout << "main end"; + + eth.close(); return 0; } -- 2.43.0 From 591c92b4bb96ce2f93a528529f219369e6546174 Mon Sep 17 00:00:00 2001 From: peri4 Date: Tue, 1 Nov 2022 09:17:24 +0300 Subject: [PATCH 02/23] ready to test --- libs/cloud/picloudclient.cpp | 8 +++--- libs/cloud/picloudserver.cpp | 7 +++-- libs/main/cloud/picloudclient.h | 2 ++ libs/main/cloud/picloudserver.h | 1 + libs/main/io_devices/piethernet.cpp | 4 +-- libs/main/io_devices/piiodevice.cpp | 6 +++-- libs/main/io_devices/piiodevice.h | 4 +++ libs/main/io_devices/piserial.cpp | 2 -- libs/main/io_utils/piconnection.cpp | 14 +++++++--- main.cpp | 42 ++++++++++++++++++----------- 10 files changed, 61 insertions(+), 29 deletions(-) diff --git a/libs/cloud/picloudclient.cpp b/libs/cloud/picloudclient.cpp index a3388719..5ebf9d70 100644 --- a/libs/cloud/picloudclient.cpp +++ b/libs/cloud/picloudclient.cpp @@ -107,7 +107,6 @@ bool PICloudClient::closeDevice() { ssize_t PICloudClient::readDevice(void * read_to, ssize_t max_size) { if (is_deleted) return -1; //piCoutObj << "readDevice"; - reading_now = true; if (!is_connected && eth.isClosed()) openDevice(); ssize_t sz = -1; mutex_buff.lock(); @@ -119,7 +118,6 @@ ssize_t PICloudClient::readDevice(void * read_to, ssize_t max_size) { } mutex_buff.unlock(); if (!is_connected) opened_ = false; - reading_now = false; //piCoutObj << "readDevice done" << sz; return sz; } @@ -132,6 +130,11 @@ ssize_t PICloudClient::writeDevice(const void * data, ssize_t size) { } +void PICloudClient::stopThreadedReadDevice() { + cond_buff.notifyOne(); +} + + void PICloudClient::internalDisconnect() { is_connected = false; cond_buff.notifyOne(); @@ -177,4 +180,3 @@ void PICloudClient::_readed(PIByteArray & ba) { while (buff.size_s() > threadedReadBufferSize()) piMSleep(100); // FIXME: sleep here is bad //piCoutObj << "_readed done"; } - diff --git a/libs/cloud/picloudserver.cpp b/libs/cloud/picloudserver.cpp index b3e61e79..a5fbe927 100644 --- a/libs/cloud/picloudserver.cpp +++ b/libs/cloud/picloudserver.cpp @@ -90,10 +90,8 @@ bool PICloudServer::closeDevice() { ssize_t PICloudServer::readDevice(void * read_to, ssize_t max_size) { //piCoutObj << "readDevice"; - reading_now = true; if (!opened_) openDevice(); else piMSleep(eth.readTimeout()); - reading_now = false; return -1; } @@ -104,6 +102,11 @@ ssize_t PICloudServer::writeDevice(const void * data, ssize_t max_size) { } +void PICloudServer::stopThreadedReadDevice() { + +} + + void PICloudServer::clientDisconnect(uint client_id) { tcp.sendDisconnected(client_id); } diff --git a/libs/main/cloud/picloudclient.h b/libs/main/cloud/picloudclient.h index 791bae85..a4c55e6f 100644 --- a/libs/main/cloud/picloudclient.h +++ b/libs/main/cloud/picloudclient.h @@ -53,6 +53,7 @@ protected: ssize_t readDevice(void * read_to, ssize_t max_size) override; ssize_t writeDevice(const void * data, ssize_t size) override; DeviceInfoFlags deviceInfoFlags() const override {return PIIODevice::Reliable;} + void stopThreadedReadDevice() override; private: EVENT_HANDLER1(void, _readed, PIByteArray &, data); @@ -65,6 +66,7 @@ private: PIConditionVariable cond_connect; std::atomic_bool is_connected; std::atomic_bool is_deleted; + }; #endif // PICLOUDCLIENT_H diff --git a/libs/main/cloud/picloudserver.h b/libs/main/cloud/picloudserver.h index 593783c2..b253b40e 100644 --- a/libs/main/cloud/picloudserver.h +++ b/libs/main/cloud/picloudserver.h @@ -73,6 +73,7 @@ protected: bool closeDevice() override; ssize_t readDevice(void * read_to, ssize_t max_size) override; ssize_t writeDevice(const void * data, ssize_t max_size) override; + void stopThreadedReadDevice() override; private: EVENT_HANDLER1(void, _readed, PIByteArray &, ba); diff --git a/libs/main/io_devices/piethernet.cpp b/libs/main/io_devices/piethernet.cpp index 7f459ef9..59013625 100644 --- a/libs/main/io_devices/piethernet.cpp +++ b/libs/main/io_devices/piethernet.cpp @@ -752,9 +752,9 @@ ssize_t PIEthernet::readDevice(void * read_to, ssize_t max_size) { #ifdef QNX PRIVATE->addr_.sin_len = sizeof(PRIVATE->addr_); #endif - //piCout << "connect to " << path() << "..."; + piCout << "connect to " << path() << "..."; connected_ = connectTCP(); - //piCout << "connect to " << path() << connected_; + piCout << "connect to " << path() << connected_; if (!connected_) piCoutObj << "Can`t connect to" << addr_r << "," << ethErrorString(); opened_ = connected_; diff --git a/libs/main/io_devices/piiodevice.cpp b/libs/main/io_devices/piiodevice.cpp index c132b702..155674a6 100644 --- a/libs/main/io_devices/piiodevice.cpp +++ b/libs/main/io_devices/piiodevice.cpp @@ -132,6 +132,7 @@ PIIODevice::PIIODevice(const PIString & path, PIIODevice::DeviceMode mode): PIOb PIIODevice::~PIIODevice() { stop(); + waitThreadedReadFinished(); } @@ -213,11 +214,12 @@ void PIIODevice::stopThreadedRead() { #ifdef MICRO_PIP read_thread.stop(); #else + read_thread.stop(); + read_thread.interrupt(); + stopThreadedReadDevice(); if (reading_now) { read_thread.terminate(); reading_now = false; - } else { - read_thread.stop(); } #endif } diff --git a/libs/main/io_devices/piiodevice.h b/libs/main/io_devices/piiodevice.h index b3af0987..c5f7936d 100644 --- a/libs/main/io_devices/piiodevice.h +++ b/libs/main/io_devices/piiodevice.h @@ -490,6 +490,10 @@ protected: //! \~english Function executed when thread read some data, default implementation execute external callback "ret_func_" //! \~russian Метод вызывается после каждого успешного потокового чтения, по умолчанию вызывает callback "ret_func_" virtual bool threadedRead(const uchar * readed, ssize_t size); + + //! \~english Function executed after PIThread::stop() and PIThread::interrupt() of read thread + //! \~russian Метод вызывается после PIThread::stop() и PIThread::interrupt() потока чтения + virtual void stopThreadedReadDevice() {} //! \~english Reimplement to construct full unambiguous string, describes this device. //! Default implementation returns \a path() diff --git a/libs/main/io_devices/piserial.cpp b/libs/main/io_devices/piserial.cpp index d781d52a..d3c97c44 100644 --- a/libs/main/io_devices/piserial.cpp +++ b/libs/main/io_devices/piserial.cpp @@ -798,9 +798,7 @@ ssize_t PISerial::readDevice(void * read_to, ssize_t max_size) { if (sending) return -1; // piCoutObj << "com event ..."; //piCoutObj << "read ..." << PRIVATE->hCom; - reading_now = true; ReadFile(PRIVATE->hCom, read_to, max_size, &PRIVATE->readed, 0); - reading_now = false; DWORD err = GetLastError(); //piCout << err; if (err == ERROR_BAD_COMMAND || err == ERROR_ACCESS_DENIED) { diff --git a/libs/main/io_utils/piconnection.cpp b/libs/main/io_utils/piconnection.cpp index 79af1255..4c32ad80 100644 --- a/libs/main/io_utils/piconnection.cpp +++ b/libs/main/io_utils/piconnection.cpp @@ -1114,7 +1114,10 @@ PIVector PIConnection::DevicePool::boundedDevices(const PIConnect PIConnection::DevicePool::DeviceData::~DeviceData() { if (rthread) { - rthread->terminate(); + rthread->stop(); + rthread->interrupt(); + if (!rthread->waitForFinish(1000)) + rthread->terminate(); delete rthread; rthread = nullptr; } @@ -1146,8 +1149,13 @@ void __DevicePool_threadReadDP(void * ddp) { } if (dev->isClosed()) { if (!dev->open()) { - piMSleep(dev->reopenTimeout()); - return; + PITimeMeasurer tm; + int timeout = dev->reopenTimeout(); + while (tm.elapsed_m() < timeout) { + if (dd->rthread->isStopping()) + return; + piMSleep(50); + } } } PIByteArray ba; diff --git a/main.cpp b/main.cpp index 78b276d7..f39e4f49 100644 --- a/main.cpp +++ b/main.cpp @@ -109,41 +109,53 @@ int main(int argc, char * argv[]) { delete threads[i]; }*/ - PIEthernet eth(PIEthernet::TCP_Server), seth(PIEthernet::TCP_Client); - //eth.setReadAddress("127.0.0.1", 50000); + PIEthernet eth(PIEthernet::TCP_Client), seth(PIEthernet::TCP_Client); + eth.connect("192.168.1.13", 22); + eth.startThreadedRead(); //piCout << eth.open(); - //PISerial ser; - //ser.setSpeed(PISerial::S9600); - //ser.setOption(PIIODevice::BlockingRead); - //piCout << ser.open("COM3"); + /* + PISerial ser; + ser.setSpeed(PISerial::S9600); + ser.setOption(PIIODevice::BlockingRead); + piCout << ser.open("COM3"); + */ /* PIThread thread; thread.start([&](void*){ piCout << "[T] start" << GetCurrentThreadId(); - //PIByteArray data = ((PIIODevice*)ð)->read(1024); + //PIByteArray data = ((PIIODevice*)&ser)->read(1024); eth.connect("192.168.1.13", 23, false); piCout << "[T] connected" << eth.isConnected() << errorString(); //piCout << "[T] readed" << data.size() << errorString(); piCout << "[T] end"; }); piMSleep(500); - eth.close(); + //eth.close(); //piMSleep(500); - //thread.stop(); - //thread.interrupt(); + thread.stop(); + thread.interrupt(); //seth.send("127.0.0.1", 50000, "string", 7); //thread.interrupt(); - thread.waitForFinish();*/ + thread.waitForFinish(); + */ + + /* eth.listen("127.0.0.1", 50000); - piMSleep(500); seth.connect("127.0.0.1", 50001, false); piMSleep(500); piCout << "connected" << seth.isConnected(); - //eth.close(); - piCout << "main end"; + */ + piMSleep(1000); + piCout << "main stop ..."; + eth.stopThreadedRead(); + piCout << "main wait ..." << eth.isThreadedRead(); + eth.waitThreadedReadFinished(); - eth.close(); + //eth.close(); + piCout << "main end" << eth.isThreadedRead(); + + //ser.close(); return 0; } -- 2.43.0 From e48d0ebaabe1aa33ad25801d413fa63161140cd0 Mon Sep 17 00:00:00 2001 From: peri4 Date: Tue, 1 Nov 2022 09:38:27 +0300 Subject: [PATCH 03/23] linux signal --- libs/main/core/pibase.h | 4 ++++ libs/main/core/piinit.cpp | 3 ++- libs/main/thread/pithread.cpp | 2 +- main.cpp | 6 +++--- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/libs/main/core/pibase.h b/libs/main/core/pibase.h index c8eff9d8..b066e6cd 100644 --- a/libs/main/core/pibase.h +++ b/libs/main/core/pibase.h @@ -248,6 +248,10 @@ typedef long time_t; #endif +#ifdef POSIX_SIGNALS +# define PIP_INTERRUPT_SIGNAL SIGTERM +#endif + #ifdef LINUX # define environ __environ #endif diff --git a/libs/main/core/piinit.cpp b/libs/main/core/piinit.cpp index 6d29486f..3c768797 100644 --- a/libs/main/core/piinit.cpp +++ b/libs/main/core/piinit.cpp @@ -104,7 +104,8 @@ void pipInitThreadSignals() { sigemptyset(&actions.sa_mask); actions.sa_flags = 0; actions.sa_handler = pipThreadSignalHandler; - sigaction(SIGUSR2, &actions, 0); + if (sigaction(PIP_INTERRUPT_SIGNAL, &actions, 0) != 0) + piCout << "sigaction error:" << errorString(); } #endif diff --git a/libs/main/thread/pithread.cpp b/libs/main/thread/pithread.cpp index dccba139..5b8f372b 100644 --- a/libs/main/thread/pithread.cpp +++ b/libs/main/thread/pithread.cpp @@ -608,7 +608,7 @@ void PIThread::interrupt() { QueueUserAPC(winThreadAPC, PRIVATE->thread, 0); #else # ifdef POSIX_SIGNALS - pthread_kill(PRIVATE->thread, SIGUSR2); + pthread_kill(PRIVATE->thread, PIP_INTERRUPT_SIGNAL); # endif #endif } diff --git a/main.cpp b/main.cpp index f39e4f49..46f90d43 100644 --- a/main.cpp +++ b/main.cpp @@ -80,7 +80,7 @@ public: }; int main(int argc, char * argv[]) { - piCout << "main" << GetCurrentThreadId(); + piCout << "main"; /*for (int i = 0; i < count; ++i) pipes[i].create(); @@ -109,8 +109,8 @@ int main(int argc, char * argv[]) { delete threads[i]; }*/ - PIEthernet eth(PIEthernet::TCP_Client), seth(PIEthernet::TCP_Client); - eth.connect("192.168.1.13", 22); + PIEthernet eth(PIEthernet::UDP), seth(PIEthernet::TCP_Client); + eth.connect("127.0.0.1", 50000); eth.startThreadedRead(); //piCout << eth.open(); -- 2.43.0 From 8a5e72c723fbf80e3cec98cb153f82915fdde0a9 Mon Sep 17 00:00:00 2001 From: peri4 Date: Sat, 5 Nov 2022 23:43:07 +0300 Subject: [PATCH 04/23] migrate to async IO model new PIIODevice::interrupt() virtual method new PIWaitEvent private class PIEthernet and PISerial basically tested on Windows and Linux --- libs/cloud/picloudclient.cpp | 10 +- libs/cloud/picloudserver.cpp | 12 +- libs/main/cloud/picloudclient.h | 1 + libs/main/cloud/picloudserver.h | 2 + libs/main/core/piincludes.h | 1 + libs/main/core/piwaitevent_p.cpp | 126 ++++++++++++++ libs/main/core/piwaitevent_p.h | 67 ++++++++ libs/main/io_devices/piethernet.cpp | 247 +++++++++++++--------------- libs/main/io_devices/piethernet.h | 9 +- libs/main/io_devices/piiodevice.cpp | 17 +- libs/main/io_devices/piiodevice.h | 10 +- libs/main/io_devices/piserial.cpp | 81 ++++++--- libs/main/io_devices/piserial.h | 12 +- libs/main/io_utils/piconnection.cpp | 2 +- main.cpp | 110 +++++++++---- 15 files changed, 498 insertions(+), 209 deletions(-) create mode 100644 libs/main/core/piwaitevent_p.cpp create mode 100644 libs/main/core/piwaitevent_p.h diff --git a/libs/cloud/picloudclient.cpp b/libs/cloud/picloudclient.cpp index 5ebf9d70..df32160d 100644 --- a/libs/cloud/picloudclient.cpp +++ b/libs/cloud/picloudclient.cpp @@ -45,10 +45,11 @@ PICloudClient::PICloudClient(const PIString & path, PIIODevice::DeviceMode mode) PICloudClient::~PICloudClient() { //piCoutObj << "~PICloudClient()"; - softStopThreadedRead(); + //softStopThreadedRead(); //eth.close(); //if (is_connected) disconnected(); - close(); + //close(); + stopAndWait(); //piCoutObj << "~PICloudClient() closed"; internalDisconnect(); // stop(false); @@ -69,6 +70,11 @@ void PICloudClient::setKeepConnection(bool on) { } +void PICloudClient::interrupt() { + eth.interrupt(); +} + + bool PICloudClient::openDevice() { //piCoutObj << "open";// << path(); bool op = eth.connect(PIEthernet::Address::resolve(path()), false); diff --git a/libs/cloud/picloudserver.cpp b/libs/cloud/picloudserver.cpp index a5fbe927..931038bc 100644 --- a/libs/cloud/picloudserver.cpp +++ b/libs/cloud/picloudserver.cpp @@ -41,7 +41,7 @@ PICloudServer::PICloudServer(const PIString & path, PIIODevice::DeviceMode mode) PICloudServer::~PICloudServer() { - stop(); + stopAndWait(); close(); } @@ -107,6 +107,11 @@ void PICloudServer::stopThreadedReadDevice() { } +void PICloudServer::interrupt() { + eth.interrupt(); +} + + void PICloudServer::clientDisconnect(uint client_id) { tcp.sendDisconnected(client_id); } @@ -170,6 +175,11 @@ ssize_t PICloudServer::Client::writeDevice(const void * data, ssize_t size) { } +void PICloudServer::Client::interrupt() { + cond_buff.notifyOne(); +} + + void PICloudServer::Client::pushBuffer(const PIByteArray & ba) { if (!is_connected) return; mutex_buff.lock(); diff --git a/libs/main/cloud/picloudclient.h b/libs/main/cloud/picloudclient.h index a4c55e6f..4fb58d9b 100644 --- a/libs/main/cloud/picloudclient.h +++ b/libs/main/cloud/picloudclient.h @@ -43,6 +43,7 @@ public: void setKeepConnection(bool on); bool isConnected() const {return is_connected;} ssize_t bytesAvailable() const override {return buff.size();} + void interrupt() override; EVENT(connected); EVENT(disconnected); diff --git a/libs/main/cloud/picloudserver.h b/libs/main/cloud/picloudserver.h index b253b40e..4f8d110d 100644 --- a/libs/main/cloud/picloudserver.h +++ b/libs/main/cloud/picloudserver.h @@ -51,6 +51,7 @@ public: ssize_t writeDevice(const void * data, ssize_t size) override; DeviceInfoFlags deviceInfoFlags() const override {return PIIODevice::Reliable;} ssize_t bytesAvailable() const override {return buff.size();} + void interrupt() override; private: void pushBuffer(const PIByteArray & ba); @@ -74,6 +75,7 @@ protected: ssize_t readDevice(void * read_to, ssize_t max_size) override; ssize_t writeDevice(const void * data, ssize_t max_size) override; void stopThreadedReadDevice() override; + void interrupt() override; private: EVENT_HANDLER1(void, _readed, PIByteArray &, ba); diff --git a/libs/main/core/piincludes.h b/libs/main/core/piincludes.h index e867a756..c348f2ea 100644 --- a/libs/main/core/piincludes.h +++ b/libs/main/core/piincludes.h @@ -44,6 +44,7 @@ class PIInit; #endif class PIChar; class PICout; +class PIWaitEvent; struct lconv; diff --git a/libs/main/core/piwaitevent_p.cpp b/libs/main/core/piwaitevent_p.cpp new file mode 100644 index 00000000..f4a832dc --- /dev/null +++ b/libs/main/core/piwaitevent_p.cpp @@ -0,0 +1,126 @@ +/* + PIP - Platform Independent Primitives + Private PIP wait object + Ivan Pelipenko peri4ko@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#include "piwaitevent_p.h" +#ifdef WINDOWS +//# ifdef _WIN32_WINNT +//# undef _WIN32_WINNT +//# define _WIN32_WINNT 0x0600 +//# endif +# include +#else +# include +# include +#endif +#include "piincludes_p.h" +#include "pistring.h" + + +PIWaitEvent::~PIWaitEvent() { + destroy(); +} + + +void PIWaitEvent::create() { + destroy(); +#ifdef WINDOWS + event = CreateEventA(NULL, TRUE, FALSE, NULL); + if (!event) { + piCout << "Error with CreateEventA:" << errorString(); + } +#else + for (int i = 0; i < 3; ++i) memset(&(fds[i]), 0, sizeof(fds[i])); + if (::pipe(pipe_fd) < 0) { + piCout << "Error with pipe:" << errorString(); + } else { + fcntl(pipe_fd[ReadEnd], F_SETFL, O_NONBLOCK); + } +#endif +} + + +void PIWaitEvent::destroy() { +#ifdef WINDOWS + if (event) { + CloseHandle(event); + event = NULL; + } +#else + for (int i = 0; i < 2; ++i) { + if (pipe_fd[i] != 0) { + ::close(pipe_fd[i]); + pipe_fd[i] = 0; + } + } +#endif +} + + +#ifdef WINDOWS +bool PIWaitEvent::wait() { +#else +bool PIWaitEvent::wait(int fd, PIWaitEvent::SelectRole role) { +#endif + if (!isCreate()) return false; +#ifdef WINDOWS + DWORD ret = WaitForSingleObjectEx(event, INFINITE, TRUE); + ResetEvent(event); + if (ret == WAIT_IO_COMPLETION || ret == WAIT_FAILED) return false; +#else + int nfds = piMaxi(pipe_fd[ReadEnd], fd) + 1; + int fd_index = 0; + switch (role) { + case CheckRead: + fd_index = 0; + break; + case CheckWrite: + fd_index = 1; + break; + } + for (int i = 0; i < 3; ++i) FD_ZERO(&(fds[i])); + FD_SET(pipe_fd[ReadEnd], &(fds[0])); + FD_SET(fd, &(fds[2])); + FD_SET(fd, &(fds[fd_index])); + ::select(nfds, &(fds[0]), &(fds[1]), &(fds[2]), nullptr); + int buf = 0; + while (::read(pipe_fd[ReadEnd], &buf, sizeof(buf)) > 0); + if (FD_ISSET(fd, &(fds[2]))) return false; + return FD_ISSET(fd, &(fds[fd_index])); +#endif + return true; +} + + +void PIWaitEvent::interrupt() { + if (!isCreate()) return; +#ifdef WINDOWS + SetEvent(event); +#else + ::write(pipe_fd[WriteEnd], "", 1); +#endif +} + + +bool PIWaitEvent::isCreate() const { +#ifdef WINDOWS + return event; +#else + return pipe_fd[ReadEnd] != 0; +#endif +} diff --git a/libs/main/core/piwaitevent_p.h b/libs/main/core/piwaitevent_p.h new file mode 100644 index 00000000..e5c7ee73 --- /dev/null +++ b/libs/main/core/piwaitevent_p.h @@ -0,0 +1,67 @@ +/* + PIP - Platform Independent Primitives + Private PIP wait object + Ivan Pelipenko peri4ko@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#ifndef PIWAITEVENT_P_H +#define PIWAITEVENT_P_H + +#include "pibase.h" +#ifdef WINDOWS +# include +# include +# include +#else +# include +# include +#endif + + +class PIWaitEvent { +public: + ~PIWaitEvent(); + + void create(); + void destroy(); +#ifdef WINDOWS + bool wait(); +#else + enum SelectRole { + CheckRead, + CheckWrite + }; + bool wait(int fd, SelectRole role = CheckRead); +#endif + void interrupt(); + bool isCreate() const; + +#ifdef WINDOWS + HANDLE event = NULL; +#else +private: + int pipe_fd[2] = {0, 0}; + fd_set fds[3]; + enum { + ReadEnd = 0, + WriteEnd = 1 + }; +#endif + +}; + + +#endif // PIWAITEVENT_P_H diff --git a/libs/main/io_devices/piethernet.cpp b/libs/main/io_devices/piethernet.cpp index 59013625..18d0f4e2 100644 --- a/libs/main/io_devices/piethernet.cpp +++ b/libs/main/io_devices/piethernet.cpp @@ -67,6 +67,7 @@ # endif # endif #endif +#include "piwaitevent_p.h" #include @@ -212,18 +213,7 @@ PRIVATE_DEFINITION_START(PIEthernet) sockaddr_in addr_; sockaddr_in saddr_; sockaddr_in raddr_; -#ifdef WINDOWS - WSAEVENT read_event = nullptr; - void createEvent() { - closeEvent(); - read_event = WSACreateEvent(); - } - void closeEvent() { - if (!read_event) return; - WSACloseEvent(read_event); - read_event = nullptr; - } -#endif + PIWaitEvent event; PRIVATE_DEFINITION_END(PIEthernet) @@ -252,23 +242,18 @@ PIEthernet::PIEthernet(int sock_, PIString ip_port): PIIODevice("", ReadWrite) { setParameters(PIEthernet::ReuseAddress | PIEthernet::MulticastLoop); setType(TCP_Client, false); setPath(ip_port); -#ifdef WINDOWS - u_long mode = 1; - ioctlsocket(sock, FIONBIO, &mode); - PRIVATE->createEvent(); -#endif + ethNonblocking(sock); + PRIVATE->event.create(); //piCoutObj << "new tcp client" << sock_; } PIEthernet::~PIEthernet() { - //piCout << "~PIEthernet" << uint(this); - stop(); + //piCout << "~PIEthernet"; + stopAndWait(); close(); -#ifdef WINDOWS - PRIVATE->closeEvent(); -#endif - //piCoutObj << "~PIEthernet done"; + PRIVATE->event.destroy(); + //piCout << "~PIEthernet done"; } @@ -294,12 +279,11 @@ void PIEthernet::construct() { bool PIEthernet::init() { if (isOpened()) return true; - //cout << "init " << type_ << endl; + if (sock != -1) return true; + //piCout << "init " << type(); + PRIVATE->event.destroy(); if (sock_s == sock) sock_s = -1; -#ifdef WINDOWS - PRIVATE->closeEvent(); -#endif closeSocket(sock); closeSocket(sock_s); int st = 0, pr = 0; @@ -312,14 +296,8 @@ bool PIEthernet::init() { } PIFlags params = parameters(); sock = ::socket(AF_INET, st, pr); -#ifdef WINDOWS - if (type() != TCP_Server) { - // non-blocking socket - u_long mode = 1; - ioctlsocket(sock, FIONBIO, &mode); - } - PRIVATE->createEvent(); -#endif + ethNonblocking(sock); + PRIVATE->event.create(); if (params[SeparateSockets]) sock_s = ::socket(AF_INET, st, pr); else @@ -332,7 +310,7 @@ bool PIEthernet::init() { if (params[PIEthernet::Broadcast]) ethSetsockoptBool(sock, SOL_SOCKET, SO_BROADCAST); applyTimeouts(); applyOptInt(IPPROTO_IP, IP_TTL, TTL()); -// piCoutObj << "inited" << path(); + //piCoutObj << "inited" << path(); return true; } @@ -386,11 +364,12 @@ PIEthernet::Address PIEthernet::getBroadcast(const PIEthernet::Address & ip, con bool PIEthernet::openDevice() { if (connected_) return true; + //piCoutObj << "open"; init(); if (sock == -1 || path().isEmpty()) return false; addr_r.set(path()); - if (type() == TCP_Client) - connecting_ = true; + //if (type() == TCP_Client) + // connecting_ = true; if (type() != UDP || mode() == PIIODevice::WriteOnly) return true; memset(&PRIVATE->addr_, 0, sizeof(PRIVATE->addr_)); @@ -423,24 +402,22 @@ bool PIEthernet::openDevice() { bool PIEthernet::closeDevice() { - //cout << "close\n"; + //piCoutObj << "close"; + bool ned = connected_; + connected_ = connecting_ = false; + server_thread_.stop(); + PRIVATE->event.interrupt(); if (server_thread_.isRunning()) { - server_thread_.stop(); - server_thread_.interrupt(); if (!server_thread_.waitForFinish(1000)) server_thread_.terminate(); } + PRIVATE->event.destroy(); if (sock_s == sock) sock_s = -1; closeSocket(sock); closeSocket(sock_s); -#ifdef WINDOWS - if (PRIVATE->read_event) WSASetEvent(PRIVATE->read_event); -#endif while (!clients_.isEmpty()) delete clients_.back(); - bool ned = connected_; - connected_ = connecting_ = false; if (ned) disconnected(false); return true; } @@ -591,6 +568,7 @@ bool PIEthernet::connect(bool threaded) { connecting_ = true; return true; } + if (connected_) return false; if (sock == -1) init(); if (sock == -1) return false; memset(&PRIVATE->addr_, 0, sizeof(PRIVATE->addr_)); @@ -710,40 +688,21 @@ bool PIEthernet::send(const PIEthernet::Address & addr, const PIByteArray & data } +void PIEthernet::interrupt() { + //piCout << "interrupt"; + PRIVATE->event.interrupt(); +} + + ssize_t PIEthernet::readDevice(void * read_to, ssize_t max_size) { //piCout << "read" << sock; if (sock == -1) init(); if (sock == -1 || read_to == 0) return -1; - int rs = 0, s = 0, lerr = 0; - sockaddr_in client_addr; - socklen_t slen = sizeof(client_addr); -// piCoutObj << "read from " << ip_ << ":" << port_; + int rs = 0, lerr = 0; + //piCoutObj << "read from " << path() << connecting_; switch (type()) { - case TCP_SingleTCP: - reading_now = true; - ::listen(sock, 64); - reading_now = false; - s = accept(sock, (sockaddr * )&client_addr, &slen); - if (s == -1) { - //piCoutObj << "Can`t accept new connection, " << ethErrorString(); - piMinSleep(); - return -1; - } - reading_now = true; - rs = ethRecv(s, read_to, max_size); - reading_now = false; - closeSocket(s); - return rs; case TCP_Client: if (connecting_) { -#ifdef ANDROID - /*if (sock_s == sock) - sock_s = -1; - closeSocket(sock); - closeSocket(sock_s); - init(); - qDebug() << "init() in read thread";*/ -#endif addr_r.set(path()); memset(&PRIVATE->addr_, 0, sizeof(PRIVATE->addr_)); PRIVATE->addr_.sin_port = htons(addr_r.port()); @@ -752,9 +711,9 @@ ssize_t PIEthernet::readDevice(void * read_to, ssize_t max_size) { #ifdef QNX PRIVATE->addr_.sin_len = sizeof(PRIVATE->addr_); #endif - piCout << "connect to " << path() << "..."; + piCoutObj << "connect to " << path() << "..."; connected_ = connectTCP(); - piCout << "connect to " << path() << connected_; + piCoutObj << "connect to " << path() << connected_; if (!connected_) piCoutObj << "Can`t connect to" << addr_r << "," << ethErrorString(); opened_ = connected_; @@ -772,18 +731,19 @@ ssize_t PIEthernet::readDevice(void * read_to, ssize_t max_size) { long wr = waitForEvent(FD_READ | FD_CLOSE); switch (wr) { case FD_READ: - piCout << "fd_read ..."; + //piCout << "fd_read ..."; rs = ethRecv(sock, read_to, max_size); break; case FD_CLOSE: - piCout << "fd_close ..."; + //piCout << "fd_close ..."; rs = -1; break; default: break; } } #else - rs = ethRecv(sock, read_to, max_size); + if (PRIVATE->event.wait(sock)) + rs = ethRecv(sock, read_to, max_size); #endif //piCoutObj << "readed" << rs; if (rs <= 0) { @@ -792,37 +752,39 @@ ssize_t PIEthernet::readDevice(void * read_to, ssize_t max_size) { #ifdef WINDOWS if ((lerr == WSAEWOULDBLOCK || lerr == WSAETIMEDOUT) && !parameters()[DisonnectOnTimeout]) { #elif defined(ANDROID) - if ((lerr == EWOULDBLOCK || lerr == EAGAIN || lerr == EINTR) && !parameters()[DisonnectOnTimeout]) { + if ((lerr == EWOULDBLOCK || lerr == EAGAIN || lerr == EINTR) && !parameters()[DisonnectOnTimeout] && rs < 0) { #else - if ((lerr == EWOULDBLOCK || lerr == EAGAIN) && !parameters()[DisonnectOnTimeout]) { + if ((lerr == EWOULDBLOCK || lerr == EAGAIN) && !parameters()[DisonnectOnTimeout] && rs < 0) { #endif //piCoutObj << errorString(); return -1; } if (connected_) { - piCoutObj << "Disconnect on read," << ethErrorString(); + //piCoutObj << "Disconnect on read," << ethErrorString(); opened_ = connected_ = false; + closeSocket(sock); init(); disconnected(rs < 0); } - if (parameters()[KeepConnection]) + if (parameters()[KeepConnection]) { connect(); + } //piCoutObj << "eth" << ip_ << "disconnected"; } if (rs > 0) received(read_to, rs); return rs; case UDP: { memset(&PRIVATE->raddr_, 0, sizeof(PRIVATE->raddr_)); - piCoutObj << "read from" << path() << "..."; + //piCoutObj << "read from" << path() << "..."; #ifdef WINDOWS long wr = waitForEvent(FD_READ | FD_CLOSE); switch (wr) { case FD_READ: - piCout << "fd_read ..."; + //piCout << "fd_read ..."; rs = ethRecvfrom(sock, read_to, max_size, 0, (sockaddr*)&PRIVATE->raddr_); break; case FD_CLOSE: - piCout << "fd_close ..."; + //piCout << "fd_close ..."; rs = -1; break; default: break; @@ -830,7 +792,7 @@ ssize_t PIEthernet::readDevice(void * read_to, ssize_t max_size) { #else rs = ethRecvfrom(sock, read_to, max_size, 0, (sockaddr*)&PRIVATE->raddr_); #endif - piCoutObj << "read from" << path() << rs << "bytes"; + //piCoutObj << "read from" << path() << rs << "bytes"; if (rs > 0) { addr_lr.set(uint(PRIVATE->raddr_.sin_addr.s_addr), ntohs(PRIVATE->raddr_.sin_port)); //piCoutObj << "read from" << ip_r << ":" << port_r << rs << "bytes"; @@ -854,26 +816,6 @@ ssize_t PIEthernet::writeDevice(const void * data, ssize_t max_size) { //piCoutObj << "sending to " << ip_s << ":" << port_s << " " << max_size << " bytes"; int ret = 0; switch (type()) { - case TCP_SingleTCP: - memset(&PRIVATE->addr_, 0, sizeof(PRIVATE->addr_)); - PRIVATE->addr_.sin_port = htons(addr_s.port()); - PRIVATE->addr_.sin_addr.s_addr = addr_s.ip(); - PRIVATE->addr_.sin_family = AF_INET; -#ifdef QNX - PRIVATE->addr_.sin_len = sizeof(PRIVATE->addr_); -#endif - //piCoutObj << "connect SingleTCP" << ip_s << ":" << port_s << "..."; - if (!connectTCP()) { - //piCoutObj << "Can`t connect to " << ip_s << ":" << port_s << ", " << ethErrorString(); - piMinSleep(); - return -1; - } - //piCoutObj << "ok, write SingleTCP" << int(data) << max_size << "bytes ..."; - ret = ::send(sock, (const char *)data, max_size, 0); - //piCoutObj << "ok, ret" << ret; - closeSocket(sock); - init(); - return ret; case UDP: PRIVATE->saddr_.sin_port = htons(addr_s.port()); PRIVATE->saddr_.sin_addr.s_addr = addr_s.ip(); @@ -912,6 +854,7 @@ ssize_t PIEthernet::writeDevice(const void * data, ssize_t max_size) { if (ret < 0) { piCoutObj << "Disconnect on write," << ethErrorString(); opened_ = connected_ = false; + closeSocket(sock); init(); disconnected(true); } @@ -926,8 +869,7 @@ PIIODevice::DeviceInfoFlags PIEthernet::deviceInfoFlags() const { switch (type()) { case UDP: return 0; case TCP_Client: - case TCP_Server: - case TCP_SingleTCP: return Sequential | Reliable; + case TCP_Server: return Sequential | Reliable; default: break; } return 0; @@ -960,9 +902,15 @@ void PIEthernet::server_func(void * eth) { piMSleep(10); return; } +#else + if (!ce->PRIVATEWB->event.wait(ce->sock)) { + piMSleep(10); + return; + } #endif + //piCout << "server" << "accept ..."; int s = accept(ce->sock, (sockaddr * )&client_addr, &slen); - piCout << ethErrorString(); + //piCout << "server" << "accept done" << ethErrorString(); if (s == -1) { int lerr = ethErrorCore(); #ifdef WINDOWS @@ -1003,44 +951,43 @@ void PIEthernet::setType(Type t, bool reopen) { bool PIEthernet::connectTCP() { -#ifdef WINDOWS ::connect(sock, (sockaddr * )&(PRIVATE->addr_), sizeof(PRIVATE->addr_)); + //piCout << errorString(); +#ifdef WINDOWS long wr = waitForEvent(FD_CONNECT | FD_CLOSE); switch (wr) { - case FD_CONNECT: { + case FD_CONNECT: //piCout << "fd_connect ..."; - timeval timeout; - timeout.tv_sec = 0; - timeout.tv_usec = 0; - fd_set fd_test; - FD_ZERO(&fd_test); - FD_SET(sock, &fd_test); - ::select(0, nullptr, &fd_test, nullptr, &timeout); - return FD_ISSET(sock, &fd_test); - } break; + return ethIsWriteable(sock); default: break; } - return false; #else - return ::connect(sock, (sockaddr * )&(PRIVATE->addr_), sizeof(PRIVATE->addr_)) == 0; + if (PRIVATE->event.wait(sock, PIWaitEvent::CheckWrite)) { + if (ethIsWriteable(sock)) return true; + else { + closeSocket(sock); + init(); + } + } #endif + return false; } #ifdef WINDOWS long PIEthernet::waitForEvent(long mask) { - if (!PRIVATE->read_event || sock < 0) return 0; - WSAEventSelect(sock, PRIVATE->read_event, mask); - DWORD wr = WSAWaitForMultipleEvents(1, &(PRIVATE->read_event), FALSE, WSA_INFINITE, TRUE); - piCout << "wait result" << wr; - if (wr == WSA_WAIT_EVENT_0) { + if (!PRIVATE->event.isCreate() || sock < 0) return 0; + WSAEventSelect(sock, PRIVATE->event.event, mask); + if (PRIVATE->event.wait()) { + //DWORD wr = WSAWaitForMultipleEvents(1, &(PRIVATE->read_event), FALSE, WSA_INFINITE, TRUE); + //piCout << "wait result" << wr; + //if (wr == WSA_WAIT_EVENT_0) { WSANETWORKEVENTS events; memset(&events, 0, sizeof(events)); - WSAEnumNetworkEvents(sock, PRIVATE->read_event, &events); - WSAResetEvent(PRIVATE->read_event); + WSAEnumNetworkEvents(sock, PRIVATE->event.event, &events); + //piCout << "wait result" << events.lNetworkEvents; return events.lNetworkEvents; } - WSAResetEvent(PRIVATE->read_event); return 0; } #endif @@ -1449,3 +1396,43 @@ int PIEthernet::ethSetsockoptBool(int sock, int level, int optname, bool value) so = (value ? 1 : 0); return ethSetsockopt(sock, level, optname, &so, sizeof(so)); } + + +void PIEthernet::ethNonblocking(int sock) { + if (sock < 0) return; +#ifdef WINDOWS + u_long mode = 1; + ioctlsocket(sock, FIONBIO, &mode); +#else + fcntl(sock, F_SETFL, O_NONBLOCK); +#endif +} + + +bool PIEthernet::ethIsWriteable(int sock) { +/* fd_set fd_test; + FD_ZERO(&fd_test); + FD_SET(sock, &fd_test); + int fds = 0; +#ifndef WINDOWS + fds = sock + 1; +#endif + timeval timeout; + timeout.tv_sec = timeout.tv_usec = 0; + ::select(fds, nullptr, &fd_test, nullptr, &timeout); + return FD_ISSET(sock, &fd_test);*/ +#ifdef WINDOWS + fd_set fd_test; + FD_ZERO(&fd_test); + FD_SET(sock, &fd_test); + timeval timeout; + timeout.tv_sec = timeout.tv_usec = 0; + ::select(0, nullptr, &fd_test, nullptr, &timeout); + return FD_ISSET(sock, &fd_test); +#else + int ret = 0; + socklen_t len = sizeof(ret); + getsockopt(sock, SOL_SOCKET, SO_ERROR, (char*)&ret, &len); + return ret == 0; +#endif +} diff --git a/libs/main/io_devices/piethernet.h b/libs/main/io_devices/piethernet.h index de8c5987..e4648874 100644 --- a/libs/main/io_devices/piethernet.h +++ b/libs/main/io_devices/piethernet.h @@ -49,8 +49,7 @@ public: enum Type { UDP /** UDP - User Datagram Protocol */ , TCP_Client /** TCP client - allow connection to TCP server */ , - TCP_Server /** TCP server - receive connections from TCP clients */ , - TCP_SingleTCP /** TCP client single mode - connect & send & disconnect, on each packet */ + TCP_Server /** TCP server - receive connections from TCP clients */ }; //! \brief Parameters of %PIEthernet @@ -315,6 +314,8 @@ public: bool canWrite() const override {return mode() & WriteOnly;} + void interrupt() override; + int socket() const {return sock;} EVENT1(newConnection, PIEthernet * , client); @@ -487,7 +488,7 @@ protected: PRIVATE_DECLARATION(PIP_EXPORT) int sock, sock_s; - bool connected_, connecting_, listen_threaded, server_bounded; + std::atomic_bool connected_, connecting_, listen_threaded, server_bounded; mutable Address addr_r, addr_s, addr_lr; Type eth_type; PIThread server_thread_; @@ -514,6 +515,8 @@ private: static int ethSetsockopt(int sock, int level, int optname, const void * optval, int optlen); static int ethSetsockoptInt(int sock, int level, int optname, int value = 1); static int ethSetsockoptBool(int sock, int level, int optname, bool value = true); + static void ethNonblocking(int sock); + static bool ethIsWriteable(int sock); }; diff --git a/libs/main/io_devices/piiodevice.cpp b/libs/main/io_devices/piiodevice.cpp index 155674a6..90c4d95b 100644 --- a/libs/main/io_devices/piiodevice.cpp +++ b/libs/main/io_devices/piiodevice.cpp @@ -131,8 +131,8 @@ PIIODevice::PIIODevice(const PIString & path, PIIODevice::DeviceMode mode): PIOb PIIODevice::~PIIODevice() { - stop(); - waitThreadedReadFinished(); + destroying = true; + stopAndWait(); } @@ -215,8 +215,10 @@ void PIIODevice::stopThreadedRead() { read_thread.stop(); #else read_thread.stop(); - read_thread.interrupt(); - stopThreadedReadDevice(); + if (!destroying) { + interrupt(); + stopThreadedReadDevice(); + } if (reading_now) { read_thread.terminate(); reading_now = false; @@ -271,6 +273,13 @@ void PIIODevice::stop() { } +void PIIODevice::stopAndWait(int timeout_ms) { + stop(); + waitThreadedReadFinished(timeout_ms); + waitThreadedWriteFinished(timeout_ms); +} + + ssize_t PIIODevice::read(void * read_to, ssize_t max_size) { ssize_t ret = readDevice(read_to, max_size); return ret; diff --git a/libs/main/io_devices/piiodevice.h b/libs/main/io_devices/piiodevice.h index c5f7936d..3bd8f3b9 100644 --- a/libs/main/io_devices/piiodevice.h +++ b/libs/main/io_devices/piiodevice.h @@ -277,6 +277,14 @@ public: //! \~russian Останавливает потоковое чтение и запись. void stop(); + //! \~english Stop both threaded read and threaded write and wait for finish. + //! \~russian Останавливает потоковое чтение и запись и ожидает завершения. + void stopAndWait(int timeout_ms = -1); + + //! \~english Interrupt blocking operation. + //! \~russian Прерывает блокирующую операцию. + virtual void interrupt() {} + //! \~english Read from device maximum "max_size" bytes to "read_to" //! \~russian Читает из устройства не более "max_size" байт в "read_to" @@ -561,7 +569,7 @@ private: PIQueue > write_queue; ullong tri = 0; uint threaded_read_buffer_size, reopen_timeout = 1000; - bool reopen_enabled = true; + bool reopen_enabled = true, destroying = false; static PIMutex nfp_mutex; static PIMap nfp_cache; diff --git a/libs/main/io_devices/piserial.cpp b/libs/main/io_devices/piserial.cpp index d3c97c44..a9437a73 100644 --- a/libs/main/io_devices/piserial.cpp +++ b/libs/main/io_devices/piserial.cpp @@ -22,6 +22,7 @@ #include "piconfig.h" #include "pidir.h" #include "pipropertystorage.h" +#include "piwaitevent_p.h" #include #if defined(MICRO_PIP) @@ -169,24 +170,22 @@ REGISTER_DEVICE(PISerial) PRIVATE_DEFINITION_START(PISerial) + PIWaitEvent event; #ifdef WINDOWS + PIWaitEvent event_write; DCB desc, sdesc; - void * hCom; - DWORD readed, mask; + HANDLE hCom = nullptr; + DWORD readed = 0, mask = 0; + OVERLAPPED overlap, overlap_write; #else termios desc, sdesc; - uint readed; + uint readed = 0; #endif PRIVATE_DEFINITION_END(PISerial) -PISerial::DeviceInfo::DeviceInfo() { - vID = pID = 0; -} - - PIString PISerial::DeviceInfo::id() const { return PIString::fromNumber(vID, 16).toLowerCase().expandLeftTo(4, '0') + ":" + PIString::fromNumber(pID, 16).toLowerCase().expandLeftTo(4, '0'); @@ -209,19 +208,18 @@ PISerial::PISerial(const PIString & device_, PISerial::Speed speed_, PIFlagsevent.destroy(); +#ifdef WINDOWS + PRIVATE->event_write.destroy(); +#endif } void PISerial::construct() { -#ifdef WINDOWS - PRIVATE->hCom = 0; -#endif - fd = -1; - //setPriority(piHigh); - vtime = 10; sending = false; + //setPriority(piHigh); setParameters(0); setSpeed(S115200); setDataBitsCount(8); @@ -628,6 +626,15 @@ bool PISerial::send(const void * data, int size) { } +void PISerial::interrupt() { + //piCoutObj << "interrupt"; + PRIVATE->event.interrupt(); +#ifdef WINDOWS + PRIVATE->event_write.interrupt(); +#endif +} + + bool PISerial::openDevice() { PIString p = path(); //piCout << "ser open" << p; @@ -651,7 +658,7 @@ bool PISerial::openDevice() { if (isReadable()) {ds |= GENERIC_READ; sm |= FILE_SHARE_READ;} if (isWriteable()) {ds |= GENERIC_WRITE; sm |= FILE_SHARE_WRITE;} PIString wp = "//./" + p; - PRIVATE->hCom = CreateFileA(wp.dataAscii(), ds, sm, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0); + PRIVATE->hCom = CreateFileA(wp.dataAscii(), ds, sm, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0); if (PRIVATE->hCom == INVALID_HANDLE_VALUE) { piCoutObj << "Unable to open \"" << p << "\""; fd = -1; @@ -675,6 +682,11 @@ bool PISerial::openDevice() { //piCoutObj << "Initialized " << p; #endif applySettings(); + PRIVATE->event.create(); +#ifdef WINDOWS + PRIVATE->event_write.create(); +#endif + return true; } @@ -696,6 +708,10 @@ bool PISerial::closeDevice() { #endif fd = -1; } + PRIVATE->event.destroy(); +#ifdef WINDOWS + PRIVATE->event_write.destroy(); +#endif return true; } @@ -796,12 +812,21 @@ ssize_t PISerial::readDevice(void * read_to, ssize_t max_size) { #ifdef WINDOWS if (!canRead()) return -1; if (sending) return -1; -// piCoutObj << "com event ..."; //piCoutObj << "read ..." << PRIVATE->hCom; - ReadFile(PRIVATE->hCom, read_to, max_size, &PRIVATE->readed, 0); + memset(&(PRIVATE->overlap), 0, sizeof(PRIVATE->overlap)); + PRIVATE->overlap.hEvent = PRIVATE->event.event; + ReadFile(PRIVATE->hCom, read_to, max_size, NULL, &(PRIVATE->overlap)); + PRIVATE->readed = 0; + if (PRIVATE->event.wait()) { + GetOverlappedResult(PRIVATE->hCom, &(PRIVATE->overlap), &(PRIVATE->readed), FALSE); + } else + return -1; + //piCoutObj << "read done" << PRIVATE->readed; DWORD err = GetLastError(); - //piCout << err; + if (err == ERROR_TIMEOUT && PRIVATE->readed == 0) + return 0; if (err == ERROR_BAD_COMMAND || err == ERROR_ACCESS_DENIED) { + piCoutObj << "read error" << (PRIVATE->readed) << errorString(); softStopThreadedRead(); close(); return 0; @@ -810,9 +835,8 @@ ssize_t PISerial::readDevice(void * read_to, ssize_t max_size) { return PRIVATE->readed; #else if (!canRead()) return -1; - reading_now = true; + if (!PRIVATE->event.wait(fd)) return -1; ssize_t ret = ::read(fd, read_to, max_size); - reading_now = false; if (ret < 0) { int err = errno; if (err == EBADF || err == EFAULT || err == EINVAL || err == EIO) { @@ -832,12 +856,17 @@ ssize_t PISerial::writeDevice(const void * data, ssize_t max_size) { return -1; } #ifdef WINDOWS - DWORD wrote; -// piCoutObj << "send ...";// << max_size;// << ": " << PIString((char*)data, max_size); + DWORD wrote(0); + //piCoutObj << "send ..." << max_size;// << ": " << PIString((char*)data, max_size); sending = true; - WriteFile(PRIVATE->hCom, data, max_size, &wrote, 0); + memset(&(PRIVATE->overlap_write), 0, sizeof(PRIVATE->overlap_write)); + PRIVATE->overlap_write.hEvent = PRIVATE->event_write.event; + WriteFile(PRIVATE->hCom, data, max_size, NULL, &(PRIVATE->overlap_write)); + if (PRIVATE->event_write.wait()) { + GetOverlappedResult(PRIVATE->hCom, &(PRIVATE->overlap_write), &wrote, FALSE); + } sending = false; -// piCoutObj << "send ok";// << wrote << " bytes in " << path(); + //piCoutObj << "send ok" << wrote;// << " bytes in " << path(); #else ssize_t wrote; wrote = ::write(fd, data, max_size); @@ -1148,7 +1177,7 @@ PIVector PISerial::availableDevicesInfo(bool test) { if (test) { for (int i = 0; i < ret.size_s(); ++i) { #ifdef WINDOWS - void * hComm = CreateFileA(ret[i].path.dataAscii(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0); + void * hComm = CreateFileA(ret[i].path.dataAscii(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0); if (hComm == INVALID_HANDLE_VALUE) { #else int fd = ::open(ret[i].path.dataAscii(), O_NOCTTY | O_RDONLY); diff --git a/libs/main/io_devices/piserial.h b/libs/main/io_devices/piserial.h index 54277eb4..aa8bdc16 100644 --- a/libs/main/io_devices/piserial.h +++ b/libs/main/io_devices/piserial.h @@ -90,19 +90,17 @@ public: //! \~english Information about serial device //! \~russian Информация о последовательном устройстве struct PIP_EXPORT DeviceInfo { - DeviceInfo(); - //! \~english Returns string representation of USB ID in format "xxxx:xxxx" (vID:pID) //! \~russian Возвращает строковое представление USB ID в формате "xxxx:xxxx" (vID:pID) PIString id() const; //! \~english USB Vendor ID //! \~russian USB Vendor ID - uint vID; + uint vID = 0; //! \~english USB Product ID //! \~russian USB Product ID - uint pID; + uint pID = 0; //! \~english Path to device, e.g. "COM2" or "/dev/ttyUSB0" //! \~russian Путь к устройству, например "COM2" или "/dev/ttyUSB0" @@ -240,6 +238,8 @@ public: //! \~russian Пишет в порт байтовый массив "data". Возвращает если количество записанных байт = размер "data" bool send(const PIByteArray & data) {return send(data.data(), data.size_s());} + void interrupt() override; + //! \~english Returns all available speeds for serial devices //! \~russian Возвращает все возможные скорости для устройств static PIVector availableSpeeds(); @@ -310,8 +310,8 @@ protected: bool closeDevice() override; PRIVATE_DECLARATION(PIP_EXPORT) - int fd, vtime; - bool sending; + int fd = -1, vtime = 10; + std::atomic_bool sending; PITimeMeasurer tm_; }; diff --git a/libs/main/io_utils/piconnection.cpp b/libs/main/io_utils/piconnection.cpp index 4c32ad80..90f36bd5 100644 --- a/libs/main/io_utils/piconnection.cpp +++ b/libs/main/io_utils/piconnection.cpp @@ -1115,7 +1115,7 @@ PIVector PIConnection::DevicePool::boundedDevices(const PIConnect PIConnection::DevicePool::DeviceData::~DeviceData() { if (rthread) { rthread->stop(); - rthread->interrupt(); + if (dev) dev->interrupt(); if (!rthread->waitForFinish(1000)) rthread->terminate(); delete rthread; diff --git a/main.cpp b/main.cpp index 46f90d43..73e4ad68 100644 --- a/main.cpp +++ b/main.cpp @@ -79,6 +79,12 @@ public: Pipe pipe; }; +PITimeMeasurer tm; +void phase(const char * msg) { + piCout << ""; + piCout << piRound(tm.elapsed_s() * 10) / 10. << "s" << msg; +} + int main(int argc, char * argv[]) { piCout << "main"; @@ -109,53 +115,87 @@ int main(int argc, char * argv[]) { delete threads[i]; }*/ - PIEthernet eth(PIEthernet::UDP), seth(PIEthernet::TCP_Client); - eth.connect("127.0.0.1", 50000); - eth.startThreadedRead(); + //PIEthernet eth(PIEthernet::UDP), seth(PIEthernet::UDP); + //eth.setReadAddress("127.0.0.1", 50000); + //eth.startThreadedRead(); //piCout << eth.open(); - /* + PIByteArray req = PIByteArray::fromHex("205e011000000000ef"); PISerial ser; ser.setSpeed(PISerial::S9600); - ser.setOption(PIIODevice::BlockingRead); - piCout << ser.open("COM3"); - */ - - /* + ser.setOption(PIIODevice::BlockingRead, false); + ser.setVTime(200); + ser.open("COM3"); + CONNECTL(&ser, threadedReadEvent, ([](const uchar * data, ssize_t size){ + piCout << "*ser readed" << size; + })); PIThread thread; thread.start([&](void*){ - piCout << "[T] start" << GetCurrentThreadId(); - //PIByteArray data = ((PIIODevice*)&ser)->read(1024); - eth.connect("192.168.1.13", 23, false); - piCout << "[T] connected" << eth.isConnected() << errorString(); - //piCout << "[T] readed" << data.size() << errorString(); + piCout << "[T] start"; + PIByteArray data = ((PIIODevice*)&ser)->read(1024); + piCout << "[T] readed" << data.size();// << errorString(); piCout << "[T] end"; - }); - piMSleep(500); - //eth.close(); - //piMSleep(500); - thread.stop(); - thread.interrupt(); - //seth.send("127.0.0.1", 50000, "string", 7); - //thread.interrupt(); - thread.waitForFinish(); - */ + }, 200); + //ser.startThreadedRead(); + + piSleep(1); + ser.write(req); + phase("Send"); + + piSleep(2); + phase("End"); /* - eth.listen("127.0.0.1", 50000); - seth.connect("127.0.0.1", 50001, false); + PIEthernet eth(PIEthernet::TCP_Client), seth(PIEthernet::TCP_Server), * server_client = nullptr; + + seth.listen("127.0.0.1", 50000, true); + //seth.startThreadedRead(); + CONNECTL(&seth, newConnection, ([&server_client](PIEthernet * e){ + server_client = e; + e->setName("TCP SC"); + piCout << "newConn" << e; + CONNECTL(e, threadedReadEvent, ([](const uchar * data, ssize_t size){ + piCout << "*TCP SC* readed" << size; + })); + CONNECTL(e, disconnected, ([](bool error){ + piCout << "*TCP SC* disconnected" << error; + })); + e->startThreadedRead(); + })); + + eth.setName("TCP CC"); + //eth.setParameter(PIEthernet::KeepConnection, false); + CONNECTL(ð, connected, ([ð](){ + piCout << "*TCP CC* connected"; + eth.send("byte", 5); + })); + CONNECTL(ð, disconnected, ([](bool error){ + piCout << "*TCP CC* disconnected" << error; + })); + piMSleep(500); - piCout << "connected" << seth.isConnected(); - */ - piMSleep(1000); - piCout << "main stop ..."; - eth.stopThreadedRead(); - piCout << "main wait ..." << eth.isThreadedRead(); - eth.waitThreadedReadFinished(); + phase("Connect"); + eth.connect("127.0.0.1", 50000); + eth.startThreadedRead(); + piMSleep(500); + phase("Send 5"); + piCout << "c-ing" << eth.isConnecting(); + piCout << "c- ed" << eth.isConnected(); + eth.send("byte", 5); + + piMSleep(500); + phase("Send 6"); + eth.send("bytes", 6); + + piMSleep(500); + phase("Disconnect"); + if (server_client) + server_client->close(); //eth.close(); - piCout << "main end" << eth.isThreadedRead(); - //ser.close(); + piMSleep(500); + phase("END"); + */ return 0; } -- 2.43.0 From f08a07cab06c753f76992fcda706645b3816e34b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D1=8B=D1=87=D0=BA=D0=BE=D0=B2=20=D0=90=D0=BD=D0=B4?= =?UTF-8?q?=D1=80=D0=B5=D0=B9?= Date: Mon, 7 Nov 2022 17:16:27 +0300 Subject: [PATCH 05/23] =?UTF-8?q?=D0=BD=D0=B5=D0=B1=D0=BE=D0=BB=D1=8C?= =?UTF-8?q?=D1=88=D0=B0=D1=8F=20=D1=87=D0=B8=D1=81=D1=82=D0=BA=D0=B0=20?= =?UTF-8?q?=D0=B8=20=D1=83=D0=BB=D1=83=D1=87=D1=88=D0=B5=D0=BD=D0=B8=D0=B5?= =?UTF-8?q?=20=D0=BA=D0=BE=D0=B4=D0=B0,=20=D0=BF=D0=BE=D0=BF=D1=8B=D1=82?= =?UTF-8?q?=D0=BA=D0=B0=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=B8=D1=82?= =?UTF-8?q?=D1=8C=20picloud?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs/cloud/picloudclient.cpp | 29 ++++++++++------------ libs/cloud/picloudserver.cpp | 17 ++++++------- libs/main/cloud/picloudclient.h | 1 - libs/main/cloud/picloudserver.h | 1 - libs/main/core/piwaitevent_p.cpp | 38 ++++++++++++----------------- libs/main/core/piwaitevent_p.h | 21 ++++++++-------- libs/main/io_devices/piethernet.cpp | 4 +-- libs/main/io_devices/pifile.cpp | 2 -- libs/main/io_devices/piiodevice.cpp | 8 ++---- libs/main/io_devices/piiodevice.h | 8 ------ libs/main/io_devices/piserial.cpp | 4 +-- 11 files changed, 54 insertions(+), 79 deletions(-) diff --git a/libs/cloud/picloudclient.cpp b/libs/cloud/picloudclient.cpp index df32160d..db0729c1 100644 --- a/libs/cloud/picloudclient.cpp +++ b/libs/cloud/picloudclient.cpp @@ -45,10 +45,7 @@ PICloudClient::PICloudClient(const PIString & path, PIIODevice::DeviceMode mode) PICloudClient::~PICloudClient() { //piCoutObj << "~PICloudClient()"; - //softStopThreadedRead(); - //eth.close(); - //if (is_connected) disconnected(); - //close(); + stopAndWait(); //piCoutObj << "~PICloudClient() closed"; internalDisconnect(); @@ -71,7 +68,8 @@ void PICloudClient::setKeepConnection(bool on) { void PICloudClient::interrupt() { - eth.interrupt(); + cond_buff.notifyOne(); + cond_connect.notifyOne(); } @@ -87,7 +85,7 @@ bool PICloudClient::openDevice() { mutex_connect.unlock(); if (!conn_ok) { mutex_connect.lock(); - eth.stop(); + eth.stopAndWait(); eth.close(); mutex_connect.unlock(); } @@ -104,7 +102,7 @@ bool PICloudClient::closeDevice() { if (is_connected) { internalDisconnect(); } - eth.stop(); + eth.stopAndWait(); eth.close(); return true; } @@ -116,11 +114,15 @@ ssize_t PICloudClient::readDevice(void * read_to, ssize_t max_size) { if (!is_connected && eth.isClosed()) openDevice(); ssize_t sz = -1; mutex_buff.lock(); - cond_buff.wait(mutex_buff, [this](){return !buff.isEmpty() || !is_connected;}); + cond_buff.wait(mutex_buff); if (is_connected) { - sz = piMini(max_size, buff.size()); - memcpy(read_to, buff.data(), sz); - buff.remove(0, sz); + if (buff.isEmpty()) { + sz = 0; + } else { + sz = piMini(max_size, buff.size()); + memcpy(read_to, buff.data(), sz); + buff.remove(0, sz); + } } mutex_buff.unlock(); if (!is_connected) opened_ = false; @@ -136,11 +138,6 @@ ssize_t PICloudClient::writeDevice(const void * data, ssize_t size) { } -void PICloudClient::stopThreadedReadDevice() { - cond_buff.notifyOne(); -} - - void PICloudClient::internalDisconnect() { is_connected = false; cond_buff.notifyOne(); diff --git a/libs/cloud/picloudserver.cpp b/libs/cloud/picloudserver.cpp index 931038bc..c968bff1 100644 --- a/libs/cloud/picloudserver.cpp +++ b/libs/cloud/picloudserver.cpp @@ -102,11 +102,6 @@ ssize_t PICloudServer::writeDevice(const void * data, ssize_t max_size) { } -void PICloudServer::stopThreadedReadDevice() { - -} - - void PICloudServer::interrupt() { eth.interrupt(); } @@ -159,11 +154,15 @@ ssize_t PICloudServer::Client::readDevice(void * read_to, ssize_t max_size) { if (!is_connected) return -1; ssize_t sz = -1; mutex_buff.lock(); - cond_buff.wait(mutex_buff, [this](){return !buff.isEmpty() || !is_connected;}); + cond_buff.wait(mutex_buff); if (is_connected) { - sz = piMini(max_size, buff.size()); - memcpy(read_to, buff.data(), sz); - buff.remove(0, sz); + if (buff.isEmpty()) { + sz = 0; + } else { + sz = piMini(max_size, buff.size()); + memcpy(read_to, buff.data(), sz); + buff.remove(0, sz); + } } mutex_buff.unlock(); return sz; diff --git a/libs/main/cloud/picloudclient.h b/libs/main/cloud/picloudclient.h index 4fb58d9b..e9217dd3 100644 --- a/libs/main/cloud/picloudclient.h +++ b/libs/main/cloud/picloudclient.h @@ -54,7 +54,6 @@ protected: ssize_t readDevice(void * read_to, ssize_t max_size) override; ssize_t writeDevice(const void * data, ssize_t size) override; DeviceInfoFlags deviceInfoFlags() const override {return PIIODevice::Reliable;} - void stopThreadedReadDevice() override; private: EVENT_HANDLER1(void, _readed, PIByteArray &, data); diff --git a/libs/main/cloud/picloudserver.h b/libs/main/cloud/picloudserver.h index 4f8d110d..a0fca4bd 100644 --- a/libs/main/cloud/picloudserver.h +++ b/libs/main/cloud/picloudserver.h @@ -74,7 +74,6 @@ protected: bool closeDevice() override; ssize_t readDevice(void * read_to, ssize_t max_size) override; ssize_t writeDevice(const void * data, ssize_t max_size) override; - void stopThreadedReadDevice() override; void interrupt() override; private: diff --git a/libs/main/core/piwaitevent_p.cpp b/libs/main/core/piwaitevent_p.cpp index f4a832dc..d576ba31 100644 --- a/libs/main/core/piwaitevent_p.cpp +++ b/libs/main/core/piwaitevent_p.cpp @@ -45,7 +45,7 @@ void PIWaitEvent::create() { piCout << "Error with CreateEventA:" << errorString(); } #else - for (int i = 0; i < 3; ++i) memset(&(fds[i]), 0, sizeof(fds[i])); + for (int i = 0; i < sizeof(fds); ++i) memset(&(fds[i]), 0, sizeof(fds[i])); if (::pipe(pipe_fd) < 0) { piCout << "Error with pipe:" << errorString(); } else { @@ -62,7 +62,7 @@ void PIWaitEvent::destroy() { event = NULL; } #else - for (int i = 0; i < 2; ++i) { + for (int i = 0; i < sizeof(pipe_fd); ++i) { if (pipe_fd[i] != 0) { ::close(pipe_fd[i]); pipe_fd[i] = 0; @@ -72,35 +72,24 @@ void PIWaitEvent::destroy() { } -#ifdef WINDOWS -bool PIWaitEvent::wait() { -#else -bool PIWaitEvent::wait(int fd, PIWaitEvent::SelectRole role) { -#endif +bool PIWaitEvent::wait(int fd, CheckRole role) { if (!isCreate()) return false; #ifdef WINDOWS DWORD ret = WaitForSingleObjectEx(event, INFINITE, TRUE); ResetEvent(event); if (ret == WAIT_IO_COMPLETION || ret == WAIT_FAILED) return false; #else + if (fd == -1) return false; int nfds = piMaxi(pipe_fd[ReadEnd], fd) + 1; - int fd_index = 0; - switch (role) { - case CheckRead: - fd_index = 0; - break; - case CheckWrite: - fd_index = 1; - break; - } - for (int i = 0; i < 3; ++i) FD_ZERO(&(fds[i])); - FD_SET(pipe_fd[ReadEnd], &(fds[0])); - FD_SET(fd, &(fds[2])); - FD_SET(fd, &(fds[fd_index])); - ::select(nfds, &(fds[0]), &(fds[1]), &(fds[2]), nullptr); + int fd_index = role; + for (int i = 0; i < sizeof(fds); ++i) FD_ZERO(&(fds[i])); + FD_SET(pipe_fd[ReadEnd], &(fds[CheckRead])); + FD_SET(fd, &(fds[CheckExeption])); + if (fd_index != CheckExeption) FD_SET(fd, &(fds[fd_index])); + ::select(nfds, &(fds[CheckRead]), &(fds[CheckWrite]), &(fds[CheckExeption]), nullptr); int buf = 0; while (::read(pipe_fd[ReadEnd], &buf, sizeof(buf)) > 0); - if (FD_ISSET(fd, &(fds[2]))) return false; + if (FD_ISSET(fd, &(fds[CheckExeption]))) return false; return FD_ISSET(fd, &(fds[fd_index])); #endif return true; @@ -124,3 +113,8 @@ bool PIWaitEvent::isCreate() const { return pipe_fd[ReadEnd] != 0; #endif } + + +void * PIWaitEvent::getEvent() const { + return event; +} diff --git a/libs/main/core/piwaitevent_p.h b/libs/main/core/piwaitevent_p.h index e5c7ee73..e0f18299 100644 --- a/libs/main/core/piwaitevent_p.h +++ b/libs/main/core/piwaitevent_p.h @@ -37,22 +37,23 @@ public: void create(); void destroy(); -#ifdef WINDOWS - bool wait(); -#else - enum SelectRole { + + enum CheckRole { // UNIX only CheckRead, - CheckWrite + CheckWrite, + CheckExeption }; - bool wait(int fd, SelectRole role = CheckRead); -#endif + bool wait(int fd = -1, CheckRole role = CheckRead); + void interrupt(); bool isCreate() const; -#ifdef WINDOWS - HANDLE event = NULL; -#else + void * getEvent() const; // WINDOWS only + private: +#ifdef WINDOWS + void * event = nullptr; +#else int pipe_fd[2] = {0, 0}; fd_set fds[3]; enum { diff --git a/libs/main/io_devices/piethernet.cpp b/libs/main/io_devices/piethernet.cpp index 18d0f4e2..8106921e 100644 --- a/libs/main/io_devices/piethernet.cpp +++ b/libs/main/io_devices/piethernet.cpp @@ -977,14 +977,14 @@ bool PIEthernet::connectTCP() { #ifdef WINDOWS long PIEthernet::waitForEvent(long mask) { if (!PRIVATE->event.isCreate() || sock < 0) return 0; - WSAEventSelect(sock, PRIVATE->event.event, mask); + WSAEventSelect(sock, PRIVATE->event.getEvent(), mask); if (PRIVATE->event.wait()) { //DWORD wr = WSAWaitForMultipleEvents(1, &(PRIVATE->read_event), FALSE, WSA_INFINITE, TRUE); //piCout << "wait result" << wr; //if (wr == WSA_WAIT_EVENT_0) { WSANETWORKEVENTS events; memset(&events, 0, sizeof(events)); - WSAEnumNetworkEvents(sock, PRIVATE->event.event, &events); + WSAEnumNetworkEvents(sock, PRIVATE->event.getEvent(), &events); //piCout << "wait result" << events.lNetworkEvents; return events.lNetworkEvents; } diff --git a/libs/main/io_devices/pifile.cpp b/libs/main/io_devices/pifile.cpp index 69bd4c44..20dae7c3 100644 --- a/libs/main/io_devices/pifile.cpp +++ b/libs/main/io_devices/pifile.cpp @@ -439,9 +439,7 @@ PIByteArray PIFile::get() { ssize_t PIFile::readDevice(void * read_to, ssize_t max_size) { if (!canRead() || PRIVATE->fd == 0) return -1; - reading_now = true; ssize_t ret = fread(read_to, 1, max_size, PRIVATE->fd); - reading_now = false; return ret; } diff --git a/libs/main/io_devices/piiodevice.cpp b/libs/main/io_devices/piiodevice.cpp index 90c4d95b..bbcfc092 100644 --- a/libs/main/io_devices/piiodevice.cpp +++ b/libs/main/io_devices/piiodevice.cpp @@ -217,11 +217,8 @@ void PIIODevice::stopThreadedRead() { read_thread.stop(); if (!destroying) { interrupt(); - stopThreadedReadDevice(); - } - if (reading_now) { - read_thread.terminate(); - reading_now = false; + } else { + piCoutObj << "Error: Device is running after destructor!"; } #endif } @@ -307,7 +304,6 @@ ssize_t PIIODevice::write(const void * data, ssize_t max_size) { void PIIODevice::_init() { - reading_now = false; setOptions(0); setReopenEnabled(true); setReopenTimeout(1000); diff --git a/libs/main/io_devices/piiodevice.h b/libs/main/io_devices/piiodevice.h index 3bd8f3b9..2ce101ef 100644 --- a/libs/main/io_devices/piiodevice.h +++ b/libs/main/io_devices/piiodevice.h @@ -498,10 +498,6 @@ protected: //! \~english Function executed when thread read some data, default implementation execute external callback "ret_func_" //! \~russian Метод вызывается после каждого успешного потокового чтения, по умолчанию вызывает callback "ret_func_" virtual bool threadedRead(const uchar * readed, ssize_t size); - - //! \~english Function executed after PIThread::stop() and PIThread::interrupt() of read thread - //! \~russian Метод вызывается после PIThread::stop() и PIThread::interrupt() потока чтения - virtual void stopThreadedReadDevice() {} //! \~english Reimplement to construct full unambiguous string, describes this device. //! Default implementation returns \a path() @@ -549,10 +545,6 @@ protected: bool opened_ = false; void * ret_data_ = nullptr; - //! \~english Set this flag while blocking operations - //! \~russian Устанавливайте этот флаг во время блокирующих операций - std::atomic_bool reading_now; - private: EVENT_HANDLER(void, read_func); EVENT_HANDLER(void, write_func); diff --git a/libs/main/io_devices/piserial.cpp b/libs/main/io_devices/piserial.cpp index a9437a73..b7590f7e 100644 --- a/libs/main/io_devices/piserial.cpp +++ b/libs/main/io_devices/piserial.cpp @@ -814,7 +814,7 @@ ssize_t PISerial::readDevice(void * read_to, ssize_t max_size) { if (sending) return -1; //piCoutObj << "read ..." << PRIVATE->hCom; memset(&(PRIVATE->overlap), 0, sizeof(PRIVATE->overlap)); - PRIVATE->overlap.hEvent = PRIVATE->event.event; + PRIVATE->overlap.hEvent = PRIVATE->event.getEvent(); ReadFile(PRIVATE->hCom, read_to, max_size, NULL, &(PRIVATE->overlap)); PRIVATE->readed = 0; if (PRIVATE->event.wait()) { @@ -860,7 +860,7 @@ ssize_t PISerial::writeDevice(const void * data, ssize_t max_size) { //piCoutObj << "send ..." << max_size;// << ": " << PIString((char*)data, max_size); sending = true; memset(&(PRIVATE->overlap_write), 0, sizeof(PRIVATE->overlap_write)); - PRIVATE->overlap_write.hEvent = PRIVATE->event_write.event; + PRIVATE->overlap_write.hEvent = PRIVATE->event_write.getEvent(); WriteFile(PRIVATE->hCom, data, max_size, NULL, &(PRIVATE->overlap_write)); if (PRIVATE->event_write.wait()) { GetOverlappedResult(PRIVATE->hCom, &(PRIVATE->overlap_write), &wrote, FALSE); -- 2.43.0 From 93a1bf4f6d0d3f38d72dc7c3990f895943af9537 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D1=8B=D1=87=D0=BA=D0=BE=D0=B2=20=D0=90=D0=BD=D0=B4?= =?UTF-8?q?=D1=80=D0=B5=D0=B9?= Date: Mon, 7 Nov 2022 17:32:10 +0300 Subject: [PATCH 06/23] some unsuccessfull fixes for picloud --- libs/cloud/picloudclient.cpp | 6 +----- libs/cloud/picloudserver.cpp | 4 ++-- utils/cloud_dispatcher/dispatcherclient.cpp | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/libs/cloud/picloudclient.cpp b/libs/cloud/picloudclient.cpp index db0729c1..4a88b807 100644 --- a/libs/cloud/picloudclient.cpp +++ b/libs/cloud/picloudclient.cpp @@ -45,14 +45,10 @@ PICloudClient::PICloudClient(const PIString & path, PIIODevice::DeviceMode mode) PICloudClient::~PICloudClient() { //piCoutObj << "~PICloudClient()"; - stopAndWait(); - //piCoutObj << "~PICloudClient() closed"; - internalDisconnect(); -// stop(false); + close(); is_deleted = true; internalDisconnect(); - //piCoutObj << "~PICloudClient() done"; } diff --git a/libs/cloud/picloudserver.cpp b/libs/cloud/picloudserver.cpp index c968bff1..98704297 100644 --- a/libs/cloud/picloudserver.cpp +++ b/libs/cloud/picloudserver.cpp @@ -30,6 +30,7 @@ PICloudServer::PICloudServer(const PIString & path, PIIODevice::DeviceMode mode) CONNECTL(ð, disconnected, [this](bool){ piCoutObj << "disconnected"; eth.softStopThreadedRead(); + eth.interrupt(); opened_ = false; ping_timer.stop(false); piMSleep(100); @@ -129,8 +130,8 @@ PICloudServer::Client::~Client() { is_connected = false; cond_buff.notifyOne(); } + stopAndWait(); close(); - stop(); } @@ -140,7 +141,6 @@ bool PICloudServer::Client::openDevice() { bool PICloudServer::Client::closeDevice() { - softStopThreadedRead(); if (is_connected) { server->clientDisconnect(client_id); is_connected = false; diff --git a/utils/cloud_dispatcher/dispatcherclient.cpp b/utils/cloud_dispatcher/dispatcherclient.cpp index b2d53fd4..b370ebb7 100644 --- a/utils/cloud_dispatcher/dispatcherclient.cpp +++ b/utils/cloud_dispatcher/dispatcherclient.cpp @@ -28,7 +28,7 @@ PIString DispatcherClient::address() { void DispatcherClient::close() { eth->softStopThreadedRead(); - eth->close(); + eth->interrupt(); } -- 2.43.0 From fffaf0726d17af63c8d9ed825a8d88886913262d Mon Sep 17 00:00:00 2001 From: peri4 Date: Mon, 7 Nov 2022 18:07:26 +0300 Subject: [PATCH 07/23] CAN adopted, Linux work --- libs/main/core/piwaitevent_p.cpp | 11 +++++++---- libs/main/core/piwaitevent_p.h | 8 +++----- libs/main/io_devices/pican.cpp | 22 +++++++++++++++++----- libs/main/io_devices/pican.h | 2 ++ 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/libs/main/core/piwaitevent_p.cpp b/libs/main/core/piwaitevent_p.cpp index d576ba31..954aa870 100644 --- a/libs/main/core/piwaitevent_p.cpp +++ b/libs/main/core/piwaitevent_p.cpp @@ -28,7 +28,6 @@ # include # include #endif -#include "piincludes_p.h" #include "pistring.h" @@ -45,7 +44,7 @@ void PIWaitEvent::create() { piCout << "Error with CreateEventA:" << errorString(); } #else - for (int i = 0; i < sizeof(fds); ++i) memset(&(fds[i]), 0, sizeof(fds[i])); + for (int i = 0; i < 3; ++i) memset(&(fds[i]), 0, sizeof(fds[i])); if (::pipe(pipe_fd) < 0) { piCout << "Error with pipe:" << errorString(); } else { @@ -62,7 +61,7 @@ void PIWaitEvent::destroy() { event = NULL; } #else - for (int i = 0; i < sizeof(pipe_fd); ++i) { + for (int i = 0; i < 2; ++i) { if (pipe_fd[i] != 0) { ::close(pipe_fd[i]); pipe_fd[i] = 0; @@ -82,7 +81,7 @@ bool PIWaitEvent::wait(int fd, CheckRole role) { if (fd == -1) return false; int nfds = piMaxi(pipe_fd[ReadEnd], fd) + 1; int fd_index = role; - for (int i = 0; i < sizeof(fds); ++i) FD_ZERO(&(fds[i])); + for (int i = 0; i < 3; ++i) FD_ZERO(&(fds[i])); FD_SET(pipe_fd[ReadEnd], &(fds[CheckRead])); FD_SET(fd, &(fds[CheckExeption])); if (fd_index != CheckExeption) FD_SET(fd, &(fds[fd_index])); @@ -116,5 +115,9 @@ bool PIWaitEvent::isCreate() const { void * PIWaitEvent::getEvent() const { +#ifdef WINDOWS return event; +#else + return nullptr; +#endif } diff --git a/libs/main/core/piwaitevent_p.h b/libs/main/core/piwaitevent_p.h index e0f18299..a4395eaf 100644 --- a/libs/main/core/piwaitevent_p.h +++ b/libs/main/core/piwaitevent_p.h @@ -35,19 +35,17 @@ class PIWaitEvent { public: ~PIWaitEvent(); - void create(); - void destroy(); - enum CheckRole { // UNIX only CheckRead, CheckWrite, CheckExeption }; - bool wait(int fd = -1, CheckRole role = CheckRead); + void create(); + void destroy(); + bool wait(int fd = -1, CheckRole role = CheckRead); void interrupt(); bool isCreate() const; - void * getEvent() const; // WINDOWS only private: diff --git a/libs/main/io_devices/pican.cpp b/libs/main/io_devices/pican.cpp index 66381091..7f42774e 100644 --- a/libs/main/io_devices/pican.cpp +++ b/libs/main/io_devices/pican.cpp @@ -18,7 +18,7 @@ */ #include "pican.h" #include "pipropertystorage.h" -#include "piincludes_p.h" +#include "piwaitevent_p.h" #if !defined(WINDOWS) && !defined(MAC_OS) && !defined(MICRO_PIP) # define PIP_CAN #endif @@ -39,17 +39,24 @@ REGISTER_DEVICE(PICAN) +PRIVATE_DEFINITION_START(PICAN) + PIWaitEvent event; +PRIVATE_DEFINITION_END(PICAN) + + PICAN::PICAN(const PIString & path, PIIODevice::DeviceMode mode) : PIIODevice(path, mode) { setThreadedReadBufferSize(256); setPath(path); can_id = 0; sock = 0; + PRIVATE->event.create(); } PICAN::~PICAN() { - stop(); + stopAndWait(); close(); + PRIVATE->event.destroy(); } @@ -92,6 +99,7 @@ bool PICAN::openDevice() { bool PICAN::closeDevice() { #ifdef PIP_CAN + interrupt(); if (sock > 0) ::close(sock); #endif return true; @@ -103,9 +111,8 @@ ssize_t PICAN::readDevice(void * read_to, ssize_t max_size) { //piCout << "PICAN read"; can_frame frame; ssize_t ret = 0; - reading_now = true; - ret = ::read(sock, &frame, sizeof(can_frame)); - reading_now = false; + if (PRIVATE->event.wait(sock)) + ret = ::read(sock, &frame, sizeof(can_frame)); if (ret < 0) {/*piCoutObj << "Error while read CAN frame " << ret;*/ return -1;} //piCoutObj << "receive CAN frame Id =" << frame.can_id; memcpy(read_to, frame.data, piMini(frame.can_dlc, max_size)); @@ -148,6 +155,11 @@ int PICAN::readedCANID() const { } +void PICAN::interrupt() { + PRIVATE->event.interrupt(); +} + + PIString PICAN::constructFullPathDevice() const { PIString ret; ret += path() + ":" + PIString::fromNumber(CANID(), 16); diff --git a/libs/main/io_devices/pican.h b/libs/main/io_devices/pican.h index 8afab4d7..199ccf5f 100644 --- a/libs/main/io_devices/pican.h +++ b/libs/main/io_devices/pican.h @@ -39,6 +39,7 @@ public: void setCANID(int id); int CANID() const; int readedCANID() const; + void interrupt() override; protected: bool openDevice() override; @@ -52,6 +53,7 @@ protected: DeviceInfoFlags deviceInfoFlags() const override {return PIIODevice::Reliable;} private: + PRIVATE_DECLARATION(PIP_EXPORT) int sock; int can_id, readed_id; }; -- 2.43.0 From 897f03f3d06bd21e54ef85d8852fef6bf091d98a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D1=8B=D1=87=D0=BA=D0=BE=D0=B2=20=D0=90=D0=BD=D0=B4?= =?UTF-8?q?=D1=80=D0=B5=D0=B9?= Date: Tue, 8 Nov 2022 14:43:52 +0300 Subject: [PATCH 08/23] some fixes for picloud, but still not working correctly --- CMakeLists.txt | 2 + libs/cloud/picloudclient.cpp | 35 ++++++++--------- libs/cloud/picloudserver.cpp | 42 +++++++++++---------- libs/main/io_devices/piiodevice.cpp | 4 -- libs/main/io_devices/piiodevice.h | 2 - libs/main/io_devices/piserial.cpp | 2 +- main_picloud_test.cpp | 6 ++- utils/cloud_dispatcher/dispatcherclient.cpp | 16 ++++---- utils/cloud_dispatcher/dispatcherclient.h | 1 - utils/cloud_dispatcher/dispatcherserver.cpp | 5 ++- 10 files changed, 60 insertions(+), 55 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 697dcaf5..f6e9daec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -492,6 +492,8 @@ if (NOT CROSSTOOLS) #target_link_libraries(pip_plugin pip) add_executable(pip_test "main.cpp") target_link_libraries(pip_test pip) + add_executable(pip_cloud_test "main_picloud_test.cpp") + target_link_libraries(pip_cloud_test pip_cloud) endif() else() diff --git a/libs/cloud/picloudclient.cpp b/libs/cloud/picloudclient.cpp index 4a88b807..a1e4cf6b 100644 --- a/libs/cloud/picloudclient.cpp +++ b/libs/cloud/picloudclient.cpp @@ -33,22 +33,22 @@ PICloudClient::PICloudClient(const PIString & path, PIIODevice::DeviceMode mode) if (is_deleted) return; bool need_disconn = is_connected; //piCoutObj << "eth disconnected"; - eth.softStopThreadedRead(); + eth.stop(); opened_ = false; internalDisconnect(); - if (need_disconn) - disconnected(); + if (need_disconn) disconnected(); //piCoutObj << "eth disconnected done"; }); } PICloudClient::~PICloudClient() { - //piCoutObj << "~PICloudClient()"; + piCoutObj << "~PICloudClient() ..." << this; + is_deleted = true; stopAndWait(); close(); - is_deleted = true; internalDisconnect(); + piCoutObj << "~PICloudClient() done" << this; } @@ -70,14 +70,14 @@ void PICloudClient::interrupt() { bool PICloudClient::openDevice() { - //piCoutObj << "open";// << path(); + piCoutObj << "open";// << path(); bool op = eth.connect(PIEthernet::Address::resolve(path()), false); if (op) { mutex_connect.lock(); eth.startThreadedRead(); - //piCoutObj << "connecting..."; + piCoutObj << "connecting..."; bool conn_ok = cond_connect.waitFor(mutex_connect, (int)eth.readTimeout()); - //piCoutObj << "conn_ok" << conn_ok << is_connected; + piCoutObj << "conn_ok" << conn_ok << is_connected; mutex_connect.unlock(); if (!conn_ok) { mutex_connect.lock(); @@ -105,36 +105,37 @@ bool PICloudClient::closeDevice() { ssize_t PICloudClient::readDevice(void * read_to, ssize_t max_size) { - if (is_deleted) return -1; - //piCoutObj << "readDevice"; + if (is_deleted || max_size <= 0) return -1; + piCoutObj << "readDevice ..."; if (!is_connected && eth.isClosed()) openDevice(); ssize_t sz = -1; mutex_buff.lock(); - cond_buff.wait(mutex_buff); if (is_connected) { if (buff.isEmpty()) { sz = 0; } else { - sz = piMini(max_size, buff.size()); + sz = piMin(max_size, buff.size_s()); memcpy(read_to, buff.data(), sz); buff.remove(0, sz); } + if (sz == 0) cond_buff.wait(mutex_buff); } mutex_buff.unlock(); if (!is_connected) opened_ = false; - //piCoutObj << "readDevice done" << sz; + piCoutObj << "readDevice done" << sz; return sz; } ssize_t PICloudClient::writeDevice(const void * data, ssize_t size) { if (is_deleted) return -1; -// piCoutObj << "writeDevice"; + piCoutObj << "writeDevice" << size; return tcp.sendData(PIByteArray(data, size)); } void PICloudClient::internalDisconnect() { + piCoutObj << "internalDisconnect"; is_connected = false; cond_buff.notifyOne(); cond_connect.notifyOne(); @@ -146,7 +147,7 @@ void PICloudClient::internalDisconnect() { void PICloudClient::_readed(PIByteArray & ba) { if (is_deleted) return; PIPair hdr = tcp.parseHeader(ba); - //piCoutObj << "_readed" << ba.size() << hdr.first << hdr.second; + piCoutObj << "_readed" << ba.size() << hdr.first << hdr.second; if (hdr.second == tcp.role()) { switch (hdr.first) { case PICloud::TCP::Connect: @@ -159,7 +160,7 @@ void PICloudClient::_readed(PIByteArray & ba) { } break; case PICloud::TCP::Disconnect: - eth.softStopThreadedRead(); + eth.stop(); opened_ = false; eth.close(); break; @@ -177,5 +178,5 @@ void PICloudClient::_readed(PIByteArray & ba) { //piCoutObj << "readed" << ba.toHex(); } while (buff.size_s() > threadedReadBufferSize()) piMSleep(100); // FIXME: sleep here is bad - //piCoutObj << "_readed done"; + piCoutObj << "_readed done"; } diff --git a/libs/cloud/picloudserver.cpp b/libs/cloud/picloudserver.cpp index 98704297..2e0949eb 100644 --- a/libs/cloud/picloudserver.cpp +++ b/libs/cloud/picloudserver.cpp @@ -26,11 +26,10 @@ PICloudServer::PICloudServer(const PIString & path, PIIODevice::DeviceMode mode) tcp.setServerName(server_name); setName("cloud_server__" + server_name); CONNECT1(void, PIByteArray, &streampacker, packetReceiveEvent, this, _readed); - CONNECTL(ð, connected, [this](){opened_ = true; piCoutObj << "connected"; tcp.sendStart();}); + CONNECTL(ð, connected, [this](){opened_ = true; piCoutObj << "connected" << ð tcp.sendStart();}); CONNECTL(ð, disconnected, [this](bool){ - piCoutObj << "disconnected"; - eth.softStopThreadedRead(); - eth.interrupt(); + piCoutObj << "disconnected" << ð + eth.stop(); opened_ = false; ping_timer.stop(false); piMSleep(100); @@ -42,8 +41,10 @@ PICloudServer::PICloudServer(const PIString & path, PIIODevice::DeviceMode mode) PICloudServer::~PICloudServer() { + piCoutObj << "~PICloudServer ..." << this; stopAndWait(); close(); + piCoutObj << "~PICloudServer done" << this; } @@ -60,7 +61,7 @@ PIVector PICloudServer::clients() const { bool PICloudServer::openDevice() { - //piCout << "PICloudServer open device" << path(); + piCout << "PICloudServer open device" << path(); bool op = eth.connect(PIEthernet::Address::resolve(path()), false); if (op) { eth.startThreadedRead(); @@ -74,17 +75,19 @@ bool PICloudServer::openDevice() { bool PICloudServer::closeDevice() { - eth.stop(); + piCoutObj << "closeDevice" << this; + eth.stopAndWait(); ping_timer.stop(false); clients_mutex.lock(); for (auto c : clients_) { + c->stopAndWait(); c->close(); - c->stop(); } clients_mutex.unlock(); eth.close(); - for (auto c : clients_) + for (auto c : clients_) { delete c; + } return true; } @@ -126,12 +129,10 @@ PICloudServer::Client::Client(PICloudServer * srv, uint id) : server(srv), clien PICloudServer::Client::~Client() { - if (is_connected) { - is_connected = false; - cond_buff.notifyOne(); - } - stopAndWait(); + piCoutObj << "~PICloudServer::Client..." << this; close(); + stopAndWait(); + piCoutObj << "~PICloudServer::Client done" << this; } @@ -141,6 +142,7 @@ bool PICloudServer::Client::openDevice() { bool PICloudServer::Client::closeDevice() { + piCoutObj << "closeDevice" << this; if (is_connected) { server->clientDisconnect(client_id); is_connected = false; @@ -154,7 +156,6 @@ ssize_t PICloudServer::Client::readDevice(void * read_to, ssize_t max_size) { if (!is_connected) return -1; ssize_t sz = -1; mutex_buff.lock(); - cond_buff.wait(mutex_buff); if (is_connected) { if (buff.isEmpty()) { sz = 0; @@ -163,6 +164,7 @@ ssize_t PICloudServer::Client::readDevice(void * read_to, ssize_t max_size) { memcpy(read_to, buff.data(), sz); buff.remove(0, sz); } + if (sz == 0) cond_buff.wait(mutex_buff); } mutex_buff.unlock(); return sz; @@ -201,8 +203,8 @@ void PICloudServer::_readed(PIByteArray & ba) { if (oc) { tcp.sendDisconnected(id); } else { - //piCoutObj << "new Client" << id; Client * c = new Client(this, id); + piCoutObj << "new Client" << id << c; CONNECT1(void, PIObject *, c, deleted, this, clientDeleted); clients_mutex.lock(); clients_ << c; @@ -213,13 +215,14 @@ void PICloudServer::_readed(PIByteArray & ba) { } break; case PICloud::TCP::Disconnect: { uint id = tcp.parseDisconnect(ba); - //piCoutObj << "remove Client" << id; + piCoutObj << "remove Client" << id; clients_mutex.lock(); Client * oc = index_clients.value(id, nullptr); clients_mutex.unlock(); if (oc) { - oc->is_connected = false; - oc->close(); + //oc->is_connected = false; + //oc->close(); + delete oc; } } break; case PICloud::TCP::Data: { @@ -227,7 +230,7 @@ void PICloudServer::_readed(PIByteArray & ba) { clients_mutex.lock(); Client * oc = index_clients.value(d.first, nullptr); clients_mutex.unlock(); - //piCoutObj << "data for" << d.first << d.second.toHex(); + piCoutObj << "data for" << d.first << d.second.size(); if (oc && !d.second.isEmpty()) oc->pushBuffer(d.second); } break; default: break; @@ -238,6 +241,7 @@ void PICloudServer::_readed(PIByteArray & ba) { void PICloudServer::clientDeleted(PIObject * o) { PICloudServer::Client * c = (PICloudServer::Client*)o; + piCoutObj << "clientDeleted" << c; clients_mutex.lock(); clients_.removeOne(c); auto it = index_clients.makeIterator(); diff --git a/libs/main/io_devices/piiodevice.cpp b/libs/main/io_devices/piiodevice.cpp index bbcfc092..4cc8b183 100644 --- a/libs/main/io_devices/piiodevice.cpp +++ b/libs/main/io_devices/piiodevice.cpp @@ -637,7 +637,3 @@ void PIIODevice::configureFromVariantDevice(const PIPropertyStorage & d) { } -void PIIODevice::softStopThreadedRead() { - read_thread.stop(); -} - diff --git a/libs/main/io_devices/piiodevice.h b/libs/main/io_devices/piiodevice.h index 2ce101ef..d75b69c4 100644 --- a/libs/main/io_devices/piiodevice.h +++ b/libs/main/io_devices/piiodevice.h @@ -390,8 +390,6 @@ public: //! \~russian Пишет в устройство блок памяти "mb" ssize_t write(const PIMemoryBlock & mb) {return write(mb.data(), mb.size());} - void softStopThreadedRead(); - EVENT_VHANDLER(void, flush) {;} EVENT(opened); diff --git a/libs/main/io_devices/piserial.cpp b/libs/main/io_devices/piserial.cpp index b7590f7e..79829a87 100644 --- a/libs/main/io_devices/piserial.cpp +++ b/libs/main/io_devices/piserial.cpp @@ -827,7 +827,7 @@ ssize_t PISerial::readDevice(void * read_to, ssize_t max_size) { return 0; if (err == ERROR_BAD_COMMAND || err == ERROR_ACCESS_DENIED) { piCoutObj << "read error" << (PRIVATE->readed) << errorString(); - softStopThreadedRead(); + stop(); close(); return 0; } diff --git a/main_picloud_test.cpp b/main_picloud_test.cpp index 5afd928b..dbaea6ba 100644 --- a/main_picloud_test.cpp +++ b/main_picloud_test.cpp @@ -18,7 +18,7 @@ int main(int argc, char * argv[]) { piCout << "[Client] send:" << str; c.write(str.toByteArray()); } - if (s.isRunning()) { + if (s.isThreadedRead()) { for (auto cl : clients) { if (cl->isOpened()) { PIString str = "ping_S"; @@ -51,9 +51,11 @@ int main(int argc, char * argv[]) { } })); CONNECTL(cl, closed, ([&clients, cl](){ + piCout << "[Server] client closed ..." << cl; cl->stop(); clients.removeAll(cl); - cl->deleteLater(); + piCout << "[Server] client closed ok" << cl; + //cl->deleteLater(); })); cl->startThreadedRead(); })); diff --git a/utils/cloud_dispatcher/dispatcherclient.cpp b/utils/cloud_dispatcher/dispatcherclient.cpp index b370ebb7..df6cd480 100644 --- a/utils/cloud_dispatcher/dispatcherclient.cpp +++ b/utils/cloud_dispatcher/dispatcherclient.cpp @@ -3,7 +3,6 @@ DispatcherClient::DispatcherClient(PIEthernet * eth_, int id) : authorised(false), eth(eth_), streampacker(eth_), tcp(&streampacker), client_id(id) { - CONNECTU(&disconnect_tm, tickEvent, eth, close); CONNECTU(&streampacker, packetReceiveEvent, this, readed); CONNECTU(eth, disconnected, this, disconnected); piCoutObj << "client connected" << client_id << eth->sendAddress(); @@ -12,7 +11,6 @@ DispatcherClient::DispatcherClient(PIEthernet * eth_, int id) : authorised(false void DispatcherClient::start() { eth->startThreadedRead(); - //disconnect_tm.start(10000); } @@ -27,18 +25,18 @@ PIString DispatcherClient::address() { void DispatcherClient::close() { - eth->softStopThreadedRead(); - eth->interrupt(); + eth->stopAndWait(); } void DispatcherClient::sendConnected(uint client_id) { - //piCoutObj << "sendConnected"; + piCoutObj << "sendConnected" << client_id; tcp.sendConnected(client_id); } void DispatcherClient::sendDisconnected(uint client_id) { + piCoutObj << "sendDisconnected" << client_id; tcp.sendDisconnected(client_id); } @@ -61,7 +59,7 @@ void DispatcherClient::authorise(bool ok) { void DispatcherClient::disconnected(bool withError) { - //piCoutObj << "client disconnected" << eth->sendAddress(); + piCoutObj << "client disconnected" << withError << eth->sendAddress(); disconnectEvent(this); } @@ -70,16 +68,18 @@ void DispatcherClient::readed(PIByteArray & ba) { PIPair hdr = tcp.parseHeader(ba); // piCoutObj << "readed" << hdr.first << hdr.second; if (hdr.first == PICloud::TCP::InvalidType) { - disconnected(true); piCoutObj << "invalid message"; + disconnected(true); return; } if (authorised) { if (hdr.second == tcp.role()) { switch (hdr.first) { case PICloud::TCP::Connect: + piCoutObj << "PICloud::TCP::Connect"; return; case PICloud::TCP::Disconnect: + piCoutObj << "PICloud::TCP::Disconnect"; disconnected(false); return; case PICloud::TCP::Data: @@ -113,9 +113,11 @@ void DispatcherClient::readed(PIByteArray & ba) { return; } case PICloud::TCP::Disconnect: + piCoutObj << "unauthorised PICloud::TCP::Disconnect"; disconnected(false); return; default: + piCoutObj << "authorised invalid message"; disconnected(true); return; } diff --git a/utils/cloud_dispatcher/dispatcherclient.h b/utils/cloud_dispatcher/dispatcherclient.h index 92497e4d..9284a7eb 100644 --- a/utils/cloud_dispatcher/dispatcherclient.h +++ b/utils/cloud_dispatcher/dispatcherclient.h @@ -33,7 +33,6 @@ private: EVENT_HANDLER1(void, readed, PIByteArray &, data); EVENT_HANDLER1(void, disconnected, bool, withError); - PITimer disconnect_tm; std::atomic_bool authorised; PIEthernet * eth; PIStreamPacker streampacker; diff --git a/utils/cloud_dispatcher/dispatcherserver.cpp b/utils/cloud_dispatcher/dispatcherserver.cpp index 29363905..e976fdd2 100644 --- a/utils/cloud_dispatcher/dispatcherserver.cpp +++ b/utils/cloud_dispatcher/dispatcherserver.cpp @@ -181,7 +181,7 @@ void DispatcherServer::disconnectClient(DispatcherClient *client) { //piCoutObj << "INVALID client" << client; return; } - piCoutObj << "remove" << client->clientId(); + piCoutObj << "remove ..." << client->clientId(); map_mutex.lock(); clients.removeAll(client); rm_clients.removeAll(client); @@ -206,9 +206,10 @@ void DispatcherServer::disconnectClient(DispatcherClient *client) { cc->removeClient(client); index_c_clients.remove(client); } - client->close(); + //client->close(); rmrf_clients << client; map_mutex.unlock(); + piCoutObj << "remove done" << client->clientId(); } -- 2.43.0 From b17510218bdcb57a2126f6ad8f1917ce17dcb887 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D1=8B=D1=87=D0=BA=D0=BE=D0=B2=20=D0=90=D0=BD=D0=B4?= =?UTF-8?q?=D1=80=D0=B5=D0=B9?= Date: Tue, 8 Nov 2022 15:25:27 +0300 Subject: [PATCH 09/23] some fix for PICloudServer --- libs/cloud/picloudserver.cpp | 9 ++++++--- main_picloud_test.cpp | 3 +-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/libs/cloud/picloudserver.cpp b/libs/cloud/picloudserver.cpp index 2e0949eb..220473a1 100644 --- a/libs/cloud/picloudserver.cpp +++ b/libs/cloud/picloudserver.cpp @@ -29,7 +29,9 @@ PICloudServer::PICloudServer(const PIString & path, PIIODevice::DeviceMode mode) CONNECTL(ð, connected, [this](){opened_ = true; piCoutObj << "connected" << ð tcp.sendStart();}); CONNECTL(ð, disconnected, [this](bool){ piCoutObj << "disconnected" << ð - eth.stop(); + for (auto c : clients_) { + delete c; + } opened_ = false; ping_timer.stop(false); piMSleep(100); @@ -88,6 +90,7 @@ bool PICloudServer::closeDevice() { for (auto c : clients_) { delete c; } + clients_.clear(); return true; } @@ -220,6 +223,7 @@ void PICloudServer::_readed(PIByteArray & ba) { Client * oc = index_clients.value(id, nullptr); clients_mutex.unlock(); if (oc) { + oc->stopAndWait(); //oc->is_connected = false; //oc->close(); delete oc; @@ -245,8 +249,7 @@ void PICloudServer::clientDeleted(PIObject * o) { clients_mutex.lock(); clients_.removeOne(c); auto it = index_clients.makeIterator(); - while (it.hasNext()) { - it.next(); + while (it.next()) { if (it.value() == c) { index_clients.remove(it.key()); break; diff --git a/main_picloud_test.cpp b/main_picloud_test.cpp index dbaea6ba..c94886b0 100644 --- a/main_picloud_test.cpp +++ b/main_picloud_test.cpp @@ -52,10 +52,9 @@ int main(int argc, char * argv[]) { })); CONNECTL(cl, closed, ([&clients, cl](){ piCout << "[Server] client closed ..." << cl; - cl->stop(); + cl->stopAndWait(); clients.removeAll(cl); piCout << "[Server] client closed ok" << cl; - //cl->deleteLater(); })); cl->startThreadedRead(); })); -- 2.43.0 From 21fa3baf4ea492cfaacedfb7cb3435d41aaae619 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D1=8B=D1=87=D0=BA=D0=BE=D0=B2=20=D0=90=D0=BD=D0=B4?= =?UTF-8?q?=D1=80=D0=B5=D0=B9?= Date: Tue, 8 Nov 2022 16:37:10 +0300 Subject: [PATCH 10/23] =?UTF-8?q?=D1=83=D0=B1=D1=80=D0=B0=D0=BB=20=D0=BB?= =?UTF-8?q?=D0=B8=D1=88=D0=BD=D0=B5=D0=B5=20=D0=B2=20PICloudServer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs/cloud/picloudbase.cpp | 2 +- libs/cloud/picloudserver.cpp | 20 +++++++++----------- main_picloud_test.cpp | 2 +- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/libs/cloud/picloudbase.cpp b/libs/cloud/picloudbase.cpp index 10110a31..658613c2 100644 --- a/libs/cloud/picloudbase.cpp +++ b/libs/cloud/picloudbase.cpp @@ -2,7 +2,7 @@ PICloudBase::PICloudBase() : eth(PIEthernet::TCP_Client), streampacker(ð), tcp(&streampacker) { - eth.setDebug(false); + //eth.setDebug(false); } diff --git a/libs/cloud/picloudserver.cpp b/libs/cloud/picloudserver.cpp index 220473a1..2c00d2f8 100644 --- a/libs/cloud/picloudserver.cpp +++ b/libs/cloud/picloudserver.cpp @@ -25,6 +25,7 @@ PICloudServer::PICloudServer(const PIString & path, PIIODevice::DeviceMode mode) tcp.setRole(PICloud::TCP::Server); tcp.setServerName(server_name); setName("cloud_server__" + server_name); + eth.setReopenEnabled(false); CONNECT1(void, PIByteArray, &streampacker, packetReceiveEvent, this, _readed); CONNECTL(ð, connected, [this](){opened_ = true; piCoutObj << "connected" << ð tcp.sendStart();}); CONNECTL(ð, disconnected, [this](bool){ @@ -44,8 +45,10 @@ PICloudServer::PICloudServer(const PIString & path, PIIODevice::DeviceMode mode) PICloudServer::~PICloudServer() { piCoutObj << "~PICloudServer ..." << this; - stopAndWait(); + stop(); close(); + piCout << "wait"; + waitThreadedReadFinished(); piCoutObj << "~PICloudServer done" << this; } @@ -69,10 +72,11 @@ bool PICloudServer::openDevice() { eth.startThreadedRead(); ping_timer.start(5000); return true; + } else { + ping_timer.stop(false); + eth.close(); + return false; } - ping_timer.stop(false); - eth.close(); - return false; } @@ -80,12 +84,6 @@ bool PICloudServer::closeDevice() { piCoutObj << "closeDevice" << this; eth.stopAndWait(); ping_timer.stop(false); - clients_mutex.lock(); - for (auto c : clients_) { - c->stopAndWait(); - c->close(); - } - clients_mutex.unlock(); eth.close(); for (auto c : clients_) { delete c; @@ -98,7 +96,7 @@ bool PICloudServer::closeDevice() { ssize_t PICloudServer::readDevice(void * read_to, ssize_t max_size) { //piCoutObj << "readDevice"; if (!opened_) openDevice(); - else piMSleep(eth.readTimeout()); + //else piMSleep(eth.readTimeout()); return -1; } diff --git a/main_picloud_test.cpp b/main_picloud_test.cpp index c94886b0..208fd746 100644 --- a/main_picloud_test.cpp +++ b/main_picloud_test.cpp @@ -52,7 +52,7 @@ int main(int argc, char * argv[]) { })); CONNECTL(cl, closed, ([&clients, cl](){ piCout << "[Server] client closed ..." << cl; - cl->stopAndWait(); + cl->stop(); clients.removeAll(cl); piCout << "[Server] client closed ok" << cl; })); -- 2.43.0 From d3dd3fb32bbc883dcaba9c28da688f9a23552f57 Mon Sep 17 00:00:00 2001 From: peri4 Date: Tue, 8 Nov 2022 17:34:06 +0300 Subject: [PATCH 11/23] blocking PIEthernet write works --- libs/main/io_devices/piethernet.cpp | 65 ++++++++++++++++++++++------- libs/main/io_devices/piethernet.h | 2 +- libs/main/io_devices/piserial.cpp | 2 +- 3 files changed, 51 insertions(+), 18 deletions(-) diff --git a/libs/main/io_devices/piethernet.cpp b/libs/main/io_devices/piethernet.cpp index 8106921e..551529df 100644 --- a/libs/main/io_devices/piethernet.cpp +++ b/libs/main/io_devices/piethernet.cpp @@ -418,7 +418,10 @@ bool PIEthernet::closeDevice() { closeSocket(sock_s); while (!clients_.isEmpty()) delete clients_.back(); - if (ned) disconnected(false); + if (ned) { + piCoutObj << "Disconnect on close"; + disconnected(false); + } return true; } @@ -579,13 +582,14 @@ bool PIEthernet::connect(bool threaded) { #ifdef QNX PRIVATE->addr_.sin_len = sizeof(PRIVATE->addr_); #endif + connecting_ = true; connected_ = connectTCP(); + connecting_ = false; if (!connected_) { piCoutObj << "Can`t connect to" << addr_r << "," << ethErrorString(); } opened_ = connected_; if (connected_) { - connecting_ = false; connected(); } return connected_; @@ -728,7 +732,7 @@ ssize_t PIEthernet::readDevice(void * read_to, ssize_t max_size) { errorClear(); #ifdef WINDOWS { - long wr = waitForEvent(FD_READ | FD_CLOSE); + long wr = waitForEvent(PRIVATE->event, FD_READ | FD_CLOSE); switch (wr) { case FD_READ: //piCout << "fd_read ..."; @@ -760,7 +764,7 @@ ssize_t PIEthernet::readDevice(void * read_to, ssize_t max_size) { return -1; } if (connected_) { - //piCoutObj << "Disconnect on read," << ethErrorString(); + piCoutObj << "Disconnect on read," << ethErrorString(); opened_ = connected_ = false; closeSocket(sock); init(); @@ -777,7 +781,7 @@ ssize_t PIEthernet::readDevice(void * read_to, ssize_t max_size) { memset(&PRIVATE->raddr_, 0, sizeof(PRIVATE->raddr_)); //piCoutObj << "read from" << path() << "..."; #ifdef WINDOWS - long wr = waitForEvent(FD_READ | FD_CLOSE); + long wr = waitForEvent(PRIVATE->event, FD_READ | FD_CLOSE); switch (wr) { case FD_READ: //piCout << "fd_read ..."; @@ -829,7 +833,7 @@ ssize_t PIEthernet::writeDevice(const void * data, ssize_t max_size) { #endif , (sockaddr * )&PRIVATE->saddr_, sizeof(PRIVATE->saddr_)); //piCout << "[PIEth] write to" << ip_s << ":" << port_s << "ok"; - case TCP_Client: + case TCP_Client: { if (connecting_) { memset(&PRIVATE->addr_, 0, sizeof(PRIVATE->addr_)); addr_r.set(path()); @@ -850,15 +854,44 @@ ssize_t PIEthernet::writeDevice(const void * data, ssize_t max_size) { } } if (!connected_) return -1; - ret = ::send(sock, (const char *)data, max_size, 0); - if (ret < 0) { + auto disconnectFunc = [this](){ piCoutObj << "Disconnect on write," << ethErrorString(); opened_ = connected_ = false; closeSocket(sock); init(); disconnected(true); + }; + if (!isOptionSet(BlockingWrite)) { + ret = ::send(sock, (const char *)data, max_size, 0); + if (ret < 0) { + disconnectFunc(); + return -1; + } + } else { + ssize_t remain_size = max_size; + const char * remain_data = (const char *)data; + while (remain_size > 0) { + int sr = ::send(sock, remain_data, remain_size, 0); + if (sr < 0) { + int err = ethErrorCore(); +#ifdef WINDOWS + if (err == WSAEWOULDBLOCK) { +#else + if (err == EAGAIN || err == EWOULDBLOCK) { +#endif + piMinSleep(); + //piCoutObj << "wait for write"; + continue; + } else { + disconnectFunc(); + return -1; + } + } + remain_data += sr; + remain_size -= sr; + } } - return ret; + return ret;} default: break; } return -1; @@ -897,7 +930,7 @@ void PIEthernet::server_func(void * eth) { sockaddr_in client_addr; socklen_t slen = sizeof(client_addr); #ifdef WINDOWS - long wr = ce->waitForEvent(FD_ACCEPT | FD_CLOSE); + long wr = ce->waitForEvent(ce->PRIVATEWB->event, FD_ACCEPT | FD_CLOSE); if (wr != FD_ACCEPT) { piMSleep(10); return; @@ -954,7 +987,7 @@ bool PIEthernet::connectTCP() { ::connect(sock, (sockaddr * )&(PRIVATE->addr_), sizeof(PRIVATE->addr_)); //piCout << errorString(); #ifdef WINDOWS - long wr = waitForEvent(FD_CONNECT | FD_CLOSE); + long wr = waitForEvent(PRIVATE->event, FD_CONNECT | FD_CLOSE); switch (wr) { case FD_CONNECT: //piCout << "fd_connect ..."; @@ -975,16 +1008,16 @@ bool PIEthernet::connectTCP() { #ifdef WINDOWS -long PIEthernet::waitForEvent(long mask) { - if (!PRIVATE->event.isCreate() || sock < 0) return 0; - WSAEventSelect(sock, PRIVATE->event.getEvent(), mask); - if (PRIVATE->event.wait()) { +long PIEthernet::waitForEvent(PIWaitEvent & event, long mask) { + if (!event.isCreate() || sock < 0) return 0; + WSAEventSelect(sock, event.getEvent(), mask); + if (event.wait()) { //DWORD wr = WSAWaitForMultipleEvents(1, &(PRIVATE->read_event), FALSE, WSA_INFINITE, TRUE); //piCout << "wait result" << wr; //if (wr == WSA_WAIT_EVENT_0) { WSANETWORKEVENTS events; memset(&events, 0, sizeof(events)); - WSAEnumNetworkEvents(sock, PRIVATE->event.getEvent(), &events); + WSAEnumNetworkEvents(sock, event.getEvent(), &events); //piCout << "wait result" << events.lNetworkEvents; return events.lNetworkEvents; } diff --git a/libs/main/io_devices/piethernet.h b/libs/main/io_devices/piethernet.h index e4648874..06b2dbb9 100644 --- a/libs/main/io_devices/piethernet.h +++ b/libs/main/io_devices/piethernet.h @@ -503,7 +503,7 @@ private: void setType(Type t, bool reopen = true); bool connectTCP(); #ifdef WINDOWS - long waitForEvent(long mask); + long waitForEvent(PIWaitEvent & event, long mask); #endif static int ethErrorCore(); diff --git a/libs/main/io_devices/piserial.cpp b/libs/main/io_devices/piserial.cpp index 79829a87..80bcd7b2 100644 --- a/libs/main/io_devices/piserial.cpp +++ b/libs/main/io_devices/piserial.cpp @@ -840,7 +840,7 @@ ssize_t PISerial::readDevice(void * read_to, ssize_t max_size) { if (ret < 0) { int err = errno; if (err == EBADF || err == EFAULT || err == EINVAL || err == EIO) { - softStopThreadedRead(); + stopThreadedRead(); close(); return 0; } -- 2.43.0 From db5c4dcf3ffb5e37fa9efd8e7a0231c6a67659d2 Mon Sep 17 00:00:00 2001 From: peri4 Date: Wed, 9 Nov 2022 17:02:28 +0300 Subject: [PATCH 12/23] PIThread::stopAndWait --- libs/main/thread/pithread.cpp | 6 ++++++ libs/main/thread/pithread.h | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/libs/main/thread/pithread.cpp b/libs/main/thread/pithread.cpp index 5b8f372b..7c984c56 100644 --- a/libs/main/thread/pithread.cpp +++ b/libs/main/thread/pithread.cpp @@ -594,6 +594,12 @@ PIThread::~PIThread() { } +void PIThread::stopAndWait(int timeout_ms) { + stop(); + waitForFinish(timeout_ms); +} + + #ifdef WINDOWS NTAPI void winThreadAPC(ULONG_PTR) { //piCout << "APC"; diff --git a/libs/main/thread/pithread.h b/libs/main/thread/pithread.h index 61b90e59..914a29f5 100644 --- a/libs/main/thread/pithread.h +++ b/libs/main/thread/pithread.h @@ -111,6 +111,10 @@ public: EVENT_HANDLER1(void, stop, bool, wait); EVENT_HANDLER0(void, terminate); + //! \~english Stop thread and wait for finish. + //! \~russian Останавливает потоков и ожидает завершения. + void stopAndWait(int timeout_ms = -1); + void interrupt(); //! \~english Set common data passed to external function -- 2.43.0 From 8738043dcea0e76598f530d9a797659594b3494b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D1=8B=D1=87=D0=BA=D0=BE=D0=B2=20=D0=90=D0=BD=D0=B4?= =?UTF-8?q?=D1=80=D0=B5=D0=B9?= Date: Wed, 9 Nov 2022 17:04:13 +0300 Subject: [PATCH 13/23] some PICloud and PIEthernet fixes --- libs/cloud/picloudclient.cpp | 2 +- libs/cloud/picloudserver.cpp | 10 ++++++++-- libs/main/cloud/picloudserver.h | 1 + libs/main/io_devices/piethernet.cpp | 7 +++++-- main_picloud_test.cpp | 8 ++++---- utils/cloud_dispatcher/dispatcherserver.cpp | 2 +- 6 files changed, 20 insertions(+), 10 deletions(-) diff --git a/libs/cloud/picloudclient.cpp b/libs/cloud/picloudclient.cpp index a1e4cf6b..9e9356a1 100644 --- a/libs/cloud/picloudclient.cpp +++ b/libs/cloud/picloudclient.cpp @@ -128,7 +128,7 @@ ssize_t PICloudClient::readDevice(void * read_to, ssize_t max_size) { ssize_t PICloudClient::writeDevice(const void * data, ssize_t size) { - if (is_deleted) return -1; + if (is_deleted || !is_connected) return -1; piCoutObj << "writeDevice" << size; return tcp.sendData(PIByteArray(data, size)); } diff --git a/libs/cloud/picloudserver.cpp b/libs/cloud/picloudserver.cpp index 2c00d2f8..ea1ef273 100644 --- a/libs/cloud/picloudserver.cpp +++ b/libs/cloud/picloudserver.cpp @@ -25,10 +25,12 @@ PICloudServer::PICloudServer(const PIString & path, PIIODevice::DeviceMode mode) tcp.setRole(PICloud::TCP::Server); tcp.setServerName(server_name); setName("cloud_server__" + server_name); + is_deleted = false; eth.setReopenEnabled(false); CONNECT1(void, PIByteArray, &streampacker, packetReceiveEvent, this, _readed); CONNECTL(ð, connected, [this](){opened_ = true; piCoutObj << "connected" << ð tcp.sendStart();}); CONNECTL(ð, disconnected, [this](bool){ + if (is_deleted) return; piCoutObj << "disconnected" << ð for (auto c : clients_) { delete c; @@ -45,6 +47,7 @@ PICloudServer::PICloudServer(const PIString & path, PIIODevice::DeviceMode mode) PICloudServer::~PICloudServer() { piCoutObj << "~PICloudServer ..." << this; + is_deleted = true; stop(); close(); piCout << "wait"; @@ -94,6 +97,7 @@ bool PICloudServer::closeDevice() { ssize_t PICloudServer::readDevice(void * read_to, ssize_t max_size) { + if (is_deleted) return -1; //piCoutObj << "readDevice"; if (!opened_) openDevice(); //else piMSleep(eth.readTimeout()); @@ -118,6 +122,7 @@ void PICloudServer::clientDisconnect(uint client_id) { int PICloudServer::sendData(const PIByteArray & data, uint client_id) { + if (!opened_) return -1; return tcp.sendData(data, client_id); } @@ -173,6 +178,7 @@ ssize_t PICloudServer::Client::readDevice(void * read_to, ssize_t max_size) { ssize_t PICloudServer::Client::writeDevice(const void * data, ssize_t size) { + if (!is_connected) return -1; return server->sendData(PIByteArray(data, size), client_id); } @@ -193,6 +199,7 @@ void PICloudServer::Client::pushBuffer(const PIByteArray & ba) { void PICloudServer::_readed(PIByteArray & ba) { + if (is_deleted) return; PIPair hdr = tcp.parseHeader(ba); if (hdr.second == tcp.role()) { switch (hdr.first) { @@ -222,8 +229,7 @@ void PICloudServer::_readed(PIByteArray & ba) { clients_mutex.unlock(); if (oc) { oc->stopAndWait(); - //oc->is_connected = false; - //oc->close(); + oc->is_connected = false; delete oc; } } break; diff --git a/libs/main/cloud/picloudserver.h b/libs/main/cloud/picloudserver.h index a0fca4bd..59f8509e 100644 --- a/libs/main/cloud/picloudserver.h +++ b/libs/main/cloud/picloudserver.h @@ -86,6 +86,7 @@ private: PIMap index_clients; PITimer ping_timer; mutable PIMutex clients_mutex; + std::atomic_bool is_deleted; }; #endif // PICLOUDSERVER_H diff --git a/libs/main/io_devices/piethernet.cpp b/libs/main/io_devices/piethernet.cpp index 551529df..17afb0ce 100644 --- a/libs/main/io_devices/piethernet.cpp +++ b/libs/main/io_devices/piethernet.cpp @@ -764,8 +764,9 @@ ssize_t PIEthernet::readDevice(void * read_to, ssize_t max_size) { return -1; } if (connected_) { + connected_ = false; + opened_ = false; piCoutObj << "Disconnect on read," << ethErrorString(); - opened_ = connected_ = false; closeSocket(sock); init(); disconnected(rs < 0); @@ -855,8 +856,10 @@ ssize_t PIEthernet::writeDevice(const void * data, ssize_t max_size) { } if (!connected_) return -1; auto disconnectFunc = [this](){ + if (!connected_) return; + connected_ = false; + opened_ = false; piCoutObj << "Disconnect on write," << ethErrorString(); - opened_ = connected_ = false; closeSocket(sock); init(); disconnected(true); diff --git a/main_picloud_test.cpp b/main_picloud_test.cpp index 208fd746..54171b88 100644 --- a/main_picloud_test.cpp +++ b/main_picloud_test.cpp @@ -11,7 +11,7 @@ int main(int argc, char * argv[]) { PICloudClient c("127.0.0.1:10101"); // c.setReopenEnabled(true); PICloudServer s("127.0.0.1:10101"); - PIVector clients; + auto clients = new PIVector(); CONNECTL(&tm, tickEvent, ([&](void *, int){ if (c.isConnected()) { PIString str = "ping"; @@ -19,7 +19,7 @@ int main(int argc, char * argv[]) { c.write(str.toByteArray()); } if (s.isThreadedRead()) { - for (auto cl : clients) { + for (auto cl : *clients) { if (cl->isOpened()) { PIString str = "ping_S"; piCout << "[Server] send to" << cl << ":" << str; @@ -40,7 +40,7 @@ int main(int argc, char * argv[]) { CONNECTL(&c, disconnected, ([](){piCout << "disconnected";})); CONNECTL(&s, newConnection, ([&](PICloudServer::Client * cl){ piCout << "[Server] new client:" << cl; - clients << cl; + clients->append(cl); CONNECTL(cl, threadedReadEvent, ([cl, &rnd](const uchar * readed, ssize_t size){ PIByteArray ba(readed, size); PIString str = PIString(ba); @@ -53,7 +53,7 @@ int main(int argc, char * argv[]) { CONNECTL(cl, closed, ([&clients, cl](){ piCout << "[Server] client closed ..." << cl; cl->stop(); - clients.removeAll(cl); + clients->removeAll(cl); piCout << "[Server] client closed ok" << cl; })); cl->startThreadedRead(); diff --git a/utils/cloud_dispatcher/dispatcherserver.cpp b/utils/cloud_dispatcher/dispatcherserver.cpp index e976fdd2..9a9b84bb 100644 --- a/utils/cloud_dispatcher/dispatcherserver.cpp +++ b/utils/cloud_dispatcher/dispatcherserver.cpp @@ -21,7 +21,7 @@ DispatcherServer::~DispatcherServer() { void DispatcherServer::start() { eth.listen(true); - timeout_timer.start(5000); + timeout_timer.start(2000); piCoutObj << "server started" << eth.readAddress(); } -- 2.43.0 From d9eac06749062aeed55e74d48f3fb32c90cc4adb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D1=8B=D1=87=D0=BA=D0=BE=D0=B2=20=D0=90=D0=BD=D0=B4?= =?UTF-8?q?=D1=80=D0=B5=D0=B9?= Date: Wed, 9 Nov 2022 17:17:21 +0300 Subject: [PATCH 14/23] pithread, pitimer stop, stopAndWait --- libs/console/piscreen.cpp | 2 +- libs/main/io_devices/pipeer.cpp | 2 +- libs/main/thread/pithread.cpp | 3 +-- libs/main/thread/pithread.h | 9 ++++----- libs/main/thread/pithreadpoolloop.cpp | 4 ++-- libs/main/thread/pitimer.cpp | 19 +++++++++++-------- libs/main/thread/pitimer.h | 4 ++++ utils/system_daemon/daemon.cpp | 2 +- 8 files changed, 25 insertions(+), 20 deletions(-) diff --git a/libs/console/piscreen.cpp b/libs/console/piscreen.cpp index abbbf657..fba57853 100644 --- a/libs/console/piscreen.cpp +++ b/libs/console/piscreen.cpp @@ -588,7 +588,7 @@ void PIScreen::waitForFinish() { void PIScreen::stop(bool clear) { - PIThread::stop(true); + PIThread::stopAndWait(); if (clear) console.clearScreen(); #ifndef WINDOWS fflush(0); diff --git a/libs/main/io_devices/pipeer.cpp b/libs/main/io_devices/pipeer.cpp index 34d04004..92177ed5 100644 --- a/libs/main/io_devices/pipeer.cpp +++ b/libs/main/io_devices/pipeer.cpp @@ -192,7 +192,7 @@ PIPeer::~PIPeer() { if (p._data) { p._data->dt_in.stop(); p._data->dt_out.stop(); - p._data->t.stop(true); + p._data->t.stopAndWait(); } destroyEths(); piForeach (PIEthernet * i, eths_mcast) { diff --git a/libs/main/thread/pithread.cpp b/libs/main/thread/pithread.cpp index 7c984c56..0276cd25 100644 --- a/libs/main/thread/pithread.cpp +++ b/libs/main/thread/pithread.cpp @@ -620,10 +620,9 @@ void PIThread::interrupt() { } -void PIThread::stop(bool wait) { +void PIThread::stop() { //PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop ..." << running_ << wait; terminating = true; - if (wait) waitForFinish(); } diff --git a/libs/main/thread/pithread.h b/libs/main/thread/pithread.h index 914a29f5..948cbefd 100644 --- a/libs/main/thread/pithread.h +++ b/libs/main/thread/pithread.h @@ -107,12 +107,11 @@ public: bool start(std::function func, int timer_delay) {ret_func = [func](void*){func();}; return start(timer_delay);} EVENT_HANDLER0(bool, startOnce); EVENT_HANDLER1(bool, startOnce, ThreadFunc, func) {ret_func = func; return startOnce();} - EVENT_HANDLER0(void, stop) {stop(false);} - EVENT_HANDLER1(void, stop, bool, wait); + EVENT_HANDLER0(void, stop); EVENT_HANDLER0(void, terminate); //! \~english Stop thread and wait for finish. - //! \~russian Останавливает потоков и ожидает завершения. + //! \~russian Останавливает поток и ожидает завершения. void stopAndWait(int timeout_ms = -1); void interrupt(); @@ -201,7 +200,7 @@ public: //! \~english Start thread without internal loop //! \~russian Запускает поток без внутреннего цикла - //! \fn void stop(bool wait = false) + //! \fn void stop() //! \brief //! \~english Stop thread //! \~russian Останавливает поток @@ -209,7 +208,7 @@ public: //! \fn void terminate() //! \brief //! \~english Strongly stop thread - //! \~russian Жестко останавливает поток + //! \~russian Жёстко прерывает поток //! \fn bool waitForStart(int timeout_msecs = -1) //! \brief diff --git a/libs/main/thread/pithreadpoolloop.cpp b/libs/main/thread/pithreadpoolloop.cpp index 47b9cbb2..18548c98 100644 --- a/libs/main/thread/pithreadpoolloop.cpp +++ b/libs/main/thread/pithreadpoolloop.cpp @@ -114,7 +114,7 @@ PIThreadPoolLoop::PIThreadPoolLoop(int thread_cnt) { PIThreadPoolLoop::~PIThreadPoolLoop() { for (auto * t: threads) { - t->stop(false); + t->stop(); if (!t->waitForFinish(100)) t->terminate(); delete t; @@ -135,7 +135,7 @@ void PIThreadPoolLoop::start(int index_start, int index_count) { while (1) { int cc = counter.fetch_add(1); if (cc >= end) { - t->stop(false); + t->stop(); return; } func(cc); diff --git a/libs/main/thread/pitimer.cpp b/libs/main/thread/pitimer.cpp index f629bb1e..271fcddc 100644 --- a/libs/main/thread/pitimer.cpp +++ b/libs/main/thread/pitimer.cpp @@ -274,15 +274,12 @@ bool _PITimerImp_Thread::startTimer(double interval_ms) { bool _PITimerImp_Thread::stopTimer(bool wait) { -#ifndef FREERTOS - thread_.stop(wait); -#else thread_.stop(); - if (wait) - if (!thread_.waitForFinish(10)) - if (thread_.isRunning()) - thread_.terminate(); -#endif + if (wait) return thread_.waitForFinish(); +// if (wait) +// if (!thread_.waitForFinish(10)) +// if (thread_.isRunning()) +// thread_.terminate(); return true; } @@ -739,3 +736,9 @@ bool PITimer::waitForFinish(int timeout_msecs) { piMinSleep(); return tm.elapsed_m() < timeout_msecs; } + +void PITimer::stopAndWait(int timeout_ms) { + init(); + imp->stop(false); + waitForFinish(timeout_ms); +} diff --git a/libs/main/thread/pitimer.h b/libs/main/thread/pitimer.h index 6a330005..d3f944c9 100644 --- a/libs/main/thread/pitimer.h +++ b/libs/main/thread/pitimer.h @@ -164,6 +164,10 @@ public: EVENT_HANDLER1(bool, stop, bool, wait); bool waitForFinish() {return waitForFinish(-1);} bool waitForFinish(int timeout_msecs); + + //! \~english Stop timer and wait for finish. + //! \~russian Останавливает таймер и ожидает завершения. + void stopAndWait(int timeout_ms = -1); //! \~english Set custom data //! \~russian Установить данные, передаваемые в метод таймера diff --git a/utils/system_daemon/daemon.cpp b/utils/system_daemon/daemon.cpp index 8d827d24..cfec7e4a 100644 --- a/utils/system_daemon/daemon.cpp +++ b/utils/system_daemon/daemon.cpp @@ -24,7 +24,7 @@ Daemon::Remote::Remote(const PIString & n): PIThread() { Daemon::Remote::~Remote() { shellClose(); ft.stop(); - stop(true); + stopAndWait(); } -- 2.43.0 From 398d760ba95aea54c9fead03989ce6893eba4771 Mon Sep 17 00:00:00 2001 From: peri4 Date: Thu, 10 Nov 2022 12:26:08 +0300 Subject: [PATCH 15/23] PIObject::deleteLater important fix PIWaitEvent::sleep() method PITimer thread imp wait optimization, migrate to interruptable sleeps --- libs/main/core/piobject.cpp | 4 +++- libs/main/core/piwaitevent_p.cpp | 21 +++++++++++++++++++++ libs/main/core/piwaitevent_p.h | 3 ++- libs/main/thread/pithread.cpp | 2 +- libs/main/thread/pitimer.cpp | 21 +++++++++++++++------ main.cpp | 16 ++++++++++++++++ 6 files changed, 58 insertions(+), 9 deletions(-) diff --git a/libs/main/core/piobject.cpp b/libs/main/core/piobject.cpp index 2297b449..95f345a1 100644 --- a/libs/main/core/piobject.cpp +++ b/libs/main/core/piobject.cpp @@ -839,7 +839,7 @@ PIObject::Deleter::Deleter() { PRIVATE->thread.setSlot([this](){ PIVector oq; PRIVATE->thread.lock(); - while(PRIVATE->obj_queue.isEmpty()) PRIVATE->cond_var.wait(PRIVATE->thread.mutex()); + PRIVATE->cond_var.wait(PRIVATE->thread.mutex()); oq.swap(PRIVATE->obj_queue); PRIVATE->thread.unlock(); for (PIObject * o : oq) deleteObject(o); @@ -851,7 +851,9 @@ PIObject::Deleter::Deleter() { PIObject::Deleter::~Deleter() { //piCout << "~Deleter ..."; PRIVATE->thread.stop(); + PRIVATE->thread.mutex().lock(); PRIVATE->cond_var.notifyAll(); + PRIVATE->thread.mutex().unlock(); PRIVATE->thread.waitForFinish(); for (PIObject * o : PRIVATE->obj_queue) deleteObject(o); //piCout << "~Deleter ok"; diff --git a/libs/main/core/piwaitevent_p.cpp b/libs/main/core/piwaitevent_p.cpp index 954aa870..72d85aee 100644 --- a/libs/main/core/piwaitevent_p.cpp +++ b/libs/main/core/piwaitevent_p.cpp @@ -95,6 +95,27 @@ bool PIWaitEvent::wait(int fd, CheckRole role) { } +bool PIWaitEvent::sleep(int us) { + if (!isCreate()) return false; +#ifdef WINDOWS + DWORD ret = WaitForSingleObjectEx(event, us / 1000, TRUE); + ResetEvent(event); + return ret == WAIT_TIMEOUT; +#else + int nfds = pipe_fd[ReadEnd] + 1; + FD_ZERO(&(fds[CheckRead])); + FD_SET(pipe_fd[ReadEnd], &(fds[CheckRead])); + timeval timeout; + timeout.tv_sec = us / 1000000; + timeout.tv_usec = us % 1000000; + int ret = ::select(nfds, &(fds[CheckRead]), nullptr, nullptr, &timeout); + int buf = 0; + while (::read(pipe_fd[ReadEnd], &buf, sizeof(buf)) > 0); + return ret == 0; +#endif +} + + void PIWaitEvent::interrupt() { if (!isCreate()) return; #ifdef WINDOWS diff --git a/libs/main/core/piwaitevent_p.h b/libs/main/core/piwaitevent_p.h index a4395eaf..3dbdb137 100644 --- a/libs/main/core/piwaitevent_p.h +++ b/libs/main/core/piwaitevent_p.h @@ -31,7 +31,7 @@ #endif -class PIWaitEvent { +class PIP_EXPORT PIWaitEvent { public: ~PIWaitEvent(); @@ -44,6 +44,7 @@ public: void create(); void destroy(); bool wait(int fd = -1, CheckRole role = CheckRead); + bool sleep(int us); // return if sleep done void interrupt(); bool isCreate() const; void * getEvent() const; // WINDOWS only diff --git a/libs/main/thread/pithread.cpp b/libs/main/thread/pithread.cpp index 0276cd25..ee5d388f 100644 --- a/libs/main/thread/pithread.cpp +++ b/libs/main/thread/pithread.cpp @@ -485,7 +485,7 @@ void __PIThreadCollection::stoppedAuto() { auto_mutex.lock(); auto_threads_.removeAll(t); auto_mutex.unlock(); - delete t; + t->deleteLater(); } diff --git a/libs/main/thread/pitimer.cpp b/libs/main/thread/pitimer.cpp index 271fcddc..bd2758f6 100644 --- a/libs/main/thread/pitimer.cpp +++ b/libs/main/thread/pitimer.cpp @@ -19,6 +19,7 @@ #include "pitimer.h" #include "piincludes_p.h" +#include "piwaitevent_p.h" #ifdef PIP_TIMER_RT # include #endif @@ -190,6 +191,7 @@ private: PIThread thread_; PISystemTime st_time, st_inc, st_wait, st_odt; + PIWaitEvent event; }; @@ -235,9 +237,10 @@ private: _PITimerImp_Thread::_PITimerImp_Thread() { thread_.setName("__S__PITimerImp_Thread::thread"); - wait_dt = 100; - wait_dd = 200; - wait_tick = 10; + wait_dt = 1000; + wait_dd = 2000; + wait_tick = 1000; + event.create(); //piCout << "_PITimerImp_Thread" << this << ", thread& =" << &thread_; //piCout << "new _PITimerImp_Thread"; } @@ -245,6 +248,7 @@ _PITimerImp_Thread::_PITimerImp_Thread() { _PITimerImp_Thread::~_PITimerImp_Thread() { stop(true); + event.destroy(); } @@ -275,6 +279,7 @@ bool _PITimerImp_Thread::startTimer(double interval_ms) { bool _PITimerImp_Thread::stopTimer(bool wait) { thread_.stop(); + event.interrupt(); if (wait) return thread_.waitForFinish(); // if (wait) // if (!thread_.waitForFinish(10)) @@ -296,10 +301,12 @@ bool _PITimerImp_Thread::threadFunc() { dwt = st_time - PISystemTime::current(true); if (wth > 0) { if (dwt.toMilliseconds() > wth + 1.) { - piMSleep(wth); + event.sleep(wth * 1000); + if (thread_.isStopping()) return false; return false; } else { - dwt.sleep(); + event.sleep(dwt.toMicroseconds()); + if (thread_.isStopping()) return false; deferred_ = false; st_time = PISystemTime::current(true); } @@ -319,10 +326,12 @@ bool _PITimerImp_Thread::threadFunc() { if (wait_tick > 0) { if (st_wait.toMilliseconds() > wait_tick + 1.) { piMSleep(wait_tick); + if (thread_.isStopping()) return false; return false; } else { //piCout << &thread_ << "sleep for" << st_wait; - st_wait.sleep(); + event.sleep(st_wait.toMicroseconds()); + if (thread_.isStopping()) return false; } } else { if (st_wait.toMilliseconds() > 0.1) diff --git a/main.cpp b/main.cpp index 73e4ad68..5ace916b 100644 --- a/main.cpp +++ b/main.cpp @@ -3,6 +3,7 @@ #include "pibytearray.h" #include "pimathbase.h" #include "pijson.h" +#include "piwaitevent_p.h" using namespace PICoutManipulators; @@ -88,6 +89,21 @@ void phase(const char * msg) { int main(int argc, char * argv[]) { piCout << "main"; + PITimer timer; + timer.setSlot([](){ + static int cnt = 0; + piCout << "tick" << ++cnt; + }); + timer.start(500); + + piSleep(1.12); + piCout << "end"; + PITimeMeasurer tm; + timer.stop(); + double tm_ms = tm.elapsed_m(); + piCout << "stop took" << tm_ms; + return 0; + /*for (int i = 0; i < count; ++i) pipes[i].create(); -- 2.43.0 From d34374d4e078f821ed0a277f835d0a3a53bc18a1 Mon Sep 17 00:00:00 2001 From: peri4 Date: Thu, 10 Nov 2022 12:29:49 +0300 Subject: [PATCH 16/23] missing --- libs/main/thread/pitimer.cpp | 2 +- main.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/main/thread/pitimer.cpp b/libs/main/thread/pitimer.cpp index bd2758f6..f0de29f4 100644 --- a/libs/main/thread/pitimer.cpp +++ b/libs/main/thread/pitimer.cpp @@ -325,7 +325,7 @@ bool _PITimerImp_Thread::threadFunc() { } if (wait_tick > 0) { if (st_wait.toMilliseconds() > wait_tick + 1.) { - piMSleep(wait_tick); + event.sleep(wait_tick * 1000); if (thread_.isStopping()) return false; return false; } else { diff --git a/main.cpp b/main.cpp index 5ace916b..56fda705 100644 --- a/main.cpp +++ b/main.cpp @@ -96,7 +96,7 @@ int main(int argc, char * argv[]) { }); timer.start(500); - piSleep(1.12); + piSleep(2.12); piCout << "end"; PITimeMeasurer tm; timer.stop(); -- 2.43.0 From 702d1642e02086ee7a0cb2f847c760485bc821f0 Mon Sep 17 00:00:00 2001 From: peri4 Date: Thu, 10 Nov 2022 13:47:57 +0300 Subject: [PATCH 17/23] PITimer thread imp changed from PIWaitEvent to PIConditionalVariable --- libs/main/thread/pitimer.cpp | 31 ++++++++++++++++++------------- main.cpp | 2 +- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/libs/main/thread/pitimer.cpp b/libs/main/thread/pitimer.cpp index f0de29f4..45aa73bc 100644 --- a/libs/main/thread/pitimer.cpp +++ b/libs/main/thread/pitimer.cpp @@ -19,7 +19,7 @@ #include "pitimer.h" #include "piincludes_p.h" -#include "piwaitevent_p.h" +#include "piconditionvar.h" #ifdef PIP_TIMER_RT # include #endif @@ -188,10 +188,11 @@ private: virtual bool stopTimer(bool wait); 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; - PIWaitEvent event; + PIConditionVariable event; }; @@ -240,7 +241,6 @@ _PITimerImp_Thread::_PITimerImp_Thread() { wait_dt = 1000; wait_dd = 2000; wait_tick = 1000; - event.create(); //piCout << "_PITimerImp_Thread" << this << ", thread& =" << &thread_; //piCout << "new _PITimerImp_Thread"; } @@ -248,7 +248,6 @@ _PITimerImp_Thread::_PITimerImp_Thread() { _PITimerImp_Thread::~_PITimerImp_Thread() { stop(true); - event.destroy(); } @@ -279,7 +278,9 @@ bool _PITimerImp_Thread::startTimer(double interval_ms) { bool _PITimerImp_Thread::stopTimer(bool wait) { thread_.stop(); - event.interrupt(); + thread_.mutex().lock(); + event.notifyAll(); + thread_.mutex().unlock(); if (wait) return thread_.waitForFinish(); // if (wait) // if (!thread_.waitForFinish(10)) @@ -301,12 +302,10 @@ bool _PITimerImp_Thread::threadFunc() { dwt = st_time - PISystemTime::current(true); if (wth > 0) { if (dwt.toMilliseconds() > wth + 1.) { - event.sleep(wth * 1000); - if (thread_.isStopping()) return false; + smallWait(wth); return false; } else { - event.sleep(dwt.toMicroseconds()); - if (thread_.isStopping()) return false; + if (!smallWait(dwt.toMilliseconds())) return false; deferred_ = false; st_time = PISystemTime::current(true); } @@ -325,13 +324,11 @@ bool _PITimerImp_Thread::threadFunc() { } if (wait_tick > 0) { if (st_wait.toMilliseconds() > wait_tick + 1.) { - event.sleep(wait_tick * 1000); - if (thread_.isStopping()) return false; + smallWait(wait_tick); return false; } else { //piCout << &thread_ << "sleep for" << st_wait; - event.sleep(st_wait.toMicroseconds()); - if (thread_.isStopping()) return false; + if (!smallWait(st_wait.toMilliseconds())) return false; } } else { if (st_wait.toMilliseconds() > 0.1) @@ -372,6 +369,14 @@ void _PITimerImp_Thread::adjustTimes() { } +bool _PITimerImp_Thread::smallWait(int ms) { + thread_.mutex().lock(); + event.waitFor(thread_.mutex(), ms); + thread_.mutex().unlock(); + return !thread_.isStopping(); +} + + #ifdef PIP_TIMER_RT diff --git a/main.cpp b/main.cpp index 56fda705..5ace916b 100644 --- a/main.cpp +++ b/main.cpp @@ -96,7 +96,7 @@ int main(int argc, char * argv[]) { }); timer.start(500); - piSleep(2.12); + piSleep(1.12); piCout << "end"; PITimeMeasurer tm; timer.stop(); -- 2.43.0 From 16c09ae6e941416efd6fd706390f5cae5b622e9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D1=8B=D1=87=D0=BA=D0=BE=D0=B2=20=D0=90=D0=BD=D0=B4?= =?UTF-8?q?=D1=80=D0=B5=D0=B9?= Date: Thu, 10 Nov 2022 14:08:42 +0300 Subject: [PATCH 18/23] PIEthernet atomic connected exchange --- libs/main/io_devices/piethernet.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/libs/main/io_devices/piethernet.cpp b/libs/main/io_devices/piethernet.cpp index 17afb0ce..f38b4efc 100644 --- a/libs/main/io_devices/piethernet.cpp +++ b/libs/main/io_devices/piethernet.cpp @@ -763,8 +763,7 @@ ssize_t PIEthernet::readDevice(void * read_to, ssize_t max_size) { //piCoutObj << errorString(); return -1; } - if (connected_) { - connected_ = false; + if (connected_.exchange(false)) { opened_ = false; piCoutObj << "Disconnect on read," << ethErrorString(); closeSocket(sock); @@ -856,13 +855,13 @@ ssize_t PIEthernet::writeDevice(const void * data, ssize_t max_size) { } if (!connected_) return -1; auto disconnectFunc = [this](){ - if (!connected_) return; - connected_ = false; - opened_ = false; - piCoutObj << "Disconnect on write," << ethErrorString(); - closeSocket(sock); - init(); - disconnected(true); + if (connected_.exchange(false)) { + opened_ = false; + piCoutObj << "Disconnect on write," << ethErrorString(); + closeSocket(sock); + init(); + disconnected(true); + } }; if (!isOptionSet(BlockingWrite)) { ret = ::send(sock, (const char *)data, max_size, 0); -- 2.43.0 From 4994d0bf66e1a43bbbe129bf8e63dc8ad7144193 Mon Sep 17 00:00:00 2001 From: peri4 Date: Thu, 10 Nov 2022 14:11:40 +0300 Subject: [PATCH 19/23] condvar fixes --- libs/main/core/piobject.cpp | 4 +--- libs/main/thread/pitimer.cpp | 2 -- main.cpp | 16 ++++++++++++++-- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/libs/main/core/piobject.cpp b/libs/main/core/piobject.cpp index 95f345a1..dd4eed43 100644 --- a/libs/main/core/piobject.cpp +++ b/libs/main/core/piobject.cpp @@ -839,7 +839,7 @@ PIObject::Deleter::Deleter() { PRIVATE->thread.setSlot([this](){ PIVector oq; PRIVATE->thread.lock(); - PRIVATE->cond_var.wait(PRIVATE->thread.mutex()); + if (PRIVATE->obj_queue.isEmpty()) PRIVATE->cond_var.wait(PRIVATE->thread.mutex()); oq.swap(PRIVATE->obj_queue); PRIVATE->thread.unlock(); for (PIObject * o : oq) deleteObject(o); @@ -851,9 +851,7 @@ PIObject::Deleter::Deleter() { PIObject::Deleter::~Deleter() { //piCout << "~Deleter ..."; PRIVATE->thread.stop(); - PRIVATE->thread.mutex().lock(); PRIVATE->cond_var.notifyAll(); - PRIVATE->thread.mutex().unlock(); PRIVATE->thread.waitForFinish(); for (PIObject * o : PRIVATE->obj_queue) deleteObject(o); //piCout << "~Deleter ok"; diff --git a/libs/main/thread/pitimer.cpp b/libs/main/thread/pitimer.cpp index 45aa73bc..a06889f2 100644 --- a/libs/main/thread/pitimer.cpp +++ b/libs/main/thread/pitimer.cpp @@ -278,9 +278,7 @@ bool _PITimerImp_Thread::startTimer(double interval_ms) { bool _PITimerImp_Thread::stopTimer(bool wait) { thread_.stop(); - thread_.mutex().lock(); event.notifyAll(); - thread_.mutex().unlock(); if (wait) return thread_.waitForFinish(); // if (wait) // if (!thread_.waitForFinish(10)) diff --git a/main.cpp b/main.cpp index 5ace916b..2b673b70 100644 --- a/main.cpp +++ b/main.cpp @@ -87,7 +87,7 @@ void phase(const char * msg) { } int main(int argc, char * argv[]) { - piCout << "main"; + /*piCout << "main"; PITimer timer; timer.setSlot([](){ @@ -101,7 +101,19 @@ int main(int argc, char * argv[]) { PITimeMeasurer tm; timer.stop(); double tm_ms = tm.elapsed_m(); - piCout << "stop took" << tm_ms; + piCout << "stop took" << tm_ms;*/ + + PIWaitEvent event; + event.create(); + tm.reset(); + PIThread::runOnce([&event](){ + //piMSleep(100); + piCout << "interrupt"; + //event.interrupt(); + }); + event.sleep(2010000); + double tm_ms = tm.elapsed_m(); + piCout << "waited for" << tm_ms; return 0; /*for (int i = 0; i < count; ++i) -- 2.43.0 From e6a501002316411d5032c8dd147a82674e5cb903 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D1=8B=D1=87=D0=BA=D0=BE=D0=B2=20=D0=90=D0=BD=D0=B4?= =?UTF-8?q?=D1=80=D0=B5=D0=B9?= Date: Thu, 10 Nov 2022 14:25:57 +0300 Subject: [PATCH 20/23] remove debug picout from cloud --- libs/cloud/picloudbase.cpp | 2 +- libs/cloud/picloudclient.cpp | 29 +++++++++++++++------------ libs/cloud/picloudserver.cpp | 38 ++++++++++++++++++++++-------------- 3 files changed, 41 insertions(+), 28 deletions(-) diff --git a/libs/cloud/picloudbase.cpp b/libs/cloud/picloudbase.cpp index 658613c2..10110a31 100644 --- a/libs/cloud/picloudbase.cpp +++ b/libs/cloud/picloudbase.cpp @@ -2,7 +2,7 @@ PICloudBase::PICloudBase() : eth(PIEthernet::TCP_Client), streampacker(ð), tcp(&streampacker) { - //eth.setDebug(false); + eth.setDebug(false); } diff --git a/libs/cloud/picloudclient.cpp b/libs/cloud/picloudclient.cpp index 9e9356a1..b259e025 100644 --- a/libs/cloud/picloudclient.cpp +++ b/libs/cloud/picloudclient.cpp @@ -43,12 +43,12 @@ PICloudClient::PICloudClient(const PIString & path, PIIODevice::DeviceMode mode) PICloudClient::~PICloudClient() { - piCoutObj << "~PICloudClient() ..." << this; + //piCoutObj << "~PICloudClient() ..." << this; is_deleted = true; stopAndWait(); close(); internalDisconnect(); - piCoutObj << "~PICloudClient() done" << this; + //piCoutObj << "~PICloudClient() done" << this; } @@ -70,14 +70,14 @@ void PICloudClient::interrupt() { bool PICloudClient::openDevice() { - piCoutObj << "open";// << path(); + //piCoutObj << "open";// << path(); bool op = eth.connect(PIEthernet::Address::resolve(path()), false); if (op) { mutex_connect.lock(); eth.startThreadedRead(); - piCoutObj << "connecting..."; + //piCoutObj << "connecting..."; bool conn_ok = cond_connect.waitFor(mutex_connect, (int)eth.readTimeout()); - piCoutObj << "conn_ok" << conn_ok << is_connected; + //piCoutObj << "conn_ok" << conn_ok << is_connected; mutex_connect.unlock(); if (!conn_ok) { mutex_connect.lock(); @@ -106,7 +106,7 @@ bool PICloudClient::closeDevice() { ssize_t PICloudClient::readDevice(void * read_to, ssize_t max_size) { if (is_deleted || max_size <= 0) return -1; - piCoutObj << "readDevice ..."; + //piCoutObj << "readDevice ..."; if (!is_connected && eth.isClosed()) openDevice(); ssize_t sz = -1; mutex_buff.lock(); @@ -122,20 +122,20 @@ ssize_t PICloudClient::readDevice(void * read_to, ssize_t max_size) { } mutex_buff.unlock(); if (!is_connected) opened_ = false; - piCoutObj << "readDevice done" << sz; + //piCoutObj << "readDevice done" << sz; return sz; } ssize_t PICloudClient::writeDevice(const void * data, ssize_t size) { if (is_deleted || !is_connected) return -1; - piCoutObj << "writeDevice" << size; + //piCoutObj << "writeDevice" << size; return tcp.sendData(PIByteArray(data, size)); } void PICloudClient::internalDisconnect() { - piCoutObj << "internalDisconnect"; + //piCoutObj << "internalDisconnect"; is_connected = false; cond_buff.notifyOne(); cond_connect.notifyOne(); @@ -147,7 +147,7 @@ void PICloudClient::internalDisconnect() { void PICloudClient::_readed(PIByteArray & ba) { if (is_deleted) return; PIPair hdr = tcp.parseHeader(ba); - piCoutObj << "_readed" << ba.size() << hdr.first << hdr.second; + //piCoutObj << "_readed" << ba.size() << hdr.first << hdr.second; if (hdr.second == tcp.role()) { switch (hdr.first) { case PICloud::TCP::Connect: @@ -167,6 +167,11 @@ void PICloudClient::_readed(PIByteArray & ba) { case PICloud::TCP::Data: if (is_connected) { mutex_buff.lock(); + if (buff.size_s() > threadedReadBufferSize()) { + piCoutObj << "Error: buffer overflow, drop" << ba.size() << "bytes"; + mutex_buff.unlock(); + return; + } buff.append(ba); mutex_buff.unlock(); cond_buff.notifyOne(); @@ -177,6 +182,6 @@ void PICloudClient::_readed(PIByteArray & ba) { } //piCoutObj << "readed" << ba.toHex(); } - while (buff.size_s() > threadedReadBufferSize()) piMSleep(100); // FIXME: sleep here is bad - piCoutObj << "_readed done"; + if (buff.size_s() > threadedReadBufferSize()) piMSleep(100); // FIXME: sleep here is bad + //piCoutObj << "_readed done"; } diff --git a/libs/cloud/picloudserver.cpp b/libs/cloud/picloudserver.cpp index ea1ef273..35ac8f49 100644 --- a/libs/cloud/picloudserver.cpp +++ b/libs/cloud/picloudserver.cpp @@ -28,10 +28,14 @@ PICloudServer::PICloudServer(const PIString & path, PIIODevice::DeviceMode mode) is_deleted = false; eth.setReopenEnabled(false); CONNECT1(void, PIByteArray, &streampacker, packetReceiveEvent, this, _readed); - CONNECTL(ð, connected, [this](){opened_ = true; piCoutObj << "connected" << ð tcp.sendStart();}); + CONNECTL(ð, connected, [this](){ + opened_ = true; + //piCoutObj << "connected" << ð + tcp.sendStart(); + }); CONNECTL(ð, disconnected, [this](bool){ if (is_deleted) return; - piCoutObj << "disconnected" << ð + //piCoutObj << "disconnected" << ð for (auto c : clients_) { delete c; } @@ -46,13 +50,13 @@ PICloudServer::PICloudServer(const PIString & path, PIIODevice::DeviceMode mode) PICloudServer::~PICloudServer() { - piCoutObj << "~PICloudServer ..." << this; + //piCoutObj << "~PICloudServer ..." << this; is_deleted = true; stop(); close(); - piCout << "wait"; + //piCout << "wait"; waitThreadedReadFinished(); - piCoutObj << "~PICloudServer done" << this; + //piCoutObj << "~PICloudServer done" << this; } @@ -69,7 +73,7 @@ PIVector PICloudServer::clients() const { bool PICloudServer::openDevice() { - piCout << "PICloudServer open device" << path(); + //piCout << "PICloudServer open device" << path(); bool op = eth.connect(PIEthernet::Address::resolve(path()), false); if (op) { eth.startThreadedRead(); @@ -84,7 +88,7 @@ bool PICloudServer::openDevice() { bool PICloudServer::closeDevice() { - piCoutObj << "closeDevice" << this; + //piCoutObj << "closeDevice" << this; eth.stopAndWait(); ping_timer.stop(false); eth.close(); @@ -135,10 +139,10 @@ PICloudServer::Client::Client(PICloudServer * srv, uint id) : server(srv), clien PICloudServer::Client::~Client() { - piCoutObj << "~PICloudServer::Client..." << this; + //piCoutObj << "~PICloudServer::Client..." << this; close(); stopAndWait(); - piCoutObj << "~PICloudServer::Client done" << this; + //piCoutObj << "~PICloudServer::Client done" << this; } @@ -148,7 +152,7 @@ bool PICloudServer::Client::openDevice() { bool PICloudServer::Client::closeDevice() { - piCoutObj << "closeDevice" << this; + //piCoutObj << "closeDevice" << this; if (is_connected) { server->clientDisconnect(client_id); is_connected = false; @@ -191,10 +195,14 @@ void PICloudServer::Client::interrupt() { void PICloudServer::Client::pushBuffer(const PIByteArray & ba) { if (!is_connected) return; mutex_buff.lock(); + if (buff.size_s() > threadedReadBufferSize()) { + piCoutObj << "Error: buffer overflow, drop" << ba.size() << "bytes"; + mutex_buff.unlock(); + return; + } buff.append(ba); cond_buff.notifyOne(); mutex_buff.unlock(); - while (buff.size_s() > threadedReadBufferSize()) piMSleep(100); // FIXME: sleep here is bad } @@ -212,7 +220,7 @@ void PICloudServer::_readed(PIByteArray & ba) { tcp.sendDisconnected(id); } else { Client * c = new Client(this, id); - piCoutObj << "new Client" << id << c; + //piCoutObj << "new Client" << id << c; CONNECT1(void, PIObject *, c, deleted, this, clientDeleted); clients_mutex.lock(); clients_ << c; @@ -223,7 +231,7 @@ void PICloudServer::_readed(PIByteArray & ba) { } break; case PICloud::TCP::Disconnect: { uint id = tcp.parseDisconnect(ba); - piCoutObj << "remove Client" << id; + //piCoutObj << "remove Client" << id; clients_mutex.lock(); Client * oc = index_clients.value(id, nullptr); clients_mutex.unlock(); @@ -238,7 +246,7 @@ void PICloudServer::_readed(PIByteArray & ba) { clients_mutex.lock(); Client * oc = index_clients.value(d.first, nullptr); clients_mutex.unlock(); - piCoutObj << "data for" << d.first << d.second.size(); + //piCoutObj << "data for" << d.first << d.second.size(); if (oc && !d.second.isEmpty()) oc->pushBuffer(d.second); } break; default: break; @@ -249,7 +257,7 @@ void PICloudServer::_readed(PIByteArray & ba) { void PICloudServer::clientDeleted(PIObject * o) { PICloudServer::Client * c = (PICloudServer::Client*)o; - piCoutObj << "clientDeleted" << c; + //piCoutObj << "clientDeleted" << c; clients_mutex.lock(); clients_.removeOne(c); auto it = index_clients.makeIterator(); -- 2.43.0 From e9a7eaa2761b3b0bc83f73ee92ff0da26e55d795 Mon Sep 17 00:00:00 2001 From: peri4 Date: Thu, 10 Nov 2022 15:03:51 +0300 Subject: [PATCH 21/23] fixes --- libs/main/thread/pitimer.cpp | 11 +++++++---- utils/system_daemon/daemon.cpp | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/libs/main/thread/pitimer.cpp b/libs/main/thread/pitimer.cpp index a06889f2..71675174 100644 --- a/libs/main/thread/pitimer.cpp +++ b/libs/main/thread/pitimer.cpp @@ -279,7 +279,7 @@ bool _PITimerImp_Thread::startTimer(double interval_ms) { bool _PITimerImp_Thread::stopTimer(bool wait) { thread_.stop(); event.notifyAll(); - if (wait) return thread_.waitForFinish(); + thread_.waitForFinish(); // if (wait) // if (!thread_.waitForFinish(10)) // if (thread_.isRunning()) @@ -368,9 +368,12 @@ void _PITimerImp_Thread::adjustTimes() { bool _PITimerImp_Thread::smallWait(int ms) { - thread_.mutex().lock(); - event.waitFor(thread_.mutex(), ms); - thread_.mutex().unlock(); + if (thread_.isStopping()) return false; + if (ms > 0) { + thread_.mutex().lock(); + event.waitFor(thread_.mutex(), ms); + thread_.mutex().unlock(); + } return !thread_.isStopping(); } diff --git a/utils/system_daemon/daemon.cpp b/utils/system_daemon/daemon.cpp index cfec7e4a..ec51c764 100644 --- a/utils/system_daemon/daemon.cpp +++ b/utils/system_daemon/daemon.cpp @@ -41,7 +41,6 @@ void Daemon::Remote::shellClose() { if (!term) return; piCoutObj << "shell close"; term_timer.stop(); - term_timer.waitForFinish(1000); term->destroy(); delete term; term = 0; @@ -331,6 +330,7 @@ Daemon::~Daemon() { delete r; } remotes.clear(); + delete _self; } -- 2.43.0 From d46f1a137a2f935703692eb997328d317806f9eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D1=8B=D1=87=D0=BA=D0=BE=D0=B2=20=D0=90=D0=BD=D0=B4?= =?UTF-8?q?=D1=80=D0=B5=D0=B9?= Date: Thu, 10 Nov 2022 15:26:19 +0300 Subject: [PATCH 22/23] PITimer remove wait in stop, waitForFinish --- libs/cloud/picloudserver.cpp | 6 ++-- libs/main/thread/pitimer.cpp | 62 ++++++++++-------------------------- libs/main/thread/pitimer.h | 11 ++----- 3 files changed, 22 insertions(+), 57 deletions(-) diff --git a/libs/cloud/picloudserver.cpp b/libs/cloud/picloudserver.cpp index 35ac8f49..f5a54766 100644 --- a/libs/cloud/picloudserver.cpp +++ b/libs/cloud/picloudserver.cpp @@ -40,7 +40,7 @@ PICloudServer::PICloudServer(const PIString & path, PIIODevice::DeviceMode mode) delete c; } opened_ = false; - ping_timer.stop(false); + ping_timer.stop(); piMSleep(100); }); CONNECTL(&ping_timer, tickEvent, [this] (void *, int){ @@ -80,7 +80,7 @@ bool PICloudServer::openDevice() { ping_timer.start(5000); return true; } else { - ping_timer.stop(false); + ping_timer.stop(); eth.close(); return false; } @@ -90,7 +90,7 @@ bool PICloudServer::openDevice() { bool PICloudServer::closeDevice() { //piCoutObj << "closeDevice" << this; eth.stopAndWait(); - ping_timer.stop(false); + ping_timer.stop(); eth.close(); for (auto c : clients_) { delete c; diff --git a/libs/main/thread/pitimer.cpp b/libs/main/thread/pitimer.cpp index 71675174..c4cabed7 100644 --- a/libs/main/thread/pitimer.cpp +++ b/libs/main/thread/pitimer.cpp @@ -128,14 +128,14 @@ void _PITimerBase::setInterval(double i) { interval_ = i; if (isRunning()) { //piCout << "change interval runtime"; - stop(true); + stop(); start(); } } bool _PITimerBase::start(double interval_ms) { - if (isRunning()) stop(true); + if (isRunning()) stop(); deferred_ = false; setInterval(interval_ms); //piCout << "_PITimerBase::startTimer"<threadFunc();} void adjustTimes(); bool smallWait(int ms); @@ -216,7 +216,7 @@ private: class _PITimerImp_Pool: public _PITimerImp_Thread { public: _PITimerImp_Pool(); - virtual ~_PITimerImp_Pool() {stop(true);} + virtual ~_PITimerImp_Pool() {stop();} private: class Pool: public PIThread { public: @@ -229,8 +229,8 @@ private: explicit Pool(); virtual ~Pool(); }; - virtual bool startTimer(double interval_ms); - virtual bool stopTimer(bool wait); + bool startTimer(double interval_ms) override; + bool stopTimer() override; }; @@ -246,11 +246,6 @@ _PITimerImp_Thread::_PITimerImp_Thread() { } -_PITimerImp_Thread::~_PITimerImp_Thread() { - stop(true); -} - - void _PITimerImp_Thread::prepareStart(double interval_ms) { if (interval_ms <= 0.) { piCout << "Achtung! Start PITimer with interval <= 0!"; @@ -276,7 +271,7 @@ bool _PITimerImp_Thread::startTimer(double interval_ms) { } -bool _PITimerImp_Thread::stopTimer(bool wait) { +bool _PITimerImp_Thread::stopTimer() { thread_.stop(); event.notifyAll(); thread_.waitForFinish(); @@ -521,7 +516,7 @@ bool _PITimerImp_Pool::startTimer(double interval_ms) { } -bool _PITimerImp_Pool::stopTimer(bool wait) { +bool _PITimerImp_Pool::stopTimer() { Pool::instance()->remove(this); return true; } @@ -633,7 +628,7 @@ void PITimer::init() const { void PITimer::destroy() { if (!imp) return; //piCout << this << "destroy" << imp; - imp->stop(false); ///BUG: WTF FreeRTOS segfault on this! + imp->stop(); delete imp; imp = 0; } @@ -723,37 +718,14 @@ void PITimer::startDeferred(double interval_ms, PIDateTime start_datetime) { bool PITimer::restart() { init(); - imp->stop(true); + imp->stop(); return imp->start(); } bool PITimer::stop() { - return stop(true); -} - - -bool PITimer::stop(bool wait) { init(); //piCout << this << "stop" << imp << wait; - return imp->stop(wait); + return imp->stop(); } - -bool PITimer::waitForFinish(int timeout_msecs) { - if (timeout_msecs < 0) { - while (isRunning()) - piMinSleep(); - return true; - } - PITimeMeasurer tm; - while (isRunning() && tm.elapsed_m() < timeout_msecs) - piMinSleep(); - return tm.elapsed_m() < timeout_msecs; -} - -void PITimer::stopAndWait(int timeout_ms) { - init(); - imp->stop(false); - waitForFinish(timeout_ms); -} diff --git a/libs/main/thread/pitimer.h b/libs/main/thread/pitimer.h index d3f944c9..73dd5ac6 100644 --- a/libs/main/thread/pitimer.h +++ b/libs/main/thread/pitimer.h @@ -53,7 +53,7 @@ public: void startDeferred(PIDateTime start_datetime) {startDeferred(interval_, start_datetime);} void startDeferred(double interval_ms, PIDateTime start_datetime); - bool stop(bool wait); + bool stop(); typedef void(*TickFunc)(PITimer*); TickFunc tfunc; @@ -62,7 +62,7 @@ public: protected: virtual bool startTimer(double interval_ms) = 0; - virtual bool stopTimer(bool wait) = 0; + virtual bool stopTimer() = 0; double interval_, deferred_delay; bool deferred_, deferred_mode; // mode: true - date, false - delay @@ -161,14 +161,7 @@ public: void startDeferred(double interval_ms, PIDateTime start_datetime); EVENT_HANDLER0(bool, stop); - EVENT_HANDLER1(bool, stop, bool, wait); - bool waitForFinish() {return waitForFinish(-1);} - bool waitForFinish(int timeout_msecs); - //! \~english Stop timer and wait for finish. - //! \~russian Останавливает таймер и ожидает завершения. - void stopAndWait(int timeout_ms = -1); - //! \~english Set custom data //! \~russian Установить данные, передаваемые в метод таймера void setData(void * data_) {data_t = data_;} -- 2.43.0 From cbac9f4253b70f1968444c276606d3ebd71a779d Mon Sep 17 00:00:00 2001 From: peri4 Date: Thu, 10 Nov 2022 15:44:35 +0300 Subject: [PATCH 23/23] PITimerImp_RT --- libs/main/thread/pitimer.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/main/thread/pitimer.cpp b/libs/main/thread/pitimer.cpp index c4cabed7..58cd12ee 100644 --- a/libs/main/thread/pitimer.cpp +++ b/libs/main/thread/pitimer.cpp @@ -204,8 +204,8 @@ public: virtual ~_PITimerImp_RT(); protected: private: - virtual bool startTimer(double interval_ms); - virtual bool stopTimer(bool wait); + bool startTimer(double interval_ms) override; + bool stopTimer() override; int ti; _PITimerImp_RT_Private_ * priv; @@ -399,7 +399,7 @@ _PITimerImp_RT::_PITimerImp_RT() { _PITimerImp_RT::~_PITimerImp_RT() { - stop(true); + stop(); delete priv; } @@ -432,7 +432,7 @@ bool _PITimerImp_RT::startTimer(double interval_ms) { } -bool _PITimerImp_RT::stopTimer(bool wait) { +bool _PITimerImp_RT::stopTimer() { if (ti < 0) return true; timer_delete(priv->tt); ti = -1; -- 2.43.0