tree changes

This commit is contained in:
2020-08-19 00:47:05 +03:00
parent c582d8ff46
commit ccd6a9888f
240 changed files with 30 additions and 12 deletions

View File

@@ -0,0 +1,113 @@
/*
PIP - Platform Independent Primitives
Dynamic library
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 "pilibrary.h"
#include "piincludes_p.h"
#ifndef WINDOWS
# include <dlfcn.h>
#endif
PRIVATE_DEFINITION_START(PILibrary)
#ifdef WINDOWS
HMODULE
#else
void *
#endif
hLib;
PRIVATE_DEFINITION_END(PILibrary)
PILibrary::PILibrary(const PIString & path_) {
PRIVATE->hLib = 0;
load(path_);
}
PILibrary::~PILibrary() {
unload();
}
bool PILibrary::load(const PIString & path_) {
libpath = path_;
return loadInternal();
}
bool PILibrary::load() {
return loadInternal();
}
void PILibrary::unload() {
if (PRIVATE->hLib == 0) return;
#ifdef WINDOWS
FreeLibrary(PRIVATE->hLib);
#else
dlclose(PRIVATE->hLib);
#endif
PRIVATE->hLib = 0;
}
bool PILibrary::isLoaded() const {
return PRIVATE->hLib;
}
void * PILibrary::resolve(const char * symbol) {
if (!isLoaded()) return 0;
void * ret;
#ifdef WINDOWS
ret = (void*)GetProcAddress(PRIVATE->hLib, symbol);
#else
ret = dlsym(PRIVATE->hLib, symbol);
#endif
getLastError();
return ret;
}
bool PILibrary::loadInternal() {
unload();
if (libpath.isEmpty()) return false;
#ifdef WINDOWS
PRIVATE->hLib = LoadLibrary(libpath.data());
#else
PRIVATE->hLib = dlopen(libpath.data(), RTLD_LAZY);
#endif
getLastError();
return PRIVATE->hLib;
}
void PILibrary::getLastError() {
#ifdef WINDOWS
liberror = errorString();
#else
const char * e = dlerror();
if (e) liberror = e;
else liberror.clear();
#endif
}
#endif // PIP_FREERTOS

View File

@@ -0,0 +1,51 @@
/*
PIP - Platform Independent Primitives
Dynamic library
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 PILIBRARY_H
#define PILIBRARY_H
#ifndef PIP_FREERTOS
#include "pistring.h"
class PIP_EXPORT PILibrary {
public:
PILibrary(const PIString & path_ = PIString());
~PILibrary();
bool load(const PIString & path_);
bool load();
void unload();
void * resolve(const char * symbol);
bool isLoaded() const;
PIString path() const {return libpath;}
PIString lastError() const {return liberror;}
private:
bool loadInternal();
void getLastError();
PRIVATE_DECLARATION(PIP_EXPORT)
PIString libpath, liberror;
};
#endif // PIP_FREERTOS
#endif // PILIBRARY_H

View File

@@ -0,0 +1,294 @@
/*
PIP - Platform Independent Primitives
Process
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 "piincludes_p.h"
#include "piprocess.h"
#ifndef WINDOWS
# include <sys/wait.h>
# include <csignal>
#endif
#ifdef MAC_OS
# include <crt_externs.h>
#endif
PRIVATE_DEFINITION_START(PIProcess)
#ifdef WINDOWS
STARTUPINFOA si;
PROCESS_INFORMATION pi;
#else
pid_t pid;
#endif
FILE * tf_in, * tf_out, * tf_err;
PRIVATE_DEFINITION_END(PIProcess)
PIProcess::PIProcess(): PIThread() {
exit_code = -1;
#ifdef WINDOWS
PRIVATE->pi.dwProcessId = 0;
#else
PRIVATE->pid = 0;
#endif
is_exec = false;
g_in = g_out = g_err = false;
t_in = t_out = t_err = false;
PRIVATE->tf_in = PRIVATE->tf_out = PRIVATE->tf_err = 0;
env = PIProcess::currentEnvironment();
}
PIProcess::~PIProcess() {
if (t_in) f_in.remove();
if (t_out) f_out.remove();
if (t_err) f_err.remove();
}
void PIProcess::exec_() {
is_exec = false;
startOnce();
//cout << "exec wait" << endl;
while (!is_exec)
msleep(PIP_MIN_MSLEEP);
//cout << "exec end" << endl;
}
void PIProcess::startProc(bool detached) {
//cout << "run" << endl;
PIString str;
/// arguments convertion
#ifdef WINDOWS
int as = 0;
piForeachC (PIString & i, args)
as += i.lengthAscii() + 3;
char * a = new char[as];
memset(a, ' ', as - 1);
as = 0;
for (int i = 0; i < args.size_s(); ++i) {
str = args[i];
a[as] = '"';
memcpy(&(a[as + 1]), str.data(), str.lengthAscii());
a[as + str.lengthAscii() + 1] = '"';
as += str.lengthAscii() + 3;
}
a[as - 1] = 0;
//piCout << a;
#else
//piCout << "#" << args;
char * a[args.size_s() + 1];
for (int i = 0; i < args.size_s(); ++i) {
str = args[i];
//piCout << i << str << str.size() << str.lengthAscii() << str.lengthAscii() << str.lengthAscii();
a[i] = new char[str.lengthAscii() + 1];
memcpy(a[i], str.data(), str.lengthAscii());
a[i][str.lengthAscii()] = 0;
}
a[args.size_s()] = 0;
#endif
/// environment convertion
char ** e = new char*[env.size_s() + 1];
for (int i = 0; i < env.size_s(); ++i) {
str = env[i];
e[i] = new char[str.lengthAscii() + 1];
memcpy(e[i], str.data(), str.lengthAscii());
e[i][str.lengthAscii()] = 0;
//cout << e[i] << endl;
}
e[env.size_s()] = 0;
/// files for stdin/out/err
t_in = t_out = t_err = false;
if (f_in.path().isEmpty()) {
f_in.openTemporary(PIIODevice::ReadWrite);
t_in = true;
}
if (f_out.path().isEmpty()) {
f_out.openTemporary(PIIODevice::ReadWrite);
t_out = true;
}
if (f_err.path().isEmpty()) {
f_err.openTemporary(PIIODevice::ReadWrite);
t_err = true;
}
str = args.front();
is_exec = true;
if (!detached) execStarted(str);
#ifndef WINDOWS
int pid_ = fork();
if (!detached) PRIVATE->pid = pid_;
if (pid_ == 0) {
#endif
PRIVATE->tf_in = PRIVATE->tf_out = PRIVATE->tf_err = 0;
//cout << "exec " << tf_in << ", " << tf_out << ", " << tf_err << endl;
//cout << f_out.path() << endl;
if (g_in) PRIVATE->tf_in = freopen(f_in.path().data(), "r", stdin);
if (g_out) PRIVATE->tf_out = freopen(f_out.path().data(), "w", stdout);
if (g_err) PRIVATE->tf_err = freopen(f_err.path().data(), "w", stderr);
#ifndef WINDOWS
if (!wd.isEmpty())
if (!chdir(wd.data()))
piCoutObj << "Error while set working directory";
#endif
#ifdef WINDOWS
GetStartupInfoA(&(PRIVATE->si));
memset(&(PRIVATE->pi), 0, sizeof(PRIVATE->pi));
if(CreateProcessA(0, // No module name (use command line)
a, // Command line
0, // Process handle not inheritable
0, // Thread handle not inheritable
false, // Set handle inheritance to FALSE
detached ? DETACHED_PROCESS/*CREATE_NEW_CONSOLE*/ : 0, // Creation flags
0,//e, // Use environment
wd.isEmpty() ? 0 : wd.data(), // Use working directory
&(PRIVATE->si), // Pointer to STARTUPINFO structure
&(PRIVATE->pi))) // Pointer to PROCESS_INFORMATION structure
{
if (!detached) WaitForSingleObject(PRIVATE->pi.hProcess, INFINITE);
CloseHandle(PRIVATE->pi.hThread);
CloseHandle(PRIVATE->pi.hProcess);
} else
piCoutObj << "\"CreateProcess\" error, " << errorString();
#else
//cout << "exec " << tf_in << ", " << tf_out << ", " << tf_err << endl;
if (execve(str.data(), a, e) < 0)
piCoutObj << "\"execve" << str << args << "\" error :" << errorString();
} else {
msleep(PIP_MIN_MSLEEP);
//cout << "wait" << endl;
if (!detached) {
wait(&exit_code);
pid_ = 0;
if (!detached) PRIVATE->pid = pid_;
//cout << "wait done" << endl;
}
}
#endif
if (!detached) execFinished(str, exit_code);
is_exec = false;
for (int i = 0; i < env.size_s(); ++i)
delete e[i];
delete[] e;
#ifdef WINDOWS
delete a;
#else
for (int i = 0; i < args.size_s(); ++i)
delete a[i];
#endif
}
void PIProcess::terminate() {
#ifdef WINDOWS
if (is_exec)
if (!TerminateProcess(PRIVATE->pi.hProcess, 0))
return;
PRIVATE->pi.dwProcessId = 0;
#else
if (is_exec)
kill(PRIVATE->pid, SIGKILL);
PRIVATE->pid = 0;
#endif
}
void PIProcess::execIndependent(const PIString & program, const PIStringList & args_) {
PIProcess p;
p.args << program << args_;
p.startProc(true);
}
int PIProcess::pID() const {
#ifdef WINDOWS
return PRIVATE->pi.dwProcessId;
#else
return PRIVATE->pid;
#endif
}
int PIProcess::currentPID() {
#ifdef WINDOWS
return GetCurrentProcessId();
#else
return getpid();
#endif
}
PIStringList PIProcess::currentEnvironment() {
PIStringList l;
int i = 0;
while (environ[i] != 0) {
l << environ[i];
++i;
}
return l;
}
void PIProcess::run() {
startProc(false);
}
void PIProcess::removeEnvironmentVariable(const PIString & variable) {
PIString s;
for (int i = 0; i < env.size_s(); ++i) {
s = env[i];
if (s.left(s.find("=")).trimmed() == variable) {
env.remove(i);
--i;
}
}
}
void PIProcess::setEnvironmentVariable(const PIString & variable, const PIString & value) {
PIString s, v;
for (int i = 0; i < env.size_s(); ++i) {
s = env[i];
v = s.left(s.find("=")).trimmed();
if (v == variable) {
env[i] = v + "=" + value;
return;
}
}
env << variable + "=" + value;
}
PIString PIProcess::getEnvironmentVariable(const PIString & variable) {
PIStringList env_ = currentEnvironment();
PIString s, v;
for (int i = 0; i < env_.size_s(); ++i) {
s = env_[i];
v = s.left(s.find("=")).trimmed();
if (v == variable) {
return s.right(s.size() - 1 - s.find("=")).trimmed();
}
}
return PIString();
}
#endif // PIP_FREERTOS

