Add ProcessRunner and PIDFile (#4225)

* feat(Foundation): PIDFile and ProcessRunner #4064
* feat(Thread): optional signal blocking on POSIX #2978
* fix(ProcessRunner):remove logger, code enhancement #4225
* feat(Foundation): add PIDFile and ProcessRunner Tests #4064
* fix(Foundation): failing ProcessRunner Test #4064
* fix(PIDFile): remove append argument #4064
* remove Windows TODO from ProcessRunner #4064
* feat(ProcessRunnerTest): add line to checkTimeout #4064
* fix(ProcessRunner): add done flag to run() #4064
* fix(ProcessRunnerTest): add missing pidFile argument #4064
* chore(ProcessRunner): remove comments #4064
* fix(ProcessRunner): add runCount flag #4064
* fix(test): SharedLibrary and Class tests paths
* fix(ProcessRunner): thread sanitizer reported data races #4064
* fix(build): pass env var to testrunner #4064
* chore(PIDFile): remove ; in comments #4064
* feat(ProcessRunner): add Win argument format #4064
* fix(Tests): add ProcessRunnerTest to vcxproj #4064
* fix(Tests): change path to TestApp #4064
* feat(Tests): windows processrunner tests #4064
* fix(Tests): duplicate  ProcessRunnerTest in TestSuite vcxproj  #4064
* fix(CodeQL): sw declaration hides variable  #4064
* fix test binaries path for cmake
* fix(Build): missing include/PIDFile.h buildWin #4064
* fix(Build): add PocoFoundation depend in buildWin #4064
* feat(ProcessRunner): test process launching multiple threads #2976

---------

Co-authored-by: Pavle <pavle@debian-gnu-linux-11.localdomain>
Co-authored-by: Alex Fabijanic <alex@pocoproject.org>
This commit is contained in:
Pavle Dragisic 2023-11-24 20:22:01 +01:00 committed by GitHub
parent 904075e1f1
commit 70bb3a40de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 1469 additions and 95 deletions

View File

@ -11,7 +11,7 @@
#ifdef Data_API
#define SQLParser_API Data_API
#ifdef Data_EXPORTS
#if defined(Data_EXPORTS) && !defined(SQLParser_EXPORTS)
#define SQLParser_EXPORTS
#endif
#else

View File

@ -1093,6 +1093,7 @@
</ClCompile>
<ClCompile Include="src\pcre2_valid_utf.c" />
<ClCompile Include="src\pcre2_xclass.c" />
<ClCompile Include="src\PIDFile.cpp" />
<ClCompile Include="src\Pipe.cpp" />
<ClCompile Include="src\PipeImpl.cpp" />
<ClCompile Include="src\PipeImpl_DUMMY.cpp">
@ -1168,6 +1169,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release_static_mt|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release_static_mt|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="src\ProcessRunner.cpp" />
<ClCompile Include="src\PurgeStrategy.cpp" />
<ClCompile Include="src\Random.cpp" />
<ClCompile Include="src\RandomStream.cpp" />
@ -1655,6 +1657,7 @@
<ClInclude Include="include\Poco\Path_WIN32U.h" />
<ClInclude Include="include\Poco\PatternFormatter.h" />
<ClInclude Include="include\Poco\PBKDF2Engine.h" />
<ClInclude Include="include\Poco\PIDFile.h" />
<ClInclude Include="include\Poco\Pipe.h" />
<ClInclude Include="include\Poco\PipeImpl.h" />
<ClInclude Include="include\Poco\PipeImpl_DUMMY.h" />
@ -1673,6 +1676,7 @@
<ClInclude Include="include\Poco\Process.h" />
<ClInclude Include="include\Poco\Process_UNIX.h" />
<ClInclude Include="include\Poco\Process_WIN32U.h" />
<ClInclude Include="include\Poco\ProcessRunner.h" />
<ClInclude Include="include\Poco\PurgeStrategy.h" />
<ClInclude Include="include\Poco\Random.h" />
<ClInclude Include="include\Poco\RandomStream.h" />

View File

@ -642,6 +642,9 @@
<ClCompile Include="src\NamedMutex_WIN32U.cpp">
<Filter>Processes\Source Files</Filter>
</ClCompile>
<ClCompile Include="src\PIDFile.cpp">
<Filter>Processes\Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Pipe.cpp">
<Filter>Processes\Source Files</Filter>
</ClCompile>
@ -669,6 +672,9 @@
<ClCompile Include="src\Process_WIN32U.cpp">
<Filter>Processes\Source Files</Filter>
</ClCompile>
<ClCompile Include="src\ProcessRunner.cpp">
<Filter>Processes\Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SharedMemory.cpp">
<Filter>Processes\Source Files</Filter>
</ClCompile>
@ -1514,6 +1520,9 @@
<ClInclude Include="include\Poco\NamedMutex_WIN32U.h">
<Filter>Processes\Header Files</Filter>
</ClInclude>
<ClInclude Include="include\Poco\PIDFile.h">
<Filter>Processes\Header Files</Filter>
</ClInclude>
<ClInclude Include="include\Poco\Pipe.h">
<Filter>Processes\Header Files</Filter>
</ClInclude>
@ -1541,6 +1550,9 @@
<ClInclude Include="include\Poco\Process_WIN32U.h">
<Filter>Processes\Header Files</Filter>
</ClInclude>
<ClInclude Include="include\Poco\ProcessRunner.h">
<Filter>Processes\Header Files</Filter>
</ClInclude>
<ClInclude Include="include\Poco\SharedMemory.h">
<Filter>Processes\Header Files</Filter>
</ClInclude>

View File

@ -1093,6 +1093,7 @@
</ClCompile>
<ClCompile Include="src\pcre2_valid_utf.c" />
<ClCompile Include="src\pcre2_xclass.c" />
<ClCompile Include="src\PIDFile.cpp" />
<ClCompile Include="src\Pipe.cpp" />
<ClCompile Include="src\PipeImpl.cpp" />
<ClCompile Include="src\PipeImpl_DUMMY.cpp">
@ -1168,6 +1169,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release_static_mt|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release_static_mt|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="src\ProcessRunner.cpp" />
<ClCompile Include="src\PurgeStrategy.cpp" />
<ClCompile Include="src\Random.cpp" />
<ClCompile Include="src\RandomStream.cpp" />
@ -1655,6 +1657,7 @@
<ClInclude Include="include\Poco\Path_WIN32U.h" />
<ClInclude Include="include\Poco\PatternFormatter.h" />
<ClInclude Include="include\Poco\PBKDF2Engine.h" />
<ClInclude Include="include\Poco\PIDFile.h" />
<ClInclude Include="include\Poco\Pipe.h" />
<ClInclude Include="include\Poco\PipeImpl.h" />
<ClInclude Include="include\Poco\PipeImpl_DUMMY.h" />
@ -1673,6 +1676,7 @@
<ClInclude Include="include\Poco\Process.h" />
<ClInclude Include="include\Poco\Process_UNIX.h" />
<ClInclude Include="include\Poco\Process_WIN32U.h" />
<ClInclude Include="include\Poco\ProcessRunner.h" />
<ClInclude Include="include\Poco\PurgeStrategy.h" />
<ClInclude Include="include\Poco\Random.h" />
<ClInclude Include="include\Poco\RandomStream.h" />

View File

@ -642,6 +642,9 @@
<ClCompile Include="src\NamedMutex_WIN32U.cpp">
<Filter>Processes\Source Files</Filter>
</ClCompile>
<ClCompile Include="src\PIDFile.cpp">
<Filter>Processes\Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Pipe.cpp">
<Filter>Processes\Source Files</Filter>
</ClCompile>
@ -669,6 +672,9 @@
<ClCompile Include="src\Process_WIN32U.cpp">
<Filter>Processes\Source Files</Filter>
</ClCompile>
<ClCompile Include="src\ProcessRunner.cpp">
<Filter>Processes\Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SharedMemory.cpp">
<Filter>Processes\Source Files</Filter>
</ClCompile>
@ -1514,6 +1520,9 @@
<ClInclude Include="include\Poco\NamedMutex_WIN32U.h">
<Filter>Processes\Header Files</Filter>
</ClInclude>
<ClInclude Include="include\Poco\PIDFile.h">
<Filter>Processes\Header Files</Filter>
</ClInclude>
<ClInclude Include="include\Poco\Pipe.h">
<Filter>Processes\Header Files</Filter>
</ClInclude>
@ -1541,6 +1550,9 @@
<ClInclude Include="include\Poco\Process_WIN32U.h">
<Filter>Processes\Header Files</Filter>
</ClInclude>
<ClInclude Include="include\Poco\ProcessRunner.h">
<Filter>Processes\Header Files</Filter>
</ClInclude>
<ClInclude Include="include\Poco\SharedMemory.h">
<Filter>Processes\Header Files</Filter>
</ClInclude>

View File

@ -1099,6 +1099,7 @@
</ClCompile>
<ClCompile Include="src\pcre2_valid_utf.c" />
<ClCompile Include="src\pcre2_xclass.c" />
<ClCompile Include="src\PIDFile.cpp" />
<ClCompile Include="src\Pipe.cpp" />
<ClCompile Include="src\PipeImpl.cpp" />
<ClCompile Include="src\PipeImpl_DUMMY.cpp">
@ -1174,6 +1175,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release_static_mt|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release_static_mt|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="src\ProcessRunner.cpp" />
<ClCompile Include="src\PurgeStrategy.cpp" />
<ClCompile Include="src\Random.cpp" />
<ClCompile Include="src\RandomStream.cpp" />
@ -1661,6 +1663,7 @@
<ClInclude Include="include\Poco\Path_WIN32U.h" />
<ClInclude Include="include\Poco\PatternFormatter.h" />
<ClInclude Include="include\Poco\PBKDF2Engine.h" />
<ClInclude Include="include\Poco\PIDFile.h" />
<ClInclude Include="include\Poco\Pipe.h" />
<ClInclude Include="include\Poco\PipeImpl.h" />
<ClInclude Include="include\Poco\PipeImpl_DUMMY.h" />
@ -1679,6 +1682,7 @@
<ClInclude Include="include\Poco\Process.h" />
<ClInclude Include="include\Poco\Process_UNIX.h" />
<ClInclude Include="include\Poco\Process_WIN32U.h" />
<ClInclude Include="include\Poco\ProcessRunner.h" />
<ClInclude Include="include\Poco\PurgeStrategy.h" />
<ClInclude Include="include\Poco\Random.h" />
<ClInclude Include="include\Poco\RandomStream.h" />

View File

@ -642,6 +642,9 @@
<ClCompile Include="src\NamedMutex_WIN32U.cpp">
<Filter>Processes\Source Files</Filter>
</ClCompile>
<ClCompile Include="src\PIDFile.cpp">
<Filter>Processes\Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Pipe.cpp">
<Filter>Processes\Source Files</Filter>
</ClCompile>
@ -669,6 +672,9 @@
<ClCompile Include="src\Process_WIN32U.cpp">
<Filter>Processes\Source Files</Filter>
</ClCompile>
<ClCompile Include="src\ProcessRunner.cpp">
<Filter>Processes\Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SharedMemory.cpp">
<Filter>Processes\Source Files</Filter>
</ClCompile>
@ -1514,6 +1520,9 @@
<ClInclude Include="include\Poco\NamedMutex_WIN32U.h">
<Filter>Processes\Header Files</Filter>
</ClInclude>
<ClInclude Include="include\Poco\PIDFile.h">
<Filter>Processes\Header Files</Filter>
</ClInclude>
<ClInclude Include="include\Poco\Pipe.h">
<Filter>Processes\Header Files</Filter>
</ClInclude>
@ -1541,6 +1550,9 @@
<ClInclude Include="include\Poco\Process_WIN32U.h">
<Filter>Processes\Header Files</Filter>
</ClInclude>
<ClInclude Include="include\Poco\ProcessRunner.h">
<Filter>Processes\Header Files</Filter>
</ClInclude>
<ClInclude Include="include\Poco\SharedMemory.h">
<Filter>Processes\Header Files</Filter>
</ClInclude>

View File

@ -1550,6 +1550,7 @@
</ClCompile>
<ClCompile Include="src\pcre2_valid_utf.c" />
<ClCompile Include="src\pcre2_xclass.c" />
<ClCompile Include="src\PIDFile.cpp" />
<ClCompile Include="src\Pipe.cpp" />
<ClCompile Include="src\PipeImpl.cpp" />
<ClCompile Include="src\PipeImpl_DUMMY.cpp">
@ -1655,6 +1656,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release_static_mt|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release_static_mt|ARM64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="src\ProcessRunner.cpp" />
<ClCompile Include="src\PurgeStrategy.cpp" />
<ClCompile Include="src\Random.cpp" />
<ClCompile Include="src\RandomStream.cpp" />
@ -2244,6 +2246,7 @@
<ClInclude Include="include\Poco\Path_WIN32U.h" />
<ClInclude Include="include\Poco\PatternFormatter.h" />
<ClInclude Include="include\Poco\PBKDF2Engine.h" />
<ClInclude Include="include\Poco\PIDFile.h" />
<ClInclude Include="include\Poco\Pipe.h" />
<ClInclude Include="include\Poco\PipeImpl.h" />
<ClInclude Include="include\Poco\PipeImpl_DUMMY.h" />
@ -2262,6 +2265,7 @@
<ClInclude Include="include\Poco\Process.h" />
<ClInclude Include="include\Poco\Process_UNIX.h" />
<ClInclude Include="include\Poco\Process_WIN32U.h" />
<ClInclude Include="include\Poco\ProcessRunner.h" />
<ClInclude Include="include\Poco\PurgeStrategy.h" />
<ClInclude Include="include\Poco\Random.h" />
<ClInclude Include="include\Poco\RandomStream.h" />

View File

@ -642,6 +642,9 @@
<ClCompile Include="src\NamedMutex_WIN32U.cpp">
<Filter>Processes\Source Files</Filter>
</ClCompile>
<ClCompile Include="src\PIDFile.cpp">
<Filter>Processes\Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Pipe.cpp">
<Filter>Processes\Source Files</Filter>
</ClCompile>
@ -669,6 +672,9 @@
<ClCompile Include="src\Process_WIN32U.cpp">
<Filter>Processes\Source Files</Filter>
</ClCompile>
<ClCompile Include="src\ProcessRunner.cpp">
<Filter>Processes\Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SharedMemory.cpp">
<Filter>Processes\Source Files</Filter>
</ClCompile>
@ -1514,6 +1520,9 @@
<ClInclude Include="include\Poco\NamedMutex_WIN32U.h">
<Filter>Processes\Header Files</Filter>
</ClInclude>
<ClInclude Include="include\Poco\PIDFile.h">
<Filter>Processes\Header Files</Filter>
</ClInclude>
<ClInclude Include="include\Poco\Pipe.h">
<Filter>Processes\Header Files</Filter>
</ClInclude>
@ -1541,6 +1550,9 @@
<ClInclude Include="include\Poco\Process_WIN32U.h">
<Filter>Processes\Header Files</Filter>
</ClInclude>
<ClInclude Include="include\Poco\ProcessRunner.h">
<Filter>Processes\Header Files</Filter>
</ClInclude>
<ClInclude Include="include\Poco\SharedMemory.h">
<Filter>Processes\Header Files</Filter>
</ClInclude>

View File

@ -19,7 +19,7 @@ objects = ArchiveStrategy Ascii ASCIIEncoding AsyncChannel ActiveThreadPool\
NestedDiagnosticContext Notification NotificationCenter \
NotificationQueue PriorityNotificationQueue TimedNotificationQueue \
NullStream NumberFormatter NumberParser NumericString AbstractObserver \
Path PatternFormatter Process PurgeStrategy RWLock Random RandomStream \
Path PatternFormatter PIDFile Process ProcessRunner PurgeStrategy RWLock Random RandomStream \
DirectoryIteratorStrategy RegularExpression RefCountedObject Runnable RotateStrategy \
SHA1Engine SHA2Engine Semaphore SharedLibrary SimpleFileChannel \
SignalHandler SplitterChannel SortedDirectoryIterator Stopwatch StreamChannel \

View File

@ -0,0 +1,101 @@
//
// PIDFile.h
//
// Library: Foundation
// Package: Processes
// Module: PIDFile
//
// Definition of the PIDFile class.
//
// Copyright (c) 2023, Applied Informatics Software Engineering GmbH.
// Aleph ONE Software Engineering d.o.o.,
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Foundation_PIDFile_INCLUDED
#define Foundation_PIDFile_INCLUDED
#include "Poco/Foundation.h"
#include <memory>
namespace Poco {
class Foundation_API PIDFile
/// A utility class, creating process ID file on
/// construction and deleting it on destruction.
{
public:
using Ptr = std::unique_ptr<PIDFile>;
static const int INVALID_PID = -1;
PIDFile();
/// Creates the PIDFile.
PIDFile(const std::string& fileName, bool write = true);
/// Creates the PIDFile.
/// If `fileName` is not empty, creates the PID file.
/// If `write` is true, the file is written.
~PIDFile();
/// Destroys the PIDFile.
/// If fileName is not empty, deletes the PID file.
const std::string& getName() const;
/// Returns the file name.
void setName(const std::string& fileName);
/// Sets the file name.
void create();
/// Creates the file and writes PID into it.
void destroy();
/// Deletes the PID file and invalidates the held PID.
int getPID() const;
/// Returns the PID.
bool exists() const;
/// Returns true if PID file exists and its content is
/// equal to the held PID.
static bool contains(const std::string& fileName, int pid);
/// Returns true if the `fileName` contains the given `pid`.
static std::string& getFileName(std::string& pidFile);
/// Returns the file name.
private:
std::string _fileName;
int _pid = INVALID_PID;
};
//
// inlines
//
inline const std::string& PIDFile::getName() const
{
return _fileName;
}
inline int PIDFile::getPID() const
{
return _pid;
}
} // namespace Poco
#endif // Foundation_ProcessRunner_INCLUDED

View File

@ -0,0 +1,199 @@
//
// ProcessRunner.h
//
// Library: Foundation
// Package: Processes
// Module: ProcessRunner
//
// Definition of the ProcessRunner class.
//
// Copyright (c) 2023, Applied Informatics Software Engineering GmbH.
// Aleph ONE Software Engineering d.o.o.,
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Foundation_ProcessRunner_INCLUDED
#define Foundation_ProcessRunner_INCLUDED
#include "Poco/Foundation.h"
#include "Poco/Process.h"
#include "Poco/ProcessOptions.h"
#include "Poco/Runnable.h"
#include "Poco/Thread.h"
#include "Poco/Format.h"
#include "Poco/Stopwatch.h"
#include <atomic>
#include <vector>
namespace Poco {
class Foundation_API ProcessRunner: public Poco::Runnable
/// ProcessRunner is a wrapper class for `Poco::ProcessHandle.
/// It starts and terminates a process with enabled or disabled (default)
/// `stdio` pipes, and optionally waits for process PID to be created before
/// returning control to the caller. The process is spawned from an
/// internal thread. Starting/stopping the process may block up to
/// a certain (configurable) period of time.
///
/// ProcessRunner can hold and control only one process at a time, which
/// can be started/stopped multiple times during the ProcessRunner lifetime.
{
public:
using Args = Poco::Process::Args;
using PID = Poco::ProcessHandle::PID;
static const int NO_OUT = Poco::PROCESS_CLOSE_STDOUT|Poco::PROCESS_CLOSE_STDERR;
/// Constant to prevent std out and err from being received from the process.
ProcessRunner(const std::string& cmd,
const Args& args,
const std::string& pidFile = "",
int options = NO_OUT,
int timeout = 10, /*seconds*/
bool startProcess = true,
const Args& pidArgFmt = pidArgFormat());
/// Creates the ProcessRunner.
///
/// If `pidFile` is not empty, the starting of the process waits
/// until the pid file has been updated with the new pid, and
/// the stopping of the process waits until the pid file is gone.
/// Waiting is terminated after timeout seconds.
///
/// If `pidFile` is empty and `pidArgFmt` is not empty, autodetect
/// of PID file from `args` is attempted; the default PID file
/// argument format corresponds to the one used by
/// `Poco::Util::Application`
///
/// The `options` are passed to the process, defaulting to
/// closed stdio output pipes.
///
/// The `timeout` in seconds determines how long the ProcessRunner
/// waits for the process to start; if PID file name is provided or
/// autodetected from arguments, ProcessRunner will wait until the file
/// exists and contains the process PID or timeout expires (in which
/// case a TimeoutException is thrown).
///
/// If `startProcess` is true, the process is started on object creation.
~ProcessRunner();
/// Destroys the ProcessRunner.
PID pid() const;
/// Returns the process PID.
const std::string& pidFile() const;
/// Returns the process PID filename.
/// Returns empty string when pid filename
/// is not specified at construction, either
/// explicitly, or implicitly through
/// command line argument.
bool running() const;
/// Returns true if process is running.
void start();
/// Starts the process and waits for it to be fully initialized.
/// Process initialization completion is indicated by a new pid in
/// the pid file (if specified at construction, otherwise there
/// is no wating for pid).
/// If pid file is not specified, there is no waiting.
///
/// Attempting to start a started process results in
/// Poco::InvalidAccessException being thrown.
void stop();
/// Stops the process.
///
/// Calling stop() on a stopped process is a no-op.
std::string cmdLine() const;
/// Returns process full command line.
int result() const;
/// Returns process return code.
int runCount() const;
/// Returns the number of times the process has been executed.
private:
static const Poco::ProcessHandle::PID INVALID_PID = -1;
static const int RESULT_UNKNOWN = -1;
static Args pidArgFormat()
{
#if defined(POCO_OS_FAMILY_WINDOWS)
return Args{"-p", "--pidfile=", "/p", "/pidfile="};
#else
return Args{"-p", "--pidfile="};
#endif
}
void run();
/// Starts the process and waits for it to be fully initialized.
/// Process initialization completion is indicated by new pid in
/// the pid file. If pid file is not specified, there is no waiting.
void checkTimeout(const Poco::Stopwatch& sw, const std::string& msg);
/// If timeout is exceeded, throws TimeoutException with `msg`
/// message.
Poco::Thread _t;
std::string _cmd;
Args _args;
std::atomic<PID> _pid;
std::string _pidFile;
int _options;
int _timeout;
std::atomic<Poco::ProcessHandle*> _pPH;
std::atomic<bool> _started;
std::atomic<int> _rc;
std::atomic<int> _runCount;
};
//
// inlines
//
inline const std::string& ProcessRunner::pidFile() const
{
return _pidFile;
}
inline bool ProcessRunner::running() const
{
return _pid != INVALID_PID;
}
inline ProcessRunner::PID ProcessRunner::pid() const
{
return _pid;
}
inline int ProcessRunner::result() const
{
return _rc;
}
inline int ProcessRunner::runCount() const
{
return _runCount;
}
} // namespace Poco
#endif // Foundation_ProcessRunner_INCLUDED

View File

@ -23,6 +23,7 @@
#include <unistd.h>
#include <vector>
#include <map>
#include <atomic>
namespace Poco {
@ -42,7 +43,7 @@ public:
int tryWait() const;
private:
pid_t _pid;
std::atomic<pid_t> _pid;
};

View File

@ -74,11 +74,23 @@ public:
POLICY_DEFAULT = POLICY_DEFAULT_IMPL
};
Thread();
Thread(uint32_t sigMask = 0);
/// Creates a thread. Call start() to start it.
///
/// The optional sigMask parameter specifies which signals should be blocked.
/// To block a specific signal, set the corresponding bit in the sigMask.
/// Multiple bits can be set in the mask to block multiple signals if needed.
///
/// Available on POSIX platforms only
Thread(const std::string& name);
Thread(const std::string& name, uint32_t sigMask = 0);
/// Creates a named thread. Call start() to start it.
///
/// The optional sigMask parameter specifies which signals should be blocked.
/// To block a specific signal, set the corresponding bit in the sigMask.
/// Multiple bits can be set in the mask to block multiple signals if needed.
///
/// Available on POSIX platforms only
~Thread();
/// Destroys the thread.

View File

@ -76,6 +76,7 @@ public:
static int getMaxOSPriorityImpl(int policy);
void setStackSizeImpl(int size);
int getStackSizeImpl() const;
void setSignalMaskImpl(uint32_t sigMask);
void startImpl(SharedPtr<Runnable> pTarget);
void joinImpl();
bool joinImpl(long milliseconds);

122
Foundation/src/PIDFile.cpp Normal file
View File

@ -0,0 +1,122 @@
//
// PIDFile.cpp
//
// Library: Foundation
// Package: Processes
// Module: PIDFile
//
// Copyright (c) 2023, Applied Informatics Software Engineering GmbH.
// Aleph ONE Software Engineering d.o.o.,
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/PIDFile.h"
#include "Poco/Path.h"
#include "Poco/File.h"
#include "Poco/Process.h"
#include "Poco/FileStream.h"
#include <fstream>
using Poco::Path;
using Poco::File;
using Poco::Process;
using Poco::FileInputStream;
using Poco::FileOutputStream;
namespace Poco {
PIDFile::PIDFile()
{
}
PIDFile::PIDFile(const std::string& fileName, bool write):
_fileName(fileName)
{
if (write) create();
}
PIDFile::~PIDFile()
{
destroy();
}
void PIDFile::setName(const std::string& fileName)
{
destroy();
_fileName = fileName;
create();
}
void PIDFile::create()
{
if (!_fileName.empty())
{
Path p(getFileName(_fileName));
if (!File(p.makeParent()).exists())
File(p).createDirectories();
_pid = static_cast<int>(Process::id());
FileOutputStream fos(_fileName);
fos << _pid; fos.close();
}
}
void PIDFile::destroy()
{
if (!_fileName.empty())
{
File f(_fileName);
if (f.exists()) f.remove();
_fileName.clear();
}
_pid = INVALID_PID;
}
bool PIDFile::exists() const
{
if (File(_fileName).exists())
{
FileInputStream fis(_fileName);
int fPID = 0;
if (fis.peek() != std::ifstream::traits_type::eof())
fis >> fPID;
return fPID == _pid;
}
return false;
}
bool PIDFile::contains(const std::string& fileName, int pid)
{
if (File(fileName).exists())
{
FileInputStream fis(fileName);
int fPID = 0;
if (fis.peek() != std::ifstream::traits_type::eof())
fis >> fPID;
return fPID == pid;
}
return false;
}
std::string& PIDFile::getFileName(std::string& pidFile)
{
Path p(pidFile);
pidFile = p.makeAbsolute().toString();
return pidFile;
}
} // namespace Poco

