merged concurrent to main library
removed PIConditionLock, use PIMutex instead
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
@@ -21,7 +21,6 @@
|
||||
#define PICONSOLEMODULE_H
|
||||
|
||||
#include "pikbdlistener.h"
|
||||
#include "piconsole.h"
|
||||
#include "piscreen.h"
|
||||
#include "piscreentiles.h"
|
||||
|
||||
|
||||
@@ -49,6 +49,9 @@ public:
|
||||
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
|
||||
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() {
|
||||
//piCout << "~PIDeque";
|
||||
PIINTROSPECTION_CONTAINER_DELETE(T)
|
||||
@@ -66,6 +69,12 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PIDeque<T> & operator =(PIDeque<T> && other) {
|
||||
if (this == &other) return *this;
|
||||
swap(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
typedef T value_type;
|
||||
|
||||
class iterator {
|
||||
@@ -256,6 +265,23 @@ public:
|
||||
elementNew(pid_data + pid_start + index, v);
|
||||
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) {
|
||||
if (other.isEmpty()) return *this;
|
||||
assert(&other != this);
|
||||
@@ -336,7 +362,14 @@ public:
|
||||
elementNew(pid_data + pid_start + pid_size - 1, v);
|
||||
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(T && v) {return push_back(v);}
|
||||
inline PIDeque<T> & append(const PIDeque<T> & t) {
|
||||
assert(&t != this);
|
||||
size_t ps = pid_size;
|
||||
@@ -345,6 +378,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
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> & 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, T && from) {piSwap(*to, from);}
|
||||
inline void elementDelete(T & from) {from.~T();}
|
||||
inline void dealloc() {
|
||||
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>::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, T && from) {(*to) = from;} \
|
||||
template<> inline void PIDeque<T>::elementDelete(T &) {;} \
|
||||
template<> inline PIDeque<T> & PIDeque<T>::_resizeRaw(size_t new_size) { \
|
||||
if (new_size > pid_size) { \
|
||||
|
||||
@@ -74,6 +74,7 @@ class PIMap {
|
||||
public:
|
||||
PIMap() {;}
|
||||
PIMap(const PIMap<Key, T> & other) {*this = other;}
|
||||
PIMap(PIMap<Key, T> && other) {swap(other);}
|
||||
virtual ~PIMap() {;}
|
||||
|
||||
PIMap<Key, T> & operator =(const PIMap<Key, T> & other) {
|
||||
@@ -84,6 +85,12 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
PIMap<Key, T> & operator =(PIMap<Key, T> && other) {
|
||||
if (this == &other) return *this;
|
||||
swap(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
typedef T mapped_type;
|
||||
typedef Key key_type;
|
||||
typedef PIPair<Key, T> value_type;
|
||||
|
||||
@@ -48,6 +48,9 @@ public:
|
||||
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
|
||||
resize(piv_size, f);
|
||||
}
|
||||
inline PIVector(PIVector<T> && other): piv_data(0), piv_size(0), piv_rsize(0) {
|
||||
swap(other);
|
||||
}
|
||||
inline virtual ~PIVector() {
|
||||
PIINTROSPECTION_CONTAINER_DELETE(T)
|
||||
PIINTROSPECTION_CONTAINER_FREE(T, (piv_rsize))
|
||||
@@ -65,6 +68,12 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PIVector<T> & operator =(PIVector<T> && other) {
|
||||
if (this == &other) return *this;
|
||||
swap(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
typedef T value_type;
|
||||
|
||||
class iterator {
|
||||
@@ -253,6 +262,16 @@ public:
|
||||
elementNew(piv_data + index, v);
|
||||
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) {
|
||||
if (other.isEmpty()) return *this;
|
||||
assert(&other != this);
|
||||
@@ -320,7 +339,14 @@ public:
|
||||
elementNew(piv_data + piv_size - 1, v);
|
||||
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(T && v) {return push_back(v);}
|
||||
inline PIVector<T> & append(const PIVector<T> & other) {
|
||||
assert(&other != this);
|
||||
size_t ps = piv_size;
|
||||
@@ -329,6 +355,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
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> & 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, T && from) {piSwap(*to, from);}
|
||||
inline void elementDelete(T & from) {from.~T();}
|
||||
inline void dealloc() {
|
||||
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>::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, T && from) {(*to) = from;} \
|
||||
template<> inline void PIVector<T>::elementDelete(T &) {;} \
|
||||
template<> inline PIVector<T> & PIVector<T>::_resizeRaw(size_t new_size) { \
|
||||
if (new_size > piv_size) { \
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
*/
|
||||
#include "piincludes_p.h"
|
||||
#include "picout.h"
|
||||
#include "piconsole.h"
|
||||
#include "pibytearray.h"
|
||||
#include "pistack.h"
|
||||
#include "piobject.h"
|
||||
#include "pistring_std.h"
|
||||
#ifdef WINDOWS
|
||||
# include <windows.h>
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#include "piincludes.h"
|
||||
#include "piincludes_p.h"
|
||||
#include "piconsole.h"
|
||||
#include "pitime.h"
|
||||
#ifndef QNX
|
||||
# include <clocale>
|
||||
|
||||
@@ -27,10 +27,9 @@
|
||||
# include <iostream>
|
||||
#endif
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
|
||||
typedef std::mutex PIMutex;
|
||||
//typedef std::lock_guard<std::mutex> PIMutexLocker;
|
||||
class PIMutex;
|
||||
class PIMutexLocker;
|
||||
class PIObject;
|
||||
class PIString;
|
||||
class PIByteArray;
|
||||
|
||||
@@ -51,6 +51,8 @@ public:
|
||||
|
||||
PIString(const PIString & o): PIDeque<PIChar>() {*this += o;}
|
||||
|
||||
PIString(PIString && o): PIDeque<PIChar>() {swap(o);}
|
||||
|
||||
|
||||
//! Contructs string with single symbol "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 =(PIString && o) {if (this == &o) return *this; swap(o); return *this;}
|
||||
|
||||
/*! \brief Return c-string representation of string
|
||||
* \details Converts content of string to c-string and return
|
||||
* pointer to first char. This buffer is valid until new convertion
|
||||
|
||||
@@ -83,6 +83,7 @@ public:
|
||||
PIStringList & operator =(const PIStringList & o) {PIDeque<PIString>::operator=(o); 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;}
|
||||
|
||||
};
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -20,7 +20,6 @@
|
||||
#ifndef PISYSTEMMODULE_H
|
||||
#define PISYSTEMMODULE_H
|
||||
|
||||
#include "picodec.h"
|
||||
#include "pisignals.h"
|
||||
#include "pilibrary.h"
|
||||
#include "pisysteminfo.h"
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIP_TESTS_PIBLOCKINGDEQUEUE_H
|
||||
#define PIP_TESTS_PIBLOCKINGDEQUEUE_H
|
||||
#ifndef PIBLOCKINGDEQUEUE_H
|
||||
#define PIBLOCKINGDEQUEUE_H
|
||||
|
||||
#include "pideque.h"
|
||||
#include "piconditionvar.h"
|
||||
@@ -140,14 +140,14 @@ public:
|
||||
* return value is retrieved value
|
||||
* @return the head of this queue, or defaultVal if the specified waiting time elapses before an element is available
|
||||
*/
|
||||
T poll(int timeoutMs, const T & defaultVal = T(), bool* isOk = nullptr) {
|
||||
T poll(int timeoutMs, const T & defaultVal = T(), bool * isOk = nullptr) {
|
||||
T t;
|
||||
mutex.lock();
|
||||
bool isNotEmpty = cond_var_add->waitFor(mutex, timeoutMs, [&]() { return !PIDeque<T>::isEmpty(); });
|
||||
t = isNotEmpty ? T(PIDeque<T>::take_front()) : defaultVal;
|
||||
mutex.unlock();
|
||||
if (isNotEmpty) cond_var_rem->notifyOne();
|
||||
if (isOk != nullptr) *isOk = isNotEmpty;
|
||||
if (isOk) *isOk = isNotEmpty;
|
||||
return t;
|
||||
}
|
||||
|
||||
@@ -160,14 +160,14 @@ public:
|
||||
* return value is retrieved value
|
||||
* @return the head of this queue, or defaultVal if the specified waiting time elapses before an element is available
|
||||
*/
|
||||
T poll(const T & defaultVal = T(), bool* isOk = nullptr) {
|
||||
T poll(const T & defaultVal = T(), bool * isOk = nullptr) {
|
||||
T t;
|
||||
mutex.lock();
|
||||
bool isNotEmpty = !PIDeque<T>::isEmpty();
|
||||
t = isNotEmpty ? T(PIDeque<T>::take_front()) : defaultVal;
|
||||
mutex.unlock();
|
||||
if (isNotEmpty) cond_var_rem->notifyOne();
|
||||
if (isOk != nullptr) *isOk = isNotEmpty;
|
||||
if (isOk) *isOk = isNotEmpty;
|
||||
return t;
|
||||
}
|
||||
|
||||
@@ -213,7 +213,7 @@ public:
|
||||
*/
|
||||
size_t drainTo(PIDeque<T>& other, size_t maxCount = SIZE_MAX) {
|
||||
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());
|
||||
mutex.unlock();
|
||||
return count;
|
||||
@@ -235,11 +235,11 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
PIConditionLock mutex;
|
||||
PIConditionVariable* cond_var_add;
|
||||
PIConditionVariable* cond_var_rem;
|
||||
PIMutex mutex;
|
||||
PIConditionVariable * cond_var_add, * cond_var_rem;
|
||||
size_t max_size;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //PIP_TESTS_PIBLOCKINGDEQUEUE_H
|
||||
#endif // PIBLOCKINGDEQUEUE_H
|
||||
141
lib/main/thread/piconditionvar.cpp
Normal file
141
lib/main/thread/piconditionvar.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
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 "piconditionvar.h"
|
||||
#include "pithread.h"
|
||||
#include "pitime.h"
|
||||
|
||||
#ifdef WINDOWS
|
||||
# undef _WIN32_WINNT
|
||||
# define _WIN32_WINNT 0x0600
|
||||
# include <synchapi.h>
|
||||
# include <windef.h>
|
||||
# include <winbase.h>
|
||||
#endif
|
||||
|
||||
|
||||
PRIVATE_DEFINITION_START(PIConditionVariable)
|
||||
#ifdef WINDOWS
|
||||
CONDITION_VARIABLE nativeHandle;
|
||||
#else
|
||||
pthread_cond_t nativeHandle;
|
||||
PIMutex * currentLock;
|
||||
#endif
|
||||
bool isDestroying;
|
||||
PRIVATE_DEFINITION_END(PIConditionVariable)
|
||||
|
||||
|
||||
PIConditionVariable::PIConditionVariable() {
|
||||
#ifdef WINDOWS
|
||||
InitializeConditionVariable(&PRIVATE->nativeHandle);
|
||||
#else
|
||||
PRIVATE->isDestroying = false;
|
||||
PRIVATE->currentLock = nullptr;
|
||||
memset(&(PRIVATE->nativeHandle), 0, sizeof(PRIVATE->nativeHandle));
|
||||
pthread_cond_init(&PRIVATE->nativeHandle, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
PIConditionVariable::~PIConditionVariable() {
|
||||
#ifdef WINDOWS
|
||||
#else
|
||||
pthread_cond_destroy(&PRIVATE->nativeHandle);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void PIConditionVariable::wait(PIMutex& lk) {
|
||||
#ifdef WINDOWS
|
||||
SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), INFINITE);
|
||||
#else
|
||||
pthread_cond_wait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void PIConditionVariable::wait(PIMutex& lk, const std::function<bool()>& condition) {
|
||||
bool isCondition;
|
||||
while (true) {
|
||||
isCondition = condition();
|
||||
if (isCondition) break;
|
||||
#ifdef WINDOWS
|
||||
SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), INFINITE);
|
||||
#else
|
||||
pthread_cond_wait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle());
|
||||
#endif
|
||||
if (PRIVATE->isDestroying) return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool PIConditionVariable::waitFor(PIMutex &lk, int timeoutMs) {
|
||||
bool isNotTimeout;
|
||||
#ifdef WINDOWS
|
||||
isNotTimeout = SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), timeoutMs) != 0;
|
||||
#else
|
||||
timespec abstime = {.tv_sec = timeoutMs / 1000, .tv_nsec = timeoutMs * 1000 * 1000};
|
||||
isNotTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle(), &abstime) == 0;
|
||||
#endif
|
||||
if (PRIVATE->isDestroying) return false;
|
||||
return isNotTimeout;
|
||||
}
|
||||
|
||||
|
||||
bool PIConditionVariable::waitFor(PIMutex& lk, int timeoutMs, const std::function<bool()> &condition) {
|
||||
bool isCondition;
|
||||
PITimeMeasurer measurer;
|
||||
while (true) {
|
||||
isCondition = condition();
|
||||
if (isCondition) break;
|
||||
#ifdef WINDOWS
|
||||
WINBOOL isTimeout = SleepConditionVariableCS(
|
||||
&PRIVATE->nativeHandle,
|
||||
(PCRITICAL_SECTION)lk.handle(),
|
||||
timeoutMs - (int)measurer.elapsed_m());
|
||||
if (isTimeout == 0) return false;
|
||||
#else
|
||||
int timeoutCurr = timeoutMs - (int)measurer.elapsed_m();
|
||||
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;
|
||||
if (isTimeout) return false;
|
||||
#endif
|
||||
if (PRIVATE->isDestroying) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void PIConditionVariable::notifyOne() {
|
||||
#ifdef WINDOWS
|
||||
WakeConditionVariable(&PRIVATE->nativeHandle);
|
||||
#else
|
||||
pthread_cond_signal(&PRIVATE->nativeHandle);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void PIConditionVariable::notifyAll() {
|
||||
#ifdef WINDOWS
|
||||
WakeAllConditionVariable(&PRIVATE->nativeHandle);
|
||||
#else
|
||||
pthread_cond_broadcast(&PRIVATE->nativeHandle);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -20,14 +20,13 @@
|
||||
#ifndef PICONDITIONVAR_H
|
||||
#define PICONDITIONVAR_H
|
||||
|
||||
#include "piconditionlock.h"
|
||||
#include "pithread.h"
|
||||
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*/
|
||||
class PIP_EXPORT PIConditionVariable {
|
||||
@@ -49,20 +48,20 @@ public:
|
||||
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
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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
|
||||
* 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
|
||||
* 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
|
||||
*
|
||||
* 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).
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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
|
||||
* 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.
|
||||
* @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_DECLARATION
|
||||
122
lib/main/thread/pimutex.cpp
Normal file
122
lib/main/thread/pimutex.cpp
Normal 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
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
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
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
@@ -24,6 +24,45 @@
|
||||
#define PIMUTEX_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
|
||||
//! \details Same as std::lock_guard<std::mutex>.
|
||||
@@ -40,7 +79,7 @@ public:
|
||||
~PIMutexLocker() {if (cond) mutex.unlock();}
|
||||
private:
|
||||
PIMutex & mutex;
|
||||
std::atomic_bool cond;
|
||||
bool cond;
|
||||
};
|
||||
|
||||
#endif // PIMUTEX_H
|
||||
|
||||
@@ -25,5 +25,7 @@
|
||||
#include "pitimer.h"
|
||||
#include "pipipelinethread.h"
|
||||
#include "pigrabberbase.h"
|
||||
#include "pithreadpoolexecutor.h"
|
||||
#include "piconditionvar.h"
|
||||
|
||||
#endif // PITHREADMODULE_H
|
||||
|
||||
89
lib/main/thread/pithreadpoolexecutor.cpp
Normal file
89
lib/main/thread/pithreadpoolexecutor.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
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 "pithreadpoolexecutor.h"
|
||||
#include "pisysteminfo.h"
|
||||
|
||||
/*! \class PIThreadPoolExecutor
|
||||
* @brief Thread pools address two different problems: they usually provide improved performance when executing large
|
||||
* numbers of asynchronous tasks, due to reduced per-task invocation overhead, and they provide a means of bounding and
|
||||
* managing the resources, including threads, consumed when executing a collection of tasks.
|
||||
*/
|
||||
|
||||
|
||||
PIThreadPoolExecutor::PIThreadPoolExecutor(size_t corePoolSize, PIBlockingDequeue<std::function<void()> > * taskQueue_) : isShutdown_(false) {
|
||||
queue_own = false;
|
||||
if (corePoolSize <= 0)
|
||||
corePoolSize = PISystemInfo::instance()->processorsCount;
|
||||
if (!taskQueue_) {
|
||||
taskQueue = new PIBlockingDequeue<std::function<void()> >();
|
||||
queue_own = true;
|
||||
}
|
||||
for (size_t i = 0; i < corePoolSize; ++i) {
|
||||
PIThread * thread = new PIThread([&, i](){
|
||||
auto runnable = taskQueue->poll(100, std::function<void()>());
|
||||
if (runnable) {
|
||||
runnable();
|
||||
}
|
||||
if (isShutdown_ && taskQueue->size() == 0) threadPool[i]->stop();
|
||||
});
|
||||
threadPool.push_back(thread);
|
||||
thread->start();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool PIThreadPoolExecutor::awaitTermination(int timeoutMs) {
|
||||
PITimeMeasurer measurer;
|
||||
for (size_t i = 0; i < threadPool.size(); ++i) {
|
||||
int dif = timeoutMs - (int)measurer.elapsed_m();
|
||||
if (dif < 0) return false;
|
||||
if (!threadPool[i]->waitForFinish(dif)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void PIThreadPoolExecutor::shutdownNow() {
|
||||
isShutdown_ = true;
|
||||
for (size_t i = 0; i < threadPool.size(); ++i) threadPool[i]->stop();
|
||||
}
|
||||
|
||||
|
||||
PIThreadPoolExecutor::~PIThreadPoolExecutor() {
|
||||
shutdownNow();
|
||||
while (threadPool.size() > 0) delete threadPool.take_back();
|
||||
if (queue_own)
|
||||
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;
|
||||
}
|
||||
@@ -17,20 +17,16 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIP_TESTS_EXECUTOR_H
|
||||
#define PIP_TESTS_EXECUTOR_H
|
||||
#ifndef PITHREADPOOLEXECUTOR_H
|
||||
#define PITHREADPOOLEXECUTOR_H
|
||||
|
||||
#include "piblockingdequeue.h"
|
||||
#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 {
|
||||
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();
|
||||
|
||||
@@ -41,7 +37,7 @@ public:
|
||||
*
|
||||
* @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();
|
||||
|
||||
@@ -55,10 +51,13 @@ public:
|
||||
bool isShutdown() const;
|
||||
|
||||
bool awaitTermination(int timeoutMs);
|
||||
|
||||
private:
|
||||
std::atomic_bool isShutdown_;
|
||||
PIBlockingDequeue<std::function<void()> >* taskQueue;
|
||||
PIBlockingDequeue<std::function<void()> > * taskQueue;
|
||||
PIVector<PIThread*> threadPool;
|
||||
bool queue_own;
|
||||
|
||||
};
|
||||
|
||||
#endif //PIP_TESTS_EXECUTOR_H
|
||||
#endif // PITHREADPOOLEXECUTOR_H
|
||||
Reference in New Issue
Block a user