merged concurrent to main library

removed PIConditionLock, use PIMutex instead
This commit is contained in:
2020-07-30 18:50:42 +03:00
parent 4dd59132d5
commit 2ffc457566
31 changed files with 558 additions and 2176 deletions

View File

@@ -66,7 +66,6 @@ set(PIP_SRC_USB "lib/usb")
set(PIP_SRC_FFTW "lib/fftw") set(PIP_SRC_FFTW "lib/fftw")
set(PIP_SRC_OPENCL "lib/opencl") set(PIP_SRC_OPENCL "lib/opencl")
set(PIP_SRC_IO_UTILS "lib/io_utils") set(PIP_SRC_IO_UTILS "lib/io_utils")
set(PIP_SRC_CONCURRENT "lib/concurrent")
set(PIP_SRC_CLOUD "lib/cloud") set(PIP_SRC_CLOUD "lib/cloud")
set(PIP_SRC_LUA "lib/lua") set(PIP_SRC_LUA "lib/lua")
set(PIP_SRC_DIRS ${PIP_SRC_MAIN} set(PIP_SRC_DIRS ${PIP_SRC_MAIN}
@@ -77,8 +76,8 @@ set(PIP_SRC_DIRS ${PIP_SRC_MAIN}
${PIP_SRC_FFTW} ${PIP_SRC_FFTW}
${PIP_SRC_OPENCL} ${PIP_SRC_OPENCL}
${PIP_SRC_IO_UTILS} ${PIP_SRC_IO_UTILS}
${PIP_SRC_CONCURRENT} ${PIP_SRC_CLOUD}
${PIP_SRC_CLOUD} ${PIP_SRC_LUA}
) )
set(PIP_LIBS_TARGETS pip) set(PIP_LIBS_TARGETS pip)
set(LIBS_MAIN) set(LIBS_MAIN)
@@ -192,7 +191,7 @@ get_filename_component(C_COMPILER "${CMAKE_C_COMPILER}" NAME)
# Sources # Sources
# Main lib # Main lib
set(PIP_FOLDERS "." "core" "containers" "thread" "system" "io_devices" "io_utils" "console" "math" "code" "geo" "resources" "opencl" "crypt" "introspection" "concurrent" "cloud" "lua") set(PIP_FOLDERS "." "core" "containers" "thread" "system" "io_devices" "io_utils" "console" "math" "code" "geo" "resources" "opencl" "crypt" "introspection" "cloud" "lua")
include_directories("${PIP_SRC_MAIN}") include_directories("${PIP_SRC_MAIN}")
set(PIP_MAIN_FOLDERS) set(PIP_MAIN_FOLDERS)
foreach(F ${PIP_FOLDERS}) foreach(F ${PIP_FOLDERS})
@@ -221,17 +220,17 @@ gather_src("${PIP_SRC_OPENCL}" CPP_LIB_OPENCL HDRS PHDRS)
# IO Utils lib # IO Utils lib
gather_src("${PIP_SRC_IO_UTILS}" CPP_LIB_IO_UTILS HDRS PHDRS) gather_src("${PIP_SRC_IO_UTILS}" CPP_LIB_IO_UTILS HDRS PHDRS)
# Concurrent lib
gather_src("${PIP_SRC_CONCURRENT}" CPP_LIB_CONCURRENT HDRS PHDRS)
gather_src("${PIP_CONCURRENT_TEST}" CPP_CONCURRENT_TEST HDRS PHDRS)
# Cloud lib # Cloud lib
gather_src("${PIP_SRC_CLOUD}" CPP_LIB_CLOUD HDRS PHDRS) gather_src("${PIP_SRC_CLOUD}" CPP_LIB_CLOUD HDRS PHDRS)
# LUA lib # LUA lib
gather_src("${PIP_SRC_LUA}" CPP_LIB_LUA HDRS PHDRS) gather_src("${PIP_SRC_LUA}" CPP_LIB_LUA HDRS PHDRS)
if (TESTS)
# Concurrent lib tests
gather_src("${PIP_CONCURRENT_TEST}" CPP_CONCURRENT_TEST HDRS PHDRS)
endif()
if(PIP_FREERTOS) if(PIP_FREERTOS)
add_definitions(-DPIP_FREERTOS) add_definitions(-DPIP_FREERTOS)
set(ICU OFF) set(ICU OFF)
@@ -580,24 +579,10 @@ if (NOT CROSSTOOLS)
list(APPEND PIP_LIBS_TARGETS pip_io_utils) list(APPEND PIP_LIBS_TARGETS pip_io_utils)
# Concurrent module
set(CONCURRENT_LIBS pip)
import_version(pip_concurrent pip)
set_deploy_property(pip_concurrent ${PIP_LIB_TYPE}
LABEL "PIP concurrent support"
FULLNAME "${_PIP_DOMAIN}.pip_concurrent"
COMPANY "${_PIP_COMPANY}"
INFO "Platform-Independent Primitives")
make_rc(pip_concurrent _RC)
add_library(pip_concurrent ${PIP_LIB_TYPE} ${CPP_LIB_CONCURRENT} ${_RC})
target_link_libraries(pip_concurrent ${CONCURRENT_LIBS})
set_property(TARGET pip_concurrent PROPERTY CXX_STANDARD 11)
list(APPEND PIP_LIBS_TARGETS pip_concurrent)
# Enable build tests for concurrent module # Enable build tests for concurrent module
if(PIP_CONCURRENT_TEST) if(PIP_CONCURRENT_TEST)
add_executable(pip_concurrent_test ${CPP_CONCURRENT_TEST}) add_executable(pip_concurrent_test ${CPP_CONCURRENT_TEST})
target_link_libraries(pip_concurrent_test gtest_main gmock_main pip_concurrent) target_link_libraries(pip_concurrent_test pip gtest_main gmock_main)
add_test(NAME pip_concurrent_test COMMAND tests) add_test(NAME pip_concurrent_test COMMAND tests)
add_custom_target(pip_concurrent_test_perform ALL COMMAND pip_concurrent_test) add_custom_target(pip_concurrent_test_perform ALL COMMAND pip_concurrent_test)
endif() endif()
@@ -813,7 +798,6 @@ message(" Compress : ${PIP_COMPRESS}")
message(" FFTW : ${PIP_FFTW}") message(" FFTW : ${PIP_FFTW}")
message(" OpenCL : ${PIP_OPENCL}") message(" OpenCL : ${PIP_OPENCL}")
message(" IOUtils : ${PIP_IOUTILS}") message(" IOUtils : ${PIP_IOUTILS}")
message(" Concurrent: yes")
message(" Cloud : ${PIP_CLOUD}") message(" Cloud : ${PIP_CLOUD}")
message(" Lua : ${PIP_LUA}") message(" Lua : ${PIP_LUA}")
message("") message("")

View File

@@ -9,7 +9,6 @@ Also create imported targets:
* PIP::FFTW * PIP::FFTW
* PIP::OpenCL * PIP::OpenCL
* PIP::IOUtils * PIP::IOUtils
* PIP::Concurrent
* PIP::Cloud * PIP::Cloud
* PIP::Lua * PIP::Lua
@@ -67,7 +66,6 @@ find_library(PIP_FFTW_LIBRARY pip_fftw${_pip_suffix} HINTS ${_PIP_LIBDIR})
find_library(PIP_COMPRESS_LIBRARY pip_compress${_pip_suffix} HINTS ${_PIP_LIBDIR}) find_library(PIP_COMPRESS_LIBRARY pip_compress${_pip_suffix} HINTS ${_PIP_LIBDIR})
find_library(PIP_OPENCL_LIBRARY pip_opencl${_pip_suffix} HINTS ${_PIP_LIBDIR}) find_library(PIP_OPENCL_LIBRARY pip_opencl${_pip_suffix} HINTS ${_PIP_LIBDIR})
find_library(PIP_IO_UTILS_LIBRARY pip_io_utils${_pip_suffix} HINTS ${_PIP_LIBDIR}) find_library(PIP_IO_UTILS_LIBRARY pip_io_utils${_pip_suffix} HINTS ${_PIP_LIBDIR})
find_library(PIP_CONCURRENT_LIBRARY pip_concurrent${_pip_suffix} HINTS ${_PIP_LIBDIR})
find_library(PIP_CLOUD_LIBRARY pip_cloud HINTS${_pip_suffix} ${_PIP_LIBDIR}) find_library(PIP_CLOUD_LIBRARY pip_cloud HINTS${_pip_suffix} ${_PIP_LIBDIR})
find_library(PIP_LUA_LIBRARY pip_lua HINTS${_pip_suffix} ${_PIP_LIBDIR}) find_library(PIP_LUA_LIBRARY pip_lua HINTS${_pip_suffix} ${_PIP_LIBDIR})
find_file(PIP_H_INCLUDE "pip.h" HINTS ${_PIP_INCDIR} $ENV{SMSDK_DIR}/include/pip) find_file(PIP_H_INCLUDE "pip.h" HINTS ${_PIP_INCDIR} $ENV{SMSDK_DIR}/include/pip)
@@ -134,15 +132,14 @@ if(PIP_FIND_VERSION VERSION_GREATER PIP_VERSION)
message(FATAL_ERROR "PIP version ${PIP_VERSION} is available, but ${PIP_FIND_VERSION} requested!") message(FATAL_ERROR "PIP version ${PIP_VERSION} is available, but ${PIP_FIND_VERSION} requested!")
endif() endif()
set(__modules "USB;Crypt;Console;FFTW;Compress;IOUtils;Concurrent;Cloud;Lua") set(__modules "USB;Crypt;Console;FFTW;Compress;IOUtils;Cloud;Lua")
set(__module_USB "${PIP_USB_LIBRARY}" ) set(__module_USB "${PIP_USB_LIBRARY}" )
set(__module_Console "${PIP_CONSOLE_LIBRARY}" ) set(__module_Console "${PIP_CONSOLE_LIBRARY}" )
set(__module_Crypt "${PIP_CRYPT_LIBRARY}" ) set(__module_Crypt "${PIP_CRYPT_LIBRARY}" )
set(__module_FFTW "${PIP_FFTW_LIBRARY}" ) set(__module_FFTW "${PIP_FFTW_LIBRARY}" )
set(__module_Compress "${PIP_COMPRESS_LIBRARY}" ) set(__module_Compress "${PIP_COMPRESS_LIBRARY}" )
set(__module_OpenCL "${PIP_OPENCL_LIBRARY}" ) set(__module_OpenCL "${PIP_OPENCL_LIBRARY}" )
set(__module_IOUtils "${PIP_IO_UTILS_LIBRARY}" ) set(__module_IOUtils "${PIP_IO_UTILS_LIBRARY}" )
set(__module_Concurrent "${PIP_CONCURRENT_LIBRARY}")
set(__module_Cloud "${PIP_CLOUD_LIBRARY}" ) set(__module_Cloud "${PIP_CLOUD_LIBRARY}" )
set(__module_Lua "${PIP_LUA_LIBRARY}" ) set(__module_Lua "${PIP_LUA_LIBRARY}" )
if((NOT TARGET PIP) AND PIP_LIBRARY) if((NOT TARGET PIP) AND PIP_LIBRARY)

View File

@@ -1,95 +0,0 @@
/*
PIP - Platform Independent Primitives
Stephan Fomenko
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "piconditionlock.h"
#ifdef WINDOWS
# include <synchapi.h>
#else
# include <pthread.h>
#endif
PRIVATE_DEFINITION_START(PIConditionLock)
#ifdef WINDOWS
CRITICAL_SECTION
#else
pthread_mutex_t
#endif
nativeHandle;
PRIVATE_DEFINITION_END(PIConditionLock)
PIConditionLock::PIConditionLock() {
#ifdef WINDOWS
InitializeCriticalSection(&PRIVATE->nativeHandle);
#else
pthread_mutexattr_t attr;
memset(&attr, 0, sizeof(attr));
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
memset(&(PRIVATE->nativeHandle), 0, sizeof(PRIVATE->nativeHandle));
pthread_mutex_init(&(PRIVATE->nativeHandle), &attr);
pthread_mutexattr_destroy(&attr);
#endif
}
PIConditionLock::~PIConditionLock() {
#ifdef WINDOWS
DeleteCriticalSection(&PRIVATE->nativeHandle);
#else
pthread_mutex_destroy(&(PRIVATE->nativeHandle));
#endif
}
void PIConditionLock::lock() {
#ifdef WINDOWS
EnterCriticalSection(&PRIVATE->nativeHandle);
#else
pthread_mutex_lock(&(PRIVATE->nativeHandle));
#endif
}
void PIConditionLock::unlock() {
#ifdef WINDOWS
LeaveCriticalSection(&PRIVATE->nativeHandle);
#else
pthread_mutex_unlock(&(PRIVATE->nativeHandle));
#endif
}
void *PIConditionLock::handle() {
#ifdef WINDOWS
return &PRIVATE->nativeHandle;
#else
return &PRIVATE->nativeHandle;
#endif
}
bool PIConditionLock::tryLock() {
#ifdef WINDOWS
return TryEnterCriticalSection(&PRIVATE->nativeHandle) != 0;
#else
return (pthread_mutex_trylock(&(PRIVATE->nativeHandle)) == 0);
#endif
}

View File

@@ -8,24 +8,24 @@ public:
bool isTrueCondition = false; bool isTrueCondition = false;
int timeout = -1; int timeout = -1;
void wait(PIConditionLock& lk) override { void wait(PIMutex& lk) override {
isWaitCalled = true; isWaitCalled = true;
} }
void wait(PIConditionLock& lk, const std::function<bool()>& condition) override { void wait(PIMutex& lk, const std::function<bool()>& condition) override {
isWaitCalled = true; isWaitCalled = true;
lk.lock(); lk.lock();
isTrueCondition = condition(); isTrueCondition = condition();
lk.unlock(); lk.unlock();
} }
bool waitFor(PIConditionLock& lk, int timeoutMs) override { bool waitFor(PIMutex& lk, int timeoutMs) override {
isWaitForCalled = true; isWaitForCalled = true;
timeout = timeoutMs; timeout = timeoutMs;
return false; return false;
} }
bool waitFor(PIConditionLock& lk, int timeoutMs, const std::function<bool()>& condition) override { bool waitFor(PIMutex& lk, int timeoutMs, const std::function<bool()>& condition) override {
isWaitForCalled = true; isWaitForCalled = true;
lk.lock(); lk.lock();
isTrueCondition = condition(); isTrueCondition = condition();

View File

@@ -2,12 +2,12 @@
#include "gmock/gmock.h" #include "gmock/gmock.h"
#include "piconditionvar.h" #include "piconditionvar.h"
#include <pithread.h> #include "pithread.h"
#include "testutil.h" #include "testutil.h"
class ConditionLock : public ::testing::Test, public TestUtil { class ConditionLock : public ::testing::Test, public TestUtil {
public: public:
PIConditionLock* m = new PIConditionLock(); PIMutex* m = new PIMutex();
}; };
TEST_F(ConditionLock, lock_is_protect) { TEST_F(ConditionLock, lock_is_protect) {
@@ -50,4 +50,4 @@ TEST_F(ConditionLock, tryLock_is_true_when_unlocked) {
TEST_F(ConditionLock, tryLock_is_recursive_lock_enable) { TEST_F(ConditionLock, tryLock_is_recursive_lock_enable) {
m->lock(); m->lock();
ASSERT_TRUE(m->tryLock()); ASSERT_TRUE(m->tryLock());
} }

View File

@@ -5,7 +5,7 @@
class ConditionVariable : public ::testing::Test, public TestUtil { class ConditionVariable : public ::testing::Test, public TestUtil {
public: public:
PIConditionLock m; PIMutex m;
PIConditionVariable* variable; PIConditionVariable* variable;
protected: protected:
@@ -197,4 +197,4 @@ TEST_F(ConditionVariable, waitFor_is_unblock_when_condition_and_notifyOne) {
variable->notifyOne(); variable->notifyOne();
msleep(WAIT_THREAD_TIME_MS); msleep(WAIT_THREAD_TIME_MS);
ASSERT_FALSE(thread->isRunning()); ASSERT_FALSE(thread->isRunning());
} }

View File

@@ -1,5 +1,5 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "executor.h" #include "pithreadpoolexecutor.h"
#include "pimutex.h" #include "pimutex.h"
const int WAIT_THREAD_TIME_MS = 30; const int WAIT_THREAD_TIME_MS = 30;
@@ -51,4 +51,4 @@ TEST(ExcutorIntegrationTest, execute_is_awaitTermination_wait) {
double waitTime = measurer.elapsed_m(); double waitTime = measurer.elapsed_m();
ASSERT_GE(waitTime, WAIT_THREAD_TIME_MS); ASSERT_GE(waitTime, WAIT_THREAD_TIME_MS);
ASSERT_LE(waitTime, 4 * WAIT_THREAD_TIME_MS); ASSERT_LE(waitTime, 4 * WAIT_THREAD_TIME_MS);
} }

View File

@@ -1,1168 +0,0 @@
/*
PIP - Platform Independent Primitives
Console output/input
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 <http://www.gnu.org/licenses/>.
*/
#include "piconsole.h"
#include "piincludes_p.h"
#include "pipeer.h"
#include "pidiagnostics.h"
#include "pisystemmonitor.h"
#ifndef WINDOWS
# include <sys/ioctl.h>
# include <fcntl.h>
# include <termios.h>
#else
# include <wincon.h>
# define COMMON_LVB_UNDERSCORE 0x8000
#endif
/** \class PIConsole
* \brief Console output class
* \details
* \section PIConsole_sec0 Synopsis
* This class provides output to console with automatic alignment and update.
* It supports tabs, keyboard listening, formats and colors.
*
* \section PIConsole_sec1 Layout
* %PIConsole works with variable pointers. You should add your variables with
* functions \a addVariable() which receives label name, pointer to variable
* and optional column and format. Columns count is dynamically increased if
* new column used. E.g. if you add variable to empty tab to column 3, columns
* count will be increased to 3, but two firsts columns will be empty. Each column
* filled from top to bottom, but you can add just string with function
* \a addString() or add empty line with function \a addEmptyLine(). Layout scheme:
* \image html piconsole_layout.png
*
* \section PIConsole_sec2 Keyboard usage
* %PIConsole should to be single in application. %PIConsole aggregate PIKbdListener
* which grab keyboard and automatic switch tabs by theirs bind keys. If there is no
* tab binded to pressed key external function "slot" will be called
*
**/
PRIVATE_DEFINITION_START(PIConsole)
#ifdef WINDOWS
void getWinCurCoord() {GetConsoleScreenBufferInfo(hOut, &csbi); ccoord = csbi.dwCursorPosition;}
COORD & getWinCoord(int dx = 0, int dy = 0) {getWinCurCoord(); ccoord.X += dx; ccoord.Y += dy; return ccoord;}
void * hOut;
CONSOLE_SCREEN_BUFFER_INFO sbi, csbi;
CONSOLE_CURSOR_INFO curinfo;
COORD ccoord, ulcoord;
WORD dattr;
DWORD smode, written;
#endif
PRIVATE_DEFINITION_END(PIConsole)
PIConsole::PIConsole(bool startNow, PIKbdListener::KBFunc slot): PIThread() {
setName("console");
setPriority(piLow);
needLockRun(true);
ret_func = slot;
num_format = systime_format = 0;
vid = 0;
cur_tab = width = height = pwidth = pheight = max_y = 0;
def_align = Nothing;
tabs.reserve(16);
#ifdef WINDOWS
PRIVATE->ulcoord.X = 0;
PRIVATE->hOut = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
PRIVATE->dattr = PRIVATE->sbi.wAttributes;
width = PRIVATE->sbi.srWindow.Right - PRIVATE->sbi.srWindow.Left;
height = PRIVATE->sbi.srWindow.Bottom - PRIVATE->sbi.srWindow.Top;
PRIVATE->ulcoord.Y = PRIVATE->sbi.srWindow.Top;
GetConsoleMode(PRIVATE->hOut, &PRIVATE->smode);
GetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo);
#else
# ifdef FREERTOS
width = 80;
height = 24;
# else
winsize ws;
ioctl(0, TIOCGWINSZ, &ws);
width = ws.ws_col;
height = ws.ws_row;
# endif
#endif
addTab("main");
listener = new PIKbdListener(key_event, this);
peer_timer = new PITimer();
peer_timer->setName("__S__.PIConsole.peer_timer");
peer = 0;
server_mode = pause_ = false;
state = Disconnected;
peer_timer->addDelimiter(20);
peer_timer->setName("__S__PIConsole::peer_timer");
CONNECT2(void, void * , int, peer_timer, tickEvent, this, peerTimer);
if (startNow) start();
}
PIConsole::~PIConsole() {
stopPeer();
if (isRunning())
stop();
clearTabs(false);
delete listener;
delete peer_timer;
#ifdef WINDOWS
SetConsoleMode(PRIVATE->hOut, PRIVATE->smode);
SetConsoleTextAttribute(PRIVATE->hOut, PRIVATE->dattr);
#endif
}
int PIConsole::addTab(const PIString & name, char bind_key) {
if (isRunning()) lock();
tabs.push_back(Tab(name, bind_key));
cur_tab = tabs.size() - 1;
if (isRunning()) unlock();
return tabs.size();
}
void PIConsole::removeTab(uint index) {
if (index >= tabs.size()) return;
if (isRunning()) lock();
tabs.remove(index);
if (cur_tab >= tabs.size()) cur_tab = tabs.size() - 1;
if (isRunning()) unlock();
}
void PIConsole::removeTab(const PIString & name) {
uint index = tabs.size() + 1;
for (uint i = 0; i < tabs.size(); ++i) {
if (tabs[i].name == name) {
index = i;
break;
}
}
removeTab(index);
}
void PIConsole::clearTab(uint index) {
if (index >= tabs.size()) return;
lock();
tabs[index].columns.clear();
if (cur_tab == index) {
clearScreen();
fillLabels();
}
if (cur_tab >= tabs.size()) cur_tab = tabs.size() - 1;
unlock();
}
void PIConsole::clearTab(const PIString & name) {
uint index = tabs.size() + 1;
for (uint i = 0; i < tabs.size(); ++i) {
if (tabs[i].name == name) {
index = i;
break;
}
}
clearTab(index);
}
void PIConsole::update() {
lock();
fillLabels();
unlock();
}
bool PIConsole::setTab(uint index) {
if (index >= tabs.size())
return false;
if (!isRunning()) {
cur_tab = index;
return true;
}
lock();
PICout::__mutex__().lock();
cur_tab = index;
clearScreen();
fillLabels();
PICout::__mutex__().unlock();
unlock();
return true;
}
bool PIConsole::setTab(const PIString & name) {
uint index = tabs.size() + 1;
for (uint i = 0; i < tabs.size(); ++i) {
if (tabs[i].name == name) {
index = i;
break;
}
}
return setTab(index);
}
bool PIConsole::setTabBindKey(uint index, char bind_key) {
if (index >= tabs.size())
return false;
tabs[index].key = bind_key;
return true;
}
bool PIConsole::setTabBindKey(const PIString & name, char bind_key) {
uint index =tabs.size() + 1;
for (uint i = 0; i < tabs.size(); ++i) {
if (tabs[i].name == name) {
index = i;
break;
}
}
return setTabBindKey(index, bind_key);
}
void PIConsole::key_event(PIKbdListener::KeyEvent key, void * t) {
PIConsole * p = (PIConsole * )t;
int ct = p->cur_tab;
if (key.key == PIKbdListener::LeftArrow) {
do {
ct--;
if (ct < 0) return;
} while (p->tabs[ct].key == 0);
p->setTab(ct);
return;
}
if (key.key == PIKbdListener::RightArrow) {
do {
ct++;
if (ct >= p->tabs.size_s()) return;
} while (p->tabs[ct].key == 0);
p->setTab(ct);
return;
}
for (uint i = 0; i < p->tabsCount(); ++i) {
if (p->tabs[i].key == key.key) {
p->setTab(i);
return;
}
}
if (p->ret_func != 0) p->ret_func(key, t);
p->keyPressed(key, t);
}
int PIConsole::couts(const PIString & v) {
return printf("%s", v.data());
}
int PIConsole::couts(const char * v) {
return printf("%s", v);
}
void PIConsole::clearVariables(bool clearScreen) {
if (isRunning()) lock();
if (clearScreen && isRunning()) {
toUpperLeft();
clearScreenLower();
}
columns().clear();
if (isRunning()) unlock();
}
void PIConsole::stop(bool clear) {
PIThread::stop(true);
if (clear) clearScreen();
moveTo(0, max_y + 4);
showCursor();
couts(fstr(Normal));
#ifdef WINDOWS
SetConsoleMode(PRIVATE->hOut, PRIVATE->smode);
SetConsoleTextAttribute(PRIVATE->hOut, PRIVATE->dattr);
#endif
fflush(0);
}
PIString PIConsole::fstr(FormatFlags f) {
num_format = systime_format = 0;
if (f[PIConsole::Dec]) num_format = 0;
if (f[PIConsole::Hex]) num_format = 1;
if (f[PIConsole::Oct]) num_format = 2;
if (f[PIConsole::Bin]) num_format = 4;
if (f[PIConsole::Scientific]) num_format = 3;
if (f[PIConsole::SystemTimeSplit]) systime_format = 0;
if (f[PIConsole::SystemTimeSeconds]) systime_format = 1;
#ifdef WINDOWS
WORD attr = 0;
if (f[PIConsole::Inverse]) {
if (f[PIConsole::Red]) attr |= BACKGROUND_RED;
if (f[PIConsole::Green]) attr |= BACKGROUND_GREEN;
if (f[PIConsole::Blue]) attr |= BACKGROUND_BLUE;
if (f[PIConsole::Yellow]) attr |= (BACKGROUND_RED | BACKGROUND_GREEN);
if (f[PIConsole::Magenta]) attr |= (BACKGROUND_RED | BACKGROUND_BLUE);
if (f[PIConsole::Cyan]) attr |= (BACKGROUND_GREEN | BACKGROUND_BLUE);
if (f[PIConsole::White]) attr |= (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
if (f[PIConsole::BackRed]) attr |= FOREGROUND_RED;
if (f[PIConsole::BackGreen]) attr |= FOREGROUND_GREEN;
if (f[PIConsole::BackBlue]) attr |= FOREGROUND_BLUE;
if (f[PIConsole::BackYellow]) attr |= (FOREGROUND_RED | FOREGROUND_GREEN);
if (f[PIConsole::BackMagenta]) attr |= (FOREGROUND_RED | FOREGROUND_BLUE);
if (f[PIConsole::BackCyan]) attr |= (FOREGROUND_GREEN | FOREGROUND_BLUE);
if (f[PIConsole::BackWhite]) attr |= (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
if ((attr & BACKGROUND_RED) + (attr & BACKGROUND_GREEN) + (attr & BACKGROUND_BLUE) == 0)
attr |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
} else {
if (f[PIConsole::Red]) attr |= FOREGROUND_RED;
if (f[PIConsole::Green]) attr |= FOREGROUND_GREEN;
if (f[PIConsole::Blue]) attr |= FOREGROUND_BLUE;
if (f[PIConsole::Yellow]) attr |= (FOREGROUND_RED | FOREGROUND_GREEN);
if (f[PIConsole::Magenta]) attr |= (FOREGROUND_RED | FOREGROUND_BLUE);
if (f[PIConsole::Cyan]) attr |= (FOREGROUND_GREEN | FOREGROUND_BLUE);
if (f[PIConsole::White]) attr |= (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
if (f[PIConsole::BackRed]) attr |= BACKGROUND_RED;
if (f[PIConsole::BackGreen]) attr |= BACKGROUND_GREEN;
if (f[PIConsole::BackBlue]) attr |= BACKGROUND_BLUE;
if (f[PIConsole::BackYellow]) attr |= (BACKGROUND_RED | BACKGROUND_GREEN);
if (f[PIConsole::BackMagenta]) attr |= (BACKGROUND_RED | BACKGROUND_BLUE);
if (f[PIConsole::BackCyan]) attr |= (BACKGROUND_GREEN | BACKGROUND_BLUE);
if (f[PIConsole::BackWhite]) attr |= (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
if ((attr & FOREGROUND_RED) + (attr & FOREGROUND_GREEN) + (attr & FOREGROUND_BLUE) == 0)
attr |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
}
if (f[PIConsole::Bold]) attr |= FOREGROUND_INTENSITY;
if (f[PIConsole::Underline]) attr |= COMMON_LVB_UNDERSCORE;
SetConsoleTextAttribute(PRIVATE->hOut, attr);
return PIString();
#else
PIString ts("\e[0");
if (f[PIConsole::Bold]) ts += ";1";
if (f[PIConsole::Faint]) ts += ";2";
if (f[PIConsole::Italic]) ts += ";3";
if (f[PIConsole::Underline]) ts += ";4";
if (f[PIConsole::Blink]) ts += ";5";
if (f[PIConsole::Inverse]) ts += ";7";
if (f[PIConsole::Black]) ts += ";30";
if (f[PIConsole::Red]) ts += ";31";
if (f[PIConsole::Green]) ts += ";32";
if (f[PIConsole::Yellow]) ts += ";33";
if (f[PIConsole::Blue]) ts += ";34";
if (f[PIConsole::Magenta]) ts += ";35";
if (f[PIConsole::Cyan]) ts += ";36";
if (f[PIConsole::White]) ts += ";37";
if (f[PIConsole::BackBlack]) ts += ";40";
if (f[PIConsole::BackRed]) ts += ";41";
if (f[PIConsole::BackGreen]) ts += ";42";
if (f[PIConsole::BackYellow]) ts += ";43";
if (f[PIConsole::BackBlue]) ts += ";44";
if (f[PIConsole::BackMagenta]) ts += ";45";
if (f[PIConsole::BackCyan]) ts += ";46";
if (f[PIConsole::BackWhite]) ts += ";47";
return ts + "m";
#endif
}
inline int PIConsole::couts(const bool v) {return (v ? printf("true") : printf("false"));}
inline int PIConsole::couts(const char v) {return printf("%c", v);}
inline int PIConsole::couts(const short v) {
switch (num_format) {case (1): return printf("0x%.4hX", v); break; case (2): return printf("%o", v); break; case (4): return printf("%s", toBin(&v, 2)); break; default: return printf("%hd", v); break;}
}
inline int PIConsole::couts(const int v) {
switch (num_format) {case (1): return printf("0x%.8X", v); break; case (2): return printf("%o", v); break; case (4): return printf("%s", toBin(&v, 4)); break; default: return printf("%d", v); break;}
}
inline int PIConsole::couts(const long v) {
switch (num_format) {case (1): return printf("0x%.16lX", v); break; case (2): return printf("%lo", v); break; case (4): return printf("%s", toBin(&v, sizeof(v))); break; default: return printf("%ld", v); break;}
}
inline int PIConsole::couts(const llong v) {
switch (num_format) {case (1): return printf("0x%.16llX", v); break; case (2): return printf("%llo", v); break; case (4): return printf("%s", toBin(&v, sizeof(v))); break; default: return printf("%lld", v); break;}
}
inline int PIConsole::couts(const uchar v) {
switch (num_format) {case (1): return printf("0x%.2X", v); break; case (2): return printf("%o", v); break; case (4): return printf("%s", toBin(&v, 1)); break; default: return printf("%u", v); break;}
}
inline int PIConsole::couts(const ushort v) {
switch (num_format) {case (1): return printf("0x%.4hX", v); break; case (2): return printf("%o", v); break; case (4): return printf("%s", toBin(&v, 2)); break; default: return printf("%hu", v); break;}
}
inline int PIConsole::couts(const uint v) {
switch (num_format) {case (1): return printf("0x%.8X", v); break; case (2): return printf("%o", v); break; case (4): return printf("%s", toBin(&v, 4)); break; default: return printf("%u", v); break;}
}
inline int PIConsole::couts(const ulong v) {
switch (num_format) {case (1): return printf("0x%.16lX", v); break; case (2): return printf("%lo", v); break; case (4): return printf("%s", toBin(&v, sizeof(v))); break; default: return printf("%lu", v); break;}
}
inline int PIConsole::couts(const ullong v) {
switch (num_format) {case (1): return printf("0x%.16llX", v); break; case (2): return printf("%llo", v); break; case (4): return printf("%s", toBin(&v, sizeof(v))); break; default: return printf("%llu", v); break;}
}
inline int PIConsole::couts(const float v) {
switch (num_format) {case (3): return printf("%e", v); break; default: return printf("%.5g", v); break;}
}
inline int PIConsole::couts(const double v) {
switch (num_format) {case (3): return printf("%le", v); break; default: return printf("%.5lg", v); break;}
}
inline int PIConsole::couts(const PISystemTime & v) {
switch (systime_format) {case (1): return printf("%.6lg", v.toSeconds()); break;
default: return couts(v.seconds) + printf(" s, ") + couts(v.nanoseconds) + printf(" ns"); break;}
}
void PIConsole::toUpperLeft() {
#ifdef WINDOWS
SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ulcoord);
#else
printf("\e[H");
#endif
}
void PIConsole::moveRight(int n) {
#ifdef WINDOWS
SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->getWinCoord(n));
#else
if (n > 0) printf("\e[%dC", n);
#endif
}
void PIConsole::moveLeft(int n) {
#ifdef WINDOWS
SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->getWinCoord(-n));
#else
if (n > 0) printf("\e[%dD", n);
#endif
}
void PIConsole::moveTo(int x, int y) {
#ifdef WINDOWS
PRIVATE->ccoord.X = x;
PRIVATE->ccoord.Y = PRIVATE->ulcoord.Y + y;
SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ccoord);
#else
printf("\e[%d;%dH", y, x);
#endif
}
void PIConsole::clearScreen() {
#ifdef WINDOWS
couts(fstr(Normal));
toUpperLeft();
FillConsoleOutputAttribute(PRIVATE->hOut, PRIVATE->dattr, width * (height + 1), PRIVATE->ulcoord, &PRIVATE->written);
FillConsoleOutputCharacter(PRIVATE->hOut, ' ', width * (height + 1), PRIVATE->ulcoord, &PRIVATE->written);
#else
couts(fstr(Normal)); printf("\e[H\e[J");
#endif
}
void PIConsole::clearScreenLower() {
#ifdef WINDOWS
couts(fstr(Normal));
PRIVATE->getWinCurCoord();
FillConsoleOutputAttribute(PRIVATE->hOut, PRIVATE->dattr, width * height - width * PRIVATE->ccoord.Y + PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written);
FillConsoleOutputCharacter(PRIVATE->hOut, ' ', width * height - width * PRIVATE->ccoord.Y + PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written);
#else
couts(fstr(Normal)); printf("\e[J");
#endif
}
void PIConsole::clearLine() {
#ifdef WINDOWS
PRIVATE->getWinCurCoord();
FillConsoleOutputAttribute(PRIVATE->hOut, PRIVATE->dattr, width - PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written);
FillConsoleOutputCharacter(PRIVATE->hOut, ' ', width - PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written);
#else
printf("\e[K");
#endif
}
void PIConsole::newLine() {
#ifdef WINDOWS
PRIVATE->getWinCurCoord();
PRIVATE->ccoord.X = 0; PRIVATE->ccoord.Y++;
SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ccoord);
#else
printf("\eE");
#endif
}
void PIConsole::hideCursor() {
#ifdef WINDOWS
PRIVATE->curinfo.bVisible = false;
SetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo);
#else
printf("\e[?25l");
#endif
}
void PIConsole::showCursor() {
#ifdef WINDOWS
PRIVATE->curinfo.bVisible = true; SetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo);
#else
printf("\e[?25h");
#endif
}
void PIConsole::begin() {
#ifdef WINDOWS
SetConsoleMode(PRIVATE->hOut, ENABLE_WRAP_AT_EOL_OUTPUT);
#endif
max_y = 0;
PICout::__mutex__().lock();
clearScreen();
hideCursor();
fillLabels();
PICout::__mutex__().unlock();
}
void PIConsole::run() {
if (pause_) return;
uint cx, clen = 0;
int j;
#ifdef WINDOWS
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
width = PRIVATE->sbi.srWindow.Right - PRIVATE->sbi.srWindow.Left;
height = PRIVATE->sbi.srWindow.Bottom - PRIVATE->sbi.srWindow.Top;
#else
# ifdef FREERTOS
width = 80;
height = 24;
# else
winsize ws;
ioctl(0, TIOCGWINSZ, &ws);
width = ws.ws_col;
height = ws.ws_row;
# endif
#endif
//fflush(0); return;
PICout::__mutex__().lock();
if (pwidth != width || pheight != height) {
clearScreen();
fillLabels();
}
pwidth = width;
pheight = height;
col_cnt = columns().size();
col_wid = (col_cnt > 0) ? width / col_cnt : width;
for (uint i = 0; i < col_cnt; ++i) {
PIVector<Variable> & cvars(tabs[cur_tab].columns[i].variables);
cx = col_wid * i;
toUpperLeft();
if (max_y < cvars.size()) max_y = cvars.size();
j = 0;
piForeachC (Variable & tv_, cvars) {
if (j > height - 3) continue;
j++;
moveRight(cx);
if (tv_.type == 15) {
newLine();
continue;
}
moveRight(tv_.offset);
const void * ptr = 0;
if (tv_.remote) {
if (tv_.type == 0) {
rstr.clear();
rba = tv_.rdata;
rba >> rstr;
rstr.trim();
ptr = &rstr;
} else
ptr = tv_.rdata.data();
} else
ptr = tv_.ptr;
switch (tv_.type) {
case 0: clen = printValue(ptr != 0 ? *(const PIString*)ptr : PIString(), tv_.format); break;
case 1: clen = printValue(ptr != 0 ? *(const bool*)ptr : false, tv_.format); break;
case 2: clen = printValue(ptr != 0 ? *(const int*)ptr : 0, tv_.format); break;
case 3: clen = printValue(ptr != 0 ? *(const long*)ptr : 0l, tv_.format); break;
case 4: clen = printValue(ptr != 0 ? *(const char*)ptr : char(0), tv_.format); break;
case 5: clen = printValue(ptr != 0 ? *(const float*)ptr : 0.f, tv_.format); break;
case 6: clen = printValue(ptr != 0 ? *(const double*)ptr : 0., tv_.format); break;
case 7: clen = printValue(ptr != 0 ? *(const short*)ptr : short(0), tv_.format); break;
case 8: clen = printValue(ptr != 0 ? *(const uint*)ptr : 0u, tv_.format); break;
case 9: clen = printValue(ptr != 0 ? *(const ulong*)ptr : 0ul, tv_.format); break;
case 10: clen = printValue(ptr != 0 ? *(const ushort*)ptr : ushort(0), tv_.format); break;
case 11: clen = printValue(ptr != 0 ? *(const uchar*)ptr : uchar(0), tv_.format); break;
case 12: clen = printValue(ptr != 0 ? *(const llong*)ptr : 0l, tv_.format); break;
case 13: clen = printValue(ptr != 0 ? *(const ullong*)ptr: 0ull, tv_.format); break;
case 20: clen = printValue(ptr != 0 ? *(const PISystemTime*)ptr: PISystemTime(), tv_.format); break;
case 14: clen = printValue(bitsValue(ptr, tv_.bitFrom, tv_.bitCount), tv_.format); break;
}
if (clen + tv_.offset < (uint)col_wid) {
PIString ts = PIString(
#if defined(QNX) || defined(FREE_BSD)
col_wid - clen - tv_.offset - 1, ' ');
#else
col_wid - clen - tv_.offset, ' ');
#endif
printf("%s", ts.data());
}
newLine();
}
}
#ifdef WINDOWS
moveTo(0, max_y + 1);
#else
moveTo(0, max_y + 2);
#endif
fflush(0);
PICout::__mutex__().unlock();
}
void PIConsole::fillLabels() {
if (!isRunning()) return;
uint cx, cy, mx = 0, dx;
#ifdef WINDOWS
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
width = PRIVATE->sbi.srWindow.Right - PRIVATE->sbi.srWindow.Left;
height = PRIVATE->sbi.srWindow.Bottom - PRIVATE->sbi.srWindow.Top;
#else
# ifdef FREERTOS
width = 80;
height = 24;
# else
winsize ws;
ioctl(0, TIOCGWINSZ, &ws);
width = ws.ws_col;
height = ws.ws_row;
# endif
#endif
max_y = 0;
col_cnt = columns().size();
col_wid = (col_cnt > 0) ? width / col_cnt : width;
for (uint i = 0; i < col_cnt; ++i) {
Column & ccol(tabs[cur_tab].columns[i]);
PIVector<Variable> & cvars(ccol.variables);
if (ccol.alignment != Nothing) {
mx = 0;
piForeachC (Variable & j, cvars)
if (!j.isEmpty())
if (mx < j.name.size())
mx = j.name.size();
mx += 2;
}
cx = col_wid * i;
cy = 1;
toUpperLeft();
for (uint j = 0; j < cvars.size(); ++j) {
if (int(j) > height - 3) continue;
if (max_y < j) max_y = j;
moveRight(cx);
Variable & tv_(cvars[j]);
cvars[j].nx = cx;
cvars[j].ny = cy;
if (tv_.name.isEmpty()) {
cvars[j].offset = 0;
clearLine();
newLine();
cy++;
continue;
}
clearLine();
//piCout << tv_.name << tv_.type << tv_.ptr;
if (tv_.type == 15) {
cvars[j].offset = cvars[j].name.length();
cvars[j].nx += cvars[j].offset;
printLine(tv_.name, cx, tv_.format);
newLine();
cy++;
continue;
}
if (!tv_.isEmpty()) {
switch (ccol.alignment) {
case Nothing:
cvars[j].offset = (tv_.name + ": ").length();
cvars[j].nx += cvars[j].offset;
printValue(tv_.name + ": ", tv_.format);
break;
case Left:
cvars[j].offset = mx;
cvars[j].nx += cvars[j].offset;
printValue(tv_.name + ": ", tv_.format);
break;
case Right:
cvars[j].offset = mx;
cvars[j].nx += cvars[j].offset;
dx = mx - (tv_.name + ": ").length();
moveRight(dx);
printValue(tv_.name + ": ", tv_.format);
moveLeft(dx);
break;
}
}
newLine();
cy++;
}
}
#ifdef WINDOWS
moveTo(0, max_y + 1);
#else
moveTo(0, max_y + 2);
#endif
if (!tabs[cur_tab].status.isEmpty()) {
printValue(tabs[cur_tab].status);
newLine();
}
status();
}
void PIConsole::status() {
Tab * ctab;
for (uint i = 0; i < tabsCount(); ++i) {
ctab = &tabs[i];
if (ctab->key == 0) continue;
printValue(ctab->key, PIConsole::White | PIConsole::Bold);
if (i == cur_tab)
printValue(ctab->name + " ", PIConsole::BackYellow | PIConsole::Black);
else
printValue(ctab->name + " ", PIConsole::Cyan | PIConsole::Inverse);
printValue(" ");
}
newLine();
}
int PIConsole::bitsValue(const void * src, int offset, int count) const {
int ret = 0, stbyte = offset / 8, cbit = offset - stbyte * 8;
char cbyte = reinterpret_cast<const char * >(src)[stbyte];
for (int i = 0; i < count; i++) {
ret |= ((cbyte >> cbit & 1) << i);
cbit++;
if (cbit == 8) {
cbit = 0;
stbyte++;
cbyte = reinterpret_cast<const char * >(src)[stbyte];
}
}
return ret;
}
const char * PIConsole::toBin(const void * d, int s) {
binstr.clear();
uchar cc, b;
for (int i = 0; i < s; ++i) {
cc = ((const uchar *)d)[i];
b = 1;
for (int j = 0; j < 8; ++j) {
binstr << (cc & b ? "1" : "0");
b <<= 1;
}
if (i < s - 1) binstr << " ";
}
binstr.reverse();
return binstr.data();
}
#define ADD_VAR_BODY vid++; tv.id = vid; tv.name = name; tv.bitFrom = tv.bitCount = 0; tv.format = format; tv.remote = false; checkColumn(col);
void PIConsole::addString(const PIString & name, int col, FormatFlags format) {
ADD_VAR_BODY tv.type = 15; tv.size = 0; tv.ptr = 0; column(col).push_back(tv);}
void PIConsole::addVariable(const PIString & name, const PIString * ptr, int col, FormatFlags format) {
ADD_VAR_BODY tv.type = 0; tv.size = 0; tv.ptr = ptr; column(col).push_back(tv);}
void PIConsole::addVariable(const PIString & name, const bool * ptr, int col, FormatFlags format) {
ADD_VAR_BODY tv.type = 1; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
void PIConsole::addVariable(const PIString & name, const int * ptr, int col, FormatFlags format) {
ADD_VAR_BODY tv.type = 2; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
void PIConsole::addVariable(const PIString & name, const long * ptr, int col, FormatFlags format) {
ADD_VAR_BODY tv.type = 3; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
void PIConsole::addVariable(const PIString & name, const char * ptr, int col, FormatFlags format) {
ADD_VAR_BODY tv.type = 4; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
void PIConsole::addVariable(const PIString & name, const float * ptr, int col, FormatFlags format) {
ADD_VAR_BODY tv.type = 5; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
void PIConsole::addVariable(const PIString & name, const double * ptr, int col, FormatFlags format) {
ADD_VAR_BODY tv.type = 6; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
void PIConsole::addVariable(const PIString & name, const short * ptr, int col, FormatFlags format) {
ADD_VAR_BODY tv.type = 7; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
void PIConsole::addVariable(const PIString & name, const uint * ptr, int col, FormatFlags format) {
ADD_VAR_BODY tv.type = 8; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
void PIConsole::addVariable(const PIString & name, const ulong * ptr, int col, FormatFlags format) {
ADD_VAR_BODY tv.type = 9; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
void PIConsole::addVariable(const PIString & name, const ushort * ptr, int col, FormatFlags format) {
ADD_VAR_BODY tv.type = 10; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
void PIConsole::addVariable(const PIString & name, const uchar * ptr, int col, FormatFlags format) {
ADD_VAR_BODY tv.type = 11; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
void PIConsole::addVariable(const PIString & name, const llong * ptr, int col, FormatFlags format) {
ADD_VAR_BODY tv.type = 12; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
void PIConsole::addVariable(const PIString & name, const ullong * ptr, int col, FormatFlags format) {
ADD_VAR_BODY tv.type = 13; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
void PIConsole::addVariable(const PIString & name, const PISystemTime * ptr, int col, FormatFlags format) {
ADD_VAR_BODY tv.type = 20; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
/** \brief Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
* \details This function add to column "column" next lines:
* * "<name> diagnostics"
* * "Received count": \a PIDiagnostics::receiveCount
* * "Invalid count": \a PIDiagnostics::wrongCount
* * "Sended count": \a PIDiagnostics::sendCount
* * "Immediate Frequency, Hz": \a PIDiagnostics::immediateFrequency
* * "Integral Frequency, Hz": \a PIDiagnostics::integralFrequency
* * "Receive speed": \a PIDiagnostics::receiveSpeed
* * "Send speed": \a PIDiagnostics::sendSpeed
* * "Quality": \a PIDiagnostics::quality
* */
void PIConsole::addVariable(const PIString & name, const PIDiagnostics * ptr, int col, FormatFlags format) {
addString(name + " diagnostics", col, format | PIConsole::Bold);
// addVariable("Received count", ptr->receiveCount_ptr(), col, format);
// addVariable("Invalid count", ptr->wrongCount_ptr(), col, format);
// addVariable("Sended count", ptr->sendCount_ptr(), col, format);
// addVariable("Immediate Frequency, Hz", ptr->immediateFrequency_ptr(), col, format);
// addVariable("Integral Frequency, Hz", ptr->integralFrequency_ptr(), col, format);
// addVariable("Receive speed", ptr->receiveSpeed_ptr(), col, format);
// addVariable("Send speed", ptr->sendSpeed_ptr(), col, format);
// addVariable("Quality", ptr->quality_ptr(), col, format);
}
void PIConsole::addVariable(const PIString & name, const PISystemMonitor * ptr, int col, FormatFlags format) {
addString("monitor " + name, col, format | PIConsole::Bold);
//addVariable("PID", &(ptr->statistic().ID), col, format);
//addVariable("state", &(ptr->statistic().state), col, format);
//addVariable("threads", &(ptr->statistic().threads), col, format);
//addVariable("priority", &(ptr->statistic().priority), col, format);
//addVariable("memory physical", &(ptr->statistic().physical_memsize_readable), col, format);
//addVariable("memory shared", &(ptr->statistic().share_memsize_readable), col, format);
//addVariable("cpu load kernel", &(ptr->statistic().cpu_load_system), col, format);
//addVariable("cpu load user", &(ptr->statistic().cpu_load_user), col, format);
}
void PIConsole::addBitVariable(const PIString & name, const void * ptr, int fromBit, int bitCount, int col, FormatFlags format) {
vid++; tv.id = vid; tv.size = sizeof(ullong); tv.name = name; tv.bitFrom = fromBit; tv.bitCount = bitCount; tv.type = 14; tv.ptr = ptr; tv.format = format;
checkColumn(col); column(col).push_back(tv);}
void PIConsole::addEmptyLine(int col, uint count) {
tv.id = 0; tv.size = 0; tv.name = ""; tv.type = 0; tv.ptr = 0; tv.format = Normal;
for (uint i = 0; i < count; ++i) {
checkColumn(col);
column(col).push_back(tv);
}
}
PIString PIConsole::getString(int x, int y) {
bool run = isRunning();
if (run) PIThread::stop(true);
listener->setActive(false);
msleep(50);
#ifdef WINDOWS
moveTo(x - 1, y - 1);
#else
moveTo(x, y);
#endif
showCursor();
PIByteArray ba(4096);
#ifdef CC_VC
int ret = scanf_s(" %s", ba.data());
#else
int ret = scanf(" %s", ba.data());
#endif
listener->setActive(true);
if (run) start();
if (ret >= 1) return PIString(ba);
else return PIString();
}
PIString PIConsole::getString(const PIString & name) {
piForeachC (Column & i, tabs[cur_tab].columns)
piForeachC (Variable & j, i.variables)
if (j.name == name)
return getString(j.nx + 1, j.ny);
return PIString();
}
#define PRINT_VAR_BODY couts(fstr(format)); int ret = couts(value); couts(fstr(PIConsole::Dec)); return ret;
inline void PIConsole::printLine(const PIString & value, int dx, FormatFlags format) {
int i = width - value.length() - dx;
#if defined(QNX) || defined(FREE_BSD)
--i;
#endif
PIString ts = fstr(format);
couts(ts);
if (i >= 0) ts = value + PIString(i, ' ');
else ts = value.left(value.size() + i);
couts(ts);
couts(fstr(Dec));
}
inline int PIConsole::printValue(const PIString & value, FormatFlags format) {
couts(fstr(format));
int ret = couts(value);
fstr(PIConsole::Dec);
return ret;
}
inline int PIConsole::printValue(const char * value, FormatFlags format) {PRINT_VAR_BODY}
inline int PIConsole::printValue(const bool value, FormatFlags format) {PRINT_VAR_BODY}
inline int PIConsole::printValue(const int value, FormatFlags format) {PRINT_VAR_BODY}
inline int PIConsole::printValue(const long value, FormatFlags format) {PRINT_VAR_BODY}
inline int PIConsole::printValue(const llong value, FormatFlags format) {PRINT_VAR_BODY}
inline int PIConsole::printValue(const float value, FormatFlags format) {PRINT_VAR_BODY}
inline int PIConsole::printValue(const double value, FormatFlags format) {PRINT_VAR_BODY}
inline int PIConsole::printValue(const char value, FormatFlags format) {PRINT_VAR_BODY}
inline int PIConsole::printValue(const short value, FormatFlags format) {PRINT_VAR_BODY}
inline int PIConsole::printValue(const uchar value, FormatFlags format) {PRINT_VAR_BODY}
inline int PIConsole::printValue(const ushort value, FormatFlags format) {PRINT_VAR_BODY}
inline int PIConsole::printValue(const uint value, FormatFlags format) {PRINT_VAR_BODY}
inline int PIConsole::printValue(const ulong value, FormatFlags format) {PRINT_VAR_BODY}
inline int PIConsole::printValue(const ullong value, FormatFlags format) {PRINT_VAR_BODY}
inline int PIConsole::printValue(const PISystemTime & value, FormatFlags format) {PRINT_VAR_BODY}
void PIConsole::startServer(const PIString & name) {
stopPeer();
server_mode = true;
peer = new PIPeer("_rcs_:" + name);
CONNECT2(void, const PIString & , const PIByteArray &, peer, dataReceivedEvent, this, peerReceived);
CONNECT1(void, const PIString & , peer, peerDisconnectedEvent, this, peerDisconnectedEvent);
peer_timer->start(50.);
serverSendInfo();
}
void PIConsole::stopPeer() {
remote_clients.clear();
peer_timer->stop();
if (peer != 0) delete peer;
peer = 0;
state = Disconnected;
}
PIStringList PIConsole::clients() const {
PIStringList sl;
if (peer == 0) return sl;
piForeachC (PIPeer::PeerInfo & i, peer->allPeers()) {
if (i.name.left(6) != "_rcc_:") continue;
sl << i.name.right(i.name.length() - 6);
}
return sl;
}
void PIConsole::listenServers() {
stopPeer();
server_mode = false;
server_name.clear();
randomize();
peer = new PIPeer("_rcc_:" + PIDateTime::current().toString("hhmmssddMMyy_") + PIString::fromNumber(randomi()));
CONNECT2(void, const PIString & , const PIByteArray &, peer, dataReceivedEvent, this, peerReceived);
peer_timer->start(100.);
}
PIStringList PIConsole::availableServers() const {
PIStringList sl;
if (peer == 0) return sl;
piForeachC (PIPeer::PeerInfo & i, peer->allPeers()) {
if (i.name.left(6) != "_rcs_:") continue;
sl << i.name.right(i.name.length() - 6);
}
return sl;
}
void PIConsole::connectToServer(const PIString & name) {
if (peer == 0) listenServers();
server_name = name;
}
void PIConsole::disconnect() {
stopPeer();
}
void PIConsole::serverSendInfo() {
if (peer == 0) return;
PIByteArray ba;
ba << int(0xAA);
peer->sendToAll(ba);
}
void PIConsole::serverSendData() {
if (peer == 0) return;
PIByteArray ba;
PIVector<VariableContent> content;
piForeach (Tab & t, tabs)
piForeach (Column & c, t.columns)
piForeach (Variable & v, c.variables)
if (!v.isEmpty() && v.id > 0) {
VariableContent vc;
vc.id = v.id;
v.writeData(vc.rdata);
content << vc;
}
piForeach (RemoteClient & rc, remote_clients) {
ba.clear();
switch (rc.state) {
case FetchingData:
ba << int(0xCC) << tabs;
//piCout << "server send const data" << rc.name << ba.size_s();
break;
case Committing:
ba << int(0xDD);
break;
case Connected:
ba << int(0xEE) << content;
//piCout << "send data" << ba.size();
break;
default: break;
}
if (!ba.isEmpty())
peer->send(rc.name, ba);
}
}
PIConsole::RemoteClient & PIConsole::remoteClient(const PIString & fname) {
piForeach (RemoteClient & i, remote_clients)
if (i.name == fname)
return i;
remote_clients << RemoteClient(fname);
return remote_clients.back();
}
void PIConsole::peerReceived(const PIString & from, const PIByteArray & data) {
int type;
PIByteArray ba(data);
ba >> type;
//piCout << "rec packet from" << from << "type" << PICoutManipulators::Hex << type;
if (server_mode) {
if (from.left(5) != "_rcc_") return;
//PIString rcn = from.right(from.length() - 6);
RemoteClient & rc(remoteClient(from));
switch (type) {
case 0xBB: // fetch const data request
//piCout << "fetch data request from" << from << rc.state;
if (rc.state != Connected)
rc.state = FetchingData;
break;
case 0xCC: // const data commit
//piCout << "commit from" << from;
if (rc.state != Connected)
rc.state = Connected;
break;
default: break;
}
} else {
PIVector<VariableContent> content;
PIMap<int, Variable * > vids;
if (from.left(5) != "_rcs_") return;
//PIString rcn = from.right(from.length() - 6);
switch (type) {
case 0xAA: // new server
//piCout << "new server" << rcn;
break;
case 0xCC: // const data
//piCout << "received const data";
state = Committing;
ba >> tabs;
cur_tab = tabs.isEmpty() ? -1 : 0;
piForeach (Tab & t, tabs)
piForeach (Column & c, t.columns)
piForeach (Variable & v, c.variables)
v.remote = true;
break;
case 0xDD: // const data commit
//piCout << "received commit";
state = Connected;
break;
case 0xEE: // dynamic data
//piCout << "received data" << ba.size_s();
piForeach (Tab & t, tabs)
piForeach (Column & c, t.columns)
piForeach (Variable & v, c.variables)
if (!v.isEmpty() && v.id > 0)
vids[v.id] = &v;
ba >> content;
piForeach (VariableContent & vc, content) {
if (vc.id <= 0) continue;
Variable * v = vids.at(vc.id);
if (v == 0) continue;
//piCout << "read" << v->name << vc.rdata.size_s();
v->rdata = vc.rdata;
}
break;
default: break;
}
}
}
void PIConsole::peerTimer(void * data, int delim) {
if (peer == 0) return;
//piCout << "timer" << delim;
if (server_mode) {
if (delim == 20)
serverSendInfo();
else
serverSendData();
} else {
if (delim != 1 || server_name.isEmpty()) return;
const PIPeer::PeerInfo * p = peer->getPeerByName("_rcs_:" + server_name);
if (p == 0) return;
PIByteArray ba;
switch (state) {
case Disconnected:
peer_tm.reset();
ba << int(0xBB);
//piCout << "send to" << server_name << "fetch request disc";
peer->send(p, ba);
state = FetchingData;
break;
case FetchingData:
if (peer_tm.elapsed_s() < 3.)
return;
peer_tm.reset();
ba << int(0xBB);
//piCout << "send to" << server_name << "fetch request fd";
peer->send(p, ba);
break;
case Committing:
peer_tm.reset();
ba << int(0xCC);
//piCout << "send to" << server_name << "committing";
state = Connected;
peer->send(p, ba);
break;
default: break;
};
}
}
void PIConsole::peerDisconnectedEvent(const PIString & name) {
for (int i = 0; i < remote_clients.size_s(); ++i)
if (remote_clients[i].name == name) {
remote_clients.remove(i);
--i;
}
}

View File

@@ -1,51 +0,0 @@
/*
PIP - Platform Independent Primitives
Stephan Fomenko
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PICONDITIONLOCK_H
#define PICONDITIONLOCK_H
#include "pibase.h"
/**
* @brief Continued
*/
class PIP_EXPORT PIConditionLock {
public:
NO_COPY_CLASS(PIConditionLock)
explicit PIConditionLock();
~PIConditionLock();
//! \brief lock
void lock();
//! \brief unlock
void unlock();
//! \brief tryLock
bool tryLock();
void * handle();
private:
PRIVATE_DECLARATION
};
#endif // PICONDITIONLOCK_H

View File

@@ -1,461 +0,0 @@
/*! \file piconsole.h
* \brief Console output class
*/
/*
PIP - Platform Independent Primitives
Console output/input
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 <http://www.gnu.org/licenses/>.
*/
#ifndef PICONSOLE_H
#define PICONSOLE_H
#include "pikbdlistener.h"
class PIProtocol;
class PIDiagnostics;
class PISystemMonitor;
class PIPeer;
class PITimer;
class PIP_EXPORT PIConsole: public PIThread
{
PIOBJECT_SUBCLASS(PIConsole, PIThread)
public:
//! Constructs %PIConsole with key handler "slot" and if "startNow" start it
explicit PIConsole(bool startNow = true, PIKbdListener::KBFunc slot = 0);
~PIConsole();
//! Variables output format
enum Format {
Normal /** Default console format */ = 0x01,
Bold /** Bold text */ = 0x02,
Faint = 0x04,
Italic = 0x08,
Underline /** Underlined text */ = 0x10,
Blink /** Blinked text */ = 0x20,
Inverse /** Swap text and background colors */ = 0x40,
Black /** Black text */ = 0x100,
Red /** Red text */ = 0x200,
Green /** Green text */ = 0x400,
Yellow /** Yellow text */ = 0x800,
Blue /** Blue text */ = 0x1000,
Magenta /** Magenta text */ = 0x2000,
Cyan /** Cyan text */ = 0x4000,
White /** White text */ = 0x8000,
BackBlack /** Black background */ = 0x10000,
BackRed /** Red background */ = 0x20000,
BackGreen /** Green background */ = 0x40000,
BackYellow /** Yellow background */ = 0x80000,
BackBlue /** Blue background */ = 0x100000,
BackMagenta /** Magenta background */ = 0x200000,
BackCyan /** Cyan background */ = 0x400000,
BackWhite /** White background */ = 0x800000,
Dec /** Decimal base for integers */ = 0x1000000,
Hex /** Hexadecimal base for integers */ = 0x2000000,
Oct /** Octal base for integers */ = 0x4000000,
Bin /** Binary base for integers */ = 0x8000000,
Scientific /** Scientific representation of floats */ = 0x10000000,
SystemTimeSplit /** PISystemTime split representation (* s, * ns) */ = 0x20000000,
SystemTimeSeconds /** PISystemTime seconds representation (*.* s) */ = 0x40000000
};
//! Column labels alignment
enum Alignment {
Nothing /** No alignment */ ,
Left /** Labels align left and variables align left */ ,
Right /** Labels align right and variables align left */
};
typedef PIFlags<PIConsole::Format> FormatFlags;
//! Add to current tab to column "column" string "name" with format "format"
void addString(const PIString & name, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
void addVariable(const PIString & name, const PIString * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
void addVariable(const PIString & name, const char * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
void addVariable(const PIString & name, const bool * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
void addVariable(const PIString & name, const short * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
void addVariable(const PIString & name, const int * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
void addVariable(const PIString & name, const long * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
void addVariable(const PIString & name, const llong * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
void addVariable(const PIString & name, const uchar * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
void addVariable(const PIString & name, const ushort * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
void addVariable(const PIString & name, const uint * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
void addVariable(const PIString & name, const ulong * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
void addVariable(const PIString & name, const ullong * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
void addVariable(const PIString & name, const float * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
void addVariable(const PIString & name, const double * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
void addVariable(const PIString & name, const PISystemTime * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
void addVariable(const PIString & name, const PIDiagnostics * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
void addVariable(const PIString & name, const PISystemMonitor * ptr, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" bits field with label "name", pointer "ptr" and format "format"
void addBitVariable(const PIString & name, const void * ptr, int fromBit, int bitsCount, int column = 1, FormatFlags format = PIConsole::Normal);
//! Add to current tab to column "column" "count" empty lines
void addEmptyLine(int column = 1, uint count = 1);
PIString getString(int x, int y);
short getShort(int x, int y) {return getString(x, y).toShort();}
int getInt(int x, int y) {return getString(x, y).toInt();}
float getFloat(int x, int y) {return getString(x, y).toFloat();}
double getDouble(int x, int y) {return getString(x, y).toDouble();}
PIString getString(const PIString & name);
short getShort(const PIString & name) {return getString(name).toShort();}
int getInt(const PIString & name) {return getString(name).toInt();}
float getFloat(const PIString & name) {return getString(name).toFloat();}
double getDouble(const PIString & name) {return getString(name).toDouble();}
//! Returns tabs count
uint tabsCount() const {return tabs.size();}
//! Returns current tab name
PIString currentTab() const {return tabs[cur_tab].name;}
//! Returns current tab index
int currentTabIndex() const {return cur_tab;}
//! Add new tab with name "name", bind key "bind_key" and returns this tab index
int addTab(const PIString & name, char bind_key = 0);
//! Remove tab with index "index"
void removeTab(uint index);
//! Remove tab with name "name"
void removeTab(const PIString & name);
//! Clear content of tab with index "index"
void clearTab(uint index);
//! Clear content of tab with name "name"
void clearTab(const PIString & name);
//! Set current tab to tab with index "index", returns if tab exists
bool setTab(uint index);
//! Set current tab to tab with name "name", returns if tab exists
bool setTab(const PIString & name);
//! Set tab with index "index" bind key to "bind_key", returns if tab exists
bool setTabBindKey(uint index, char bind_key);
//! Set tab with name "name" bind key to "bind_key", returns if tab exists
bool setTabBindKey(const PIString & name, char bind_key);
//! Remove all tabs and if "clearScreen" clear the screen
void clearTabs(bool clearScreen = true) {if (clearScreen && isRunning()) {toUpperLeft(); clearScreenLower();} tabs.clear();}
//! Set custom status text of current tab to "str"
void addCustomStatus(const PIString & str) {tabs[cur_tab].status = str;}
//! Clear custom status text of current tab
void clearCustomStatus() {tabs[cur_tab].status.clear();}
//! Returns default alignment
Alignment defaultAlignment() const {return def_align;}
//! Set default alignment to "align"
void setDefaultAlignment(Alignment align) {def_align = align;}
//! Set column "col" alignment to "align"
void setColumnAlignment(int col, Alignment align) {if (col < 0 || col >= columns().size_s()) return; column(col).alignment = align;}
//! Set all columns of all tabs alignment to "align"
void setColumnAlignmentToAll(Alignment align) {piForeach (Tab & i, tabs) piForeach (Column & j, i.columns) j.alignment = align; fillLabels();}
//! Directly call function from \a PIKbdListener
void enableExitCapture(char key = 'Q') {listener->enableExitCapture(key);}
//! Directly call function from \a PIKbdListener
void disableExitCapture() {listener->disableExitCapture();}
//! Directly call function from \a PIKbdListener
bool exitCaptured() const {return listener->exitCaptured();}
//! Directly call function from \a PIKbdListener
char exitKey() const {return listener->exitKey();}
int windowWidth() const {return width;}
int windowHeight() const {return height;}
PIString fstr(FormatFlags f);
void update();
void pause(bool yes) {pause_ = yes;}
// Server functions
void startServer(const PIString & name);
void stopPeer();
bool isServerStarted() const {return peer != 0;}
PIStringList clients() const;
// Client functions
void listenServers();
PIStringList availableServers() const;
PIString selectedServer() const {return server_name;}
void connectToServer(const PIString & name);
void disconnect();
bool isConnected() const {return state == Connected;}
void toUpperLeft();
void moveRight(int n = 1);
void moveLeft(int n = 1);
void moveTo(int x = 0, int y = 0);
void clearScreen();
void clearScreenLower();
void clearLine();
void newLine();
void hideCursor();
void showCursor();
EVENT_HANDLER0(void, clearVariables) {clearVariables(true);}
EVENT_HANDLER1(void, clearVariables, bool, clearScreen);
EVENT_HANDLER0(void, waitForFinish) {WAIT_FOR_EXIT}
EVENT_HANDLER0(void, start) {start(false);}
EVENT_HANDLER1(void, start, bool, wait) {PIThread::start(40); if (wait) waitForFinish();}
EVENT_HANDLER0(void, stop) {stop(false);}
EVENT_HANDLER1(void, stop, bool, clear);
EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void * , data)
//! \handlers
//! \{
//! \fn void waitForFinish()
//! \brief block until finished (exit key will be pressed)
//! \fn void clearVariables(bool clearScreen = true)
//! \brief Remove all columns at current tab and if "clearScreen" clear the screen
//! \fn void start(bool wait = false)
//! \brief Start console output and if "wait" block until finished (exit key will be pressed)
//! \fn void stop(bool clear = false)
//! \brief Stop console output and if "clear" clear the screen
//! \}
//! \events
//! \{
//! \fn void keyPressed(PIKbdListener::KeyEvent key, void * data)
//! \brief Raise on key "key" pressed, "data" is pointer to %PIConsole object
//! \}
private:
void begin();
void run();
void fillLabels();
void status();
void checkColumn(uint col) {while (columns().size() < col) columns().push_back(Column(def_align));}
int bitsValue(const void * src, int offset, int count) const;
const char * toBin(const void * d, int s);
inline void printLine(const PIString & str, int dx = 0, FormatFlags format = PIConsole::Normal);
inline int printValue(const PIString & str, FormatFlags format = PIConsole::Normal);
inline int printValue(const char * str, FormatFlags format = PIConsole::Normal);
inline int printValue(const bool value, FormatFlags format = PIConsole::Normal);
inline int printValue(const int value, FormatFlags format = PIConsole::Normal);
inline int printValue(const long value, FormatFlags format = PIConsole::Normal);
inline int printValue(const llong value, FormatFlags format = PIConsole::Normal);
inline int printValue(const float value, FormatFlags format = PIConsole::Normal);
inline int printValue(const double value, FormatFlags format = PIConsole::Normal);
inline int printValue(const char value, FormatFlags format = PIConsole::Normal);
inline int printValue(const short value, FormatFlags format = PIConsole::Normal);
inline int printValue(const uchar value, FormatFlags format = PIConsole::Normal);
inline int printValue(const ushort value, FormatFlags format = PIConsole::Normal);
inline int printValue(const uint value, FormatFlags format = PIConsole::Normal);
inline int printValue(const ulong value, FormatFlags format = PIConsole::Normal);
inline int printValue(const ullong value, FormatFlags format = PIConsole::Normal);
inline int printValue(const PISystemTime & value, FormatFlags format = PIConsole::Normal);
static void key_event(PIKbdListener::KeyEvent key, void * t);
struct Variable {
Variable() {nx = ny = type = offset = bitFrom = bitCount = size = 0; format = Normal; remote = false; ptr = 0; id = 1;}
Variable(const Variable & src) {remote = src.remote; name = src.name; format = src.format; type = src.type; offset = src.offset; size = src.size;
bitFrom = src.bitFrom; bitCount = src.bitCount; ptr = src.ptr; nx = src.nx; ny = src.ny; rdata = src.rdata; id = src.id;}
bool isEmpty() const {return (remote ? false : ptr == 0);}
const void * data() {return (remote ? rdata.data() : ptr);}
void writeData(PIByteArray & ba) {
if (remote) ba << rdata;
else {
if (type == 0) ba << (*(PIString * )ptr);
else ba << PIByteArray::RawData(ptr, size);
}
}
PIString name;
FormatFlags format;
int nx;
int ny;
int type;
int offset;
int bitFrom;
int bitCount;
int size;
int id;
bool remote;
const void * ptr;
PIByteArray rdata;
void operator =(const Variable & src) {remote = src.remote; name = src.name; format = src.format; type = src.type; offset = src.offset; size = src.size;
bitFrom = src.bitFrom; bitCount = src.bitCount; ptr = src.ptr; nx = src.nx; ny = src.ny; rdata = src.rdata; id = src.id;}
};
struct VariableContent {
int id;
PIByteArray rdata;
};
struct Column {
Column(Alignment align = PIConsole::Right) {variables.reserve(32); alignment = align;}
PIVector<Variable> variables;
Alignment alignment;
uint size() const {return variables.size();}
Variable & operator [](int index) {return variables[index];}
const Variable & operator [](int index) const {return variables[index];}
void push_back(const Variable & v) {variables.push_back(v);}
void operator =(const Column & src) {variables = src.variables; alignment = src.alignment;}
};
struct Tab {
Tab(PIString n = "", char k = 0) {columns.reserve(8); name = n; key = k;}
PIVector<Column> columns;
PIString name;
PIString status;
char key;
};
enum ConnectedState {Disconnected, FetchingData, Committing, Connected};
friend PIByteArray & operator <<(PIByteArray & ba, const PIConsole::VariableContent & v);
friend PIByteArray & operator >>(PIByteArray & ba, PIConsole::VariableContent & v);
friend PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Variable & v);
friend PIByteArray & operator >>(PIByteArray & ba, PIConsole::Variable & v);
friend PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Column & v);
friend PIByteArray & operator >>(PIByteArray & ba, PIConsole::Column & v);
friend PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Tab & v);
friend PIByteArray & operator >>(PIByteArray & ba, PIConsole::Tab & v);
PIVector<Column> & columns() {return tabs[cur_tab].columns;}
Column & column(int index) {return tabs[cur_tab].columns[index - 1];}
int couts(const PIString & v);
int couts(const char * v);
int couts(const bool v);
int couts(const char v);
int couts(const short v);
int couts(const int v);
int couts(const long v);
int couts(const llong v);
int couts(const uchar v);
int couts(const ushort v);
int couts(const uint v);
int couts(const ulong v);
int couts(const ullong v);
int couts(const float v);
int couts(const double v);
int couts(const PISystemTime & v);
struct RemoteClient;
void serverSendInfo();
void serverSendData();
RemoteClient & remoteClient(const PIString & fname);
EVENT_HANDLER2(void, peerReceived, const PIString &, from, const PIByteArray &, data);
EVENT_HANDLER2(void, peerTimer, void * , data, int, delim);
EVENT_HANDLER1(void, peerDisconnectedEvent, const PIString &, name);
PRIVATE_DECLARATION
PIVector<Tab> tabs;
PIString binstr, rstr;
PIByteArray rba;
Variable tv;
PIKbdListener * listener;
Alignment def_align;
PIKbdListener::KBFunc ret_func;
int width, height, pwidth, pheight, col_wid, num_format, systime_format;
uint max_y;
int vid;
uint cur_tab, col_cnt;
PIPeer * peer;
PITimer * peer_timer;
PITimeMeasurer peer_tm;
PIString server_name;
bool server_mode, pause_;
ConnectedState state;
struct RemoteClient {
RemoteClient(const PIString & n = "") {name = n; state = Disconnected;}
PIString name;
ConnectedState state;
};
PIVector<RemoteClient> remote_clients;
};
inline PIByteArray & operator <<(PIByteArray & ba, const PIConsole::VariableContent & v) {ba << v.id << v.rdata; return ba;}
inline PIByteArray & operator >>(PIByteArray & ba, PIConsole::VariableContent & v) {ba >> v.id; ba >> v.rdata; return ba;}
inline PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Variable & v) {ba << v.name << v.id << (int)v.format << v.type << v.size << v.bitFrom << v.bitCount; return ba;}
inline PIByteArray & operator >>(PIByteArray & ba, PIConsole::Variable & v) {ba >> v.name >> v.id >> (int & )v.format >> v.type >> v.size >> v.bitFrom >> v.bitCount; return ba;}
inline PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Column & v) {ba << (int)v.alignment << v.variables; return ba;}
inline PIByteArray & operator >>(PIByteArray & ba, PIConsole::Column & v) {int a; ba >> a >> v.variables; v.alignment = (PIConsole::Alignment)a; return ba;}
inline PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Tab & v) {ba << v.name << v.status << (uchar)v.key << v.columns; return ba;}
inline PIByteArray & operator >>(PIByteArray & ba, PIConsole::Tab & v) {ba >> v.name >> v.status >> (uchar&)v.key >> v.columns; return ba;}
#endif // PICONSOLE_H

View File

@@ -21,7 +21,6 @@
#define PICONSOLEMODULE_H #define PICONSOLEMODULE_H
#include "pikbdlistener.h" #include "pikbdlistener.h"
#include "piconsole.h"
#include "piscreen.h" #include "piscreen.h"
#include "piscreentiles.h" #include "piscreentiles.h"

View File

@@ -49,6 +49,9 @@ public:
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
resize(pid_size, f); resize(pid_size, f);
} }
inline PIDeque(PIDeque<T> && other): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
swap(other);
}
inline virtual ~PIDeque() { inline virtual ~PIDeque() {
//piCout << "~PIDeque"; //piCout << "~PIDeque";
PIINTROSPECTION_CONTAINER_DELETE(T) PIINTROSPECTION_CONTAINER_DELETE(T)
@@ -66,6 +69,12 @@ public:
return *this; return *this;
} }
inline PIDeque<T> & operator =(PIDeque<T> && other) {
if (this == &other) return *this;
swap(other);
return *this;
}
typedef T value_type; typedef T value_type;
class iterator { class iterator {
@@ -256,6 +265,23 @@ public:
elementNew(pid_data + pid_start + index, v); elementNew(pid_data + pid_start + index, v);
return *this; return *this;
} }
inline PIDeque<T> & insert(size_t index, T && v) {
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
if (dir) {
alloc(pid_size + 1, true);
if (index < pid_size - 1) {
size_t os = pid_size - index - 1;
memmove((void*)(&(pid_data[index + pid_start + 1])), (const void*)(&(pid_data[index + pid_start])), os * sizeof(T));
}
} else {
alloc(pid_size + 1, false, -1);
if (index > 0)
memmove((void*)(&(pid_data[pid_start])), (const void*)(&(pid_data[pid_start + 1])), index * sizeof(T));
}
PIINTROSPECTION_CONTAINER_USED(T, 1)
elementNew(pid_data + pid_start + index, v);
return *this;
}
inline PIDeque<T> & insert(size_t index, const PIDeque<T> & other) { inline PIDeque<T> & insert(size_t index, const PIDeque<T> & other) {
if (other.isEmpty()) return *this; if (other.isEmpty()) return *this;
assert(&other != this); assert(&other != this);
@@ -336,7 +362,14 @@ public:
elementNew(pid_data + pid_start + pid_size - 1, v); elementNew(pid_data + pid_start + pid_size - 1, v);
return *this; return *this;
} }
inline PIDeque<T> & push_back(T && v) {
alloc(pid_size + 1, true);
PIINTROSPECTION_CONTAINER_USED(T, 1);
elementNew(pid_data + pid_start + pid_size - 1, v);
return *this;
}
inline PIDeque<T> & append(const T & v) {return push_back(v);} inline PIDeque<T> & append(const T & v) {return push_back(v);}
inline PIDeque<T> & append(T && v) {return push_back(v);}
inline PIDeque<T> & append(const PIDeque<T> & t) { inline PIDeque<T> & append(const PIDeque<T> & t) {
assert(&t != this); assert(&t != this);
size_t ps = pid_size; size_t ps = pid_size;
@@ -345,6 +378,7 @@ public:
return *this; return *this;
} }
inline PIDeque<T> & operator <<(const T & v) {return push_back(v);} inline PIDeque<T> & operator <<(const T & v) {return push_back(v);}
inline PIDeque<T> & operator <<(T && v) {return push_back(v);}
inline PIDeque<T> & operator <<(const PIDeque<T> & t) {return append(t);} inline PIDeque<T> & operator <<(const PIDeque<T> & t) {return append(t);}
inline PIDeque<T> & push_front(const T & v) {insert(0, v); return *this;} inline PIDeque<T> & push_front(const T & v) {insert(0, v); return *this;}
@@ -412,6 +446,7 @@ private:
} }
} }
inline void elementNew(T * to, const T & from) {new(to)T(from);} inline void elementNew(T * to, const T & from) {new(to)T(from);}
inline void elementNew(T * to, T && from) {piSwap(*to, from);}
inline void elementDelete(T & from) {from.~T();} inline void elementDelete(T & from) {from.~T();}
inline void dealloc() { inline void dealloc() {
if ((uchar*)pid_data != 0) free((uchar*)pid_data); if ((uchar*)pid_data != 0) free((uchar*)pid_data);
@@ -485,6 +520,7 @@ private:
template<> inline void PIDeque<T>::newT(T * dst, const T * src, size_t s) {PIINTROSPECTION_CONTAINER_USED(T, s); memcpy((void*)(dst), (const void*)(src), s * sizeof(T));} \ template<> inline void PIDeque<T>::newT(T * dst, const T * src, size_t s) {PIINTROSPECTION_CONTAINER_USED(T, s); memcpy((void*)(dst), (const void*)(src), s * sizeof(T));} \
template<> inline void PIDeque<T>::deleteT(T *, size_t sz) {PIINTROSPECTION_CONTAINER_UNUSED(T, sz);} \ template<> inline void PIDeque<T>::deleteT(T *, size_t sz) {PIINTROSPECTION_CONTAINER_UNUSED(T, sz);} \
template<> inline void PIDeque<T>::elementNew(T * to, const T & from) {(*to) = from;} \ template<> inline void PIDeque<T>::elementNew(T * to, const T & from) {(*to) = from;} \
template<> inline void PIDeque<T>::elementNew(T * to, T && from) {(*to) = from;} \
template<> inline void PIDeque<T>::elementDelete(T &) {;} \ template<> inline void PIDeque<T>::elementDelete(T &) {;} \
template<> inline PIDeque<T> & PIDeque<T>::_resizeRaw(size_t new_size) { \ template<> inline PIDeque<T> & PIDeque<T>::_resizeRaw(size_t new_size) { \
if (new_size > pid_size) { \ if (new_size > pid_size) { \

View File

@@ -74,6 +74,7 @@ class PIMap {
public: public:
PIMap() {;} PIMap() {;}
PIMap(const PIMap<Key, T> & other) {*this = other;} PIMap(const PIMap<Key, T> & other) {*this = other;}
PIMap(PIMap<Key, T> && other) {swap(other);}
virtual ~PIMap() {;} virtual ~PIMap() {;}
PIMap<Key, T> & operator =(const PIMap<Key, T> & other) { PIMap<Key, T> & operator =(const PIMap<Key, T> & other) {
@@ -84,6 +85,12 @@ public:
return *this; return *this;
} }
PIMap<Key, T> & operator =(PIMap<Key, T> && other) {
if (this == &other) return *this;
swap(other);
return *this;
}
typedef T mapped_type; typedef T mapped_type;
typedef Key key_type; typedef Key key_type;
typedef PIPair<Key, T> value_type; typedef PIPair<Key, T> value_type;

View File

@@ -48,6 +48,9 @@ public:
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
resize(piv_size, f); resize(piv_size, f);
} }
inline PIVector(PIVector<T> && other): piv_data(0), piv_size(0), piv_rsize(0) {
swap(other);
}
inline virtual ~PIVector() { inline virtual ~PIVector() {
PIINTROSPECTION_CONTAINER_DELETE(T) PIINTROSPECTION_CONTAINER_DELETE(T)
PIINTROSPECTION_CONTAINER_FREE(T, (piv_rsize)) PIINTROSPECTION_CONTAINER_FREE(T, (piv_rsize))
@@ -65,6 +68,12 @@ public:
return *this; return *this;
} }
inline PIVector<T> & operator =(PIVector<T> && other) {
if (this == &other) return *this;
swap(other);
return *this;
}
typedef T value_type; typedef T value_type;
class iterator { class iterator {
@@ -253,6 +262,16 @@ public:
elementNew(piv_data + index, v); elementNew(piv_data + index, v);
return *this; return *this;
} }
inline PIVector<T> & insert(size_t index, T && v) {
alloc(piv_size + 1);
if (index < piv_size - 1) {
size_t os = piv_size - index - 1;
memmove((void*)(&(piv_data[index + 1])), (const void*)(&(piv_data[index])), os * sizeof(T));
}
PIINTROSPECTION_CONTAINER_USED(T, 1)
elementNew(piv_data + index, v);
return *this;
}
inline PIVector<T> & insert(size_t index, const PIVector<T> & other) { inline PIVector<T> & insert(size_t index, const PIVector<T> & other) {
if (other.isEmpty()) return *this; if (other.isEmpty()) return *this;
assert(&other != this); assert(&other != this);
@@ -320,7 +339,14 @@ public:
elementNew(piv_data + piv_size - 1, v); elementNew(piv_data + piv_size - 1, v);
return *this; return *this;
} }
inline PIVector<T> & push_back(T && v) {
alloc(piv_size + 1);
PIINTROSPECTION_CONTAINER_USED(T, 1);
elementNew(piv_data + piv_size - 1, v);
return *this;
}
inline PIVector<T> & append(const T & v) {return push_back(v);} inline PIVector<T> & append(const T & v) {return push_back(v);}
inline PIVector<T> & append(T && v) {return push_back(v);}
inline PIVector<T> & append(const PIVector<T> & other) { inline PIVector<T> & append(const PIVector<T> & other) {
assert(&other != this); assert(&other != this);
size_t ps = piv_size; size_t ps = piv_size;
@@ -329,6 +355,7 @@ public:
return *this; return *this;
} }
inline PIVector<T> & operator <<(const T & v) {return push_back(v);} inline PIVector<T> & operator <<(const T & v) {return push_back(v);}
inline PIVector<T> & operator <<(T && v) {return push_back(v);}
inline PIVector<T> & operator <<(const PIVector<T> & other) {return append(other);} inline PIVector<T> & operator <<(const PIVector<T> & other) {return append(other);}
inline PIVector<T> & push_front(const T & v) {insert(0, v); return *this;} inline PIVector<T> & push_front(const T & v) {insert(0, v); return *this;}
@@ -405,6 +432,7 @@ private:
} }
} }
inline void elementNew(T * to, const T & from) {new(to)T(from);} inline void elementNew(T * to, const T & from) {new(to)T(from);}
inline void elementNew(T * to, T && from) {piSwap(*to, from);}
inline void elementDelete(T & from) {from.~T();} inline void elementDelete(T & from) {from.~T();}
inline void dealloc() { inline void dealloc() {
if ((uchar*)piv_data != 0) free((uchar*)piv_data); if ((uchar*)piv_data != 0) free((uchar*)piv_data);
@@ -434,6 +462,7 @@ private:
template<> inline void PIVector<T>::newT(T * dst, const T * src, size_t s) {PIINTROSPECTION_CONTAINER_USED(T, s); memcpy((void*)(dst), (const void*)(src), s * sizeof(T));} \ template<> inline void PIVector<T>::newT(T * dst, const T * src, size_t s) {PIINTROSPECTION_CONTAINER_USED(T, s); memcpy((void*)(dst), (const void*)(src), s * sizeof(T));} \
template<> inline void PIVector<T>::deleteT(T *, size_t sz) {PIINTROSPECTION_CONTAINER_UNUSED(T, sz);} \ template<> inline void PIVector<T>::deleteT(T *, size_t sz) {PIINTROSPECTION_CONTAINER_UNUSED(T, sz);} \
template<> inline void PIVector<T>::elementNew(T * to, const T & from) {(*to) = from;} \ template<> inline void PIVector<T>::elementNew(T * to, const T & from) {(*to) = from;} \
template<> inline void PIVector<T>::elementNew(T * to, T && from) {(*to) = from;} \
template<> inline void PIVector<T>::elementDelete(T &) {;} \ template<> inline void PIVector<T>::elementDelete(T &) {;} \
template<> inline PIVector<T> & PIVector<T>::_resizeRaw(size_t new_size) { \ template<> inline PIVector<T> & PIVector<T>::_resizeRaw(size_t new_size) { \
if (new_size > piv_size) { \ if (new_size > piv_size) { \

View File

@@ -18,9 +18,9 @@
*/ */
#include "piincludes_p.h" #include "piincludes_p.h"
#include "picout.h" #include "picout.h"
#include "piconsole.h"
#include "pibytearray.h" #include "pibytearray.h"
#include "pistack.h" #include "pistack.h"
#include "piobject.h"
#include "pistring_std.h" #include "pistring_std.h"
#ifdef WINDOWS #ifdef WINDOWS
# include <windows.h> # include <windows.h>

View File

@@ -19,7 +19,6 @@
#include "piincludes.h" #include "piincludes.h"
#include "piincludes_p.h" #include "piincludes_p.h"
#include "piconsole.h"
#include "pitime.h" #include "pitime.h"
#ifndef QNX #ifndef QNX
# include <clocale> # include <clocale>

View File

@@ -27,10 +27,9 @@
# include <iostream> # include <iostream>
#endif #endif
#include <atomic> #include <atomic>
#include <mutex>
typedef std::mutex PIMutex; class PIMutex;
//typedef std::lock_guard<std::mutex> PIMutexLocker; class PIMutexLocker;
class PIObject; class PIObject;
class PIString; class PIString;
class PIByteArray; class PIByteArray;

View File

@@ -51,6 +51,8 @@ public:
PIString(const PIString & o): PIDeque<PIChar>() {*this += o;} PIString(const PIString & o): PIDeque<PIChar>() {*this += o;}
PIString(PIString && o): PIDeque<PIChar>() {swap(o);}
//! Contructs string with single symbol "c" //! Contructs string with single symbol "c"
PIString(const PIChar & c): PIDeque<PIChar>() {*this += c;} PIString(const PIChar & c): PIDeque<PIChar>() {*this += c;}
@@ -89,6 +91,8 @@ public:
PIString & operator =(const PIString & o) {if (this == &o) return *this; clear(); *this += o; return *this;} PIString & operator =(const PIString & o) {if (this == &o) return *this; clear(); *this += o; return *this;}
PIString & operator =(PIString && o) {if (this == &o) return *this; swap(o); return *this;}
/*! \brief Return c-string representation of string /*! \brief Return c-string representation of string
* \details Converts content of string to c-string and return * \details Converts content of string to c-string and return
* pointer to first char. This buffer is valid until new convertion * pointer to first char. This buffer is valid until new convertion

View File

@@ -83,6 +83,7 @@ public:
PIStringList & operator =(const PIStringList & o) {PIDeque<PIString>::operator=(o); return *this;} PIStringList & operator =(const PIStringList & o) {PIDeque<PIString>::operator=(o); return *this;}
PIStringList & operator <<(const PIString & str) {append(str); return *this;} PIStringList & operator <<(const PIString & str) {append(str); return *this;}
PIStringList & operator <<(PIString && str) {append(str); return *this;}
PIStringList & operator <<(const PIStringList & sl) {append(sl); return *this;} PIStringList & operator <<(const PIStringList & sl) {append(sl); return *this;}
}; };

View File

@@ -1,45 +0,0 @@
/*
PIP - Platform Independent Primitives
Text codings coder, based on "iconv"
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 <http://www.gnu.org/licenses/>.
*/
#ifndef PIP_FREERTOS
#include "picodec.h"
PIStringList PICodec::availableCodecs() {
exec("/usr/bin/iconv", "-l");
waitForFinish();
PIString str(readOutput());
str.cutLeft(str.find("\n "));
str.replaceAll("\n", "");
return str.split("//");
}
PIByteArray PICodec::exec_iconv(const PIString & from, const PIString & to, const PIByteArray & str) {
tf.openTemporary(PIIODevice::ReadWrite);
tf.clear();
tf << str;
tf.close();
exec("/usr/bin/iconv", PIStringList() << ("-f=" + from) << ("-t=" + to) << tf.path());
waitForFinish();
return readOutput();
}
#endif // PIP_FREERTOS

View File

@@ -1,54 +0,0 @@
/*
PIP - Platform Independent Primitives
Text codings coder, based on "iconv"
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 <http://www.gnu.org/licenses/>.
*/
#ifndef PICODEC_H
#define PICODEC_H
#ifndef PIP_FREERTOS
#include "piprocess.h"
class PIP_EXPORT PICodec: protected PIProcess
{
PIOBJECT(PICodec)
public:
PICodec(): PIProcess() {setGrabOutput(true);}
PICodec(const PIString & from, const PIString & to): PIProcess() {setCodings(from, to);}
~PICodec() {tf.remove();}
void setFromCoding(const PIString & from) {c_from = from;}
void setToCoding(const PIString & to) {c_to = to;}
void setCodings(const PIString & from, const PIString & to) {c_from = from; c_to = to;}
PIStringList availableCodecs();
PIString encode(PIString & str) {return PIString(exec_iconv(c_from, c_to, str.toByteArray()));}
PIString encode(const PIByteArray & str) {return PIString(exec_iconv(c_from, c_to, str));}
PIString decode(PIString & str) {return PIString(exec_iconv(c_to, c_from, str.toByteArray()));}
PIString decode(const PIByteArray & str) {return PIString(exec_iconv(c_to, c_from, str));}
private:
PIByteArray exec_iconv(const PIString & from, const PIString & to, const PIByteArray & str);
PIString c_from, c_to;
PIFile tf;
};
#endif // PIP_FREERTOS
#endif // PICODEC_H

View File

@@ -20,7 +20,6 @@
#ifndef PISYSTEMMODULE_H #ifndef PISYSTEMMODULE_H
#define PISYSTEMMODULE_H #define PISYSTEMMODULE_H
#include "picodec.h"
#include "pisignals.h" #include "pisignals.h"
#include "pilibrary.h" #include "pilibrary.h"
#include "pisysteminfo.h" #include "pisysteminfo.h"

View File

@@ -17,8 +17,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef PIP_TESTS_PIBLOCKINGDEQUEUE_H #ifndef PIBLOCKINGDEQUEUE_H
#define PIP_TESTS_PIBLOCKINGDEQUEUE_H #define PIBLOCKINGDEQUEUE_H
#include "pideque.h" #include "pideque.h"
#include "piconditionvar.h" #include "piconditionvar.h"
@@ -140,14 +140,14 @@ public:
* return value is retrieved value * return value is retrieved value
* @return the head of this queue, or defaultVal if the specified waiting time elapses before an element is available * @return the head of this queue, or defaultVal if the specified waiting time elapses before an element is available
*/ */
T poll(int timeoutMs, const T & defaultVal = T(), bool* isOk = nullptr) { T poll(int timeoutMs, const T & defaultVal = T(), bool * isOk = nullptr) {
T t; T t;
mutex.lock(); mutex.lock();
bool isNotEmpty = cond_var_add->waitFor(mutex, timeoutMs, [&]() { return !PIDeque<T>::isEmpty(); }); bool isNotEmpty = cond_var_add->waitFor(mutex, timeoutMs, [&]() { return !PIDeque<T>::isEmpty(); });
t = isNotEmpty ? T(PIDeque<T>::take_front()) : defaultVal; t = isNotEmpty ? T(PIDeque<T>::take_front()) : defaultVal;
mutex.unlock(); mutex.unlock();
if (isNotEmpty) cond_var_rem->notifyOne(); if (isNotEmpty) cond_var_rem->notifyOne();
if (isOk != nullptr) *isOk = isNotEmpty; if (isOk) *isOk = isNotEmpty;
return t; return t;
} }
@@ -160,14 +160,14 @@ public:
* return value is retrieved value * return value is retrieved value
* @return the head of this queue, or defaultVal if the specified waiting time elapses before an element is available * @return the head of this queue, or defaultVal if the specified waiting time elapses before an element is available
*/ */
T poll(const T & defaultVal = T(), bool* isOk = nullptr) { T poll(const T & defaultVal = T(), bool * isOk = nullptr) {
T t; T t;
mutex.lock(); mutex.lock();
bool isNotEmpty = !PIDeque<T>::isEmpty(); bool isNotEmpty = !PIDeque<T>::isEmpty();
t = isNotEmpty ? T(PIDeque<T>::take_front()) : defaultVal; t = isNotEmpty ? T(PIDeque<T>::take_front()) : defaultVal;
mutex.unlock(); mutex.unlock();
if (isNotEmpty) cond_var_rem->notifyOne(); if (isNotEmpty) cond_var_rem->notifyOne();
if (isOk != nullptr) *isOk = isNotEmpty; if (isOk) *isOk = isNotEmpty;
return t; return t;
} }
@@ -213,7 +213,7 @@ public:
*/ */
size_t drainTo(PIDeque<T>& other, size_t maxCount = SIZE_MAX) { size_t drainTo(PIDeque<T>& other, size_t maxCount = SIZE_MAX) {
mutex.lock(); mutex.lock();
size_t count = maxCount > PIDeque<T>::size() ? PIDeque<T>::size() : maxCount; size_t count = ((maxCount > PIDeque<T>::size()) ? PIDeque<T>::size() : maxCount);
for (size_t i = 0; i < count; ++i) other.push_back(PIDeque<T>::take_front()); for (size_t i = 0; i < count; ++i) other.push_back(PIDeque<T>::take_front());
mutex.unlock(); mutex.unlock();
return count; return count;
@@ -235,11 +235,11 @@ public:
} }
private: private:
PIConditionLock mutex; PIMutex mutex;
PIConditionVariable* cond_var_add; PIConditionVariable * cond_var_add, * cond_var_rem;
PIConditionVariable* cond_var_rem;
size_t max_size; size_t max_size;
}; };
#endif //PIP_TESTS_PIBLOCKINGDEQUEUE_H #endif // PIBLOCKINGDEQUEUE_H

View File

@@ -1,141 +1,141 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Stephan Fomenko Stephan Fomenko
This program is free software: you can redistribute it and/or modify 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 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 the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "piconditionvar.h" #include "piconditionvar.h"
#include "pithread.h" #include "pithread.h"
#include "pitime.h" #include "pitime.h"
#ifdef WINDOWS #ifdef WINDOWS
# undef _WIN32_WINNT # undef _WIN32_WINNT
# define _WIN32_WINNT 0x0600 # define _WIN32_WINNT 0x0600
# include <synchapi.h> # include <synchapi.h>
# include <windef.h> # include <windef.h>
# include <winbase.h> # include <winbase.h>
#endif #endif
PRIVATE_DEFINITION_START(PIConditionVariable) PRIVATE_DEFINITION_START(PIConditionVariable)
#ifdef WINDOWS #ifdef WINDOWS
CONDITION_VARIABLE nativeHandle; CONDITION_VARIABLE nativeHandle;
#else #else
pthread_cond_t nativeHandle; pthread_cond_t nativeHandle;
PIConditionLock* currentLock; PIMutex * currentLock;
#endif #endif
bool isDestroying; bool isDestroying;
PRIVATE_DEFINITION_END(PIConditionVariable) PRIVATE_DEFINITION_END(PIConditionVariable)
PIConditionVariable::PIConditionVariable() { PIConditionVariable::PIConditionVariable() {
#ifdef WINDOWS #ifdef WINDOWS
InitializeConditionVariable(&PRIVATE->nativeHandle); InitializeConditionVariable(&PRIVATE->nativeHandle);
#else #else
PRIVATE->isDestroying = false; PRIVATE->isDestroying = false;
PRIVATE->currentLock = nullptr; PRIVATE->currentLock = nullptr;
memset(&(PRIVATE->nativeHandle), 0, sizeof(PRIVATE->nativeHandle)); memset(&(PRIVATE->nativeHandle), 0, sizeof(PRIVATE->nativeHandle));
pthread_cond_init(&PRIVATE->nativeHandle, NULL); pthread_cond_init(&PRIVATE->nativeHandle, NULL);
#endif #endif
} }
PIConditionVariable::~PIConditionVariable() { PIConditionVariable::~PIConditionVariable() {
#ifdef WINDOWS #ifdef WINDOWS
#else #else
pthread_cond_destroy(&PRIVATE->nativeHandle); pthread_cond_destroy(&PRIVATE->nativeHandle);
#endif #endif
} }
void PIConditionVariable::wait(PIConditionLock& lk) { void PIConditionVariable::wait(PIMutex& lk) {
#ifdef WINDOWS #ifdef WINDOWS
SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), INFINITE); SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), INFINITE);
#else #else
pthread_cond_wait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle()); pthread_cond_wait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle());
#endif #endif
} }
void PIConditionVariable::wait(PIConditionLock& lk, const std::function<bool()>& condition) { void PIConditionVariable::wait(PIMutex& lk, const std::function<bool()>& condition) {
bool isCondition; bool isCondition;
while (true) { while (true) {
isCondition = condition(); isCondition = condition();
if (isCondition) break; if (isCondition) break;
#ifdef WINDOWS #ifdef WINDOWS
SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), INFINITE); SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), INFINITE);
#else #else
pthread_cond_wait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle()); pthread_cond_wait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle());
#endif #endif
if (PRIVATE->isDestroying) return; if (PRIVATE->isDestroying) return;
} }
} }
bool PIConditionVariable::waitFor(PIConditionLock &lk, int timeoutMs) { bool PIConditionVariable::waitFor(PIMutex &lk, int timeoutMs) {
bool isNotTimeout; bool isNotTimeout;
#ifdef WINDOWS #ifdef WINDOWS
isNotTimeout = SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), timeoutMs) != 0; isNotTimeout = SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), timeoutMs) != 0;
#else #else
timespec abstime = {.tv_sec = timeoutMs / 1000, .tv_nsec = timeoutMs * 1000 * 1000}; timespec abstime = {.tv_sec = timeoutMs / 1000, .tv_nsec = timeoutMs * 1000 * 1000};
isNotTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle(), &abstime) == 0; isNotTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle(), &abstime) == 0;
#endif #endif
if (PRIVATE->isDestroying) return false; if (PRIVATE->isDestroying) return false;
return isNotTimeout; return isNotTimeout;
} }
bool PIConditionVariable::waitFor(PIConditionLock& lk, int timeoutMs, const std::function<bool()> &condition) { bool PIConditionVariable::waitFor(PIMutex& lk, int timeoutMs, const std::function<bool()> &condition) {
bool isCondition; bool isCondition;
PITimeMeasurer measurer; PITimeMeasurer measurer;
while (true) { while (true) {
isCondition = condition(); isCondition = condition();
if (isCondition) break; if (isCondition) break;
#ifdef WINDOWS #ifdef WINDOWS
WINBOOL isTimeout = SleepConditionVariableCS( WINBOOL isTimeout = SleepConditionVariableCS(
&PRIVATE->nativeHandle, &PRIVATE->nativeHandle,
(PCRITICAL_SECTION)lk.handle(), (PCRITICAL_SECTION)lk.handle(),
timeoutMs - (int)measurer.elapsed_m()); timeoutMs - (int)measurer.elapsed_m());
if (isTimeout == 0) return false; if (isTimeout == 0) return false;
#else #else
int timeoutCurr = timeoutMs - (int)measurer.elapsed_m(); int timeoutCurr = timeoutMs - (int)measurer.elapsed_m();
timespec abstime = {.tv_sec = timeoutCurr / 1000, .tv_nsec = timeoutCurr * 1000 * 1000}; timespec abstime = {.tv_sec = timeoutCurr / 1000, .tv_nsec = timeoutCurr * 1000 * 1000};
bool isTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle(), &abstime) == 0; bool isTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle(), &abstime) == 0;
if (isTimeout) return false; if (isTimeout) return false;
#endif #endif
if (PRIVATE->isDestroying) return false; if (PRIVATE->isDestroying) return false;
} }
return true; return true;
} }
void PIConditionVariable::notifyOne() { void PIConditionVariable::notifyOne() {
#ifdef WINDOWS #ifdef WINDOWS
WakeConditionVariable(&PRIVATE->nativeHandle); WakeConditionVariable(&PRIVATE->nativeHandle);
#else #else
pthread_cond_signal(&PRIVATE->nativeHandle); pthread_cond_signal(&PRIVATE->nativeHandle);
#endif #endif
} }
void PIConditionVariable::notifyAll() { void PIConditionVariable::notifyAll() {
#ifdef WINDOWS #ifdef WINDOWS
WakeAllConditionVariable(&PRIVATE->nativeHandle); WakeAllConditionVariable(&PRIVATE->nativeHandle);
#else #else
pthread_cond_broadcast(&PRIVATE->nativeHandle); pthread_cond_broadcast(&PRIVATE->nativeHandle);
#endif #endif
} }

View File

@@ -20,14 +20,13 @@
#ifndef PICONDITIONVAR_H #ifndef PICONDITIONVAR_H
#define PICONDITIONVAR_H #define PICONDITIONVAR_H
#include "piconditionlock.h"
#include "pithread.h" #include "pithread.h"
/** /**
* @brief A condition variable is an object able to block the calling thread until notified to resume. * @brief A condition variable is an object able to block the calling thread until notified to resume.
* *
* It uses a PIConditionLock to lock the thread when one of its wait functions is called. The thread remains * It uses a PIMutex to lock the thread when one of its wait functions is called. The thread remains
* blocked until woken up by another thread that calls a notification function on the same PIConditionVariable object. * blocked until woken up by another thread that calls a notification function on the same PIConditionVariable object.
*/ */
class PIP_EXPORT PIConditionVariable { class PIP_EXPORT PIConditionVariable {
@@ -49,20 +48,20 @@ public:
void notifyAll(); void notifyAll();
/** /**
* @brief see wait(PIConditionLock&, const std::function<bool()>&) * @brief see wait(PIMutex &, const std::function<bool()>&)
*/ */
virtual void wait(PIConditionLock& lk); virtual void wait(PIMutex & lk);
/** /**
* @brief Wait until notified * @brief Wait until notified
* *
* The execution of the current thread (which shall have locked with lk method PIConditionLock::lock()) is blocked * The execution of the current thread (which shall have locked with lk method PIMutex::lock()) is blocked
* until notified. * until notified.
* *
* At the moment of blocking the thread, the function automatically calls lk.unlock() (PIConditionLock::unlock()), * At the moment of blocking the thread, the function automatically calls lk.unlock() (PIMutex::unlock()),
* allowing other locked threads to continue. * allowing other locked threads to continue.
* *
* Once notified (explicitly, by some other thread), the function unblocks and calls lk.lock() (PIConditionLock::lock()), * Once notified (explicitly, by some other thread), the function unblocks and calls lk.lock() (PIMutex::lock()),
* leaving lk in the same state as when the function was called. Then the function returns (notice that this last mutex * leaving lk in the same state as when the function was called. Then the function returns (notice that this last mutex
* locking may block again the thread before returning). * locking may block again the thread before returning).
* *
@@ -77,23 +76,23 @@ public:
* @param condition A callable object or function that takes no arguments and returns a value that can be evaluated * @param condition A callable object or function that takes no arguments and returns a value that can be evaluated
* as a bool. This is called repeatedly until it evaluates to true. * as a bool. This is called repeatedly until it evaluates to true.
*/ */
virtual void wait(PIConditionLock& lk, const std::function<bool()>& condition); virtual void wait(PIMutex& lk, const std::function<bool()>& condition);
/** /**
* @brief see waitFor(PIConditionLock&, int, const std::function<bool()>&) * @brief see waitFor(PIMutex &, int, const std::function<bool()>&)
*/ */
virtual bool waitFor(PIConditionLock& lk, int timeoutMs); virtual bool waitFor(PIMutex & lk, int timeoutMs);
/** /**
* @brief Wait for timeout or until notified * @brief Wait for timeout or until notified
* *
* The execution of the current thread (which shall have locked with lk method PIConditionLock::lock()) is blocked * The execution of the current thread (which shall have locked with lk method PIMutex::lock()) is blocked
* during timeoutMs, or until notified (if the latter happens first). * during timeoutMs, or until notified (if the latter happens first).
* *
* At the moment of blocking the thread, the function automatically calls lk.lock() (PIConditionLock::lock()), allowing * At the moment of blocking the thread, the function automatically calls lk.lock() (PIMutex::lock()), allowing
* other locked threads to continue. * other locked threads to continue.
* *
* Once notified or once timeoutMs has passed, the function unblocks and calls lk.unlock() (PIConditionLock::unlock()), * Once notified or once timeoutMs has passed, the function unblocks and calls lk.unlock() (PIMutex::unlock()),
* leaving lk in the same state as when the function was called. Then the function returns (notice that this last * leaving lk in the same state as when the function was called. Then the function returns (notice that this last
* mutex locking may block again the thread before returning). * mutex locking may block again the thread before returning).
* *
@@ -109,7 +108,7 @@ public:
* as a bool. This is called repeatedly until it evaluates to true. * as a bool. This is called repeatedly until it evaluates to true.
* @return false if timeout reached or true if wakeup condition is true * @return false if timeout reached or true if wakeup condition is true
*/ */
virtual bool waitFor(PIConditionLock& lk, int timeoutMs, const std::function<bool()>& condition); virtual bool waitFor(PIMutex& lk, int timeoutMs, const std::function<bool()>& condition);
private: private:
PRIVATE_DECLARATION PRIVATE_DECLARATION

122
lib/main/thread/pimutex.cpp Normal file
View File

@@ -0,0 +1,122 @@
/*
PIP - Platform Independent Primitives
Mutex
Ivan Pelipenko peri4ko@yandex.ru, Stephan Fomenko, Andrey Bychkov work.a.b@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 <http://www.gnu.org/licenses/>.
*/
/** \class PIMutex
* \brief Mutex
* \details
* \section PIMutex_sec0 Synopsis
* %PIMutex provides synchronization blocks between several threads.
* Using mutex guarantees execution of some code only one of threads.
* Mutex contains logic state and functions to change it: \a lock(),
* \a unlock() and \a tryLock().
*
* \section PIMutex_sec1 Usage
* Block of code that should to be executed only one thread simultaniously
* should to be started with \a lock() and ended with \a unlock().
* \snippet pimutex.cpp main
* "mutex" in this example is one for all threads.
*
* */
#include "pimutex.h"
#include "piincludes_p.h"
#ifdef WINDOWS
# include <synchapi.h>
#else
# include <pthread.h>
#endif
PRIVATE_DEFINITION_START(PIMutex)
#ifdef WINDOWS
CRITICAL_SECTION
#else
pthread_mutex_t
#endif
mutex;
PRIVATE_DEFINITION_END(PIMutex)
PIMutex::PIMutex() {
init();
}
PIMutex::~PIMutex() {
destroy();
}
void PIMutex::lock() {
#ifdef WINDOWS
EnterCriticalSection(&(PRIVATE->mutex));
#else
pthread_mutex_lock(&(PRIVATE->mutex));
#endif
}
void PIMutex::unlock() {
#ifdef WINDOWS
LeaveCriticalSection(&(PRIVATE->mutex));
#else
pthread_mutex_unlock(&(PRIVATE->mutex));
#endif
}
bool PIMutex::tryLock() {
bool ret =
#ifdef WINDOWS
(TryEnterCriticalSection(&(PRIVATE->mutex)) != 0);
#else
(pthread_mutex_trylock(&(PRIVATE->mutex)) == 0);
#endif
return ret;
}
void * PIMutex::handle() {
return (void*)&(PRIVATE->mutex);
}
void PIMutex::init() {
#ifdef WINDOWS
InitializeCriticalSection(&(PRIVATE->mutex));
#else
pthread_mutexattr_t attr;
memset(&attr, 0, sizeof(attr));
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
memset(&(PRIVATE->mutex), 0, sizeof(PRIVATE->mutex));
pthread_mutex_init(&(PRIVATE->mutex), &attr);
pthread_mutexattr_destroy(&attr);
#endif
}
void PIMutex::destroy() {
#ifdef WINDOWS
DeleteCriticalSection(&(PRIVATE->mutex));
#else
pthread_mutex_destroy(&(PRIVATE->mutex));
#endif
}

View File

@@ -4,7 +4,7 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
PIMutexLocker PIMutexLocker
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru Ivan Pelipenko peri4ko@yandex.ru, Stephan Fomenko, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU Lesser General Public License as published by
@@ -24,6 +24,45 @@
#define PIMUTEX_H #define PIMUTEX_H
#include "piinit.h" #include "piinit.h"
#include <mutex>
class PIP_EXPORT PIMutex
{
public:
NO_COPY_CLASS(PIMutex)
//! Constructs unlocked mutex
explicit PIMutex();
//! Destroy mutex
~PIMutex();
//! \brief Lock mutex
//! \details If mutex is unlocked it set to locked state and returns immediate.
//! If mutex is already locked function blocks until mutex will be unlocked
void lock();
//! \brief Unlock mutex
//! \details In any case this function returns immediate
void unlock() ;
//! \brief Try to lock mutex
//! \details If mutex is unlocked it set to locked state and returns "true" immediate.
//! If mutex is already locked function returns immediate an returns "false"
bool tryLock();
void * handle();
private:
void init();
void destroy();
PRIVATE_DECLARATION
};
//! \brief PIMutexLocker //! \brief PIMutexLocker
//! \details Same as std::lock_guard<std::mutex>. //! \details Same as std::lock_guard<std::mutex>.
@@ -40,7 +79,7 @@ public:
~PIMutexLocker() {if (cond) mutex.unlock();} ~PIMutexLocker() {if (cond) mutex.unlock();}
private: private:
PIMutex & mutex; PIMutex & mutex;
std::atomic_bool cond; bool cond;
}; };
#endif // PIMUTEX_H #endif // PIMUTEX_H

View File

@@ -25,5 +25,7 @@
#include "pitimer.h" #include "pitimer.h"
#include "pipipelinethread.h" #include "pipipelinethread.h"
#include "pigrabberbase.h" #include "pigrabberbase.h"
#include "pithreadpoolexecutor.h"
#include "piconditionvar.h"
#endif // PITHREADMODULE_H #endif // PITHREADMODULE_H

View File

@@ -1,74 +1,89 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Stephan Fomenko Stephan Fomenko
This program is free software: you can redistribute it and/or modify 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 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 the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "executor.h" #include "pithreadpoolexecutor.h"
#include "pisysteminfo.h"
PIThreadPoolExecutor::PIThreadPoolExecutor(size_t corePoolSize, PIBlockingDequeue<std::function<void()>> *taskQueue_) : isShutdown_(false), taskQueue(taskQueue_) { /*! \class PIThreadPoolExecutor
for (size_t i = 0; i < corePoolSize; ++i) { * @brief Thread pools address two different problems: they usually provide improved performance when executing large
PIThread * thread = new PIThread([&, i](){ * numbers of asynchronous tasks, due to reduced per-task invocation overhead, and they provide a means of bounding and
auto runnable = taskQueue->poll(100, std::function<void()>()); * managing the resources, including threads, consumed when executing a collection of tasks.
if (runnable) { */
runnable();
}
if (isShutdown_ && taskQueue->size() == 0) threadPool[i]->stop(); PIThreadPoolExecutor::PIThreadPoolExecutor(size_t corePoolSize, PIBlockingDequeue<std::function<void()> > * taskQueue_) : isShutdown_(false) {
}); queue_own = false;
threadPool.push_back(thread); if (corePoolSize <= 0)
thread->start(); corePoolSize = PISystemInfo::instance()->processorsCount;
} if (!taskQueue_) {
} taskQueue = new PIBlockingDequeue<std::function<void()> >();
queue_own = true;
}
bool PIThreadPoolExecutor::awaitTermination(int timeoutMs) { for (size_t i = 0; i < corePoolSize; ++i) {
PITimeMeasurer measurer; PIThread * thread = new PIThread([&, i](){
for (size_t i = 0; i < threadPool.size(); ++i) { auto runnable = taskQueue->poll(100, std::function<void()>());
int dif = timeoutMs - (int)measurer.elapsed_m(); if (runnable) {
if (dif < 0) return false; runnable();
if (!threadPool[i]->waitForFinish(dif)) return false; }
} if (isShutdown_ && taskQueue->size() == 0) threadPool[i]->stop();
return true; });
} threadPool.push_back(thread);
thread->start();
}
void PIThreadPoolExecutor::shutdownNow() { }
isShutdown_ = true;
for (size_t i = 0; i < threadPool.size(); ++i) threadPool[i]->stop();
} bool PIThreadPoolExecutor::awaitTermination(int timeoutMs) {
PITimeMeasurer measurer;
for (size_t i = 0; i < threadPool.size(); ++i) {
PIThreadPoolExecutor::~PIThreadPoolExecutor() { int dif = timeoutMs - (int)measurer.elapsed_m();
shutdownNow(); if (dif < 0) return false;
while (threadPool.size() > 0) delete threadPool.take_back(); if (!threadPool[i]->waitForFinish(dif)) return false;
delete taskQueue; }
} return true;
}
void PIThreadPoolExecutor::execute(const std::function<void()> &runnable) {
if (!isShutdown_) taskQueue->offer(runnable); void PIThreadPoolExecutor::shutdownNow() {
} isShutdown_ = true;
for (size_t i = 0; i < threadPool.size(); ++i) threadPool[i]->stop();
}
bool PIThreadPoolExecutor::isShutdown() const {
return isShutdown_;
} PIThreadPoolExecutor::~PIThreadPoolExecutor() {
shutdownNow();
while (threadPool.size() > 0) delete threadPool.take_back();
void PIThreadPoolExecutor::shutdown() { if (queue_own)
isShutdown_ = true; delete taskQueue;
} }
void PIThreadPoolExecutor::execute(const std::function<void()> & runnable) {
if (!isShutdown_) taskQueue->offer(runnable);
}
bool PIThreadPoolExecutor::isShutdown() const {
return isShutdown_;
}
void PIThreadPoolExecutor::shutdown() {
isShutdown_ = true;
}

