bool CProcess::KillGroupById(TPid pgid, unsigned long timeout)
{
#if   defined(NCBI_OS_UNIX)

    // Try to kill the process group with SIGTERM first
    if (kill(-pgid, SIGTERM) < 0  &&  errno == EPERM) {
        return false;
    }

    // Check process group termination within the timeout 
    unsigned long x_timeout = timeout;
    for (;;) {
        // Reap the zombie (if group leader is a child) up from the system
        TPid reap = waitpid(pgid, static_cast<int*>(NULL), WNOHANG);
        if (reap) {
            if (reap != (TPid)(-1)) {
                _ASSERT(reap == pgid);
                return true;
            }
            if (errno != ECHILD)
                return false;
            if (kill(-pgid, 0) < 0) {
                return true;
            }
        }
        unsigned long x_sleep = kWaitPrecision;
        if (x_sleep > x_timeout) {
            x_sleep = x_timeout;
        }
        if ( !x_sleep ) {
             break;
        }
        SleepMilliSec(x_sleep);
        x_timeout  -= x_sleep;
    }
    _ASSERT(!x_timeout);

    // Try harder to kill the stubborn processes -- SIGKILL may not be caught!
    int res = kill(-pgid, SIGKILL);
    if ( !timeout ) {
        return res <= 0;
    }
    SleepMilliSec(kWaitPrecision);
    // Reap the zombie (if group leader is a child) up from the system
    waitpid(pgid, static_cast<int*>(NULL), WNOHANG);
    // Check whether the process cannot be killed
    // (most likely due to a kernel problem)
    return kill(-pgid, 0) < 0;

#elif defined(NCBI_OS_MSWIN)

    // Cannot be implemented, use non-static version of KillGroup()
    // for specified process.
    return false;

#endif
}
示例#2
0
    int Run(void)
    {
        CMyThread* thr[10];
        for (int i = 0; i < 10; ++i) {
            thr[i] = new CMyThread(i);
            thr[i]->Run();
        }

        //for (int i = 0; i < 10; ++i) {
        for (;;) {
            string errMsg;
            list<string> servers;
            CSDBAPI::EMirrorStatus status = CSDBAPI::UpdateMirror("MSDEV", &servers, &errMsg);
            if(status == CSDBAPI::eMirror_Unavailable)
                ERR_POST("SQL mirror check failed, error: " << errMsg);
            else if(status == CSDBAPI::eMirror_NewMaster)
                ERR_POST(Warning << "Master server has been switched. New master: " 
                                 << (servers.empty() ? kEmptyStr : servers.front()));
            else if(status != CSDBAPI::eMirror_Steady)
                ERR_POST("DB connection pool unknown status.");
            SleepMilliSec(1000);
        }

        for (int i = 0; i < 10; ++i) {
            thr[i]->Join();
        }
        return 0;
    }
示例#3
0
 virtual void* Main(void) {
     //for (int i = 0; i < 10; ++i) {
     for (;;) {
         try {
             CDatabase db("MSDEV");
             db.Connect();
             CQuery q = db.NewQuery("select serverproperty('servername')");
             q.Execute();
             LOG_POST("Thread " << m_Num << " connected to " << q.begin()[1].AsString());
             try {
                 q.SetSql("drop table #t");
                 q.Execute();
             }
             catch (CSDB_Exception&) {
                 //
             }
             q.SetSql("create table #t (tt varchar(100))");
             q.Execute();
             q.SetSql("insert into #t values (@tt)");
             for (int i = 0; i < 500; ++i) {
                 q.SetParameter("@tt", i, eSDB_String);
                 q.Execute();
             }
             SleepMilliSec(100);
         }
         catch (CSDB_Exception& ex) {
             LOG_POST("Error from SDBAPI in thread " << m_Num << ": " << ex);
         }
     }
     return NULL;
 }