View File

@ -0,0 +1,217 @@
//
// ProcessRunner.cpp
//
// Library: Foundation
// Package: Processes
// Module: ProcessRunner
//
// Copyright (c) 2023, Applied Informatics Software Engineering GmbH.
// Aleph ONE Software Engineering d.o.o.,
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/ProcessRunner.h"
#include "Poco/PIDFile.h"
#include "Poco/FileStream.h"
#include "Poco/AutoPtr.h"
#include "Poco/File.h"
#include "Poco/Path.h"
#include "Poco/String.h"
#include <fstream>
using Poco::Thread;
using Poco::Process;
using Poco::ProcessHandle;
using Poco::FileInputStream;
using Poco::AutoPtr;
using Poco::File;
using Poco::Path;
using Poco::Stopwatch;
namespace Poco {
ProcessRunner::ProcessRunner(const std::string& cmd,
const Args& args,
const std::string& pidFile,
int options,
int timeout,
bool startProcess,
const Args& pidArgFmt): _cmd(cmd),
_args(args),
_pid(INVALID_PID),
_pidFile(pidFile),
_options(options),
_timeout(timeout),
_pPH(nullptr),
_started(false),
_rc(RESULT_UNKNOWN),
_runCount(0)
{
if (_pidFile.empty() && !_args.empty() && !pidArgFmt.empty())
{
for (const auto& fmt : pidArgFmt)
{
for (const auto& arg : _args)
{
std::string a = Poco::trim(arg);
std::size_t pos = a.find(fmt);
if (pos == 0)
{
_pidFile = a.substr(fmt.length());
PIDFile::getFileName(_pidFile);
break;
}
}
}
}
if (startProcess) start();
}
ProcessRunner::~ProcessRunner()
{
try
{
stop();
}
catch (...)
{
poco_unexpected();
}
}
std::string ProcessRunner::cmdLine() const
{
std::string cmdL = _cmd + ' ';
auto it = _args.begin();
auto end = _args.end();
for (; it != end;)
{
cmdL.append(*it);
if (++it == end) break;
cmdL.append(1, ' ');
}
return cmdL;
}
void ProcessRunner::run()
{
ProcessHandle* pPH = nullptr;
try
{
_pPH = pPH = new ProcessHandle(Process::launch(_cmd, _args, _options));
_pid = pPH->id();
_rc = pPH->wait();
}
catch (...)
{
}
_pid = INVALID_PID;
_pPH = nullptr;
++_runCount;
delete pPH;
}
void ProcessRunner::stop()
{
if (_started)
{
PID pid;
Stopwatch sw; sw.start();
if (_pPH.exchange(nullptr) && ((pid = _pid.exchange(INVALID_PID))) != INVALID_PID)
{
while (Process::isRunning(pid))
{
if (pid > 0)
{
Process::requestTermination(pid);
checkTimeout(sw, "Waiting for process termination");
}
else throw Poco::IllegalStateException("Invalid PID, can;t terminate process");
}
_t.join();
}
if (!_pidFile.empty())
{
if (!_pidFile.empty())
{
File pidFile(_pidFile);
_pidFile.clear();
std::string msg;
Poco::format(msg, "Waiting for PID file (pidFile: '%s')", _pidFile);
sw.restart();
while (pidFile.exists())
checkTimeout(sw, msg);
}
}
}
_started.store(false);
}
void ProcessRunner::checkTimeout(const Stopwatch& sw, const std::string& msg)
{
if (sw.elapsedSeconds() > _timeout)
{
throw Poco::TimeoutException(
Poco::format("ProcessRunner::checkTimeout(): %s", msg));
}
Thread::sleep(10);
}
void ProcessRunner::start()
{
if (!_started.exchange(true))
{
int prevRunCnt = runCount();
_t.start(*this);
std::string msg;
Poco::format(msg, "Waiting for process to start (pidFile: '%s')", _pidFile);
Stopwatch sw; sw.start();
// wait for the process to be either running or completed by monitoring run counts.
while (!running() && prevRunCnt >= runCount()) checkTimeout(sw, msg);
// we could wait for the process handle != INVALID_PID,
// but if pidFile name was given, we should wait for
// the process to write it
if (!_pidFile.empty())
{
sw.restart();
// wait until process is fully initialized
File pidFile(_pidFile);
while (!pidFile.exists())
checkTimeout(sw, "waiting for PID file");
// verify that the file content is actually the process PID
FileInputStream fis(_pidFile);
int fPID = 0;
if (fis.peek() != std::ifstream::traits_type::eof())
fis >> fPID;
while (fPID != pid())
{
fis.clear(); fis.seekg(0); fis >> fPID;
checkTimeout(sw, Poco::format("waiting for new PID (%s)", _pidFile));
}
}
}
else
throw Poco::InvalidAccessException("start() called on started ProcessRunner");
}
} // namespace Poco

