diff --git a/main.cpp b/main.cpp index 7a09a0a5..29e5637c 100644 --- a/main.cpp +++ b/main.cpp @@ -6,7 +6,7 @@ #include "piethernet.h" #include "piintrospection.h" #include "pifile.h" -#include "piprocess.h" +#include "pisingleapplication.h" //struct MS { // //MS() {i = 0; f = 0.;} @@ -33,9 +33,13 @@ public: int main (int argc, char * argv[]) { - //PIProcess proc; - PIProcess::execIndependent("D:/orders/libs_build_win/pip/utils/system_daemon/pisd.exe", PIStringList() << "-d" << "-n" << "peer"); - piMSleep(1000); + PISingleApplication sa("app"); + if (!sa.isFirst()) + sa.sendMessage(PIString("message to first").toByteArray()); + else + piMSleep(5000); + //piCout << PIString(argv[1]).toInt(); + //sh.destroy(); //proc.terminate(); /*PIByteArray v = PIString("Mandfg;kjngel").toByteArray(); PIByteArray b64 = convertToBase64(v); diff --git a/src/io/pifile.h b/src/io/pifile.h index 55648c9e..a3125ca6 100755 --- a/src/io/pifile.h +++ b/src/io/pifile.h @@ -83,7 +83,7 @@ public: bool isHidden() const {return flags[Hidden];} }; - //! Constructs a file with path "path" nad open mode "type" + //! Constructs a file with path "path" and open mode "mode" explicit PIFile(const PIString & path, DeviceMode mode = ReadWrite); PIFile(const PIFile & other); diff --git a/src/io/piiomodule.h b/src/io/piiomodule.h index 6c0cb47c..106deb98 100644 --- a/src/io/piiomodule.h +++ b/src/io/piiomodule.h @@ -34,5 +34,6 @@ #include "pipacketextractor.h" #include "piprotocol.h" #include "piconnection.h" +#include "pisharedmemory.h" #endif // PIIOMODULE_H diff --git a/src/io/pisharedmemory.cpp b/src/io/pisharedmemory.cpp new file mode 100644 index 00000000..35aba568 --- /dev/null +++ b/src/io/pisharedmemory.cpp @@ -0,0 +1,240 @@ +/* + PIP - Platform Independent Primitives + File + Copyright (C) 2016 Ivan Pelipenko peri4ko@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "pisharedmemory.h" +#ifdef WINDOWS + +#endif +#if defined(QNX) || defined(ANDROID) + +#endif +#ifdef MAC_OS + +#endif +#ifdef LINUX +# include +# include +# include +#endif + + +/*! \class PISharedMemory + * \brief Shared memory + * + * \section PISharedMemory_sec0 Synopsis + * This class provide access to local file. You can manipulate + * binary content or use this class as text stream. To binary + * access there are function \a read(), \a write(), and many + * \a writeBinary() functions. For write variables to file in + * their text representation threr are many "<<" operators. + * + * \section PISharedMemory_sec1 Position + * Each opened file has a read/write position - logical position + * in the file content you read from or you write to. You can + * find out current position with function \a pos(). Function + * \a seek(llong position) move position to position "position", + * \a seekToBegin() move position to the begin of file, + * \a seekToEnd() move position to the end of file. + * + */ + +//REGISTER_DEVICE(PISharedMemory); + +PRIVATE_DEFINITION_START(PISharedMemory) + PIByteArray name; +#ifdef WINDOWS + HANDLE map; + void * data; +#endif +#ifdef LINUX + void * data; + bool owner; +#endif +PRIVATE_DEFINITION_END(PISharedMemory) + + +PISharedMemory::PISharedMemory(): PIIODevice() { + initPrivate(); + dsize = -1; +} + + +PISharedMemory::PISharedMemory(const PIString & shm_name, int size, PIIODevice::DeviceMode mode): PIIODevice(shm_name, mode) { + initPrivate(); + dsize = size; + if (!shm_name.isEmpty()) + open(); +} + + +PISharedMemory::PISharedMemory(const PISharedMemory & other) { + initPrivate(); + dsize = other.dsize; + setPath(other.path()); + mode_ = other.mode_; +} + + +bool PISharedMemory::openDevice() { + close(); +#ifdef WINDOWS + DWORD m = PAGE_READWRITE; + if (!isWriteable()) m = PAGE_READONLY; + PRIVATE->name = ("Global\\PIP_SHM_" + path()).toByteArray(); + PRIVATE->name.push_back(0); + PRIVATE->map = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, m, 0, (DWORD)dsize, (const char *)PRIVATE->name.data()); + if (!PRIVATE->map) { + piCoutObj << "CreateFileMapping error," << errorString(); + return false; + } + if (!isWriteable()) m = FILE_MAP_READ; + else m = FILE_MAP_ALL_ACCESS; + PRIVATE->data = MapViewOfFile(PRIVATE->map, m, 0, 0, dsize); + if (!PRIVATE->data) { + piCoutObj << "MapViewOfFile error," << errorString(); + CloseHandle(PRIVATE->map); + return false; + } + //piCout << PRIVATE->map << PRIVATE->data; +#endif +#ifdef LINUX + int m = O_RDWR; + if (!isWriteable()) m = O_RDONLY; + PRIVATE->name = ("/pip_shm_" + path()).toByteArray(); + PRIVATE->name.push_back(0); + int fd = shm_open((const char *)PRIVATE->name.data(), m, 0777); + //piCout << "try open" << PICoutManipulators::Hex << fd; + if (fd < 0) { + //piCoutObj << "shm_open error," << errorString(); + fd = shm_open((const char *)PRIVATE->name.data(), m | O_CREAT, 0777); + //piCout << "try create" << PICoutManipulators::Hex << (m | O_CREAT) << fd; + if (fd < 0) { + piCoutObj << "shm_open error," << errorString(); + return false; + } + PRIVATE->owner = true; + ftruncate(fd, dsize); + //piCout << "created" << fd; + } + m = PROT_WRITE; + if (!isWriteable()) m = PROT_READ; + PRIVATE->data = mmap(0, dsize, m, MAP_SHARED, fd, 0); + ::close(fd); + if (!PRIVATE->data) { + piCoutObj << "mmap error," << errorString(); + return false; + } + //piCout << "opened" << PRIVATE->data; +#endif + return true; +} + + +bool PISharedMemory::closeDevice() { +#ifdef WINDOWS + if (PRIVATE->data) UnmapViewOfFile(PRIVATE->data); + if (PRIVATE->map) CloseHandle(PRIVATE->map); +#endif +#ifdef LINUX + //piCout << "close" << PIString(PRIVATE->name) << PRIVATE->data; + if (PRIVATE->data) munmap(PRIVATE->data, dsize); + if (PRIVATE->owner) { + //if (!PRIVATE->name.isEmpty()) { + //piCout << "unlink" << PIString(PRIVATE->name); + shm_unlink((const char *)PRIVATE->name.data()); + } + //if (fd > 0) +#endif + initPrivate(); + return true; +} + + +void PISharedMemory::initPrivate() { +#ifdef WINDOWS + PRIVATE->map = 0; + PRIVATE->data = 0; +#endif +#ifdef LINUX + PRIVATE->data = 0; + PRIVATE->owner = false; +#endif +} + + +PIByteArray PISharedMemory::readAll() { + if (dsize <= 0) return PIByteArray(); +#ifdef WINDOWS + if (!PRIVATE->data) return PIByteArray(); +#endif +#ifdef LINUX + if (!PRIVATE->data) return PIByteArray(); +#endif + PIByteArray a(dsize); + read(a.data(), a.size_s()); + /*llong cp = pos(); + if (forceRead) { + seekToBegin(); + while (!isEnd()) + a.push_back(readChar()); + seek(cp); + return a; + } + llong s = size(); + if (s < 0) return a; + a.resize(s); + s = readAll(a.data()); + seek(cp); + if (s >= 0) a.resize(s);*/ + return a; +} + + +llong PISharedMemory::size() const { + if (isClosed()) return -1; + return dsize; +} + + +int PISharedMemory::read(void * read_to, int max_size) { +#ifdef WINDOWS + if (!PRIVATE->data) return -1; + CopyMemory(read_to, PRIVATE->data, max_size); + return max_size; +#endif +#ifdef LINUX + if (!PRIVATE->data) return -1; + memcpy(read_to, PRIVATE->data, max_size); + return max_size; +#endif +} + + +int PISharedMemory::write(const void * data, int max_size) { +#ifdef WINDOWS + if (!PRIVATE->data) return -1; + CopyMemory(PRIVATE->data, data, max_size); + return max_size; +#endif +#ifdef LINUX + if (!PRIVATE->data) return -1; + memcpy(PRIVATE->data, data, max_size); + return max_size; +#endif +} diff --git a/src/io/pisharedmemory.h b/src/io/pisharedmemory.h new file mode 100644 index 00000000..b26c1e5f --- /dev/null +++ b/src/io/pisharedmemory.h @@ -0,0 +1,76 @@ +/*! \file pisharedmemory.h + * \brief Shared memory +*/ +/* + PIP - Platform Independent Primitives + Shared Memory + Copyright (C) 2016 Ivan Pelipenko peri4ko@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef PISHAREDMEMORY_H +#define PISHAREDMEMORY_H + +#include "piiodevice.h" + + +class PIP_EXPORT PISharedMemory: public PIIODevice +{ + PIIODEVICE(PISharedMemory) +public: + + explicit PISharedMemory(); + + //! Constructs a shared memory object with name "shm_name", size "size" and open mode "mode" + explicit PISharedMemory(const PIString & shm_name, int size, DeviceMode mode = ReadWrite); + + PISharedMemory(const PISharedMemory & other); + + virtual ~PISharedMemory() {close();} + + //! Read all shared memory object content to byte array and return it + PIByteArray readAll(); + + //! Returns shared memory object size + llong size() const; + + //! Returns if shared memory object is empty + bool isEmpty() const {return (size() <= 0);} + + //! Read from shared memory object to "read_to" no more than "max_size" and return readed bytes count + int read(void * read_to, int max_size); + + //! Write to shared memory object "data" with size "max_size" and return written bytes count + int write(const void * data, int max_size); + + //! Write "data" to shared memory object + int write(const PIByteArray & data) {return write(data.data(), data.size_s());} + + +protected: + bool openDevice(); + bool closeDevice(); + +private: + void initPrivate(); + + int dsize; + PRIVATE_DECLARATION + + +}; + + +#endif // PISHAREDMEMORY_H diff --git a/src/system/pisingleapplication.cpp b/src/system/pisingleapplication.cpp new file mode 100644 index 00000000..bedfb12e --- /dev/null +++ b/src/system/pisingleapplication.cpp @@ -0,0 +1,104 @@ +/* + PIP - Platform Independent Primitives + Single application + Copyright (C) 2016 Ivan Pelipenko peri4ko@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#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 << int(1) << m; + shm->write(ba); +} + + +void PISingleApplication::begin() { + int cnt[2] = {0, 0}; + for (int i = 0; i < 5; ++i) { + cnt[1] = cnt[0]; + shm->read(cnt, 4); + if (cnt[0] != cnt[1]) { + first = false; + break; + } + piMSleep(100); + } + //piCoutObj << "started" << first << shm->size(); + readed.reserve(shm->size()); + started = true; +} + + +void PISingleApplication::run() { + if (!first) return; + ++sacnt; + shm->write(&sacnt, 4); + //piCoutObj << "write" << sacnt; + readed = shm->readAll(); + int t(0), nm(0); + readed >> t >> nm; + if (nm != 0) { + PIByteArray msg; + readed >> msg; + if (!msg.isEmpty()) { + messageReceived(msg); + //piCoutObj << "message" << msg; + } + int wi[2] = {sacnt, 0}; + shm->write(wi, 8); + } +} + + +void PISingleApplication::waitFirst() const { + while (!started) + piMSleep(50); +} diff --git a/src/system/pisingleapplication.h b/src/system/pisingleapplication.h new file mode 100644 index 00000000..80f45673 --- /dev/null +++ b/src/system/pisingleapplication.h @@ -0,0 +1,51 @@ +/* + PIP - Platform Independent Primitives + Single application + Copyright (C) 2016 Ivan Pelipenko peri4ko@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef PISINGLEAPPLICATION_H +#define PISINGLEAPPLICATION_H + +#include "pithread.h" + +class PISharedMemory; + +class PIP_EXPORT PISingleApplication: protected 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 diff --git a/src/system/pisystemmodule.h b/src/system/pisystemmodule.h index e84a8753..01a9f154 100644 --- a/src/system/pisystemmodule.h +++ b/src/system/pisystemmodule.h @@ -27,5 +27,6 @@ #include "pisysteminfo.h" #include "pisystemtests.h" #include "pisystemmonitor.h" +#include "pisingleapplication.h" #endif // PISYSTEMMODULE_H diff --git a/utils/system_daemon/main.cpp b/utils/system_daemon/main.cpp index 379bb69c..09d86395 100755 --- a/utils/system_daemon/main.cpp +++ b/utils/system_daemon/main.cpp @@ -17,10 +17,11 @@ along with this program. If not, see . */ -#include "picli.h" +#include "pisingleapplication.h" #include "pisystemmonitor.h" #include "pisysteminfo.h" #include "piprocess.h" +#include "picli.h" #include "file_manager.h" #include "daemon.h" #include "shared.h" @@ -285,14 +286,24 @@ int main(int argc, char * argv[]) { cli.addArgument("help"); cli.addArgument("daemon"); cli.addArgument("force"); + cli.addArgument("1"); cli.addArgument("name", true); if (cli.hasArgument("help")) { usage(); return 0; } PIString name = cli.argumentValue("name"); + PISingleApplication * sapp = 0; + if (cli.hasArgument("1") && !cli.hasArgument("force")) { + sapp = new PISingleApplication("pisd"); + if (!sapp->isFirst()) { + piCout << "Another pisd is running, exit"; + return 0; + } + } if (cli.hasArgument("daemon")) { PIStringList args; + args << "-1"; if (cli.hasArgument("force")) args << "-f"; if (!name.isEmpty()) @@ -314,5 +325,6 @@ int main(int argc, char * argv[]) { delete menu; delete daemon; delete screen; + if (sapp) delete sapp; return 0; } diff --git a/utils/system_daemon/shared.cpp b/utils/system_daemon/shared.cpp index 28cd99ac..165ccf33 100644 --- a/utils/system_daemon/shared.cpp +++ b/utils/system_daemon/shared.cpp @@ -1,7 +1,7 @@ #include "shared.h" #include "picrypt.h" -extern PIScreen screen; +extern PIScreen * screen; class DlgWatcher: public PIThread { @@ -56,9 +56,9 @@ PIString askUserInput(const PIString & desc) { dlg.addTile(input); dlg.addTile(btns); DlgWatcher w; - CONNECTU(&screen, keyPressed, &w, keyPressed) - CONNECTU(&screen, tileEvent, &w, tileEvent) - screen.setDialogTile(&dlg); + CONNECTU(screen, keyPressed, &w, keyPressed) + CONNECTU(screen, tileEvent, &w, tileEvent) + screen->setDialogTile(&dlg); while (!w.close) { PIKbdListener::instance()->readKeyboard(); piMSleep(10); @@ -83,9 +83,9 @@ bool askQuestion(const PIString & t) { dlg.addTile(lbl); dlg.addTile(btns); DlgWatcher w; - CONNECTU(&screen, keyPressed, &w, keyPressed) - CONNECTU(&screen, tileEvent, &w, tileEvent) - screen.setDialogTile(&dlg); + CONNECTU(screen, keyPressed, &w, keyPressed) + CONNECTU(screen, tileEvent, &w, tileEvent) + screen->setDialogTile(&dlg); while (!w.close) { PIKbdListener::instance()->readKeyboard(); piMSleep(10); @@ -108,9 +108,9 @@ void showInfo(const PIString & t) { dlg.addTile(lbl); dlg.addTile(btns); DlgWatcher w; - CONNECTU(&screen, keyPressed, &w, keyPressed) - CONNECTU(&screen, tileEvent, &w, tileEvent) - screen.setDialogTile(&dlg); + CONNECTU(screen, keyPressed, &w, keyPressed) + CONNECTU(screen, tileEvent, &w, tileEvent) + screen->setDialogTile(&dlg); while (!w.close) { PIKbdListener::instance()->readKeyboard(); piMSleep(10);