示例#4
0
CTestTask::EStatus CTestTask::Execute(void)
{
    int duration = s_WaitPeriods[m_Serial];
    CStopWatch timer(CStopWatch::eStart);

    if (s_CancelTypes[m_Serial] == eCheckCancel) {
        MSG_POST("Task " << m_Serial << ": " << duration << " with checking");
        for (int i = 0; i < 10; ++i) {
            SleepMicroSec(duration * 100);
            if (IsCancelRequested()) {
                MSG_POST("Task " << m_Serial << " was cancelled");
                return eCanceled;
            }
        }
    }
    else {
        MSG_POST("Task " << m_Serial << ": " << duration);
        SleepMilliSec(duration);
    }

    if (IsCancelRequested()) {
        MSG_POST("Task " << m_Serial
                    << " was cancelled without check (time spent - "
                    << timer.Elapsed() << ")");
        return eCanceled;
    }
    else {
        MSG_POST("Task " << m_Serial << " complete (time spent - "
                    << timer.Elapsed() << ")");
        return eCompleted;
    }
}
示例#5
0
void CTestSemaphoreApp::Consume(int Num)
{
    for (int i = Num; i > 0; --i ) {
        // we can only consume one by one
        s_semContent.Wait();
        s_semStorage.Wait();
        --s_Counter;
        NcbiCout << "-1=" << s_Counter << NcbiEndl;
        s_semStorage.Post();
        SleepMilliSec(500);
    }
}
    int Do(CWorkerNodeJobContext& context)
    {
        CNcbiIstream& is = context.GetIStream();
        string input_type;
        is >> input_type;
        if (input_type != "doubles") {
            context.CommitJobWithFailure(
                "This worker node can only process the 'doubles' input type.");
            return 1;
        }
        int vsize;
        is >> vsize;
        vector<double> v(vsize);
        for (int i = 0; i < vsize; ++i)
            is >> v[i];

        unsigned delay = m_SleepTimeDistr.GetNextValue();

        if (delay > 0)
            SleepMilliSec(delay);

        if (m_Random.GetRand() <
                TParam_FailureRate::GetDefault() * m_Random.GetMax())
            context.CommitJobWithFailure("FAILED");
        else {
            sort(v.begin(), v.end());

            CNcbiOstream& os = context.GetOStream();
            os << vsize << ' ';
            for (int i = 0; i < vsize; ++i)
                os << v[i] << ' ';
            context.CommitJob();
        }

        return 0;
    }