View File

@ -88,21 +88,27 @@ private:
} // namespace
Thread::Thread():
Thread::Thread(uint32_t sigMask):
_id(uniqueId()),
_pTLS(0),
_event(true)
{
setNameImpl(makeName());
#if defined(POCO_OS_FAMILY_UNIX)
setSignalMaskImpl(sigMask);
#endif
}
Thread::Thread(const std::string& name):
Thread::Thread(const std::string& name, uint32_t sigMask):
_id(uniqueId()),
_pTLS(0),
_event(true)
{
setNameImpl(name);
#if defined(POCO_OS_FAMILY_UNIX)
setSignalMaskImpl(sigMask);
#endif
}

View File

@ -257,6 +257,21 @@ void ThreadImpl::setStackSizeImpl(int size)
}
void ThreadImpl::setSignalMaskImpl(uint32_t sigMask)
{
sigset_t sset;
sigemptyset(&sset);
for (int sig = 0; sig < sizeof(uint32_t) * 8; ++sig)
{
if ((sigMask & (1 << sig)) != 0)
sigaddset(&sset, sig);
}
pthread_sigmask(SIG_BLOCK, &sset, 0);
}
void ThreadImpl::startImpl(SharedPtr<Runnable> pTarget)
{
{

View File

@ -20,7 +20,7 @@ objects = ActiveMethodTest ActivityTest ActiveDispatcherTest \
NDCTest NotificationCenterTest NotificationQueueTest \
PriorityNotificationQueueTest TimedNotificationQueueTest \
NotificationsTestSuite NullStreamTest NumberFormatterTest \
NumberParserTest PathTest PatternFormatterTest PBKDF2EngineTest RWLockTest \
NumberParserTest PathTest PatternFormatterTest PBKDF2EngineTest ProcessRunnerTest RWLockTest \
RandomStreamTest RandomTest RegularExpressionTest SHA1EngineTest SHA2EngineTest \
SemaphoreTest ConditionTest SharedLibraryTest SharedLibraryTestSuite \
SimpleFileChannelTest StopwatchTest \

View File

@ -344,7 +344,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='debug_shared|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;WINVER=0x0500;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
@ -361,8 +361,9 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<AdditionalDependencies>ws2_32.lib;iphlpapi.lib;PocoFoundationd.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>bin\TestAppd.exe</OutputFile>
<AdditionalLibraryDirectories>..\..\..\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>..\..\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>bin\TestAppd.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
@ -372,7 +373,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='debug_shared|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;WINVER=0x0500;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
@ -388,8 +389,9 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<AdditionalDependencies>ws2_32.lib;iphlpapi.lib;PocoFoundationd.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>bin64\TestAppd.exe</OutputFile>
<AdditionalLibraryDirectories>..\..\..\lib64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>..\..\lib64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>bin64\TestAppd.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
@ -398,7 +400,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='debug_shared|ARM64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;WINVER=0x0500;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
@ -414,8 +416,9 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<AdditionalDependencies>ws2_32.lib;iphlpapi.lib;PocoFoundationd.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>binA64\TestAppd.exe</OutputFile>
<AdditionalLibraryDirectories>..\..\..\libA64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>..\..\libA64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>binA64\TestAppd.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
@ -428,7 +431,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;WINVER=0x0500;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
@ -445,8 +448,9 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<AdditionalDependencies>ws2_32.lib;iphlpapi.lib;PocoFoundation.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>bin\TestApp.exe</OutputFile>
<AdditionalLibraryDirectories>..\..\..\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>..\..\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>false</GenerateDebugInformation>
<ProgramDatabaseFile>
</ProgramDatabaseFile>
@ -463,7 +467,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;WINVER=0x0500;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
@ -480,8 +484,9 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<AdditionalDependencies>ws2_32.lib;iphlpapi.lib;PocoFoundation.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>bin64\TestApp.exe</OutputFile>
<AdditionalLibraryDirectories>..\..\..\lib64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>..\..\lib64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>false</GenerateDebugInformation>
<ProgramDatabaseFile>
</ProgramDatabaseFile>
@ -497,7 +502,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;WINVER=0x0500;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
@ -514,8 +519,9 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<AdditionalDependencies>ws2_32.lib;iphlpapi.lib;PocoFoundation.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>binA64\TestApp.exe</OutputFile>
<AdditionalLibraryDirectories>..\..\..\libA64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>..\..\libA64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>false</GenerateDebugInformation>
<ProgramDatabaseFile>
</ProgramDatabaseFile>
@ -531,7 +537,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
@ -548,8 +554,9 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<AdditionalDependencies>PocoFoundationmd.lib;winmm.lib;ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>bin\static_md\TestApp.exe</OutputFile>
<AdditionalLibraryDirectories>..\..\..\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>..\..\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>false</GenerateDebugInformation>
<ProgramDatabaseFile>
</ProgramDatabaseFile>
@ -566,7 +573,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
@ -583,8 +590,9 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<AdditionalDependencies>PocoFoundationmd.lib;winmm.lib;ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>bin64\static_md\TestApp.exe</OutputFile>
<AdditionalLibraryDirectories>..\..\..\lib64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>..\..\lib64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>false</GenerateDebugInformation>
<ProgramDatabaseFile>
</ProgramDatabaseFile>
@ -600,7 +608,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
@ -617,8 +625,9 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<AdditionalDependencies>PocoFoundationmd.lib;winmm.lib;ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>binA64\static_md\TestApp.exe</OutputFile>
<AdditionalLibraryDirectories>..\..\..\libA64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>..\..\libA64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>false</GenerateDebugInformation>
<ProgramDatabaseFile>
</ProgramDatabaseFile>
@ -630,7 +639,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='debug_static_md|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
@ -647,8 +656,9 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<AdditionalDependencies>PocoFoundationmdd.lib;winmm.lib;ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>bin\static_md\TestAppd.exe</OutputFile>
<AdditionalLibraryDirectories>..\..\..\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>..\..\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>bin\static_md\TestAppd.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
@ -658,7 +668,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='debug_static_md|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
@ -674,8 +684,9 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<AdditionalDependencies>PocoFoundationmdd.lib;winmm.lib;ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>bin64\static_md\TestAppd.exe</OutputFile>
<AdditionalLibraryDirectories>..\..\..\lib64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>..\..\lib64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>bin64\static_md\TestAppd.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
@ -684,7 +695,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='debug_static_md|ARM64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
@ -700,8 +711,9 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<AdditionalDependencies>PocoFoundationmdd.lib;winmm.lib;ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>binA64\static_md\TestAppd.exe</OutputFile>
<AdditionalLibraryDirectories>..\..\..\libA64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>..\..\libA64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>binA64\static_md\TestAppd.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
@ -710,7 +722,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='debug_static_mt|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
@ -727,8 +739,9 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<AdditionalDependencies>PocoFoundationmtd.lib;winmm.lib;ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>bin\static_mt\TestAppd.exe</OutputFile>
<AdditionalLibraryDirectories>..\..\..\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>..\..\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>bin\static_mt\TestAppd.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
@ -738,7 +751,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='debug_static_mt|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
@ -754,8 +767,9 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<AdditionalDependencies>PocoFoundationmtd.lib;winmm.lib;ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>bin64\static_mt\TestAppd.exe</OutputFile>
<AdditionalLibraryDirectories>..\..\..\lib64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>..\..\lib64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>bin64\static_mt\TestAppd.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
@ -764,7 +778,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='debug_static_mt|ARM64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
@ -780,8 +794,9 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<AdditionalDependencies>PocoFoundationmtd.lib;winmm.lib;ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>binA64\static_mt\TestAppd.exe</OutputFile>
<AdditionalLibraryDirectories>..\..\..\libA64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>..\..\libA64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>binA64\static_mt\TestAppd.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
@ -794,7 +809,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
@ -811,8 +826,9 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<AdditionalDependencies>PocoFoundationmt.lib;winmm.lib;ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>bin\static_mt\TestApp.exe</OutputFile>
<AdditionalLibraryDirectories>..\..\..\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>..\..\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>false</GenerateDebugInformation>
<ProgramDatabaseFile>
</ProgramDatabaseFile>
@ -829,7 +845,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
@ -846,8 +862,9 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<AdditionalDependencies>PocoFoundationmt.lib;winmm.lib;ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>bin64\static_mt\TestApp.exe</OutputFile>
<AdditionalLibraryDirectories>..\..\..\lib64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>..\..\lib64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>false</GenerateDebugInformation>
<ProgramDatabaseFile>
</ProgramDatabaseFile>
@ -863,7 +880,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;WINVER=0x0500;POCO_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
@ -880,8 +897,9 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<AdditionalDependencies>PocoFoundationmt.lib;winmm.lib;ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>binA64\static_mt\TestApp.exe</OutputFile>
<AdditionalLibraryDirectories>..\..\..\libA64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>..\..\libA64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>false</GenerateDebugInformation>
<ProgramDatabaseFile>
</ProgramDatabaseFile>

View File

@ -985,6 +985,7 @@
<ClCompile Include="src\PBKDF2EngineTest.cpp" />
<ClCompile Include="src\PriorityEventTest.cpp" />
<ClCompile Include="src\PriorityNotificationQueueTest.cpp" />
<ClCompile Include="src\ProcessRunnerTest.cpp" />
<ClCompile Include="src\ProcessesTestSuite.cpp" />
<ClCompile Include="src\ProcessTest.cpp" />
<ClCompile Include="src\RandomStreamTest.cpp" />
@ -1127,6 +1128,7 @@
<ClInclude Include="src\PBKDF2EngineTest.h" />
<ClInclude Include="src\PriorityEventTest.h" />
<ClInclude Include="src\PriorityNotificationQueueTest.h" />
<ClInclude Include="src\ProcessRunnerTest.h" />
<ClInclude Include="src\ProcessesTestSuite.h" />
<ClInclude Include="src\ProcessTest.h" />
<ClInclude Include="src\RandomStreamTest.h" />

View File

@ -519,6 +519,9 @@
<ClCompile Include="src\NamedMutexTest.cpp">
<Filter>Processes\Source Files</Filter>
</ClCompile>
<ClCompile Include="src\ProcessRunnerTest.cpp">
<Filter>Processes\Source Files</Filter>
</ClCompile>
<ClCompile Include="src\ProcessesTestSuite.cpp">
<Filter>Processes\Source Files</Filter>
</ClCompile>
@ -938,6 +941,9 @@
<ClInclude Include="src\NamedMutexTest.h">
<Filter>Processes\Header Files</Filter>
</ClInclude>
<ClInclude Include="src\ProcessRunnerTest.h">
<Filter>Processes\Header Files</Filter>
</ClInclude>
<ClInclude Include="src\ProcessesTestSuite.h">
<Filter>Processes\Header Files</Filter>
</ClInclude>

View File

@ -15,6 +15,8 @@
#include "Poco/Manifest.h"
#include "Poco/Exception.h"
#include "Poco/Path.h"
#include "Poco/File.h"
#include "Poco/Format.h"
#include "TestPlugin.h"
@ -24,6 +26,8 @@ using Poco::SharedLibrary;
using Poco::AbstractMetaObject;
using Poco::NotFoundException;
using Poco::InvalidAccessException;
using Poco::Path;
using Poco::File;
ClassLoaderTest::ClassLoaderTest(const std::string& name): CppUnit::TestCase(name)
@ -38,17 +42,14 @@ ClassLoaderTest::~ClassLoaderTest()
void ClassLoaderTest::testClassLoader1()
{
std::string path = "TestLibrary";
path.append(SharedLibrary::suffix());
Poco::Path libraryPath = Poco::Path::current();
libraryPath.append(path);
std::string libraryPath = getFullName("TestLibrary");
ClassLoader<TestPlugin> cl;
assertTrue (cl.begin() == cl.end());
assertNullPtr (cl.findClass("PluginA"));
assertNullPtr (cl.findManifest(libraryPath.toString()));
assertNullPtr (cl.findManifest(libraryPath));
assertTrue (!cl.isLibraryLoaded(libraryPath.toString()));
assertTrue (!cl.isLibraryLoaded(libraryPath));
try
{
@ -65,7 +66,7 @@ void ClassLoaderTest::testClassLoader1()
try
{
const ClassLoader<TestPlugin>::Manif& POCO_UNUSED manif = cl.manifestFor(libraryPath.toString());
const ClassLoader<TestPlugin>::Manif& POCO_UNUSED manif = cl.manifestFor(libraryPath);
fail("not found - must throw exception");
}
catch (NotFoundException&)
@ -80,25 +81,22 @@ void ClassLoaderTest::testClassLoader1()
void ClassLoaderTest::testClassLoader2()
{
std::string path = "TestLibrary";
path.append(SharedLibrary::suffix());
Poco::Path libraryPath = Poco::Path::current();
libraryPath.append(path);
std::string libraryPath = getFullName("TestLibrary");
ClassLoader<TestPlugin> cl;
cl.loadLibrary(libraryPath.toString());
cl.loadLibrary(libraryPath);
assertTrue (cl.begin() != cl.end());
assertNotNullPtr (cl.findClass("PluginA"));
assertNotNullPtr (cl.findClass("PluginB"));
assertNotNullPtr (cl.findClass("PluginC"));
assertNotNullPtr (cl.findManifest(libraryPath.toString()));
assertNotNullPtr (cl.findManifest(libraryPath));
assertTrue (cl.isLibraryLoaded(libraryPath.toString()));
assertTrue (cl.manifestFor(libraryPath.toString()).size() == 3);
assertTrue (cl.isLibraryLoaded(libraryPath));
assertTrue (cl.manifestFor(libraryPath).size() == 3);
ClassLoader<TestPlugin>::Iterator it = cl.begin();
assertTrue (it != cl.end());
assertTrue (it->first == libraryPath.toString());
assertTrue (it->first == libraryPath);
assertTrue (it->second->size() == 3);
++it;
assertTrue (it == cl.end());
@ -165,32 +163,55 @@ void ClassLoaderTest::testClassLoader2()
meta2.destroy(pPlugin);
assertTrue (!meta2.isAutoDelete(pPlugin));
cl.unloadLibrary(libraryPath.toString());
cl.unloadLibrary(libraryPath);
}
void ClassLoaderTest::testClassLoader3()
{
std::string path = "TestLibrary";
path.append(SharedLibrary::suffix());
Poco::Path libraryPath = Poco::Path::current();
libraryPath.append(path);
std::string libraryPath = getFullName("TestLibrary");
ClassLoader<TestPlugin> cl;
cl.loadLibrary(libraryPath.toString());
cl.loadLibrary(libraryPath.toString());
cl.unloadLibrary(libraryPath.toString());
cl.loadLibrary(libraryPath);
cl.loadLibrary(libraryPath);
cl.unloadLibrary(libraryPath);
assertTrue (cl.manifestFor(libraryPath.toString()).size() == 3);
assertTrue (cl.manifestFor(libraryPath).size() == 3);
ClassLoader<TestPlugin>::Iterator it = cl.begin();
assertTrue (it != cl.end());
assertTrue (it->first == libraryPath.toString());
assertTrue (it->first == libraryPath);
assertTrue (it->second->size() == 3);
++it;
assertTrue (it == cl.end());
cl.unloadLibrary(libraryPath.toString());
assertNullPtr (cl.findManifest(libraryPath.toString()));
cl.unloadLibrary(libraryPath);
assertNullPtr (cl.findManifest(libraryPath));
}
std::string ClassLoaderTest::getFullName(const std::string& libName)
{
std::string name = Path::expand("$POCO_BASE");
char c = Path::separator();
std::string OSNAME = Path::expand("$OSNAME");
std::string OSARCH = Path::expand("$OSARCH");
name.append(1, c)
.append(Poco::format("Foundation%ctestsuite%cbin%c", c, c, c))
.append(Poco::format("%s%c%s%c", OSNAME, c, OSARCH, c))
.append(libName).append(SharedLibrary::suffix());
// CMake
if (!File(name).exists())
{
name = Path::expand("$POCO_BASE");
name.append(Poco::format("%ccmake-build%cbin%c", c, c, c))
.append(libName).append(SharedLibrary::suffix());
}
if (!File(name).exists())
name = libName + SharedLibrary::suffix();
return name;
}

View File

@ -34,6 +34,7 @@ public:
static CppUnit::Test* suite();
private:
static std::string getFullName(const std::string& libName);
};

View File

@ -0,0 +1,348 @@
//
// ProcessRunnerTest.cpp
//
// Copyright (c) 2023, Applied Informatics Software Engineering GmbH.
// Aleph ONE Software Engineering d.o.o.,
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "ProcessRunnerTest.h"
#include "CppUnit/TestCaller.h"
#include "CppUnit/TestSuite.h"
#include "Poco/PIDFile.h"
#include "Poco/Format.h"
#include "Poco/Path.h"
#include "Poco/File.h"
#include "Poco/FileStream.h"
using namespace Poco;
ProcessRunnerTest::ProcessRunnerTest(const std::string& name):
CppUnit::TestCase(name)
{
}
ProcessRunnerTest::~ProcessRunnerTest()
{
}
void ProcessRunnerTest::testPIDFile()
{
std::string pidFile = Path::tempHome() + "test.pid";
{
PIDFile f;
assertTrue (f.getName().empty());
assertTrue (f.getPID() == PIDFile::INVALID_PID);
assertFalse (File(pidFile).exists());
f.setName(pidFile);
assertTrue (f.getName() == pidFile);
assertTrue (f.getPID() != PIDFile::INVALID_PID);
assertTrue (File(pidFile).exists());
}
assertFalse (File(pidFile).exists());
{
PIDFile f(pidFile);
std::string pf = pidFile;
assertTrue (f.getName() == pf);
assertTrue (File(pf).exists());
assertTrue (f.getPID() != PIDFile::INVALID_PID);
assertTrue (f.exists());
}
assertFalse (File(pidFile).exists());
{
PIDFile f(pidFile);
assertTrue (f.getName() == pidFile);
assertTrue (File(pidFile).exists());
assertTrue (f.getPID() != PIDFile::INVALID_PID);
assertTrue (f.exists());
}
assertFalse (File(pidFile).exists());
{
PIDFile f(pidFile, false);
std::string pf = pidFile;
assertTrue (f.getName() == pf);
assertTrue (!File(pf).exists());
assertTrue (f.getPID() == PIDFile::INVALID_PID);
f.create();
assertTrue (f.exists());
}
assertFalse (File(pidFile).exists());
}
void ProcessRunnerTest::testProcessRunner()
{
std::string name("TestApp");
std::string cmd;
#if defined(_DEBUG) && (POCO_OS != POCO_OS_ANDROID)
name += "d";
#endif
#if defined(POCO_OS_FAMILY_UNIX)
cmd += name;
#elif defined(_WIN32_WCE)
cmd = "\\";
cmd += name;
cmd += ".EXE";
#else
cmd = name;
#endif
// non-auto start, no PID
{
std::vector<std::string> args;
char c = Path::separator();
std::string pidFile = Poco::format("run%c%s.pid", c, name);
args.push_back(std::string("--pidfile=").append(pidFile));
ProcessRunner pr(cmd, args, "", ProcessRunner::NO_OUT, 10, false);
assertTrue (pr.cmdLine() == cmdLine(cmd, args));
assertFalse (pr.running());
pr.start();
Stopwatch sw; sw.start();
while (!pr.running())
checkTimeout(sw, "Waiting for process to start", 1000, __LINE__);
assertTrue (pr.running());
try
{
pr.start();
fail("It should not be possible to start a started process.");
}
catch(const Poco::InvalidAccessException&) {}
pr.stop();
sw.restart();
while (pr.running())
checkTimeout(sw, "Waiting for process to stop", 1000, __LINE__);
assertFalse (pr.running());
pr.start();
while (!pr.running())
checkTimeout(sw, "Waiting for process to start", 1000, __LINE__);
assertTrue (pr.running());
pr.stop();
pr.stop(); // second stop() should be silent no-op
}
// non-auto start with PID
{
std::vector<std::string> args;
char c = Path::separator();
std::string pidFile = Poco::format("run%c%s.pid", c, name);
args.push_back(std::string("--pidfile=").append(pidFile));
ProcessRunner pr(cmd, args, "", ProcessRunner::NO_OUT, 10, false);
assertTrue (pr.cmdLine() == cmdLine(cmd, args));
assertFalse (pr.running());
pr.start();
Stopwatch sw; sw.start();
while (!pr.running())
checkTimeout(sw, "Waiting for process to start", 1000, __LINE__);
assertTrue (pr.running());
try
{
pr.start();
fail("It should not be possible to start a started process.");
}
catch(const Poco::InvalidAccessException&) {}
pr.stop();
sw.restart();
while (pr.running())
checkTimeout(sw, "Waiting for process to stop", 1000, __LINE__);
assertFalse (pr.running());
pr.start();
while (!pr.running())
checkTimeout(sw, "Waiting for process to start", 1000, __LINE__);
assertTrue (pr.running());
pr.stop();
pr.stop(); // second stop() should be silent no-op
}
// autodetect PID file from the long command line argument
{
std::vector<std::string> args;
char c = Path::separator();
std::string pidFile = Poco::format("run%c%s.pid", c, name);
args.push_back(std::string("--pidfile=").append(pidFile));
{
ProcessRunner pr(cmd, args);
assertTrue (pr.cmdLine() == cmdLine(cmd, args));
assertTrue (pr.pidFile() == PIDFile::getFileName(pidFile));
assertTrue (File(pidFile).exists());
assertTrue (PIDFile::contains(pidFile, pr.pid()));
}
assertTrue (!File(pidFile).exists());
}
// autodetect PID file from the short command line argument
{
std::vector<std::string> args;
char c = Path::separator();
std::string pidFile = Poco::format("run%c%s.pid", c, name);
args.push_back(std::string("-p=").append(pidFile));
{
ProcessRunner pr(cmd, args, PIDFile::getFileName(pidFile));
assertTrue (pr.cmdLine() == cmdLine(cmd, args));
assertTrue (pr.pidFile() == pidFile);
assertTrue (File(pidFile).exists());
assertTrue (PIDFile::contains(pidFile, pr.pid()));
}
assertTrue (!File(pidFile).exists());
}
// ProcessRunner should NOT autodetect PID from command line args
// if argument formats list is empty
{
std::vector<std::string> args;
char c = Path::separator();
std::string pidFile = Poco::format("run%c%s.pid", c, name);
args.push_back(std::string("--pidfile=").append(pidFile));
{
ProcessRunner pr(cmd, args, "", ProcessRunner::NO_OUT, 10, true, {});
assertTrue (pr.cmdLine() == cmdLine(cmd, args));
assertTrue (pr.pidFile().empty()); // ProcessRunner has no PID file
PIDFile::getFileName(pidFile);
Stopwatch sw; sw.start();
while (!File(pidFile).exists())
checkTimeout(sw, "Waiting for PID file", 1000, __LINE__);
// PID file exists and is valid
assertTrue (File(pidFile).exists());
assertTrue (PIDFile::contains(pidFile, pr.pid()));
}
assertTrue (!File(pidFile).exists());
}
{
std::vector<std::string> args;
char c = Path::separator();
std::string pidFile = Poco::format("run%c%s.pid", c, name);
args.push_back(std::string("-p=").append(pidFile));
{
ProcessRunner pr(cmd, args, "", ProcessRunner::NO_OUT, 10, true, {});
assertTrue (pr.cmdLine() == cmdLine(cmd, args));
assertTrue (pr.pidFile().empty()); // ProcessRunner has no PID file
PIDFile::getFileName(pidFile);
Stopwatch sw; sw.start();
while (!File(pidFile).exists())
checkTimeout(sw, "Waiting for PID file", 1000, __LINE__);
// PID file exists and is valid
assertTrue (File(pidFile).exists());
assertTrue (PIDFile::contains(pidFile, pr.pid()));
}
assertTrue (!File(pidFile).exists());
}
// no PID file created at all
{
std::vector<std::string> args;
char c = Path::separator();
std::string pidFile = Poco::format("run%c%s.pid", c, name);
{
ProcessRunner pr(cmd, args);
assertTrue (pr.cmdLine() == cmdLine(cmd, args));
assertTrue (pr.pidFile().empty());
Thread::sleep(500);
assertTrue (!File(pidFile).exists());
assertTrue (!PIDFile::contains(pidFile, pr.pid()));
}
assertTrue (!File(pidFile).exists());
}
#if defined(POCO_OS_FAMILY_UNIX)
// start process launching multiple threads
{
std::vector<std::string> args;
char c = Path::separator();
std::string pidFile = Poco::format("run%c%s.pid", c, name);
args.push_back(std::string("--pidfile=").append(pidFile));
args.push_back(std::string("--launch-thread"));
ProcessRunner pr(cmd, args, "", ProcessRunner::NO_OUT, 10, false);
assertTrue (pr.cmdLine() == cmdLine(cmd, args));
assertFalse (pr.running());
pr.start();
Stopwatch sw; sw.start();
while (!pr.running())
checkTimeout(sw, "Waiting for process to start", 1000, __LINE__);
assertTrue (pr.running());
try
{
pr.start();
fail("It should not be possible to start a started process.");
}
catch(const Poco::InvalidAccessException&) {}
pr.stop();
sw.restart();
while (pr.running())
checkTimeout(sw, "Waiting for process to stop", 1000, __LINE__);
assertFalse (pr.running());
assertEqual (pr.result(), 0);
}
#endif
}
std::string ProcessRunnerTest::cmdLine(const std::string& cmd, const ProcessRunner::Args& args)
{
std::string cmdL = cmd + ' ';
auto it = args.begin();
auto end = args.end();
for (; it != end;)
{
cmdL.append(*it);
if (++it == end) break;
cmdL.append(1, ' ');
}
return cmdL;
}
void ProcessRunnerTest::checkTimeout(const Stopwatch& sw, const std::string& msg, int timeoutMS, int line)
{
if (sw.elapsedSeconds()*1000 > timeoutMS)
{
throw Poco::TimeoutException(
Poco::format("ProcessRunner::checkTimeout(): %s, line: %d", msg, line));
}
Thread::sleep(10);
}
void ProcessRunnerTest::setUp()
{
}
void ProcessRunnerTest::tearDown()
{
}
CppUnit::Test* ProcessRunnerTest::suite()
{
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("ProcessRunnerTest");
CppUnit_addTest(pSuite, ProcessRunnerTest, testPIDFile);
CppUnit_addTest(pSuite, ProcessRunnerTest, testProcessRunner);
return pSuite;
}

View File

@ -0,0 +1,44 @@
//
// ProcessRunnerTest.h
//
// Definition of the ProcessRunnerTest class.
//
// Copyright (c) 2023, Applied Informatics Software Engineering GmbH.
// Aleph ONE Software Engineering d.o.o.,
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef ProcessRunnerTest_INCLUDED
#define ProcessRunnerTest_INCLUDED
#include "CppUnit/TestCase.h"
#include "Poco/ProcessRunner.h"
#include "Poco/Stopwatch.h"
class ProcessRunnerTest: public CppUnit::TestCase
{
public:
ProcessRunnerTest(const std::string& name);
~ProcessRunnerTest();
void testPIDFile();
void testProcessRunner();
void setUp();
void tearDown();
static CppUnit::Test* suite();
private:
std::string cmdLine(const std::string& cmd, const Poco::ProcessRunner::Args& args);
void checkTimeout(const Poco::Stopwatch& sw, const std::string& msg, int timeoutMS, int line);
};
#endif // ProcessRunnerTest_INCLUDED

View File

@ -14,12 +14,15 @@
#include "Poco/Process.h"
#include "Poco/Pipe.h"
#include "Poco/PipeStream.h"
#include "Poco/Path.h"
#include "Poco/Format.h"
using namespace std::string_literals;
using Poco::Process;
using Poco::ProcessHandle;
using Poco::Pipe;
using Poco::Path;
using Poco::PipeInputStream;
using Poco::PipeOutputStream;

View File

@ -39,6 +39,7 @@ public:
static CppUnit::Test* suite();
private:
static std::string getFullName(const std::string& name);
};

View File

@ -13,6 +13,7 @@
#include "NamedMutexTest.h"
#include "NamedEventTest.h"
#include "SharedMemoryTest.h"
#include "ProcessRunnerTest.h"
CppUnit::Test* ProcessesTestSuite::suite()
@ -23,6 +24,7 @@ CppUnit::Test* ProcessesTestSuite::suite()
pSuite->addTest(NamedMutexTest::suite());
pSuite->addTest(NamedEventTest::suite());
pSuite->addTest(SharedMemoryTest::suite());
pSuite->addTest(ProcessRunnerTest::suite());
return pSuite;
}

View File

@ -14,12 +14,16 @@
#include "Poco/SharedLibrary.h"
#include "Poco/Exception.h"
#include "Poco/Path.h"
#include "Poco/File.h"
#include "Poco/Format.h"
using Poco::SharedLibrary;
using Poco::NotFoundException;
using Poco::LibraryLoadException;
using Poco::LibraryAlreadyLoadedException;
using Poco::Path;
using Poco::File;
typedef int (*GimmeFiveFunc)();
@ -37,14 +41,11 @@ SharedLibraryTest::~SharedLibraryTest()
void SharedLibraryTest::testSharedLibrary1()
{
std::string path = "TestLibrary";
path.append(SharedLibrary::suffix());
Poco::Path libraryPath = Poco::Path::current();
libraryPath.append(path);
std::string libraryPath = getFullName("TestLibrary");
SharedLibrary sl;
assertTrue (!sl.isLoaded());
sl.load(libraryPath.toString());
assertTrue (sl.getPath() == libraryPath.toString());
sl.load(libraryPath);
assertTrue (sl.getPath() == libraryPath);
assertTrue (sl.isLoaded());
assertTrue (sl.hasSymbol("pocoBuildManifest"));
assertTrue (sl.hasSymbol("pocoInitializeLibrary"));
@ -73,12 +74,9 @@ void SharedLibraryTest::testSharedLibrary1()
void SharedLibraryTest::testSharedLibrary2()
{
std::string path = "TestLibrary";
path.append(SharedLibrary::suffix());
Poco::Path libraryPath = Poco::Path::current();
libraryPath.append(path);
SharedLibrary sl(libraryPath.toString());
assertTrue (sl.getPath() == libraryPath.toString());
std::string libraryPath = getFullName("TestLibrary");
SharedLibrary sl(libraryPath);
assertTrue (sl.getPath() == libraryPath);
assertTrue (sl.isLoaded());
GimmeFiveFunc gimmeFive = (GimmeFiveFunc) sl.getSymbol("gimmeFive");
@ -91,12 +89,12 @@ void SharedLibraryTest::testSharedLibrary2()
void SharedLibraryTest::testSharedLibrary3()
{
std::string path = "NonexistentLibrary";
path.append(SharedLibrary::suffix());
std::string libraryPath = "NonexistentLibrary";
libraryPath.append(libraryPath);
SharedLibrary sl;
try
{
sl.load(path);
sl.load(libraryPath);
failmsg("no such library - must throw exception");
}
catch (LibraryLoadException&)
@ -108,16 +106,13 @@ void SharedLibraryTest::testSharedLibrary3()
}
assertTrue (!sl.isLoaded());
path = "TestLibrary";
path.append(SharedLibrary::suffix());
Poco::Path libraryPath = Poco::Path::current();
libraryPath.append(path);
sl.load(libraryPath.toString());
libraryPath = getFullName("TestLibrary");
sl.load(libraryPath);
assertTrue (sl.isLoaded());
try
{
sl.load(libraryPath.toString());
sl.load(libraryPath);
failmsg("library already loaded - must throw exception");
}
catch (LibraryAlreadyLoadedException&)
@ -134,6 +129,33 @@ void SharedLibraryTest::testSharedLibrary3()
}
std::string SharedLibraryTest::getFullName(const std::string& libName)
{
// make
std::string name = Path::expand("$POCO_BASE");
char c = Path::separator();
std::string OSNAME = Path::expand("$OSNAME");
std::string OSARCH = Path::expand("$OSARCH");
name.append(1, c)
.append(Poco::format("Foundation%ctestsuite%cbin%c", c, c, c))
.append(Poco::format("%s%c%s%c", OSNAME, c, OSARCH, c))
.append(libName).append(SharedLibrary::suffix());
// CMake
if (!File(name).exists())
{
name = Path::expand("$POCO_BASE");
name.append(Poco::format("%ccmake-build%cbin%c", c, c, c))
.append(libName).append(SharedLibrary::suffix());
}
if (!File(name).exists())
name = libName + SharedLibrary::suffix();
return name;
}
void SharedLibraryTest::setUp()
{
}

View File

@ -34,6 +34,7 @@ public:
static CppUnit::Test* suite();
private:
static std::string getFullName(const std::string& libName);
};

View File

@ -12,12 +12,151 @@
#define _CRT_SECURE_NO_DEPRECATE
#endif
#include "Poco/PIDFile.h"
#include <string>
#include <iostream>
#include <cstdlib>
#include <signal.h>
#if defined(POCO_OS_FAMILY_UNIX)
#include "Poco/Thread.h"
#include "Poco/Runnable.h"
#elif defined(POCO_OS_FAMILY_WINDOWS)
#include "Poco/Process.h"
#include "Poco/Event.h"
#include "Poco/NamedEvent.h"
#endif
using namespace Poco;
#if defined(POCO_OS_FAMILY_UNIX)
class MyRunnable: public Runnable
{
public:
MyRunnable(): _ran(false)
{
}
void run()
{
Thread* pThread = Thread::current();
if (pThread)
{
_threadName = pThread->name();
}
_ran = true;
}
bool ran() const
{
return _ran;
}
private:
bool _ran;
std::string _threadName;
};
#endif
#if POCO_OS != POCO_OS_ANDROID
class MyApp
{
public:
MyApp() {}
~MyApp() {}
std::unique_ptr<PIDFile> _pPIDFile;
#if defined(POCO_OS_FAMILY_WINDOWS)
static Poco::Event _terminated;
static Poco::NamedEvent _terminate;
static void terminate()
{
_terminate.set();
}
static BOOL WINAPI ConsoleCtrlHandler(DWORD ctrlType)
{
switch (ctrlType)
{
case CTRL_C_EVENT:
case CTRL_CLOSE_EVENT:
case CTRL_BREAK_EVENT:
terminate();
return _terminated.tryWait(10000) ? TRUE : FALSE;
default:
return FALSE;
}
}
void waitForTerminationRequest()
{
SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
_terminate.wait();
_terminated.set();
}
#elif defined(POCO_OS_FAMILY_UNIX)
void waitForTerminationRequest()
{
sigset_t sset;
sigemptyset(&sset);
if (!std::getenv("POCO_ENABLE_DEBUGGER"))
{
sigaddset(&sset, SIGINT);
}
sigaddset(&sset, SIGQUIT);
sigaddset(&sset, SIGTERM);
sigprocmask(SIG_BLOCK, &sset, NULL);
int sig;
sigwait(&sset, &sig);
}
int runThreads(std::string pidPath)
{
_pPIDFile.reset(new PIDFile(pidPath, true));
uint32_t sigMask = 4; // Block SIGINT
Thread thread1(sigMask);
Thread thread2(sigMask);
Thread thread3(sigMask);
Thread thread4(sigMask);
MyRunnable r1;
MyRunnable r2;
MyRunnable r3;
MyRunnable r4;
thread1.start(r1);
thread2.start(r2);
thread3.start(r3);
thread4.start(r4);
waitForTerminationRequest();
thread1.join();
thread2.join();
thread3.join();
thread4.join();
return 0;
}
#endif
int run(std::string pidPath)
{
_pPIDFile.reset(new PIDFile(pidPath, true));
waitForTerminationRequest();
return 0;
}
};
#endif
#if defined(POCO_OS_FAMILY_WINDOWS)
Poco::Event MyApp::_terminated;
Poco::NamedEvent MyApp::_terminate(Poco::ProcessImpl::terminationEventName(Poco::Process::id()));
#endif
int main(int argc, char** argv)
{
@ -57,6 +196,32 @@ int main(int argc, char** argv)
std::cout << argv[i] << std::endl;
}
}
#if defined(POCO_OS_FAMILY_UNIX)
else if (argc > 2 && arg.find("--pidfile") != std::string::npos && std::string(argv[2]) == "--launch-thread")
{
size_t equals_pos = arg.find('=');
if (equals_pos != std::string::npos)
{
std::string pidPath = arg.substr(equals_pos + 1);
MyApp myApp;
int result = myApp.runThreads(pidPath);
return result;
}
}
#endif
#if POCO_OS != POCO_OS_ANDROID
else if (arg.find("--pidfile") != std::string::npos || arg.find("-p") != std::string::npos)
{
size_t equals_pos = arg.find('=');
if (equals_pos != std::string::npos)
{
std::string pidPath = arg.substr(equals_pos + 1);
MyApp myApp;
int result = myApp.run(pidPath);
return result;
}
}
#endif
}
return argc - 1;
}

View File

@ -87,7 +87,7 @@ do
echo ""
runs=$((runs + 1))
if ! sh -c "cd $POCO_BUILD/$comp/testsuite/$BINDIR && PATH=.:$PATH && LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH $TESTRUNNER $IGNORE $TESTRUNNERARGS";
if ! sh -c "export POCO_BASE='$POCO_BASE'; export OSNAME='$OSNAME'; export OSARCH='$OSARCH'; cd $POCO_BUILD/$comp/testsuite/$BINDIR && PATH=.:$PATH && LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH $TESTRUNNER $IGNORE $TESTRUNNERARGS";
then
failures=$((failures + 1))
failedTests="$failedTests $comp"

View File

@ -93,6 +93,8 @@ esac
# uncomment for sanitizer builds
#LSAN_OPTIONS=verbosity=1:log_threads=1
#export LSAN_OPTIONS
#TSAN_OPTIONS="suppressions=$POCO_BASE/tsan.suppress,second_deadlock_stack=1"
#export TSAN_OPTIONS
echo "\$OSNAME = $OSNAME"
echo "\$OSARCH = $OSARCH"

View File

@ -3,7 +3,7 @@
# https://github.com/google/sanitizers/wiki/ThreadSanitizerSuppressions
#
# To apply:
# export TSAN_OPTIONS="suppressions=$POCO_BASE/tsan.supress,second_deadlock_stack=1"
# export TSAN_OPTIONS="suppressions=$POCO_BASE/tsan.suppress,second_deadlock_stack=1"
##############
# Suppressions: