⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ncbi_process.cpp

📁 ncbi源码
💻 CPP
字号:
/* * =========================================================================== * PRODUCTION $Log: ncbi_process.cpp,v $ * PRODUCTION Revision 1000.3  2004/06/01 19:08:38  gouriano * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.8 * PRODUCTION * =========================================================================== *//*  $Id: ncbi_process.cpp,v 1000.3 2004/06/01 19:08:38 gouriano Exp $ * =========================================================================== * *                            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 * * */#include <ncbi_pch.hpp>#include <corelib/ncbifile.hpp>#include <corelib/ncbi_system.hpp>#include <corelib/ncbi_process.hpp>#include <corelib/ncbi_safe_static.hpp>#if defined(NCBI_OS_MSWIN)#  include <process.h>#elif defined(NCBI_OS_UNIX)#  include <sys/types.h>#  include <signal.h>#  include <sys/wait.h>#  include <errno.h>#  include <unistd.h>#endifBEGIN_NCBI_SCOPE///////////////////////////////////////////////////////////////////////////////// CProcess //// Predefined timeouts (in microseconds)const unsigned long kWaitPrecision = 100; const unsigned long CProcess::kDefaultKillTimeout = 1000;CProcess::CProcess(long process, EProcessType type)    : m_Process(process), m_Type(type){    return;}#if defined(NCBI_OS_MSWIN)// The helper constructor for MS Windows to avoid cast from HANDLE to longCProcess::CProcess(HANDLE process, EProcessType type)    : m_Process((long)process), m_Type(type){    return;}#endifTPid CProcess::GetCurrentPid(void){#ifdef NCBI_OS_UNIX    return getpid();#elif defined(NCBI_OS_MSWIN)    return GetCurrentProcessId();#else#  error "Not implemented on this platform"#endif}bool CProcess::IsAlive(void) const{#ifdef NCBI_OS_UNIX    if ( kill((TPid)m_Process, 0) < 0  &&  errno != EPERM ) {        return false;    }    return true;#elif defined(NCBI_OS_MSWIN)    HANDLE hProcess = 0;    if (m_Type == ePid) {        hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, m_Process);        if (!hProcess) {            return GetLastError() == ERROR_ACCESS_DENIED;        }    } else {        hProcess = (HANDLE)m_Process;    }    DWORD status = 0;    _ASSERT(STILL_ACTIVE != 0);    GetExitCodeProcess(hProcess, &status);    if (m_Type == ePid) {        CloseHandle(hProcess);    }    return status == STILL_ACTIVE;#else#  error "Not implemented on this platform"#endif}bool CProcess::Kill(unsigned long timeout) const{#ifdef NCBI_OS_UNIX    TPid pid = (TPid)m_Process;    int status;    // Try to kill process    if (kill(pid, SIGTERM) == -1  &&  errno == EPERM) {        return false;    }    // Check process termination within timeout    do {        if (waitpid(pid, &status, WNOHANG) == pid) {            // Release zombie process from the system            waitpid(pid, &status, 0);            return true;        }        unsigned long x_sleep = kWaitPrecision;        if (timeout < kWaitPrecision) {            x_sleep = timeout;        }        if ( x_sleep ) {            timeout -= x_sleep;            SleepMilliSec(x_sleep);        }    } while (timeout);    // Try harder to kill stubborn process    if (kill(pid, SIGKILL) == -1  &&  errno == EPERM) {        return false;    }    // Release zombie process from the system    if (waitpid(pid, &status, WNOHANG) == pid) {        waitpid(pid, &status, 0);    }    return true;#elif defined(NCBI_OS_MSWIN)    HANDLE hProcess    = NULL;    HANDLE hThread     = NULL;    bool   enable_sync = true;    // Get process handle    if (m_Type == ePid) {        hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_TERMINATE |                               SYNCHRONIZE, FALSE, m_Process);        if ( !hProcess ) {            enable_sync = false;            hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, m_Process);            if (!hProcess   &&  GetLastError() == ERROR_ACCESS_DENIED) {                return false;            }        }    } else {        hProcess = (HANDLE)m_Process;    }    // Check process handle    if ( !hProcess  ||  hProcess == INVALID_HANDLE_VALUE ) {        return true;    }    // Terminate process    bool terminated = false;    try {        // Safe process termination        // (kernel32.dll loaded at same address in each process)        FARPROC exitproc = GetProcAddress(GetModuleHandle("KERNEL32.DLL"),                                          "ExitProcess");        if ( exitproc ) {            hThread = CreateRemoteThread(hProcess, NULL, 0,                                         (LPTHREAD_START_ROUTINE)exitproc,                                         0, 0, 0);        }        // Wait for process terminated, or timeout expired        if (enable_sync  &&  timeout) {            if (WaitForSingleObject(hProcess, timeout) == WAIT_OBJECT_0) {                throw true;            }        }        // Try harder to kill stubborn process        if ( TerminateProcess(hProcess, -1) != 0  ||             GetLastError() == ERROR_INVALID_HANDLE ) {            // If process terminated succesfuly or error occur but            // process handle became invalid -- process has terminated            terminated = true;        }    }    catch (bool e) {        terminated = e;    }    // Close opened temporary process handle    if ( hThread ) {        CloseHandle(hThread);    }    if (m_Type == ePid ) {        CloseHandle(hProcess);    }    return terminated;#else#  error "Not implemented on this platform"#endif}int CProcess::Wait(unsigned long timeout) const{#if defined(NCBI_OS_UNIX)    TPid  pid     = (TPid)m_Process;    int   options = (timeout == kMax_ULong /*infinite*/) ? 0 : WNOHANG;    int   status;    // Check process termination within timeout (or infinite)    do {        TPid ws = waitpid(pid, &status, options);        if (ws > 0) {            // Process has terminated.            if ( options ) {                // Release zombie process from the system.                waitpid(pid, &status, 0);            }            return WEXITSTATUS(status);        }         else if (ws < 0  &&  errno != EINTR ) {            // Some error            break;        }        // Process is still running        unsigned long x_sleep = kWaitPrecision;        if (timeout != kMax_ULong /*infinite*/) {            if (timeout < kWaitPrecision) {                x_sleep = timeout;            }            timeout -= x_sleep;        }        if ( x_sleep ) {            SleepMilliSec(x_sleep);        }    } while (timeout);     return -1;#elif defined(NCBI_OS_MSWIN)    HANDLE hProcess;    bool   enable_sync = true;    // Get process handle    if (m_Type == ePid) {        hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE,                               FALSE, m_Process);        if ( !hProcess ) {            enable_sync = false;            hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, m_Process);            if (!hProcess   &&  GetLastError() == ERROR_ACCESS_DENIED) {                return false;            }        }    } else {        hProcess = (HANDLE)m_Process;    }    DWORD status = -1;    try {        // Is process still running?        if ( !hProcess  || hProcess == INVALID_HANDLE_VALUE ) {            throw -1;        }        if ( GetExitCodeProcess(hProcess, &status)  &&             status != STILL_ACTIVE ) {            throw (int)status;        }        // Wait for process termination, or timeout expired        if (enable_sync  &&  timeout) {            DWORD tv = (timeout == kMax_ULong) ? INFINITE : (DWORD)timeout;            if (WaitForSingleObject(hProcess, tv) != WAIT_OBJECT_0) {                throw -1;            }        }        // Get process exit code        if ( !GetExitCodeProcess(hProcess, &status) ) {            throw -1;        }    }    catch (int e) {        status = e;    }    if (m_Type == ePid ) {        CloseHandle(hProcess);    }    return (int)status;#else#  error "Not implemented on this platform"#endif}///////////////////////////////////////////////////////////////////////////////// CPIDGuard//// Protective mutexDEFINE_STATIC_FAST_MUTEX(s_PidGuardMutex);// NOTE: This method to protect PID file works only within one process.//       CPIDGuard know nothing about PID file modification or deletion //       by other processes. Be aware.CPIDGuard::CPIDGuard(const string& filename, const string& dir)    : m_OldPID(0), m_NewPID(0){    string real_dir;    CDirEntry::SplitPath(filename, &real_dir, 0, 0);    if (real_dir.empty()) {        if (dir.empty()) {            real_dir = CDir::GetTmpDir();        } else {            real_dir = dir;        }        m_Path = CDirEntry::MakePath(real_dir, filename);    } else {        m_Path = filename;    }    UpdatePID();}CPIDGuard::~CPIDGuard(void){    Release();}void CPIDGuard::Release(void){    if ( !m_Path.empty() ) {        // MT-Safe protect        CFastMutexGuard LOCK(s_PidGuardMutex);        // Read info        TPid pid = 0;        unsigned int ref = 0;        CNcbiIfstream in(m_Path.c_str());        if ( in.good() ) {            in >> pid >> ref;            in.close();            if ( m_NewPID != pid ) {                // We do not own this file more                return;            }            if ( ref ) {                ref--;            }            // Check reference counter            if ( ref ) {                // Write updated reference counter into the file                CNcbiOfstream out(m_Path.c_str(),                                  IOS_BASE::out | IOS_BASE::trunc);                if ( out.good() ) {                    out << pid << endl << ref << endl;                }                if ( !out.good() ) {                    NCBI_THROW(CPIDGuardException, eWrite,                               "Unable to write into PID file " + m_Path +": "                               + strerror(errno));                }            } else {                // Remove the file                CDirEntry(m_Path).Remove();            }        }        m_Path.erase();    }}void CPIDGuard::UpdatePID(TPid pid){    if (pid == 0) {        pid = CProcess::GetCurrentPid();    }    // MT-Safe protect    CFastMutexGuard LOCK(s_PidGuardMutex);    // Read old PID    unsigned int ref = 1;    CNcbiIfstream in(m_Path.c_str());    if ( in.good() ) {        in >> m_OldPID >> ref;        if ( m_OldPID == pid ) {            // Guard the same PID. Just increase the reference counter.            ref++;        } else {            if ( CProcess(m_OldPID,CProcess::ePid).IsAlive() ) {                NCBI_THROW2(CPIDGuardException, eStillRunning,                            "Process is still running", m_OldPID);            }            ref = 1;        }    }    in.close();    // Write new PID    CNcbiOfstream out(m_Path.c_str(), IOS_BASE::out | IOS_BASE::trunc);    if ( out.good() ) {        out << pid << endl << ref << endl;    }    if ( !out.good() ) {        NCBI_THROW(CPIDGuardException, eWrite,                   "Unable to write into PID file " + m_Path + ": "                   + strerror(errno));    }    // Save updated pid    m_NewPID = pid;}END_NCBI_SCOPE/* * =========================================================================== * $Log: ncbi_process.cpp,v $ * Revision 1000.3  2004/06/01 19:08:38  gouriano * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.8 * * Revision 1.8  2004/05/18 17:01:15  ivanov * CProcess:: *     + WaitForAlive(), WaitForTerminate(). *     Fixed UNIX version Wait() to correct work with infinite timeouts. * CPIDGuard:: *     Fixed CPIDGuard to use reference counters in PID file. *     Added CPIDGuard::Remove(). * * Revision 1.7  2004/05/14 13:59:26  gorelenk * Added include of ncbi_pch.hpp * * Revision 1.6  2004/03/04 19:08:36  ivanov * Fixed CProcess::IsAlive() * * Revision 1.5  2003/12/04 18:45:35  ivanov * Added helper constructor for MS Windows to avoid cast from HANDLE to long * * Revision 1.4  2003/12/03 17:03:01  ivanov * Fixed Kill() to handle zero timeouts * * Revision 1.3  2003/10/01 20:23:26  ivanov * Added const specifier to CProcess class member functions * * Revision 1.2  2003/09/25 17:18:21  ucko * UNIX: +<unistd.h> for getpid() * * Revision 1.1  2003/09/25 16:53:41  ivanov * Initial revision. CPIDGuard class moved from ncbi_system.cpp. * * =========================================================================== */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -