#ifndef CORELIB___NCBI_PROCESS__HPP #define CORELIB___NCBI_PROCESS__HPP /* $Id: ncbi_process.hpp 99384 2023-03-20 17:50:49Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE * National Center for Biotechnology Information * * This software/database is a "United States Government Work" under the * terms of the United States Copyright Act. It was written as part of * the author's official duties as a United States Government employee and * thus cannot be copyrighted. This software/database is freely available * to the public for use. The National Library of Medicine and the U.S. * Government have not placed any restriction on its use or reproduction. * * Although all reasonable efforts have been taken to ensure the accuracy * and reliability of the software and data, the NLM and the U.S. * Government do not and cannot warrant the performance or results that * may be obtained by using this software or data. The NLM and the U.S. * Government disclaim all warranties, express or implied, including * warranties of performance, merchantability or fitness for any particular * purpose. * * Please cite the author in any work or product based on this material. * * =========================================================================== * * Authors: Aaron Ucko, Vladimir Ivanov * * */ /// @file ncbi_process.hpp /// Defines process management classes. /// /// Defines classes: /// CProcess /// CPIDGuard /// /// Implemented for: UNIX, MS-Windows #include <corelib/interprocess_lock.hpp> #if defined(NCBI_OS_UNIX) # include <sys/types.h> #elif defined(NCBI_OS_MSWIN) # include <corelib/ncbi_os_mswin.hpp> #else # error "CProcess is not implemented on this platform" #endif BEGIN_NCBI_SCOPE /** @addtogroup Process * * @{ */ /// Infinite timeout in milliseconds. /// @deprecated Need to be removed to use constants from CProcessBase and derived classes const unsigned long kInfiniteTimeoutMs = kMax_ULong; // This workaround is obsolete now. LinuxThreads library has been replaced by NPTL // which does not need it. /* /// Turn on/off workaround for Linux PID and PPID #if defined(NCBI_OS_LINUX) # define NCBI_THREAD_PID_WORKAROUND #endif */ /// Process identifier (PID) and process handle. #if defined(NCBI_OS_UNIX) typedef pid_t TPid; typedef TPid TProcessHandle; #elif defined(NCBI_OS_MSWIN) typedef DWORD TPid; typedef HANDLE TProcessHandle; #else typedef int TPid; typedef TPid TProcessHandle; #endif ///////////////////////////////////////////////////////////////////////////// /// /// CProcessBase -- /// /// Base class that defines common types and constants for CProcess and CCurrentProcess. /// @sa CProcess, CCurrentProcess class NCBI_XNCBI_EXPORT CProcessBase { public: /// Process information "target" enum EWhat { eProcess, ///< Current process eChildren, ///< All children of the calling process eThread ///< Current thread }; /// Process memory usage information, in bytes. /// /// Values sets to 0 if unknown, /// @note /// Resident set size represent physical memory usage, /// all other members - virtual memory usage. /// @note /// Resident size alone is the wrong place to look to determine if your processes /// are getting too big. If the system gets overloaded with processes that /// using more and more (virtual) memory over time, that resident portion can even shrink. struct SMemoryUsage { size_t total; ///< Total memory usage size_t total_peak; ///< Peak total memory usage size_t resident; ///< Resident/working set size (RSS). ///< RSS is the portion of memory occupied by a process ///< that is held in main memory (RAM). size_t resident_peak; ///< Peak resident set size ("high water mark") size_t shared; ///< Shared memory usage size_t data; ///< Data segment size size_t stack; ///< Stack size of the initial thread in the process size_t text; ///< Text (code) segment size size_t lib; ///< Shared library code size size_t swap; ///< Swap space usage }; /// Default wait time (milliseconds) between "soft" and "hard" /// attempts to terminate a process. static const unsigned long kDefaultKillTimeout; /// Infinite timeout (milliseconds). static const unsigned long kInfiniteTimeoutMs; }; ///////////////////////////////////////////////////////////////////////////// /// /// CCurrentProcess -- /// /// This class defines methods related to the current process. /// For arbitrary process please see CProcess. /// /// Static methods only. /// /// @sa CProcess class NCBI_XNCBI_EXPORT CCurrentProcess : public CProcessBase { public: ///////////////////////////////////////////////////////////////////////////// // Process information /// Get process handle for the current process (esp. on Windows). /// @note /// On Windows process identifiers and process handles are different. /// On UNIX handle/pid are the same and GetHandle()/GetPid() /// return the same value. /// @sa /// GetPid static TProcessHandle GetHandle(void); /// Get process identifier (pid) for the current process. /// @sa /// GetHandle static TPid GetPid(void); /// Get process identifier (pid) for the parent of the current process. /// @sa /// GetPid static TPid GetParentPid(void); /// Get current process execution times. /// /// @param real /// Pointer to a variable that receives the amount of time in second that /// the current process/thread has executed, when available. /// @note /// Here is no portable solution to get 'real' process execution time, /// not all OS have an API to get such information from the system, /// or it can include children times as well... /// but it is available on some platforms like Windows, Linux and BSD. /// @param user /// Pointer to a variable that receives the amount of time in seconds that /// the process, process tree or thread has executed in user mode. /// Note, that this value can exceed the amount of "real" time if /// the process executes across multiple CPU cores (OS dependent). /// @param sys /// Pointer to a variable that receives the amount of time in second that /// the current process, process tree or thread has executed in kernel mode. /// @param what /// Applies to user and system time parameters only, /// real time calculates for the current process only. /// Defines what times to measure: current thread, process or children processes: /// - eProcess: /// Current process, which is the sum of resources used /// by all threads in the process. /// - eChildren: (limited support) /// All children of the calling process that have terminated already /// and been waited for. These statistics will include the resources /// used by grandchildren, and further removed descendants, if all of /// the intervening descendants waited on their terminated children. /// - eThread: (limited support) /// Usage statistics for the calling thread. /// @return /// TRUE on success; or FALSE on error. /// If some value cannot be calculated on a current platform for "what" target, /// it will be set to a negative value. /// @note /// NULL arguments will not be filled in. /// @sa /// CProcess::GetTimes static bool GetTimes(double* real, double* user, double* sys, EWhat what = eProcess); /// Get current process memory usage. /// /// @sa /// CProcess::GetMemoryUsage, SMemoryUsage static bool GetMemoryUsage(SMemoryUsage& usage); /// Get the number of threads in the current process. /// /// @return /// Number of threads in the current process, or -1 on error. /// @sa /// CProcess::GetThreadCount static int GetThreadCount(void); /// Get the number of file descriptors consumed by the current process, /// and optional system wide file descriptor limits. /// /// @param soft_limit /// Pointer to a variable that receives system wide soft limit. /// -1 means it was impossible to get the limit. /// @param hard_limit /// Pointer to a variable that receives system wide hard limit. /// -1 means it was impossible to get the limit. /// @return /// Number of file descriptors consumed by the process, or -1 on error. /// @note /// NULL arguments will not be filled in. /// @sa /// CProcess::GetFileDescriptorsCount /// @note Unix inly static int GetFileDescriptorsCount(int* soft_limit = NULL, int* hard_limit = NULL); ///////////////////////////////////////////////////////////////////////////// // Forks & Daemons /// Forking flags. enum FForkFlags { fFF_UpdateDiag = 1, ///< Reset diagnostics timer and log an ///< app-start message in the child process. fFF_Exec = 2, ///< User plans to use exec(3) or execve(2) to "replace" forked child ///< process with another program as soon as possible after fork, ///< so we can skip some initialization and checks. Cancels fFF_UpdateDiag. fFF_AllowExceptions = 32 ///< Throw an exception on error. }; /// Bit-wise OR of FForkFlags @sa FForkFlags typedef unsigned TForkFlags; /// Fork the process. Update PID and GUID used for logging (by default). /// /// @warning /// The child process is created with a single thread, the one that called fork(). /// The entire virtual address space of the parent is replicated in the child, /// including the states of mutexes, condition variables, open file descriptors, /// pthreads objects, and etc. But child process doesn't inherit or reset many /// other properties. Be aware. Consult fork(2) man-pages for a full details. /// @warning /// Fork() should be called from a single-threaded application, even if it built /// in MT configurations. If you have many running threads in the parent process, /// this can lead to unpredictable results and various deadlocks. /// "After a fork() in a multithreaded program, the child can safely call only /// async-signal-safe functions." until it calls execve(2) to replace a forked /// child process as soon as possible after Fork(). /// See https://man7.org/linux/man-pages/man2/fork.2.html /// @return /// In the parent process, the call returns the child process ID. /// In the child process, the call returns zero. /// In case of an error, unless the fFF_AllowExceptions flag is specified, /// the call returns -1. /// @throw /// If the fFF_AllowExceptions flag is specified, throws a CCoreException /// in case of a fork(2) failure. If the platform does not support process /// forking, an exception is always thrown regardless of whether /// the fFF_AllowExceptions flag is specified. /// @note /// Implemented for Unix only. /// @sa ForkForExec /// static TPid Fork(TForkFlags flags = fFF_UpdateDiag); /// Fork the process for "replacing" a child process with a new process. /// /// Special version of Fork() with a different name for easier recognizing. /// Assumes that the user will replace child process after this call with using /// exec(3) or execve(2) calls as soon as possible. The child can safely call /// only async-signal-safe functions after Fork() until the child process /// has replaced. This mean no memory allocation, streams, logging and etc. /// Please consult the list of sync-signal-safe functions before using, like: /// https://man7.org/linux/man-pages/man7/signal-safety.7.html /// /// @return /// In the parent process, the call returns the child process ID. /// In the child process, the call returns zero. /// In case of an error, unless the fFF_AllowExceptions flag is specified, /// the call returns -1. /// @sa Fork /// static TPid ForkForExec(TForkFlags flags = 0) { return Fork(flags | fFF_Exec); }; /// Daemonization flags enum FDaemonFlags { fDF_KeepCWD = 1, ///< Don't change CWD to "/" fDF_KeepStdin = 2, ///< Keep stdin open as "/dev/null" (RO) fDF_KeepStdout = 4, ///< Keep stdout open as "/dev/null" (WO) fDF_ImmuneTTY = 8, ///< Make daemon immune to re-acquiring a controlling terminal fDF_KeepParent = 16, ///< Do not exit the parent process but return fDF_AllowExceptions = 32, ///< Throw an exception in case of an error. fDF_AllowThreads = 64 ///< Do not fail if pre-existing threads are detected }; /// Bit-wise OR of FDaemonFlags @sa FDaemonFlags typedef unsigned int TDaemonFlags; /// Go daemon. /// /// Return TPid(-1) in the daemon thread (the parent thread doesn't return /// unless fKeepParent is set), or TPid(daemon) in the parent thread. /// On error return 0 in the parent thread (no daemon created), see errno. /// /// Reopen stderr/cerr in the daemon thread if "logfile" specified as /// non-NULL (stderr will open to "/dev/null" if "logfile" has been passed /// as ""), otherwise stderr is closed in the daemon thread. /// /// Unless instructed by the "flags" parameter, the daemon thread has its /// stdin/cin and stdout/cout closed, and the current working directory /// changed to the root directory ("/"). /// /// If kept open, stdin and stdout are both redirected to "/dev/null". /// Opening a terminal device as a controlling terminal is allowed, unless /// fImmuneTTY is specified in the flags, which then causes a second /// fork() so that the resultant process won't be allowed to open a TTY as /// its controlling TTY (but only with an explicit O_NOCTTY, see open(2)), /// thus protecting the process from any blocking via TTY signaling. /// /// Note that this call is somewhat destructive and may not be able /// to restore the process that called it to a state prior to the call /// in case of an error. So that calling process can find the standard // file pointers (and sometimes descriptors) clobbered up. /// static TPid Daemonize(const char* logfile = 0, TDaemonFlags flags = 0); private: #if defined NCBI_THREAD_PID_WORKAROUND // Flags for internal sx_GetPid() enum EGetPidFlag { // get real or cached PID depending on thread ID ePID_GetCurrent, // get parent PID - real or cached depending on thread ID ePID_GetParent, // get real PID (of the thread) but do not cache it ePID_GetThread }; static TPid sx_GetPid(EGetPidFlag flag); friend class CThread; #endif }; ///////////////////////////////////////////////////////////////////////////// /// /// CProcess -- /// /// Process management functions. /// /// Class works with process identifiers and process handles. /// On Unix both terms are equivalent and correspond a pid. /// On MS Windows they are different. /// /// @note: All CExec:: functions work with process handles. class NCBI_XNCBI_EXPORT CProcess : public CProcessBase { public: /// How to interpret the used process identifier. enum EType { ePid, ///< A real process identifier (pid). eHandle ///< A process handle (MS Windows). }; /// Default constructor. Uses the current process pid. CProcess(void); /// Constructor. CProcess(TPid process, EType type = eHandle); #if defined(NCBI_OS_MSWIN) // Note: // On MS Windows process identifiers and process handles are different. // so we need a separate constructor for process handles. CProcess(TProcessHandle process, EType type = eHandle); #endif /// Get type of stored process identifier. /// @note /// On Windows process identifiers and process handles are different. /// On UNIX handle/pid is the same, and GetHandle()/GetPid() return /// the same value. EType GetType(void) const { return m_Type; } /// Get stored process handle. /// @sa /// GetCurrentHandle TProcessHandle GetHandle(void) const { return (TProcessHandle)m_Process; } /// Get stored process identifier (pid). /// @sa /// GetCurrentPid TPid GetPid(void) const { return (TPid) m_Process; } /// Checks that stored process identifier (pid) represent the current process. /// @sa /// GetCurrentPid bool IsCurrent(void); /// Check for process existence. /// /// @return /// TRUE - if the process is still running. /// FALSE - if the process does exist or has already been terminated. /// @note /// On Unix this method returns TRUE also for "zombie" processes, /// those finished executing but waiting to post their exit code. /// Usually the parent process should call Wait() for such processes /// and release (aka reap) them. /// @sa /// Wait bool IsAlive(void) const; /// Terminate process. /// /// First try "soft" and then try "hard" attempt to terminate the process. /// @note Even the "hard" attempt does not guarantee that the process will /// be actually killed. Process termination can take some time, and the /// process may remain "alive" even after the "hard" termination attempt. /// /// @param timeout /// Wait time in milliseconds between first "soft" and second "hard" /// attempts to terminate the process. /// If timeout is zero then use an unsafe process termination: just /// try to terminate the process without checks that it is really gone. /// @note /// On UNIX in case of a zero or very small timeout, the killed process /// may not be released immediately (and continue to persist as a zombie /// process) even after this call. /// @return /// TRUE - if the process did not exist or was successfully terminated. /// FALSE - if the process is still running, cannot be terminated, or /// it is terminating right now (but is still incomplete). /// @sa KillGroup, KillGroupById bool Kill(unsigned long timeout = kDefaultKillTimeout); /// Terminate a group of processes. /// /// This method tries to terminate all processes in the group to which /// process, specified in the constructor, belongs. /// /// @param timeout /// Wait time in milliseconds between first "soft" and second "hard" /// attempts to terminate the process group. /// If timeout is zero then use an unsafe process termination: just /// try to terminate the group without checks that it is really gone. /// @note /// On UNIX in case of a zero or very small timeout, some processes /// may not be released (and continue to persist as zombie processes) /// even after this call. /// On MS Windows this method tries to terminate the process itself /// and all of its children. But in case when one of the processes, /// which should be terminated, spawns a new process at the very moment /// that this method gets called, the new process may not be terminated. /// @return /// TRUE - if the process group did not exist or was successfully /// terminated. /// FALSE - if the process group is still running, cannot be terminated, /// or it is terminating right now (but is still incomplete). /// @sa Kill bool KillGroup(unsigned long timeout = kDefaultKillTimeout) const; /// Terminate a group of processes with specified ID. /// /// Note: Implemented on UNIX only, on Windows returns FALSE. /// @param pgid /// Process group ID to terminate. /// if "pgid" parameter is zero, terminate the process group of /// the current process /// @param timeout /// Wait time in milliseconds between first "soft" and second "hard" /// attempts to terminate the process group. /// If timeout is zero then use an unsafe process termination: just /// try to terminate the process group without checks whether it is /// really gone. /// @note /// On UNIX in case of a zero or very small timeout, some processes from /// the process group to be killed may not be released immediately /// (and continue to persist as zombie processes) even after this call. /// @return /// TRUE - if the process group did not exist or was successfully /// terminated. /// FALSE - if the process group is still running, cannot be terminated, /// or it is terminating right now (but is still incomplete). /// @sa Kill static bool KillGroupById(TPid pgid, unsigned long timeout = kDefaultKillTimeout); /// Extended exit information for waited process. /// All information about the process available only after Wait() method /// with specified parameter 'info' and if IsPresent() method returns TRUE. class NCBI_XNCBI_EXPORT CExitInfo { public: /// Constructor. CExitInfo(void); /// TRUE if the object contains information about the process state. /// /// All other methods' return values are good only if this method /// returns TRUE, otherwise they may throw exceptions. bool IsPresent(void) const; /// TRUE if the process is still alive. bool IsAlive(void) const; /// TRUE if the process terminated normally. bool IsExited(void) const; /// TRUE if the process terminated by a signal (UNIX only). bool IsSignaled(void) const; /// Get process exit code. /// Works only if IsExited() returns TRUE, otherwise returns -1. int GetExitCode(void) const; /// Get the signal number that has caused the process to terminate /// (UNIX only). /// Works only if IsSignaled() returns TRUE, otherwise returns -1. int GetSignal(void) const; private: int state; ///< Process state (unknown/alive/terminated). int status; ///< Process status information. friend class CProcess; }; /// Wait until process terminates. /// /// Wait until the process terminates or timeout expires. /// Return immediately if the specified process has already terminated. /// @param timeout /// Time interval in milliseconds (infinite by default) to wait. /// @param info /// Extended exit information for terminated process. /// Note that if CProcess::Kill() was used to terminate the process /// then the extended information may not be available. /// @return /// - Exit code of the process, if the call completed without errors. /// - (-1) if an error occurred or it was impossible to get the exit /// code of the process. If 'info' parameter is specified, then it /// is filled with additional information about the process. /// @note /// It is recommended to call this method for all processes started /// in eNoWait or eDetach modes (except on Windows for eDetach), because /// it releases "zombie" processes, i.e. those finished running and /// waiting for their parent to obtain their exit code. If Wait() is /// not called somewhere, then the child process will be completely /// removed from the system only when its parent process ends. /// @note /// Infinite timeout can cause an application to stop responding. /// @sa /// IsAlive, CExitInfo, CExec, WaitInfinite, WaitTimeout int Wait(unsigned long timeout = kInfiniteTimeoutMs, CExitInfo* info = 0) const; /// Wait until the process terminates or timeout expires. /// @sa Wait int WaitTimeout(unsigned long timeout, CExitInfo* info = 0) const { return Wait(timeout, info); } /// Wait indefinitely until the process terminates. /// @sa Wait int WaitInfinite(CExitInfo* info = 0) const { return Wait(kInfiniteTimeoutMs, info); } ///////////////////////////////////////////////////////////////////////////// // Process information /// @deprecated Please use CCurrentProcess::GetHandle() instead NCBI_DEPRECATED static TProcessHandle GetCurrentHandle(void) { return CCurrentProcess::GetHandle(); } /// @deprecated Please use CCurrentProcess::GetPid() instead NCBI_DEPRECATED static TPid GetCurrentPid(void) { return CCurrentProcess::GetPid(); } /// @deprecated Please use CCurrentProcess::GetParentPid() instead NCBI_DEPRECATED static TPid GetParentPid(void) { return CCurrentProcess::GetParentPid(); } /// Get process execution times. /// For current process pid/handle it is the same as CCurrentProcess::GetTimes(). /// /// @param real /// Pointer to a variable that receives the amount of time in second that /// the process/thread has executed, when available. /// @note /// Here is no portable solution to get 'real' process execution time, /// not all OS have an API to get such information from the system, /// or it can include children times as well... /// but it is available on some platforms like Windows, Linux and BSD. /// @param user /// Pointer to a variable that receives the amount of time in seconds that /// the process, process tree or thread has executed in user mode. /// Note, that this value can exceed the amount of "real" time if /// the process executes across multiple CPU cores (OS dependent). /// @param sys /// Pointer to a variable that receives the amount of time in second that /// the current process, process tree or thread has executed in kernel mode. /// @param what /// Defines what times to measure: current thread, process or children processes: /// - eProcess: /// Current process, which is the sum of resources used /// by all threads in the process. /// - eChildren: (limited support) /// All children of the process that have terminated already /// and been waited for. These statistics will include the resources /// used by grandchildren, and further removed descendants, if all of /// the intervening descendants waited on their terminated children. /// - eThread: (limited support) /// Usage statistics for the calling thread. /// CProcess should be initialized with the current process pid/handle, /// or result is undefined. /// @return /// TRUE on success; or FALSE on error. /// If some value cannot be calculated on a current platform for "what" target, /// it will be set to a negative value. /// @note /// NULL arguments will not be filled in. /// @note /// Usually it is possible to query information from users own processes, /// but you should have an appropriate permissions to query other processes. /// @note /// On Windows it is possible to get process times even for terminated processes, /// that are Wait()-ed for, even if IsAlive() returns false. /// @sa /// CCurrentProcess::GetTimes bool GetTimes(double* real, double* user, double* sys, EWhat what = eProcess); /// Get process memory usage. /// For current process pid/handle it is the same as CCurrentProcess::GetMemoryUsage(). /// /// @param usage /// Total memory usage by a process, in bytes. See SMemoryUsage structure. /// @param resident /// Resident set size (RSS), in bytes. /// RSS is the portion of memory occupied by a process that is held in main memory (RAM). /// @param shared /// (optional) Shared memory usage, in bytes. /// @param data /// (optional) Data + stack usage, in bytes. /// @return /// TRUE on success; or FALSE otherwise. /// @note /// NULL arguments will not be filled in. /// @sa /// CCurrentProcess::GetMemoryUsage, SMemoryUsage bool GetMemoryUsage(SMemoryUsage& usage); /// Get the number of threads in the process. /// For current process pid/handle it is the same as CCurrentProcess::GetThreadCount(). /// /// @return /// Number of threads in the current process, or -1 on error. /// @sa /// CCurrentProcess::GetThreadCount int GetThreadCount(void); /// Get the number of file descriptors consumed by the current process. /// For current process pid/handle it is the same as CCurrentProcess::GetFileDescriptorsCount(). /// /// @return /// Number of file descriptors consumed by the process, or -1 on error. /// @sa /// CCurrentProcess::GetFileDescriptorsCount /// @note Unix inly int GetFileDescriptorsCount(void); ///////////////////////////////////////////////////////////////////////////// // Forks & Daemons /// Forking flags. /// @ deprecated Please use CCurrentProcess::FForkFlags instead enum FForkFlags { fFF_UpdateDiag = CCurrentProcess::fFF_UpdateDiag, fFF_AllowExceptions = CCurrentProcess::fFF_AllowExceptions }; /// Bit-wise OR of FForkFlags @sa FForkFlags /// @ deprecated Please use CCurrentProcess::TForkFlags instead typedef unsigned TForkFlags; /// Fork the process. /// @deprecated Please use CCurrentProcess::Fork() instead NCBI_DEPRECATED static TPid Fork(TForkFlags flags = fFF_UpdateDiag) { return CCurrentProcess::Fork(flags); } /// Daemonization flags /// @ deprecated Please use CCurrentProcess::FDaemonFlags instead enum FDaemonFlags { fDF_KeepCWD = CCurrentProcess::fDF_KeepCWD, fDF_KeepStdin = CCurrentProcess::fDF_KeepStdin, fDF_KeepStdout = CCurrentProcess::fDF_KeepStdout, fDF_ImmuneTTY = CCurrentProcess::fDF_ImmuneTTY, fDF_KeepParent = CCurrentProcess::fDF_KeepParent, fDF_AllowExceptions = CCurrentProcess::fDF_AllowExceptions, fDF_AllowThreads = CCurrentProcess::fDF_AllowThreads, fDontChroot = CCurrentProcess::fDF_KeepCWD, fKeepStdin = CCurrentProcess::fDF_KeepStdin, fKeepStdout = CCurrentProcess::fDF_KeepStdout, fImmuneTTY = CCurrentProcess::fDF_ImmuneTTY, fKeepParent = CCurrentProcess::fDF_KeepParent }; /// Bit-wise OR of FDaemonFlags @sa FDaemonFlags /// @ deprecated Please use CCurrentProcess::TDaemonFlags instead typedef unsigned int TDaemonFlags; /// Go daemon. /// /// Return TPid(-1) in the daemon thread (the parent thread doesn't return /// unless fKeepParent is set), or TPid(daemon) in the parent thread. /// On error return 0 in the parent thread (no daemon created), see errno. /// /// Reopen stderr/cerr in the daemon thread if "logfile" specified as /// non-NULL (stderr will open to "/dev/null" if "logfile" has been passed /// as ""), otherwise stderr is closed in the daemon thread. /// /// Unless instructed by the "flags" parameter, the daemon thread has its /// stdin/cin and stdout/cout closed, and the current working directory /// changed to the root directory ("/"). /// /// If kept open, stdin and stdout are both redirected to "/dev/null". /// Opening a terminal device as a controlling terminal is allowed, unless /// fImmuneTTY is specified in the flags, which then causes a second /// fork() so that the resultant process won't be allowed to open a TTY as /// its controlling TTY (but only with an explicit O_NOCTTY, see open(2)), /// thus protecting the process from any blocking via TTY signaling. /// /// Note that this call is somewhat destructive and may not be able /// to restore the process that called it to a state prior to the call /// in case of an error. So that calling process can find the standard // file pointers (and sometimes descriptors) clobbered up. /// @deprecated Please use CCurrentProcess::Daemonize() instead NCBI_DEPRECATED static TPid Daemonize(const char* logfile = 0, TDaemonFlags flags = 0) { return CCurrentProcess::Daemonize(logfile, flags); }; private: #if defined(NCBI_OS_MSWIN) // Return pid, converts from handle if necessary TPid x_GetPid(void) const; // Return process handle, converts from pid with desired rights if necessary. // Return NULL on error. Don't forget to close handle with x_CloseHandle(). TProcessHandle x_GetHandle(DWORD desired_access, DWORD* errcode = 0 /*optional errcode to return*/) const; // Close handle, if necessary void x_CloseHandle(TProcessHandle handle) const; #endif // itptr_t type can store both pid and process handle. intptr_t m_Process; ///< Process identifier. EType m_Type; ///< Type of process identifier. ETriState m_IsCurrent; ///< Status that m_Process represent the current process. }; ///////////////////////////////////////////////////////////////////////////// /// /// CPIDGuardException -- /// class NCBI_XNCBI_EXPORT CPIDGuardException : EXCEPTION_VIRTUAL_BASE public CException { public: enum EErrCode { eStillRunning, ///< The process listed in the file is still around. eWrite ///< Unable to write into the PID file. }; virtual const char* GetErrCodeString(void) const override; /// Constructor. CPIDGuardException(const CDiagCompileInfo& info, const CException* prev_exception, EErrCode err_code, const string& message, TPid pid = 0, EDiagSev severity = eDiag_Error) : CException(info, prev_exception, message, severity), m_PID(pid) NCBI_EXCEPTION_DEFAULT_IMPLEMENTATION(CPIDGuardException, CException); public: virtual void ReportExtra(ostream& out) const override { out << "pid " << m_PID; } TPid GetPID(void) const throw() { return m_PID; } protected: virtual void x_Assign(const CException& src) override { CException::x_Assign(src); m_PID = dynamic_cast<const CPIDGuardException&>(src).m_PID; } private: TPid m_PID; }; ///////////////////////////////////////////////////////////////////////////// /// /// CPIDGuard -- Process guard. /// /// If file already exists, CPIDGuard try to check that the process with PID /// specified in the file is running or not. If guarded process is still /// running, CPIDGuard throw an exception. Otherwise, it create file with /// current PID. CPIDGuard use reference counters in the PID file. /// This means that some CPIDGuard objects can be created for the same PID /// and file name. /// /// @note /// If you need something just to prevent run some application twice, /// please look to CInterProcessLock class. /// @note /// CPIDGuard know nothing about PID file modification or deletion /// by other processes directly, without using this API. Be aware. /// class NCBI_XNCBI_EXPORT CPIDGuard { public: /// Create/check PID file. /// /// If the file already exists and identifies a live process, /// throws CPIDGuardException. /// @param filename /// Name of the file to store PID. /// If "filename" contains path, it should be absolute /// and points to an existing directory. /// If "filename" contains no path, that $TMPDIR will be used on Unix, /// and %HOME% on Windows to store it. CPIDGuard(const string& filename); /// Create/check PID file. /// /// If the file already exists and identifies a live process, /// throws CPIDGuardException. /// /// @param filename /// Name of the file to store PID. /// If should not include any path, relative or absolute. /// @param dir /// An absolute path to the existing directory on the file system /// to store PID file "filename". /// If "dir" is empty and "filename" contains no path, /// that $TMPDIR will be used on Unix, and %HOME% on Windows to store it. /// @deprecated NCBI_DEPRECATED CPIDGuard(const string& filename, const string& dir); /// Destructor. /// /// Just calls Release(); ~CPIDGuard(void); /// Release PID. /// /// Decrease reference counter for current PID and remove the file /// if it is not used more (reference counter is 0). void Release(void); /// Remove the file. /// /// Remove PID file forcibly, ignoring any reference counter. void Remove(void); /// Update PID in the file. /// /// @param pid /// The new process ID to store (defaults to the current PID); /// useful when the real work occurs in a child process that outlives /// the parent. void UpdatePID(TPid pid = 0); /// Returns non-zero if there was a stale file. /// Always return 0, because new implementation don't allow /// any stale file left on the file system. /// /// @deprecated NCBI_DEPRECATED TPid GetOldPID(void) { return 0; } private: string m_Path; //< File path to store PID. TPid m_PID; //< Sored PID. unique_ptr<CInterProcessLock> m_MTGuard; //< MT-Safe protection guard. unique_ptr<CInterProcessLock> m_PIDGuard; //< Guard to help with "PID reuse" problem. }; /* @} */ END_NCBI_SCOPE #endif /* CORELIB___NCBI_PROCESS__HPP */
0001 0002 0003 0004 0005 0006 0007 0008 0009 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 0100 0101 0102 0103 0104 0105 0106 0107 0108 0109 0110 0111 0112 0113 0114 0115 0116 0117 0118 0119 0120 0121 0122 0123 0124 0125 0126 0127 0128 0129 0130 0131 0132 0133 0134 0135 0136 0137 0138 0139 0140 0141 0142 0143 0144 0145 0146 0147 0148 0149 0150 0151 0152 0153 0154 0155 0156 0157 0158 0159 0160 0161 0162 0163 0164 0165 0166 0167 0168 0169 0170 0171 0172 0173 0174 0175 0176 0177 0178 0179 0180 0181 0182 0183 0184 0185 0186 0187 0188 0189 0190 0191 0192 0193 0194 0195 0196 0197 0198 0199 0200 0201 0202 0203 0204 0205 0206 0207 0208 0209 0210 0211 0212 0213 0214 0215 0216 0217 0218 0219 0220 0221 0222 0223 0224 0225 0226 0227 0228 0229 0230 0231 0232 0233 0234 0235 0236 0237 0238 0239 0240 0241 0242 0243 0244 0245 0246 0247 0248 0249 0250 0251 0252 0253 0254 0255 0256 0257 0258 0259 0260 0261 0262 0263 0264 0265 0266 0267 0268 0269 0270 0271 0272 0273 0274 0275 0276 0277 0278 0279 0280 0281 0282 0283 0284 0285 0286 0287 0288 0289 0290 0291 0292 0293 0294 0295 0296 0297 0298 0299 0300 0301 0302 0303 0304 0305 0306 0307 0308 0309 0310 0311 0312 0313 0314 0315 0316 0317 0318 0319 0320 0321 0322 0323 0324 0325 0326 0327 0328 0329 0330 0331 0332 0333 0334 0335 0336 0337 0338 0339 0340 0341 0342 0343 0344 0345 0346 0347 0348 0349 0350 0351 0352 0353 0354 0355 0356 0357 0358 0359 0360 0361 0362 0363 0364 0365 0366 0367 0368 0369 0370 0371 0372 0373 0374 0375 0376 0377 0378 0379 0380 0381 0382 0383 0384 0385 0386 0387 0388 0389 0390 0391 0392 0393 0394 0395 0396 0397 0398 0399 0400 0401 0402 0403 0404 0405 0406 0407 0408 0409 0410 0411 0412 0413 0414 0415 0416 0417 0418 0419 0420 0421 0422 0423 0424 0425 0426 0427 0428 0429 0430 0431 0432 0433 0434 0435 0436 0437 0438 0439 0440 0441 0442 0443 0444 0445 0446 0447 0448 0449 0450 0451 0452 0453 0454 0455 0456 0457 0458 0459 0460 0461 0462 0463 0464 0465 0466 0467 0468 0469 0470 0471 0472 0473 0474 0475 0476 0477 0478 0479 0480 0481 0482 0483 0484 0485 0486 0487 0488 0489 0490 0491 0492 0493 0494 0495 0496 0497 0498 0499 0500 0501 0502 0503 0504 0505 0506 0507 0508 0509 0510 0511 0512 0513 0514 0515 0516 0517 0518 0519 0520 0521 0522 0523 0524 0525 0526 0527 0528 0529 0530 0531 0532 0533 0534 0535 0536 0537 0538 0539 0540 0541 0542 0543 0544 0545 0546 0547 0548 0549 0550 0551 0552 0553 0554 0555 0556 0557 0558 0559 0560 0561 0562 0563 0564 0565 0566 0567 0568 0569 0570 0571 0572 0573 0574 0575 0576 0577 0578 0579 0580 0581 0582 0583 0584 0585 0586 0587 0588 0589 0590 0591 0592 0593 0594 0595 0596 0597 0598 0599 0600 0601 0602 0603 0604 0605 0606 0607 0608 0609 0610 0611 0612 0613 0614 0615 0616 0617 0618 0619 0620 0621 0622 0623 0624 0625 0626 0627 0628 0629 0630 0631 0632 0633 0634 0635 0636 0637 0638 0639 0640 0641 0642 0643 0644 0645 0646 0647 0648 0649 0650 0651 0652 0653 0654 0655 0656 0657 0658 0659 0660 0661 0662 0663 0664 0665 0666 0667 0668 0669 0670 0671 0672 0673 0674 0675 0676 0677 0678 0679 0680 0681 0682 0683 0684 0685 0686 0687 0688 0689 0690 0691 0692 0693 0694 0695 0696 0697 0698 0699 0700 0701 0702 0703 0704 0705 0706 0707 0708 0709 0710 0711 0712 0713 0714 0715 0716 0717 0718 0719 0720 0721 0722 0723 0724 0725 0726 0727 0728 0729 0730 0731 0732 0733 0734 0735 0736 0737 0738 0739 0740 0741 0742 0743 0744 0745 0746 0747 0748 0749 0750 0751 0752 0753 0754 0755 0756 0757 0758 0759 0760 0761 0762 0763 0764 0765 0766 0767 0768 0769 0770 0771 0772 0773 0774 0775 0776 0777 0778 0779 0780 0781 0782 0783 0784 0785 0786 0787 0788 0789 0790 0791 0792 0793 0794 0795 0796 0797 0798 0799 0800 0801 0802 0803 0804 0805 0806 0807 0808 0809 0810 0811 0812 0813 0814 0815 0816 0817 0818 0819 0820 0821 0822 0823 0824 0825 0826 0827 0828 0829 0830 0831 0832 0833 0834 0835 0836 0837 0838 0839 0840 0841 0842 0843 0844 0845 0846 0847 0848 0849 0850 0851 0852 0853 0854 0855 0856 0857 0858 0859 0860 0861 0862 0863 0864 0865 0866 0867 0868 0869 0870 0871 0872 0873 0874 0875 0876 0877 0878 0879 0880 0881 0882 0883 0884 0885 0886 0887 0888 0889 0890 0891 0892 0893 0894 0895 0896 0897 0898 0899 0900 0901 0902 0903 0904 0905 0906 0907 0908 0909 0910 0911 0912 0913 0914 0915 0916 0917 0918 0919 0920 0921 0922 0923 0924 0925 0926 0927 0928 0929 0930 0931 0932 0933 0934 0935 0936 0937 0938 0939 0940 0941 0942 0943