View File

@@ -17,20 +17,16 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef PIP_TESTS_EXECUTOR_H #ifndef PITHREADPOOLEXECUTOR_H
#define PIP_TESTS_EXECUTOR_H #define PITHREADPOOLEXECUTOR_H
#include "piblockingdequeue.h" #include "piblockingdequeue.h"
#include <atomic> #include <atomic>
/**
* @brief Thread pools address two different problems: they usually provide improved performance when executing large
* numbers of asynchronous tasks, due to reduced per-task invocation overhead, and they provide a means of bounding and
* managing the resources, including threads, consumed when executing a collection of tasks.
*/
class PIThreadPoolExecutor { class PIThreadPoolExecutor {
public: public:
explicit PIThreadPoolExecutor(size_t corePoolSize = 1, PIBlockingDequeue<std::function<void()> >* taskQueue_ = new PIBlockingDequeue<std::function<void()> >()); explicit PIThreadPoolExecutor(size_t corePoolSize = -1, PIBlockingDequeue<std::function<void()> > * taskQueue_ = 0);
virtual ~PIThreadPoolExecutor(); virtual ~PIThreadPoolExecutor();
@@ -41,7 +37,7 @@ public:
* *
* @param runnable not empty function for thread pool execution * @param runnable not empty function for thread pool execution
*/ */
void execute(const std::function<void()>& runnable); void execute(const std::function<void()> & runnable);
void shutdownNow(); void shutdownNow();
@@ -55,10 +51,13 @@ public:
bool isShutdown() const; bool isShutdown() const;
bool awaitTermination(int timeoutMs); bool awaitTermination(int timeoutMs);
private: private:
std::atomic_bool isShutdown_; std::atomic_bool isShutdown_;
PIBlockingDequeue<std::function<void()> >* taskQueue; PIBlockingDequeue<std::function<void()> > * taskQueue;
PIVector<PIThread*> threadPool; PIVector<PIThread*> threadPool;
bool queue_own;
}; };
#endif //PIP_TESTS_EXECUTOR_H #endif // PITHREADPOOLEXECUTOR_H

View File

@@ -1,5 +1,5 @@
#include "pip.h" #include "pip.h"
#ifdef PIP_LUA /*#ifdef PIP_LUA
#include "piluaprogram.h" #include "piluaprogram.h"
static const char * script static const char * script
@@ -30,3 +30,29 @@ int main() {
return 0; return 0;
} }
#endif #endif
*/
#include "picodeparser.h"
int main() {
piDebug = false;
double min = -1, max = -1, mean = 0;
for (int i = 0; i < 50; ++i) {
PITimeMeasurer tm;
/*PICodeParser cp;
cp.parseFile("SH_plugin_base.h");*/
PIStringList sl;
for (int i = 0; i < 5000; ++i) {
//PIString s("1234567890-=");
//sl << s;
sl << PIString("1234567890-=");
}
double ms = tm.elapsed_m();
if (min < 0) min = ms;
if (max < 0) max = ms;
min = piMin(min, ms);
max = piMax(max, ms);
mean += ms;
}
piDebug = true;
piCout << min << (mean / 50) << max;
}