View File

@@ -0,0 +1,108 @@
/*! \file piprocess.h
* \brief Process
*/
/*
PIP - Platform Independent Primitives
Process
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 PIPROCESS_H
#define PIPROCESS_H
#ifndef PIP_FREERTOS
#include "pithread.h"
#include "pifile.h"
/// events:
/// execStarted(PIString program)
/// execFinished(PIString program, int exit_code)
///
/// handlers:
/// bool exec(const PIString & program)
/// bool exec(const PIString & program, const PIString & arg1)
/// bool exec(const PIString & program, const PIString & arg1, const PIString & arg2)
/// bool exec(const PIString & program, const PIString & arg1, const PIString & arg2, const PIString & arg3)
/// bool exec(const PIString & program, const PIStringList & args)
/// void terminate()
/// bool waitForFinish(int timeout_msecs = 60000)
class PIP_EXPORT PIProcess: public PIThread
{
PIOBJECT_SUBCLASS(PIProcess, PIThread)
public:
PIProcess();
virtual ~PIProcess();
int exitCode() const {return exit_code;}
int pID() const;
void setGrabInput(bool yes) {g_in = yes;}
void setGrabOutput(bool yes) {g_out = yes;}
void setGrabError(bool yes) {g_err = yes;}
void setInputFile(const PIString & path) {f_in.setPath(path);}
void setOutputFile(const PIString & path) {f_out.setPath(path);}
void setErrorFile(const PIString & path) {f_err.setPath(path);}
void unsetInputFile() {f_in.setPath("");}
void unsetOutputFile() {f_out.setPath("");}
void unsetErrorFile() {f_err.setPath("");}
PIString workingDirectory() const {return wd;}
void setWorkingDirectory(const PIString & path) {wd = path;}
void resetWorkingDirectory() {wd.clear();}
PIByteArray readOutput() {f_out.open(PIIODevice::ReadOnly); return f_out.readAll();}
PIByteArray readError() {f_err.open(PIIODevice::ReadOnly); return f_err.readAll();}
PIStringList environment() {return env;}
void clearEnvironment() {env.clear();}
void removeEnvironmentVariable(const PIString & variable);
void setEnvironmentVariable(const PIString & variable, const PIString & value);
EVENT_HANDLER1(void, exec, const PIString & , program) {args.clear(); args << program; exec_();}
void exec(const PIString & program, const PIString & arg) {args.clear(); args << program << arg; exec_();}
EVENT_HANDLER2(void, exec, const PIString & , program, const PIStringList & , args_) {args.clear(); args << program << args_; exec_();}
EVENT_HANDLER(void, terminate);
EVENT_HANDLER(bool, waitForFinish) {return waitForFinish(60000);}
EVENT_HANDLER1(bool, waitForFinish, int, timeout_msecs) {return PIThread::waitForFinish(timeout_msecs);}
EVENT1(execStarted, PIString, program)
EVENT2(execFinished, PIString, program, int, exit_code)
static void execIndependent(const PIString & program) {execIndependent(program, PIStringList());}
static void execIndependent(const PIString & program, const PIString & arg) {execIndependent(program, PIStringList() << arg);}
static void execIndependent(const PIString & program, const PIStringList & args_);
static PIStringList currentEnvironment();
static int currentPID();
static PIString getEnvironmentVariable(const PIString & variable);
private:
virtual void run();
void exec_();
void startProc(bool detached);
PRIVATE_DECLARATION(PIP_EXPORT)
PIStringList args, env;
PIString wd;
PIByteArray out;
PIFile f_in, f_out, f_err;
bool g_in, g_out, g_err, t_in, t_out, t_err;
int exit_code;
bool is_exec;
};
#endif // PIP_FREERTOS
#endif // PIPROCESS_H

View File

@@ -0,0 +1,132 @@
/*
PIP - Platform Independent Primitives
Signals
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 "piincludes.h"
#include "pisignals.h"
#ifdef BLACKBERRY
# include <signal.h>
#else
# include <csignal>
#endif
#ifdef WINDOWS
# define SIGUSR1 10
# define SIGUSR2 12
#endif
PISignals::SignalEvent PISignals::ret_func;
void PISignals::grabSignals(PIFlags<PISignals::Signal> signals_) {
if (signals_[PISignals::Interrupt]) signal(signalCode(PISignals::Interrupt), PISignals::signal_event);
if (signals_[PISignals::Illegal]) signal(signalCode(PISignals::Illegal), PISignals::signal_event);
if (signals_[PISignals::Abort]) signal(signalCode(PISignals::Abort), PISignals::signal_event);
if (signals_[PISignals::FPE]) signal(signalCode(PISignals::FPE), PISignals::signal_event);
if (signals_[PISignals::SegFault]) signal(signalCode(PISignals::SegFault), PISignals::signal_event);
if (signals_[PISignals::Termination]) signal(signalCode(PISignals::Termination), PISignals::signal_event);
# ifndef CC_VC
if (signals_[PISignals::UserDefined1]) signal(signalCode(PISignals::UserDefined1), PISignals::signal_event);
if (signals_[PISignals::UserDefined2]) signal(signalCode(PISignals::UserDefined2), PISignals::signal_event);
# endif
#ifndef WINDOWS
if (signals_[PISignals::Hangup]) signal(signalCode(PISignals::Hangup), PISignals::signal_event);
if (signals_[PISignals::Quit]) signal(signalCode(PISignals::Quit), PISignals::signal_event);
if (signals_[PISignals::Kill]) signal(signalCode(PISignals::Kill), PISignals::signal_event);
if (signals_[PISignals::BrokenPipe]) signal(signalCode(PISignals::BrokenPipe), PISignals::signal_event);
if (signals_[PISignals::Timer]) signal(signalCode(PISignals::Timer), PISignals::signal_event);
if (signals_[PISignals::ChildStopped]) signal(signalCode(PISignals::ChildStopped), PISignals::signal_event);
if (signals_[PISignals::Continue]) signal(signalCode(PISignals::Continue), PISignals::signal_event);
if (signals_[PISignals::StopProcess]) signal(signalCode(PISignals::StopProcess), PISignals::signal_event);
if (signals_[PISignals::StopTTY]) signal(signalCode(PISignals::StopTTY), PISignals::signal_event);
if (signals_[PISignals::StopTTYInput]) signal(signalCode(PISignals::StopTTYInput), PISignals::signal_event);
if (signals_[PISignals::StopTTYOutput]) signal(signalCode(PISignals::StopTTYOutput), PISignals::signal_event);
#endif
}
void PISignals::raiseSignal(PISignals::Signal signal) {
raise(signalCode(signal));
}
int PISignals::signalCode(PISignals::Signal signal) {
switch (signal) {
case PISignals::Interrupt: return SIGINT;
case PISignals::Illegal: return SIGILL;
case PISignals::Abort: return SIGABRT;
case PISignals::FPE: return SIGFPE;
case PISignals::SegFault: return SIGSEGV;
case PISignals::Termination: return SIGTERM;
# ifndef CC_VC
case PISignals::UserDefined1: return SIGUSR1;
case PISignals::UserDefined2: return SIGUSR2;
# endif
#ifndef WINDOWS
case PISignals::Hangup: return SIGHUP;
case PISignals::Quit: return SIGQUIT;
case PISignals::Kill: return SIGKILL;
case PISignals::BrokenPipe: return SIGPIPE;
case PISignals::Timer: return SIGALRM;
case PISignals::ChildStopped: return SIGCHLD;
case PISignals::Continue: return SIGCONT;
case PISignals::StopProcess: return SIGSTOP;
case PISignals::StopTTY: return SIGTSTP;
case PISignals::StopTTYInput: return SIGTTIN;
case PISignals::StopTTYOutput:return SIGTTOU;
#endif
default:;
}
return 0;
}
PISignals::Signal PISignals::signalFromCode(int signal) {
switch (signal) {
case SIGINT: return PISignals::Interrupt;
case SIGILL: return PISignals::Illegal;
case SIGABRT: return PISignals::Abort;
case SIGFPE: return PISignals::FPE;
case SIGSEGV: return PISignals::SegFault;
case SIGTERM: return PISignals::Termination;
# ifndef CC_VC
case SIGUSR1: return PISignals::UserDefined1;
case SIGUSR2: return PISignals::UserDefined2;
# endif
#ifndef WINDOWS
case SIGHUP: return PISignals::Hangup;
case SIGQUIT: return PISignals::Quit;
case SIGKILL: return PISignals::Kill;
case SIGPIPE: return PISignals::BrokenPipe;
case SIGALRM: return PISignals::Timer;
case SIGCHLD: return PISignals::ChildStopped;
case SIGCONT: return PISignals::Continue;
case SIGSTOP: return PISignals::StopProcess;
case SIGTSTP: return PISignals::StopTTY;
case SIGTTIN: return PISignals::StopTTYInput;
case SIGTTOU: return PISignals::StopTTYOutput;
#endif
default:;
}
return PISignals::Termination;
}
void PISignals::signal_event(int signal) {
if (PISignals::ret_func == 0) return;
PISignals::ret_func(PISignals::signalFromCode(signal));
}

View File

@@ -0,0 +1,73 @@
/*! \file pisignals.h
* \brief System signals
*/
/*
PIP - Platform Independent Primitives
Signals
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 PISIGNALS_H
#define PISIGNALS_H
#include "piflags.h"
class PIP_EXPORT PISignals
{
public:
enum Signal {
Interrupt /** Interrupt from keyboard */ = 0x01, // Term Interrupt from keyboard
Illegal /** Illegal Instruction */ = 0x02, // Core Illegal Instruction
Abort /** Abort signal */ = 0x04, // Core Abort signal from abort
FPE /** Floating point exception */ = 0x08, // Core Floating point exception
SegFault /** Invalid memory reference */ = 0x10, // Core Invalid memory reference
Termination /** Termination signal */ = 0x20, // Term Termination signal
Hangup = 0x40, // Term Hangup detected on controlling terminal or death of controlling process
Quit = 0x80, // Core Quit from keyboard
Kill = 0x100, // Term Kill signal
BrokenPipe = 0x200, // Term Broken pipe: write to pipe with no readers
Timer = 0x400, // Term Timer signal from alarm
UserDefined1 = 0x800, // Term User-defined signal 1
UserDefined2 = 0x1000, // Term User-defined signal 2
ChildStopped = 0x2000, // Ign Child stopped or terminated
Continue = 0x4000, // Cont Continue if stopped
StopProcess = 0x8000, // Stop Stop process
StopTTY = 0x10000, // Stop Stop typed at tty
StopTTYInput = 0x20000, // Stop tty input for background process
StopTTYOutput = 0x40000, // Stop tty output for background process
All = 0xFFFFF
};
typedef void (*SignalEvent)(PISignals::Signal);
// slot is any function format "void <func>(PISignals::Signal)"
static void setSlot(SignalEvent slot) {ret_func = slot;}
static void grabSignals(PIFlags<PISignals::Signal> signals_);
static void raiseSignal(PISignals::Signal signal);
private:
PISignals() {ret_func = 0;}
~PISignals() {}
static int signalCode(PISignals::Signal signal);
static PISignals::Signal signalFromCode(int signal);
static void signal_event(int signal);
static SignalEvent ret_func;
};
#endif // PISIGNALS_H