示例#7
0
void CTestSemaphoreApp::Produce(int Num)
{
    // Storage semaphore acts as a kind of mutex - its only purpose
    // is to protect Counter
    s_semStorage.Wait();
    s_Counter += Num;
    NcbiCout << "+" << Num << "=" << s_Counter << NcbiEndl;
    s_semStorage.Post();

    // Content semaphore notifies consumer threads of how many items can be
    // consumed. Slow consumption with fast production causes Content semaphore
    // to overflow from time to time. We catch exception and wait for consumers
    // to consume something
    for (bool Posted=false; !Posted;) {
        try {
            s_semContent.Post(Num);
            Posted = true;
        }
        catch (exception& e) {
            NcbiCout << e.what() << NcbiEndl;
            SleepMilliSec(500);
        }
    }
}
示例#8
0
void CLockVectorGuard<TLockVect>::DoLock()
{
    _ASSERT(m_LockSet == false);

    // Strategy implemented here is spin-and-lock
    // works fine if rate of contention is relatively low
    // in the future needs to be changed so lock vector returns semaphor to
    // wait until requested id is free
    //
    for (unsigned i = 0; i < m_Spins; ++i) {
        m_LockSet = m_LockVector->TryLock(m_Id);
        if (m_LockSet) {
            return;
        }
    } // for

    // plain spin lock did not work -- try to lock it gracefully
    //
    unsigned sleep_ms = 10;
    unsigned time_spent = 0;
    while (true) {
        m_LockSet = m_LockVector->TryLock(m_Id);
        if (m_LockSet) {
            return;
        }
        SleepMilliSec(sleep_ms);
        if (m_Timeout) {
            time_spent += sleep_ms;
            if (time_spent > m_Timeout) {
                string msg = "Lock vector timeout error on object id="
                    + NStr::UIntToString(m_Id);
                NCBI_THROW(CMutexException, eTryLock, msg);
            }
        }
    } // while
}
int CProcess::Wait(unsigned long timeout, CExitInfo* info) const
{
    int  status;

    // Reset extended information
    if (info) {
        info->state  = eExitInfo_Unknown;
        info->status = 0;
    }

#if   defined(NCBI_OS_UNIX)

    TPid pid     = (TPid)m_Process;
    int  options = timeout == kInfiniteTimeoutMs ? 0 : WNOHANG;

    // Check process termination (with timeout or indefinitely)
    for (;;) {
        TPid ws = waitpid(pid, &status, options);
        if (ws > 0) {
            // terminated
            _ASSERT(ws == pid);
            if (info) {
                info->state  = eExitInfo_Terminated;
                info->status = status;
            }
            return WIFEXITED(status) ? WEXITSTATUS(status) : -1;
        } else if (ws == 0) {
            // still running
            _ASSERT(timeout != kInfiniteTimeoutMs);
            if ( !timeout ) {
                if (info) {
                    info->state = eExitInfo_Alive;
                }
                break;
            }
            unsigned long x_sleep = kWaitPrecision;
            if (x_sleep > timeout) {
                x_sleep = timeout;
            }
            SleepMilliSec(x_sleep);
            timeout    -= x_sleep;
        } else if (errno != EINTR) {
            // error
            break;
        }
    }
    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, (TPid)m_Process);
        if ( !hProcess ) {
            enable_sync = false;
            hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, (TPid)m_Process);
            if (!hProcess   &&  GetLastError() == ERROR_ACCESS_DENIED) {
                return -1;
            }
        }
    } else {
        hProcess = (TProcessHandle)m_Process;
        if (!hProcess  ||  hProcess == INVALID_HANDLE_VALUE) {
            return -1;
        }
    }

    status = -1;
    DWORD x_status;
    // Is process still running?
    if (GetExitCodeProcess(hProcess, &x_status)) {
        if (x_status == STILL_ACTIVE) {
            if (enable_sync  &&  timeout) {
                DWORD tv = (timeout == kInfiniteTimeoutMs
                            ? INFINITE
                            : (DWORD)timeout);
                DWORD ws = WaitForSingleObject(hProcess, tv);
                switch(ws) {
                case WAIT_TIMEOUT:
                    // still running
                    _ASSERT(x_status == STILL_ACTIVE);
                    break;
                case WAIT_OBJECT_0:
                    if (GetExitCodeProcess(hProcess, &x_status)) {
                        if (x_status != STILL_ACTIVE) {
                            // terminated
                            status = 0;
                        } // else still running
                        break;
                    }
                    /*FALLTHRU*/
                default:
                    // error
                    x_status = 0;
                    break;
                }
            } // else still running
        } else {
            // terminated
            status = 0;
        }
    } else {
        // error
        x_status = 0;
    }

    if (status < 0) {
        if (info  &&  x_status == STILL_ACTIVE) {
            info->state  = eExitInfo_Alive;
        }
    } else {
        if (info) {
            info->state  = eExitInfo_Terminated;
            info->status = x_status;
        }
        status = x_status;
    }

    if (m_Type == ePid) {
        CloseHandle(hProcess);
    }
    return status;

#endif
}
示例#10
0
bool CProcess::Kill(unsigned long timeout) const
{
#if   defined(NCBI_OS_UNIX)

    TPid pid = (TPid)m_Process;

    // Try to kill the process with SIGTERM first
    if (kill(pid, SIGTERM) < 0  &&  errno == EPERM) {
        return false;
    }

    // Check process termination within the timeout
    unsigned long x_timeout = timeout;
    for (;;) {
        TPid reap = waitpid(pid, static_cast<int*>(NULL), WNOHANG);
        if (reap) {
            if (reap != (TPid)(-1)) {
                _ASSERT(reap == pid);
                return true;
            }
            if (errno != ECHILD)
                return false;
            if (kill(pid, 0) < 0)
                return true;
        }
        unsigned long x_sleep = kWaitPrecision;
        if (x_sleep > x_timeout) {
            x_sleep = x_timeout;
        }
        if ( !x_sleep ) {
             break;
        }
        SleepMilliSec(x_sleep);
        x_timeout  -= x_sleep;
    }
    _ASSERT(!x_timeout);

    // Try harder to kill the stubborn process -- SIGKILL may not be caught!
    int res = kill(pid, SIGKILL);
    if ( !timeout ) {
        return res <= 0;
    }
    SleepMilliSec(kWaitPrecision);
    // Reap the zombie (if child) up from the system
    waitpid(pid, static_cast<int*>(NULL), WNOHANG);
    // Check whether the process cannot be killed
    // (most likely due to a kernel problem)
    return kill(pid, 0) < 0;

#elif defined(NCBI_OS_MSWIN)

    // Safe process termination
    bool safe = (timeout > 0);

    // Try to kill current process?
    if ( m_Type == ePid  &&  (TPid)m_Process == GetCurrentPid() ) {
        ExitProcess(-1);
        // NOTREACHED
        return false;
    }

    HANDLE hProcess    = NULL;
    HANDLE hThread     = NULL;
    bool   enable_sync = true;

    // Get process handle
    if (m_Type == eHandle) {
        hProcess = (TProcessHandle)m_Process;

    } else {  // m_Type == ePid
        hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_TERMINATE |
                               SYNCHRONIZE, FALSE, (TPid)m_Process);
        if ( !hProcess ) {
            // Try to open with minimal access right needed
            // to terminate process.
            enable_sync = false;
            hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, (TPid)m_Process);
            if (!hProcess) {
                if (GetLastError() != ERROR_ACCESS_DENIED) {
                    return false;
                }
                // If we have an administrative rights, that we can try
                // to terminate the process using SE_DEBUG_NAME privilege,
                // which system administrators normally have, but it might
                // be disabled by default. When this privilege is enabled,
                // the calling thread can open processes with any access
                // rights regardless of the security descriptor assigned
                // to the process.

                // Determine OS version
                OSVERSIONINFO vi;
                vi.dwOSVersionInfoSize = sizeof(vi);
                GetVersionEx(&vi);
                if (vi.dwPlatformId != VER_PLATFORM_WIN32_NT) {
                    return false;
                }

                // Get current thread token 
                HANDLE hToken;
                if (!OpenThreadToken(GetCurrentThread(), 
                                     TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES,
                                     FALSE, &hToken)) {
                    if (GetLastError() != ERROR_NO_TOKEN) {
                        return false;
                    }
                    // Rrevert to the process token, if not impersonating
                    if (!OpenProcessToken(GetCurrentProcess(),
                                          TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES,
                                          &hToken)) {
                        return false;
                    }
                }

                // Try to enable the SE_DEBUG_NAME privilege

                TOKEN_PRIVILEGES tp, tp_prev;
                DWORD            tp_prev_size = sizeof(tp_prev);

                tp.PrivilegeCount = 1;
                tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
                LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);

                if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp),
                                           &tp_prev, &tp_prev_size)) {
                    CloseHandle(hToken);
                    return false;
                }
                if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) {
                    // The AdjustTokenPrivileges function cannot add new
                    // privileges to the access token. It can only enable or
                    // disable the token's existing privileges.
                    CloseHandle(hToken);
                    return false;
                }

                // Try to open process handle again
                hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, (TPid)m_Process);
                
                // Restore original privilege state
                AdjustTokenPrivileges(hToken, FALSE, &tp_prev, sizeof(tp_prev),
                                      NULL, NULL);
                CloseHandle(hToken);
            }
        }
    }

    // Check process handle
    if ( !hProcess  ||  hProcess == INVALID_HANDLE_VALUE ) {
        return true;
    }
    // Terminate process
    bool terminated = false;

    CStopWatch timer;
    if ( safe ) {
        timer.Start();
    }
    // Safe process termination
    if ( safe  &&  enable_sync ) {
        // (kernel32.dll loaded at same address in each process)
        FARPROC exitproc = GetProcAddress(GetModuleHandleA("KERNEL32.DLL"),
                                          "ExitProcess");
        if ( exitproc ) {
            hThread = CreateRemoteThread(hProcess, NULL, 0,
                                        (LPTHREAD_START_ROUTINE)exitproc,
                                        0, 0, 0);
            // Wait until process terminated, or timeout expired
            if (hThread   &&
                (WaitForSingleObject(hProcess, timeout) == WAIT_OBJECT_0)){
                terminated = true;
            }
        }
    }
    // Try harder to kill stubborn process
    if ( !terminated ) {
        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;
        }
    }
    if (safe  &&  terminated) {
        // The process terminating now.
        // Reset flag, and wait for real process termination.

        terminated = false;
        double elapsed = timer.Elapsed() * kMilliSecondsPerSecond;
        unsigned long linger_timeout = (elapsed < timeout) ? 
            (unsigned long)((double)timeout - elapsed) : 0;

        for (;;) {
            if ( !IsAlive() ) {
                terminated = true;
                break;
            }
            unsigned long x_sleep = kWaitPrecision;
            if (x_sleep > linger_timeout) {
                x_sleep = linger_timeout;
            }
            if ( !x_sleep ) {
                break;
            }
            SleepMilliSec(x_sleep);
            linger_timeout -= x_sleep;
        }
    }
    // Close temporary process handle
    if ( hThread ) {
        CloseHandle(hThread);
    }
    if (m_Type == ePid) {
        CloseHandle(hProcess);
    }
    return terminated;

#endif
}
示例#11
0
void CInterProcessLock::Lock(const CTimeout& timeout,
                             const CTimeout& granularity)
{
    CFastMutexGuard LOCK(s_ProcessLock);

    // Check that lock with specified name not already locked
    // in the current process.
    TLocks::iterator it = s_Locks->find(m_SystemName);

    if (m_Handle != kInvalidLockHandle) {
        // The lock is already set in this CInterProcessLock object,
        // just increase reference counter.
        _VERIFY(it != s_Locks->end());
        it->second++;
        return;
    } else {
        if (it != s_Locks->end()) {
            // The lock already exists in the current process.
            // We can use one CInterProcessLock object with
            // multiple Lock() calls, but not with different
            // CInterProcessLock objects. For example, on MS-Windows,
            // we cannot wait on the same mutex in the same thread.
            // So, two different objects can set locks simultaneously.
            // And for OS-compatibility we can do nothing here,
            // except throwing an exception.
            NCBI_THROW(CInterProcessLockException, eMultipleLocks,
                       "Attempt to lock already locked object " \
                       "in the same process");
        }
    }

    // Try to acquire a lock with specified timeout

#if defined(NCBI_OS_UNIX)

    // Open lock file
    mode_t perm = CDirEntry::MakeModeT(
        CDirEntry::fRead | CDirEntry::fWrite /* user */,
        CDirEntry::fRead | CDirEntry::fWrite /* group */,
        0, 0 /* other & special */);
    int fd = open(m_SystemName.c_str(), O_CREAT | O_RDWR, perm);
    if (fd == -1) {
        NCBI_THROW(CInterProcessLockException, eCreateError,
                   string("Error creating lockfile ") + m_SystemName + 
                   ": " + strerror(errno));
    }

    // Try to acquire the lock
    
    int x_errno = 0;
    
    if (timeout.IsInfinite()  ||  timeout.IsDefault()) {
        while ((x_errno = s_UnixLock(fd))) {
            if (errno != EAGAIN)
                break;
        }

    } else {
        unsigned long ms = timeout.GetAsMilliSeconds();
        if ( !ms ) {
            // Timeout == 0
            x_errno = s_UnixLock(fd);
        } else {
            // Timeout > 0
            unsigned long ms_gran;
            if ( granularity.IsInfinite()  ||
                 granularity.IsDefault() ) 
            {
                ms_gran = min(ms/5, (unsigned long)500);
            } else {
                ms_gran = granularity.GetAsMilliSeconds();
            }
            // Try to lock within specified timeout
            for (;;) {
                x_errno = s_UnixLock(fd);
                if ( !x_errno ) {
                    // Successfully locked
                    break;
                }
                if (x_errno != EACCES  &&
                    x_errno != EAGAIN ) {
                    // Error
                    break;
                }
                // Otherwise -- sleep granularity timeout
                unsigned long ms_sleep = ms_gran;
                if (ms_sleep > ms) {
                    ms_sleep = ms;
                }
                if ( !ms_sleep ) {
                     break;
                }
                SleepMilliSec(ms_sleep);
                ms -= ms_sleep;
            }
            // Timeout
            if ( !ms ) {
                close(fd);
                NCBI_THROW(CInterProcessLockException, eLockTimeout,
                           "The lock could not be acquired in the time " \
                           "allotted");
            }
        } // if (!ms)
    } // if (timeout.IsInfinite())
    
    // Error
    if ( x_errno ) {
        close(fd);
        NCBI_THROW(CInterProcessLockException, eLockError,
                   "Error creating lock");
    }
    // Success
    m_Handle = fd;

#elif defined(NCBI_OS_MSWIN)

    HANDLE  handle  = ::CreateMutex(NULL, TRUE, _T_XCSTRING(m_SystemName));
    errno_t errcode = ::GetLastError();
    if (handle == kInvalidLockHandle) {
        switch(errcode) {
            case ERROR_ACCESS_DENIED:
                // Mutex with specified name already exists, 
                // but we don't have enough rights to open it.
                NCBI_THROW(CInterProcessLockException, eLockError,
                           "The lock already exists");
                break;
            case ERROR_INVALID_HANDLE:
                // Some system object with the same name already exists
                NCBI_THROW(CInterProcessLockException, eLockError,
                           "Error creating lock, system object with the same" \
                           "name already exists");
                break;
            default:
                // Unknown error
                NCBI_THROW(CInterProcessLockException, eCreateError,
                           "Error creating lock");
                break;
        }
    } else {
        // Mutex with specified name already exists
        if (errcode == ERROR_ALREADY_EXISTS) {
            // Wait
            DWORD res;
            if (timeout.IsInfinite()  ||  timeout.IsDefault()) {
                res = WaitForSingleObject(handle, INFINITE);
            } else {
                res = WaitForSingleObject(handle, timeout.GetAsMilliSeconds());
            }
            switch(res) {
                case WAIT_OBJECT_0:
                    // The lock has been acquired
                    break;
                case WAIT_TIMEOUT:
                    ::CloseHandle(handle);
                    NCBI_THROW(CInterProcessLockException, eLockTimeout,
                               "The lock could not be acquired in the time " \
                               "allotted");
                    break;
                case WAIT_ABANDONED:
                    // The lock is in abandoned state... Other thread/process
                    // owning it was terminated. We can reuse this mutex, but 
                    // it is better to wait until it will be released by OS.
                    /* FALLTHRU */
                default:
                    ::CloseHandle(handle);
                    NCBI_THROW(CInterProcessLockException, eLockError,
                               "Error creating lock");
                    break;
            }
        }
        m_Handle = handle;
    }
#endif
    // Set reference counter to 1
    (*s_Locks)[m_SystemName] = 1;
}
示例#12
0
bool CThreadPoolTester::Thread_Run(int idx)
{
    bool status = true;

    try {
        for (int i = 0;  i < kTasksPerThread;  ++i) {
            int serial_num = s_SerialNum.Add(1);
            double need_time = double(s_PostTimes[serial_num]) / 1000;
            double now_time = s_Timer.Elapsed();
            if (now_time < need_time) {
                SleepMicroSec(int((need_time - now_time) * 1000000));
            }

            int req_num = s_ActionTasks[serial_num];
            switch (s_Actions[serial_num]) {
            case eAddTask:
                MSG_POST("Task " << req_num << " to be queued");
                s_Pool->AddTask(new CTestTask(req_num));
                MSG_POST("Task " << req_num << " queued");
                break;

            case eAddExclusiveTask:
                MSG_POST("Task " << req_num << " to be queued");
                s_Pool->RequestExclusiveExecution(new CExclusiveTask(req_num),
                                CThreadPool::fFlushThreads
                                + CThreadPool::fCancelExecutingTasks
                                + CThreadPool::fCancelQueuedTasks);
                MSG_POST("Task " << req_num << " queued");
                break;

            case eCancelTask:
                while (!s_Tasks[req_num]) {
                    SleepMilliSec(10);
                }
                MSG_POST("Task " << req_num << " to be cancelled");
                s_Pool->CancelTask(s_Tasks[req_num]);
                MSG_POST("Cancelation of task " << req_num << " requested");
                break;

            case eFlushWaiting:
            case eFlushNoWait:
                MSG_POST("Flushing threads with "
                            << (s_Actions[serial_num] == eFlushWaiting?
                                    "waiting": "immediate restart"));
                s_Pool->FlushThreads(
                                s_Actions[serial_num] == eFlushWaiting?
                                        CThreadPool::eWaitToFinish:
                                        CThreadPool::eStartImmediately);
                MSG_POST("Flushing process began");
                break;

            case eCancelAll:
                MSG_POST("Cancelling all tasks");
                s_Pool->CancelTasks(CThreadPool::fCancelExecutingTasks
                                     + CThreadPool::fCancelQueuedTasks);
                MSG_POST("Cancellation of all tasks requested");
                break;
            }
        }
    } STD_CATCH_ALL("CThreadPoolTester: status " << (status = false))

    return status;
}