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 }
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; }
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; }
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; } }
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; }
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); } } }
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 }
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 }
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; }
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; }