View File

@@ -0,0 +1,107 @@
/*
PIP - Platform Independent Primitives
Single application
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 "pisingleapplication.h"
#include "pisharedmemory.h"
#define SHM_SIZE 1024*32
PISingleApplication::PISingleApplication(const PIString & app_name): PIThread() {
first = true;
started = false;
sacnt = 0;
shm = new PISharedMemory("sa_" + app_name, SHM_SIZE);
start(100);
}
PISingleApplication::~PISingleApplication() {
stop();
if (!waitForFinish(5000))
terminate();
delete shm;
}
bool PISingleApplication::isFirst() const {
waitFirst();
return first;
}
void PISingleApplication::sendMessage(const PIByteArray & m) {
waitFirst();
PIByteArray ba;
int lm[2] = {0, 0};
for (;;) {
shm->read(lm, 8);
if (lm[1] == 0) break;
piMSleep(10);
}
ba << sacnt << sacnt << int(1) << m;
shm->write(ba);
}
void PISingleApplication::begin() {
int cnt[2] = {0, 0};
int tcnt = 0;
shm->read(cnt, 8);
for (int i = 0; i < 5; ++i) {
tcnt = cnt[0];
shm->read(cnt, 8);
if (cnt[0] == cnt[1] && cnt[0] != tcnt) {
first = false;
break;
}
piMSleep(100);
}
//piCoutObj << "started" << first << shm->size();
readed.reserve(shm->size());
started = true;
}
void PISingleApplication::run() {
if (!first) return;
++sacnt;
int st_[2] = {sacnt, sacnt};
shm->write(st_, 8);
//piCoutObj << "write" << sacnt;
readed = shm->readAll();
int t1(0), t2(0), nm(0);
readed >> t1 >> t2 >> nm;
if (nm != 0 && t1 == t2) {
PIByteArray msg;
readed >> msg;
if (!msg.isEmpty()) {
messageReceived(msg);
//piCoutObj << "message" << msg;
}
int wi[3] = {sacnt, sacnt, 0};
shm->write(wi, 12);
}
}
void PISingleApplication::waitFirst() const {
while (!started)
piMSleep(50);
}

View File

@@ -0,0 +1,51 @@
/*
PIP - Platform Independent Primitives
Single application
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 PISINGLEAPPLICATION_H
#define PISINGLEAPPLICATION_H
#include "pithread.h"
class PISharedMemory;
class PIP_EXPORT PISingleApplication: public PIThread {
PIOBJECT_SUBCLASS(PISingleApplication, PIThread)
public:
PISingleApplication(const PIString & app_name = PIString());
~PISingleApplication();
bool isFirst() const;
EVENT_HANDLER1(void, sendMessage, const PIByteArray &, m);
EVENT1(messageReceived, const PIByteArray &, m)
private:
void begin();
void run();
void waitFirst() const;
PISharedMemory * shm;
PITimeMeasurer ftm;
PIByteArray readed;
bool first, started;
int sacnt;
};
#endif // PISINGLEAPPLICATION_H

View File

@@ -0,0 +1,265 @@
/*
PIP - Platform Independent Primitives
System information
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 "pisysteminfo.h"
#include "piincludes_p.h"
#include "pidir.h"
#include "picrc.h"
#ifdef ESP_PLATFORM
# include "esp_system.h"
# include "esp_spi_flash.h"
#endif
#define SALT_SIZE 8
PISystemInfo::MountInfo::MountInfo() {
space_all = space_used = space_free = 0;
removable = false;
}
PISystemInfo::PISystemInfo() {
processorsCount = 1;
}
PISystemInfo * PISystemInfo::instance() {
static PISystemInfo ret;
return &ret;
}
PIStringList PISystemInfo::mountRoots() {
PIStringList ret;
#ifdef WINDOWS
char letters[1024];
DWORD ll = GetLogicalDriveStrings(1023, letters);
PIString clet;
for (uint i = 0; i < ll; ++i) {
if (letters[i] == '\0') {
if (clet.size_s() > 2) ret << clet.cutRight(1);
clet.clear();
} else
clet += PIChar(letters[i]);
}
#else
# ifdef LINUX
PIString s_df, s_m;
char in[1024];
memset(in, 0, 1024);
FILE * fp = popen("mount -l", "r");
PIStringList tl;
if (fp) {
while (fgets(in, 1024, fp)) {
tl = PIString(in).trim().replaceAll(" ", " ").split(" ");
if (tl.size_s() < 2) continue;
for (int i = 0; i < tl.size_s() - 1; ++i)
if (tl[i] == "on") {if (!ret.contains(tl[i + 1])) ret << tl[i + 1]; break;}
}
pclose(fp);
}
# else
# endif
#endif
return ret;
}
struct String3 {PIString mp, type, label;};
PIVector<PISystemInfo::MountInfo> PISystemInfo::mountInfo(bool ignore_cache) {
static PIVector<PISystemInfo::MountInfo> cache;
static PITimeMeasurer tm;
static bool first = true;
if (!ignore_cache) {
if (tm.elapsed_m() < piMountInfoRefreshIntervalMs && !first)
return cache;
}
first = false;
tm.reset();
cache.clear();
PIVector<PISystemInfo::MountInfo> ret;
MountInfo m;
#ifdef WINDOWS
char letters[1024], volname[1024], volfs[1024];
DWORD ll = GetLogicalDriveStrings(1023, letters);
PIString clet;
for (DWORD i = 0; i < ll; ++i) {
if (letters[i] == '\0') {
if (GetVolumeInformation(clet.data(), volname, 1023, 0, 0, 0, volfs, 1023)) {
m.mount_point = clet;
m.filesystem = volfs;
m.label = volname;
DWORD spc, bps, free_cl, all_cl;
if (GetDiskFreeSpace(clet.data(), &spc, &bps, &free_cl, &all_cl)) {
ullong bpc = ullong(spc) * ullong(bps);
m.space_all = bpc * ullong(all_cl);
m.space_free = bpc * ullong(free_cl);
m.space_used = m.space_all - m.space_free;
} else
m.space_all = m.space_free = m.space_used = 0U;
if (GetDriveType(clet.dataAscii()) == DRIVE_REMOVABLE)
m.removable = true;
clet.cutRight(1);
int qdd = QueryDosDevice(clet.data(), volfs, 1023);
if (qdd > 0)
m.device = volfs;
else
m.device.clear();
ret << m;
}
clet.clear();
} else
clet += PIChar(letters[i]);
}
#endif
#ifdef LINUX
PIString s_df, s_m;
char in[1024];
memset(in, 0, 1024);
//piCout << "mountInfo 0";
FILE * fp = popen("df -B1", "r");
PIStringList l_df;
PIMap<PIString, String3> fs;
if (fp) {
while (fgets(in, 1024, fp))
l_df << PIString(in).trim();
pclose(fp);
fp = 0;
}
//piCout << "mountInfo 1";
memset(in, 0, 1024);
fp = popen("mount -l", "r");
PIStringList tl;
if (fp) {
while (fgets(in, 1024, fp)) {
tl = PIString(in).trim().replaceAll(" ", " ").split(" ");
if (tl.size_s() < 2) continue;
String3 me;
PIString dev;
dev = tl.front();
for (int i = 0; i < tl.size_s() - 1; ++i) {
if (tl[i] == "on") {me.mp = tl[i + 1]; ++i; continue;}
if (tl[i] == "type") {me.type = tl[i + 1]; ++i; continue;}
}
if (tl.back().startsWith("[")) {
me.label = tl.back();
me.label.cutLeft(1).cutRight(1);
}
fs[dev] = me;
//piCout << fsmp << fstl;
}
pclose(fp);
fp = 0;
}
if (l_df.size_s() < 2) return ret;
l_df.pop_front();
piForeachC (PIString & s, l_df) {
PIStringList ml(s.replacedAll(" ", " ").split(" "));
if (ml.size_s() < 2) continue;
if (ml.front() == "none") continue;
m.space_all = ml[1].toULLong();
m.space_used = ml[2].toULLong();
m.space_free = m.space_all - m.space_used;
String3 s3 = fs.value(ml.front());
m.device = ml.front();
m.filesystem = s3.type;
m.mount_point = s3.mp;
m.label = s3.label;
ret << m;
//piCout << ml;
}
#endif
#ifdef ESP_PLATFORM
esp_chip_info_t chip_info;
esp_chip_info(&chip_info);
m.device = ((chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded SPI flash" : "external SPI flash");
m.space_all = spi_flash_get_chip_size();
m.mount_point = "/";
ret << m;
#endif
cache = ret;
return ret;
}
PIString confDir() {
return
#ifdef WINDOWS
PIDir::home().path() + "/AppData/Local"
#elif defined(ANDROID)
""
#else
PIDir::home().path() + "/.config"
#endif
;
}
PIByteArray generateSalt() {
PIByteArray ret;
piForTimes (SALT_SIZE) {
piMSleep(randomi() % 10);
randomize();
ret << uchar(randomi() % 0x100);
}
return ret;
}
PIString PISystemInfo::machineKey() {
static PIString ret;
if (ret.isEmpty()) {
PISystemInfo * si = instance();
PIByteArray salt;
PIString conf = confDir() + "/.pip_machine_salt";
if (PIFile::isExists(conf)) {
PIFile f(conf, PIIODevice::ReadOnly);
f.open();
salt = f.readAll();
}
if (salt.size_s() != SALT_SIZE){
salt = generateSalt();
PIFile f(conf, PIIODevice::ReadWrite);
f.open();
f.clear();
f.write(salt);
}
ret = si->OS_name + "_" + si->architecture + "_" + si->hostname + "_" + salt.toHex();
}
return ret;
}
uint PISystemInfo::machineID() {
static uint ret = 0;
if (ret == 0) {
CRC_32 crc = standardCRC_32();
ret = crc.calculate(machineKey().toByteArray());
piCout << "machineID \"" << machineKey() << "\" =" << PICoutManipulators::Hex << ret;
}
return ret;
}

View File

@@ -0,0 +1,64 @@
/*
PIP - Platform Independent Primitives
System information
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 PISYSTEMINFO_H
#define PISYSTEMINFO_H
#include "pitime.h"
class PIP_EXPORT PISystemInfo {
public:
PISystemInfo();
struct PIP_EXPORT MountInfo {
MountInfo();
PIString mount_point;
PIString device;
PIString filesystem;
PIString label;
ullong space_all;
ullong space_used;
ullong space_free;
bool removable;
};
PIString ifconfigPath, execCommand, hostname, user, OS_name, OS_version, architecture;
PIDateTime execDateTime;
int processorsCount;
static PIStringList mountRoots();
static PIVector<MountInfo> mountInfo(bool ignore_cache = false);
static PIString machineKey();
static uint machineID();
static PISystemInfo * instance();
};
inline PICout operator <<(PICout s, const PISystemInfo::MountInfo & v) {
s.setControl(0, true);
s << "MountInfo(" << v.device << " mounted on \"" << v.mount_point << "\", type " << v.filesystem
<< ", label \"" << v.label << "\", all " << PIString::readableSize(v.space_all)
<< ", used " << PIString::readableSize(v.space_used)
<< ", free " << PIString::readableSize(v.space_free) << ")";
s.restoreControl();
return s;
}
#endif // PISYSTEMINFO_H

View File

@@ -0,0 +1,30 @@
/*
PIP - Platform Independent Primitives
Module includes
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 PISYSTEMMODULE_H
#define PISYSTEMMODULE_H
#include "pisignals.h"
#include "pilibrary.h"
#include "pisysteminfo.h"
#include "pisystemtests.h"
#include "pisystemmonitor.h"
#include "pisingleapplication.h"
#endif // PISYSTEMMODULE_H

View File

@@ -0,0 +1,501 @@
/*
PIP - Platform Independent Primitives
Process resource monitor
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 "piincludes_p.h"
#include "pisystemmonitor.h"
#include "pisysteminfo.h"
#include "piprocess.h"
#include "pidir.h"
#include "pitime_win.h"
#ifdef WINDOWS
# include <psapi.h>
# include <tlhelp32.h>
#endif
#ifdef MAC_OS
struct kqueue_id_t;
# include <libproc.h>
# include <sys/proc_info.h>
#endif
#ifdef ESP_PLATFORM
# include "esp_heap_caps.h"
#endif
PISystemMonitor::ProcessStatsFixed::ProcessStatsFixed() {
ID = parent_ID = group_ID = session_ID = priority = threads = 0;
physical_memsize = resident_memsize = share_memsize = virtual_memsize = data_memsize = 0;
cpu_load_user = cpu_load_system = 0.f;
}
void PISystemMonitor::ProcessStats::makeStrings() {
physical_memsize_readable.setReadableSize(physical_memsize);
resident_memsize_readable.setReadableSize(resident_memsize);
share_memsize_readable.setReadableSize(share_memsize);
virtual_memsize_readable.setReadableSize(virtual_memsize);
data_memsize_readable.setReadableSize(data_memsize);
}
PISystemMonitor::ThreadStatsFixed::ThreadStatsFixed() {
id = 0;
cpu_load_kernel = cpu_load_user = -1.f;
}
#ifndef FREERTOS
PRIVATE_DEFINITION_START(PISystemMonitor)
#ifndef WINDOWS
# ifdef MAC_OS
PISystemTime
# else
llong
# endif
cpu_u_cur, cpu_u_prev, cpu_s_cur, cpu_s_prev;
PIString proc_dir;
PIFile file, filem;
#else
HANDLE hProc;
PROCESS_MEMORY_COUNTERS mem_cnt;
PISystemTime tm_kernel, tm_user;
PITimeMeasurer tm;
#endif
PRIVATE_DEFINITION_END(PISystemMonitor)
#endif
PISystemMonitor::PISystemMonitor(): PIThread() {
pID_ = cycle = 0;
cpu_count = PISystemInfo::instance()->processorsCount;
#ifndef FREERTOS
#ifndef WINDOWS
# ifdef QNX
page_size = 4096;
# else
page_size = getpagesize();
# endif
#else
PRIVATE->hProc = 0;
PRIVATE->mem_cnt.cb = sizeof(PRIVATE->mem_cnt);
#endif
#endif
setName("system_monitor");
}
PISystemMonitor::~PISystemMonitor() {
stop();
}
#ifndef FREERTOS
bool PISystemMonitor::startOnProcess(int pID, int interval_ms) {
stop();
pID_ = pID;
Pool::instance()->add(this);
cycle = -1;
#ifndef WINDOWS
# ifndef MAC_OS
PRIVATE->proc_dir = PIStringAscii("/proc/") + PIString::fromNumber(pID_) + PIStringAscii("/");
PRIVATE->file. open(PRIVATE->proc_dir + "stat", PIIODevice::ReadOnly);
PRIVATE->filem.open(PRIVATE->proc_dir + "statm", PIIODevice::ReadOnly);
if (!PRIVATE->file.isOpened()) {
piCoutObj << "Can`t find process with ID = " << pID_ << "!";
return false;
}
# endif
#else
PRIVATE->hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pID_);
if (PRIVATE->hProc == 0) {
piCoutObj << "Can`t open process with ID = " << pID_ << "," << errorString();
return false;
}
PRIVATE->tm.reset();
#endif
return start(interval_ms);
}
#endif
bool PISystemMonitor::startOnSelf(int interval_ms) {
#ifndef FREERTOS
bool ret = startOnProcess(PIProcess::currentPID(), interval_ms);
cycle = -1;
#else
bool ret = start(interval_ms);
#endif
return ret;
}
PIVector<PISystemMonitor::ThreadStats> PISystemMonitor::threadsStatistic() const {
mutex_.lock();
PIVector<PISystemMonitor::ThreadStats> ret = cur_ts;
mutex_.unlock();
return ret;
}
void PISystemMonitor::setStatistic(const PISystemMonitor::ProcessStats & s) {
PIMutexLocker _ml(stat_mutex);
stat = s;
stat.makeStrings();
}
void PISystemMonitor::stop() {
PIThread::stop();
#ifdef WINDOWS
if (PRIVATE->hProc != 0) {
CloseHandle(PRIVATE->hProc);
PRIVATE->hProc = 0;
}
#endif
Pool::instance()->remove(this);
}
PISystemMonitor::ProcessStats PISystemMonitor::statistic() const {
PIMutexLocker _ml(stat_mutex);
return stat;
}
#ifdef MAC_OS
PISystemTime uint64toST(uint64_t v) {
return PISystemTime(((uint*)&(v))[1], ((uint*)&(v))[0]);
}
#endif
void PISystemMonitor::run() {
cur_tm.clear();
tbid.clear();
__PIThreadCollection * pitc = __PIThreadCollection::instance();
pitc->lock();
PIVector<PIThread * > tv = pitc->threads();
piForeach (PIThread * t, tv)
if (t->isPIObject())
tbid[t->tid()] = t->name();
pitc->unlock();
//piCout << tbid.keys().toType<uint>();
ProcessStats tstat;
tstat.ID = pID_;
#ifdef FREERTOS
piForeach (PIThread * t, tv)
if (t->isPIObject())
gatherThread(t->tid());
#else
#ifndef WINDOWS
tbid[pID_] = "main";
# ifdef MAC_OS
rusage_info_current ru;
proc_pid_rusage(pID_, RUSAGE_INFO_CURRENT, (rusage_info_t*)&ru);
//piCout << PISystemTime(((uint*)&(ru.ri_user_time))[1], ((uint*)&(ru.ri_user_time))[0]);
if (cycle < 0) {
PRIVATE->cpu_u_prev = PRIVATE->cpu_u_cur = uint64toST(ru.ri_user_time);
PRIVATE->cpu_s_prev = PRIVATE->cpu_s_cur = uint64toST(ru.ri_system_time);
}
PRIVATE->cpu_u_prev = PRIVATE->cpu_u_cur;
PRIVATE->cpu_s_prev = PRIVATE->cpu_s_cur;
PRIVATE->cpu_u_cur = uint64toST(ru.ri_user_time);
PRIVATE->cpu_s_cur = uint64toST(ru.ri_system_time);
tstat.cpu_load_system = 100.f * (PRIVATE->cpu_s_cur - PRIVATE->cpu_s_prev).toMilliseconds() / delay_;
tstat.cpu_load_user = 100.f * (PRIVATE->cpu_u_cur - PRIVATE->cpu_u_prev).toMilliseconds() / delay_;
cycle = 0;
//piCout << (PRIVATE->cpu_u_cur - PRIVATE->cpu_u_prev).toMilliseconds() / delay_;
# else
PRIVATE->file.seekToBegin();
PIString str(PRIVATE->file.readAll(true));
int si = str.find('(') + 1, fi = 0, cc = 1;
for (int i = si; i < str.size_s(); ++i) {
if (str[i] == '(') cc++;
if (str[i] == ')') cc--;
if (cc <= 0) {
fi = i;
break;
}
}
tstat.exec_name = str.mid(si, fi - si);
str.cutMid(si - 1, fi - si + 3);
PIStringList sl = str.split(" ");
if (sl.size_s() < 19) return;
tstat.ID = sl[0].toInt();
tstat.state = sl[1];
tstat.parent_ID = sl[2].toInt();
tstat.group_ID = sl[3].toInt();
tstat.session_ID = sl[4].toInt();
if (cycle < 0) {
PRIVATE->cpu_u_prev = PRIVATE->cpu_u_cur = sl[12].toLLong();
PRIVATE->cpu_s_prev = PRIVATE->cpu_s_cur = sl[13].toLLong();
}
PRIVATE->cpu_u_prev = PRIVATE->cpu_u_cur;
PRIVATE->cpu_s_prev = PRIVATE->cpu_s_cur;
PRIVATE->cpu_u_cur = sl[12].toLLong();
PRIVATE->cpu_s_cur = sl[13].toLLong();
tstat.cpu_load_system = (PRIVATE->cpu_s_cur - PRIVATE->cpu_s_prev) / (delay_ / 1000.);
tstat.cpu_load_user = (PRIVATE->cpu_u_cur - PRIVATE->cpu_u_prev) / (delay_ / 1000.);
tstat.cpu_load_system /= cpu_count;
tstat.cpu_load_user /= cpu_count;
cycle = 0;
tstat.priority = sl[16].toInt();
tstat.threads = sl[18].toInt();
//piCout << "\n";
//piCout << sl[0] << sl[12] << sl[13];
PRIVATE->filem.seekToBegin();
str = PRIVATE->filem.readAll(true);
sl = str.split(" ");
if (sl.size_s() < 6) return;
tstat.virtual_memsize = sl[0].toLong() * page_size;
tstat.resident_memsize = sl[1].toLong() * page_size;
tstat.share_memsize = sl[2].toLong() * page_size;
tstat.data_memsize = sl[5].toLong() * page_size;
tstat.physical_memsize = tstat.resident_memsize - tstat.share_memsize;
PIVector<PIFile::FileInfo> tld = PIDir(PRIVATE->proc_dir + "task").entries();
piForeachC (PIFile::FileInfo & i, tld) {
if (i.flags[PIFile::FileInfo::Dot] || i.flags[PIFile::FileInfo::DotDot])
continue;
gatherThread(i.name().toInt());
}
# endif
#else
if (GetProcessMemoryInfo(PRIVATE->hProc, &PRIVATE->mem_cnt, sizeof(PRIVATE->mem_cnt)) != 0) {
tstat.physical_memsize = PRIVATE->mem_cnt.WorkingSetSize;
}
tstat.priority = GetPriorityClass(PRIVATE->hProc);
HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, pID_);
int thcnt = 0;
if (snap != 0) {
THREADENTRY32 thread;
thread.dwSize = sizeof(THREADENTRY32);
if (Thread32First(snap, &thread) == TRUE) {
if (thread.th32OwnerProcessID == DWORD(pID_)) {
++thcnt;
gatherThread(thread.th32ThreadID);
}
while (Thread32Next(snap, &thread) == TRUE) {
if (thread.th32OwnerProcessID == DWORD(pID_)) {
++thcnt;
gatherThread(thread.th32ThreadID);
}
//piCout << thread.th32ThreadID;
}
}
tstat.threads = thcnt;
CloseHandle(snap);
}
FILETIME ft0, ft1, ft_kernel, ft_user;
double el_s = PRIVATE->tm.elapsed_s() * cpu_count / 100.;
if (GetProcessTimes(PRIVATE->hProc, &ft0, &ft1, &ft_kernel, &ft_user) != 0) {
PISystemTime tm_kernel_c = FILETIME2PISystemTime(ft_kernel);
PISystemTime tm_user_c = FILETIME2PISystemTime(ft_user);
if (cycle < 0) {
PRIVATE->tm_kernel = tm_kernel_c;
PRIVATE->tm_user = tm_user_c;
}
cycle = 0;
if (el_s <= 0.) {
tstat.cpu_load_system = 0.f;
tstat.cpu_load_user = 0.f;
} else {
tstat.cpu_load_system = (tm_kernel_c - PRIVATE->tm_kernel).toSeconds() / el_s;
tstat.cpu_load_user = (tm_user_c - PRIVATE->tm_user).toSeconds() / el_s;
}
PRIVATE->tm_kernel = tm_kernel_c;
PRIVATE->tm_user = tm_user_c;
} else {
tstat.cpu_load_system = 0.f;
tstat.cpu_load_user = 0.f;
}
PRIVATE->tm.reset();
#endif
#endif
tstat.cpu_load_system = piClampf(tstat.cpu_load_system, 0.f, 100.f);
tstat.cpu_load_user = piClampf(tstat.cpu_load_user , 0.f, 100.f);
auto i = cur_tm.makeIterator();
while (i.next()) {
if (!last_tm.contains(i.key())) continue;
ThreadStats & ts_new(i.valueRef());
ThreadStats & ts_old(last_tm[i.key()]);
ts_new.cpu_load_kernel = calcThreadUsage(ts_new.kernel_time, ts_old.kernel_time);
ts_new.cpu_load_user = calcThreadUsage(ts_new.user_time, ts_old.user_time);
//piCout << ts_new.cpu_load_user;
}
last_tm = cur_tm;
lock();
cur_ts = cur_tm.values();
unlock();
tstat.ram_total = totalRAM();
tstat.ram_used = usedRAM();
tstat.ram_free = freeRAM();
stat_mutex.lock();
stat = tstat;
stat.makeStrings();
stat_mutex.unlock();
}
void PISystemMonitor::gatherThread(llong id) {
PISystemMonitor::ThreadStats ts;
ts.id = id;
#ifdef FREERTOS
ts.name = tbid.value(id, "<PIThread>");
#else
ts.name = tbid.value(id, "<non-PIThread>");
# ifndef WINDOWS
PIFile f(PRIVATE->proc_dir + "task/" + PIString::fromNumber(id) + "/stat");
//piCout << f.path();
if (!f.open(PIIODevice::ReadOnly))
return;
PIString str = f.readAll(true);
int si = str.find('(') + 1, fi = 0, cc = 1;
for (int i = si; i < str.size_s(); ++i) {
if (str[i] == '(') cc++;
if (str[i] == ')') cc--;
if (cc <= 0) {
fi = i;
break;
}
}
str.cutMid(si - 1, fi - si + 3);
PIStringList sl = str.split(" ");
if (sl.size_s() < 14) return;
//piCout << sl[0] << sl[12] << sl[13];
ts.user_time = PISystemTime::fromMilliseconds(sl[12].toInt() * 10.);
ts.kernel_time = PISystemTime::fromMilliseconds(sl[13].toInt() * 10.);
# else
PISystemTime ct = PISystemTime::current();
FILETIME times[4];
HANDLE thdl = OpenThread(THREAD_QUERY_INFORMATION, FALSE, DWORD(id));
if (thdl == NULL) {
piCout << "[PISystemMonitor] gatherThread(" << id << "):: OpenThread() error:" << errorString();
return;
}
if (GetThreadTimes(thdl, &(times[0]), &(times[1]), &(times[2]), &(times[3])) == 0) {
piCout << "[PISystemMonitor] gatherThread(" << id << "):: GetThreadTimes() error:" << errorString();
return;
}
CloseHandle(thdl);
ts.created = FILETIME2PIDateTime(times[0]);
ts.work_time = ct - ts.created.toSystemTime();
ts.kernel_time = FILETIME2PISystemTime(times[2]);
ts.user_time = FILETIME2PISystemTime(times[3]);
# endif
#endif
cur_tm[id] = ts;
}
float PISystemMonitor::calcThreadUsage(PISystemTime & t_new, PISystemTime & t_old) {
if (delay_ <= 0) return -1.;
return piClampf(100. * ((t_new - t_old).toMilliseconds() / delay_), 0.f, 100.f);
}
ullong PISystemMonitor::totalRAM() {
#ifdef ESP_PLATFORM
multi_heap_info_t heap_info;
memset(&heap_info, 0, sizeof(multi_heap_info_t));
heap_caps_get_info(&heap_info, MALLOC_CAP_8BIT);
return heap_info.total_allocated_bytes + heap_info.total_free_bytes;
#endif
return 0;
}
ullong PISystemMonitor::freeRAM() {
#ifdef ESP_PLATFORM
multi_heap_info_t heap_info;
memset(&heap_info, 0, sizeof(multi_heap_info_t));
heap_caps_get_info(&heap_info, MALLOC_CAP_8BIT);
return heap_info.total_free_bytes;
#endif
return 0;
}
ullong PISystemMonitor::usedRAM() {
#ifdef ESP_PLATFORM
multi_heap_info_t heap_info;
memset(&heap_info, 0, sizeof(multi_heap_info_t));
heap_caps_get_info(&heap_info, MALLOC_CAP_8BIT);
return heap_info.total_allocated_bytes;
#endif
return 0;
}
PISystemMonitor::Pool * PISystemMonitor::Pool::instance() {
static Pool ret;
return &ret;
}
PISystemMonitor * PISystemMonitor::Pool::getByPID(int pID) {
PIMutexLocker _ml(mutex);
return sysmons.value(pID, 0);
}
void PISystemMonitor::Pool::add(PISystemMonitor * sm) {
PIMutexLocker _ml(mutex);
sysmons[sm->pID()] = sm;
}
void PISystemMonitor::Pool::remove(PISystemMonitor * sm) {
PIMutexLocker _ml(mutex);
sysmons.remove(sm->pID());
}
PIByteArray & operator <<(PIByteArray & s, const PISystemMonitor::ProcessStats & v) {
s << PIByteArray::RawData(&v, sizeof(PISystemMonitor::ProcessStatsFixed))
<< v.exec_name << v.state;
return s;
}
PIByteArray & operator >>(PIByteArray & s, PISystemMonitor::ProcessStats & v) {
s >> PIByteArray::RawData(&v, sizeof(PISystemMonitor::ProcessStatsFixed))
>> v.exec_name >> v.state;
v.makeStrings();
return s;
}
PIByteArray & operator <<(PIByteArray & s, const PISystemMonitor::ThreadStats & v) {
s << PIByteArray::RawData(&v, sizeof(PISystemMonitor::ThreadStatsFixed))
<< v.name << v.created;
return s;
}
PIByteArray & operator >>(PIByteArray & s, PISystemMonitor::ThreadStats & v) {
s >> PIByteArray::RawData(&v, sizeof(PISystemMonitor::ThreadStatsFixed))
>> v.name >> v.created;
return s;
}

View File

@@ -0,0 +1,144 @@
/*
PIP - Platform Independent Primitives
Process resource monitor
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 PISYSTEMMONITOR_H
#define PISYSTEMMONITOR_H
#include "pithread.h"
#include "pifile.h"
class PIP_EXPORT PISystemMonitor: public PIThread
{
PIOBJECT_SUBCLASS(PISystemMonitor, PIThread)
friend class PIIntrospectionServer;
public:
PISystemMonitor();
~PISystemMonitor();
#pragma pack(push, 1)
struct PIP_EXPORT ProcessStatsFixed {
ProcessStatsFixed();
int ID;
int parent_ID;
int group_ID;
int session_ID;
int priority;
int threads;
ullong physical_memsize;
ullong resident_memsize;
ullong share_memsize;
ullong virtual_memsize;
ullong data_memsize;
ullong ram_total;
ullong ram_free;
ullong ram_used;
float cpu_load_system;
float cpu_load_user;
};
struct PIP_EXPORT ThreadStatsFixed {
ThreadStatsFixed();
llong id;
PISystemTime work_time;
PISystemTime kernel_time;
PISystemTime user_time;
float cpu_load_kernel;
float cpu_load_user;
};
#pragma pack(pop)
struct PIP_EXPORT ProcessStats: ProcessStatsFixed {
void makeStrings();
PIString exec_name;
PIString state;
PIString physical_memsize_readable;
PIString resident_memsize_readable;
PIString share_memsize_readable;
PIString virtual_memsize_readable;
PIString data_memsize_readable;
};
struct PIP_EXPORT ThreadStats: ThreadStatsFixed {
PIString name;
PIDateTime created;
};
#ifndef FREERTOS
bool startOnProcess(int pID, int interval_ms = 1000);
#endif
bool startOnSelf(int interval_ms = 1000);
void stop();
int pID() const {return pID_;}
ProcessStats statistic() const;
PIVector<ThreadStats> threadsStatistic() const;
void setStatistic(const ProcessStats & s);
static ullong totalRAM();
static ullong freeRAM();
static ullong usedRAM();
private:
void run();
void gatherThread(llong id);
float calcThreadUsage(PISystemTime & t_new, PISystemTime & t_old);
ProcessStats stat;
PIVector<ThreadStats> cur_ts;
PIMap<llong, ThreadStats> last_tm, cur_tm;
PIMap<llong, PIString> tbid;
mutable PIMutex stat_mutex;
int pID_, page_size, cpu_count, cycle;
#ifndef FREERTOS
PRIVATE_DECLARATION(PIP_EXPORT)
#endif
class PIP_EXPORT Pool {
friend class PISystemMonitor;
public:
static Pool * instance();
PISystemMonitor * getByPID(int pID);
private:
void add(PISystemMonitor * sm);
void remove(PISystemMonitor * sm);
PIMap<int, PISystemMonitor*> sysmons;
PIMutex mutex;
};
};
inline PICout operator <<(PICout s, const PISystemMonitor::ThreadStats & v) {
s.setControl(0, true);
s << "ThreadInfo(\"" << v.name << "\", created " << v.created
<< ", work " << v.work_time.toMilliseconds() << " ms"
<< ", kernel " << v.kernel_time.toMilliseconds() << " ms"
<< ", user " << v.user_time.toMilliseconds() << " ms"
<< ")\n";
s.restoreControl();
return s;
}
PIP_EXPORT PIByteArray & operator <<(PIByteArray & s, const PISystemMonitor::ProcessStats & v);
PIP_EXPORT PIByteArray & operator >>(PIByteArray & s, PISystemMonitor::ProcessStats & v);
PIP_EXPORT PIByteArray & operator <<(PIByteArray & s, const PISystemMonitor::ThreadStats & v);
PIP_EXPORT PIByteArray & operator >>(PIByteArray & s, PISystemMonitor::ThreadStats & v);
#endif // PISYSTEMMONITOR_H

View File

@@ -0,0 +1,46 @@
/*
PIP - Platform Independent Primitives
System tests results (see system_test folder)
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 "pisystemtests.h"
#ifndef PIP_FREERTOS
# include "piconfig.h"
#endif
namespace PISystemTests {
long time_resolution_ns = 1;
long time_elapsed_ns = 0;
long usleep_offset_us = 60;
PISystemTestReader pisystestreader;
};
PISystemTests::PISystemTestReader::PISystemTestReader() {
#if !defined(WINDOWS) && !defined(FREERTOS)
PIConfig conf(PIStringAscii("/etc/pip.conf"), PIIODevice::ReadOnly);
time_resolution_ns = conf.getValue(PIStringAscii("time_resolution_ns"), 1).toLong();
time_elapsed_ns = conf.getValue(PIStringAscii("time_elapsed_ns"), 0).toLong();
usleep_offset_us = conf.getValue(PIStringAscii("usleep_offset_us"), 60).toLong();
#endif
}

View File

@@ -0,0 +1,38 @@
/*
PIP - Platform Independent Primitives
System tests results (see system_test folder)
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 PISYSTEMTESTS_H
#define PISYSTEMTESTS_H
#include "pibase.h"
namespace PISystemTests {
extern PIP_EXPORT long time_resolution_ns;
extern PIP_EXPORT long time_elapsed_ns;
extern PIP_EXPORT long usleep_offset_us;
class PIP_EXPORT PISystemTestReader {
public:
PISystemTestReader();
};
extern PIP_EXPORT PISystemTestReader pisystestreader;
}
#endif // PISYSTEMTESTS_H