diff --git a/src/common/Task.cpp b/src/common/Task.cpp index 719fba2de8d..dabd2a01fce 100644 --- a/src/common/Task.cpp +++ b/src/common/Task.cpp @@ -42,7 +42,7 @@ WorkerThread* WorkerThread::start(Coordinator* coordinator) { AutoPtr thd = FB_NEW WorkerThread(coordinator); - Thread::start(workerThreadRoutine, thd, THREAD_medium, &thd->m_thdHandle); + Thread::start(workerThreadRoutine, thd, THREAD_medium, &thd->m_thread); return thd.release(); } @@ -122,7 +122,7 @@ void WorkerThread::shutdown(bool wait) if (wait) { - Thread::waitForCompletion(m_thdHandle); + m_thread.waitForCompletion(); m_state = SHUTDOWN; } } diff --git a/src/common/Task.h b/src/common/Task.h index 5297cf853f9..2ab32f396f8 100644 --- a/src/common/Task.h +++ b/src/common/Task.h @@ -168,11 +168,6 @@ class WorkerThread final ~WorkerThread() { shutdown(true); - -#ifdef WIN_NT - if (m_thdHandle != INVALID_HANDLE_VALUE) - CloseHandle(m_thdHandle); -#endif } static WorkerThread* start(Coordinator*); @@ -196,7 +191,7 @@ class WorkerThread final Semaphore m_waitSem; // idle thread waits on this semaphore to start work or go out Semaphore m_signalSem; // semaphore is released when thread going idle STATE m_state; - Thread::Handle m_thdHandle; + Thread m_thread; }; } // namespace Jrd diff --git a/src/common/ThreadStart.cpp b/src/common/ThreadStart.cpp index c066d4c526e..77b5eb8b506 100644 --- a/src/common/ThreadStart.cpp +++ b/src/common/ThreadStart.cpp @@ -104,7 +104,7 @@ THREAD_ENTRY_DECLARE threadStart(THREAD_ENTRY_PARAM arg) #ifdef USE_POSIX_THREADS #define START_THREAD -Thread Thread::start(ThreadEntryPoint* routine, void* arg, int priority_arg, Handle* p_handle) +void Thread::start(ThreadEntryPoint* routine, void* arg, int priority_arg, Thread* pThread) { /************************************** * @@ -117,17 +117,18 @@ Thread Thread::start(ThreadEntryPoint* routine, void* arg, int priority_arg, Han * status if not. * **************************************/ - pthread_t thread; - pthread_t* p_thread = p_handle ? p_handle : &thread; + Thread thread; + if (!pThread) + pThread = &thread; int state; #if defined (LINUX) || defined (FREEBSD) - if ((state = pthread_create(p_thread, NULL, THREAD_ENTRYPOINT, THREAD_ARG))) + if ((state = pthread_create(&pThread->m_handle, NULL, THREAD_ENTRYPOINT, THREAD_ARG))) Firebird::system_call_failed::raise("pthread_create", state); - if (!p_handle) + if (pThread == &thread) { - if ((state = pthread_detach(*p_thread))) + if ((state = pthread_detach(pThread->m_handle))) Firebird::system_call_failed::raise("pthread_detach", state); } #else @@ -162,13 +163,13 @@ Thread Thread::start(ThreadEntryPoint* routine, void* arg, int priority_arg, Han if (state) Firebird::system_call_failed::raise("pthread_attr_setscope", state); - if (!p_handle) + if (pThread == &thread) { state = pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_DETACHED); if (state) Firebird::system_call_failed::raise("pthread_attr_setdetachstate", state); } - state = pthread_create(p_thread, &pattr, THREAD_ENTRYPOINT, THREAD_ARG); + state = pthread_create(&pThread->m_handle, &pattr, THREAD_ENTRYPOINT, THREAD_ARG); int state2 = pthread_attr_destroy(&pattr); if (state) Firebird::system_call_failed::raise("pthread_create", state); @@ -177,37 +178,45 @@ Thread Thread::start(ThreadEntryPoint* routine, void* arg, int priority_arg, Han #endif - if (p_handle) - { #ifdef HAVE_PTHREAD_CANCEL + if (pThread != &thread) + { int dummy; // We do not want to know old cancel type state = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &dummy); if (state) Firebird::system_call_failed::raise("pthread_setcanceltype", state); -#endif } - - return Thread(*p_thread); +#endif } -void Thread::waitForCompletion(Handle& thread) +void Thread::waitForCompletion() { - int state = pthread_join(thread, NULL); - if (state) - Firebird::system_call_failed::raise("pthread_join", state); + if (isValid()) + { + int state = pthread_join(m_handle, NULL); + if (state) + Firebird::system_call_failed::raise("pthread_join", state); + m_handle = INVALID_HANDLE; + } } -void Thread::kill(Handle& thread) +// ignore errors - this is abnormal completion call +void Thread::kill() noexcept { #ifdef HAVE_PTHREAD_CANCEL - int state = pthread_cancel(thread); - if (state) - Firebird::system_call_failed::raise("pthread_cancel", state); - waitForCompletion(thread); + if (isValid()) + { + pthread_cancel(m_handle); + try + { + waitForCompletion(); + } + catch(...) { } + } #endif } -ThreadId Thread::getId() +ThreadId Thread::getCurrentThreadId() { #ifdef USE_LWP_AS_THREAD_ID static __thread int tid = 0; @@ -219,15 +228,9 @@ ThreadId Thread::getId() #endif } -bool Thread::isCurrent(Handle threadHandle) +bool Thread::isCurrent() const noexcept { - static_assert(std::is_same().value, "type mismatch"); - return pthread_equal(threadHandle, pthread_self()); -} - -bool Thread::isCurrent() -{ - return pthread_equal(internalId, pthread_self()); + return isValid() && pthread_equal(m_handle, pthread_self()); } void Thread::sleep(unsigned milliseconds) @@ -274,7 +277,7 @@ void Thread::yield() #ifdef WIN_NT #define START_THREAD -Thread Thread::start(ThreadEntryPoint* routine, void* arg, int priority_arg, Handle* p_handle) +void Thread::start(ThreadEntryPoint* routine, void* arg, int priority_arg, Thread* pThread) { /************************************** * @@ -331,9 +334,9 @@ Thread Thread::start(ThreadEntryPoint* routine, void* arg, int priority_arg, Han SetThreadPriority(handle, priority); - if (p_handle) + if (pThread) { - *p_handle = handle; + *pThread = Thread(handle, thread_id); ResumeThread(handle); } else @@ -341,42 +344,47 @@ Thread Thread::start(ThreadEntryPoint* routine, void* arg, int priority_arg, Han ResumeThread(handle); CloseHandle(handle); } +} - return Thread(thread_id); +bool Thread::waitFor(unsigned milliseconds) const noexcept +{ + if (!isValid()) + return true; + + return WaitForSingleObject(m_handle, milliseconds) != WAIT_TIMEOUT; } -void Thread::waitForCompletion(Handle& handle) +void Thread::waitForCompletion() { + if (!isValid()) + return; + // When current DLL is unloading, OS loader holds loader lock. When thread is // exiting, OS notifies every DLL about it, and acquires loader lock. In such // scenario waiting on thread handle will never succeed. if (!Firebird::dDllUnloadTID) { - WaitForSingleObject(handle, 10000); + WaitForSingleObject(m_handle, 10000); // error handler ???????????? } - CloseHandle(handle); - handle = 0; + detach(); } -void Thread::kill(Handle& handle) +void Thread::kill() noexcept { - TerminateThread(handle, -1); - CloseHandle(handle); - handle = 0; + if (isValid()) + { + TerminateThread(m_handle, -1); + detach(); + } } -ThreadId Thread::getId() +ThreadId Thread::getCurrentThreadId() { return GetCurrentThreadId(); } -bool Thread::isCurrent(Handle threadHandle) -{ - return GetCurrentThreadId() == GetThreadId(threadHandle); -} - -bool Thread::isCurrent() +bool Thread::isCurrent() const noexcept { - return GetCurrentThreadId() == internalId; + return isValid() && (GetCurrentThreadId() == m_Id); } void Thread::sleep(unsigned milliseconds) @@ -390,43 +398,3 @@ void Thread::yield() } #endif // WIN_NT - - -#ifndef START_THREAD -ThreadId Thread::start(ThreadEntryPoint* routine, void* arg, int priority_arg, Handle* p_handle) -{ -/************************************** - * - * t h r e a d _ s t a r t ( G e n e r i c ) - * - ************************************** - * - * Functional description - * Wrong attempt to start a new thread. - * - **************************************/ - fb_assert(false); - return 0; -} - -void Thread::waitForCompletion(Handle&) -{ -} - -void Thread::kill(Handle&) -{ -} - -Thread::Handle Thread::getId() -{ -} - -void Thread::sleep(unsigned milliseconds) -{ -} - -void Thread::yield() -{ -} - -#endif // START_THREAD diff --git a/src/common/ThreadStart.h b/src/common/ThreadStart.h index eb1ce698678..40412735e4f 100644 --- a/src/common/ThreadStart.h +++ b/src/common/ThreadStart.h @@ -57,11 +57,14 @@ typedef THREAD_ENTRY_DECLARE ThreadEntryPoint(THREAD_ENTRY_PARAM); #if defined(WIN_NT) typedef DWORD ThreadId; +constexpr static ThreadId INVALID_ID = 0; #elif defined(LINUX) && !defined(ANDROID) && !defined(LSB_BUILD) #define USE_LWP_AS_THREAD_ID typedef int ThreadId; +constexpr static ThreadId INVALID_ID = 0; #elif defined(USE_POSIX_THREADS) typedef pthread_t ThreadId; +constexpr static ThreadId INVALID_ID = 0; #else error - unknown ThreadId type #endif @@ -70,39 +73,149 @@ class Thread { public: #ifdef WIN_NT - typedef DWORD InternalId; typedef HANDLE Handle; + constexpr static Handle INVALID_HANDLE = INVALID_HANDLE_VALUE; #endif #ifdef USE_POSIX_THREADS typedef pthread_t Handle; - typedef pthread_t InternalId; + constexpr static Handle INVALID_HANDLE = 0; #endif - static Thread start(ThreadEntryPoint* routine, void* arg, int priority_arg, Handle* p_handle = NULL); - static void waitForCompletion(Handle& handle); - static void kill(Handle& handle); + class Mark + { + friend class Thread; + + public: + Mark(const Thread& t); + + bool operator==(const Mark&) const noexcept; + + private: + Mark() = delete; + Mark(const Mark&) = delete; + Mark(const Mark&&) = delete; + Mark& operator=(const Mark&) = delete; + Mark& operator=(const Mark&&) = delete; + +#ifdef WIN_NT + ThreadId m_Id; +#endif +#ifdef USE_POSIX_THREADS + Thread::Handle m_handle; +#endif + }; - static ThreadId getId(); + friend class Mark; + + static void start(ThreadEntryPoint* routine, void* arg, int priority_arg, Thread* pThread = nullptr); + +#ifdef WIN_NT + bool waitFor(unsigned milliseconds) const noexcept; +#endif + void waitForCompletion(); + void kill() noexcept; + + static ThreadId getCurrentThreadId(); + + Handle getHandle() const noexcept + { + return m_handle; + } static void sleep(unsigned milliseconds); static void yield(); - static bool isCurrent(Handle threadHandle); - bool isCurrent(); + bool isCurrent() const noexcept; + + bool isValid() const noexcept + { + return m_handle != INVALID_HANDLE; + } + + // invoked from dtor - ignore syscall's error + void detach(bool close = true) noexcept + { + if (isValid() && close) + { +#ifdef WIN_NT + CloseHandle(m_handle); +#endif +#ifdef USE_POSIX_THREADS + pthread_detach(m_handle); +#endif + } + m_handle = INVALID_HANDLE; + } Thread() noexcept { } + Thread(Thread&& other) noexcept + { + moveFrom(std::move(other)); + } + + ~Thread() noexcept + { + detach(); + } + + Thread& operator= (Thread&& other) noexcept + { + detach(); + moveFrom(std::move(other)); + return *this; + } + private: - Thread(InternalId iid) noexcept - : internalId(iid) +#ifdef WIN_NT + Thread(Handle handle, ThreadId id) noexcept + : m_handle(handle), m_Id(id) { } +#endif + + void moveFrom(Thread&& other) noexcept + { + fb_assert(!isValid()); + + m_handle = other.m_handle; + other.m_handle = INVALID_HANDLE; +#ifdef WIN_NT + m_Id = other.m_Id; + other.m_Id = INVALID_ID; +#endif + } - InternalId internalId{}; + Handle m_handle = INVALID_HANDLE; +#ifdef WIN_NT + ThreadId m_Id = INVALID_ID; +#endif }; + +inline bool Thread::Mark::operator==(const Thread::Mark& other) const noexcept +{ +#ifdef WIN_NT + return m_Id == other.m_Id; +#endif +#ifdef USE_POSIX_THREADS + return pthread_equal(m_handle, other.m_handle); +#endif +} + + +inline Thread::Mark::Mark(const Thread& t) +#ifdef WIN_NT + : m_Id(t.m_Id) +#endif +#ifdef USE_POSIX_THREADS + : m_handle(t.m_handle) +#endif +{ } + + inline ThreadId getThreadId() { - return Thread::getId(); + return Thread::getCurrentThreadId(); } @@ -113,8 +226,7 @@ class ThreadFinishSync typedef void ThreadRoutine(TA); ThreadFinishSync(Firebird::MemoryPool& pool, ThreadRoutine* routine, int priority_arg = THREAD_medium) - : threadHandle(0), - threadRoutine(routine), + : threadRoutine(routine), threadPriority(priority_arg), closing(false) { } @@ -122,7 +234,7 @@ class ThreadFinishSync void run(TA arg) { threadArg = arg; - Thread::start(internalRun, this, threadPriority, &threadHandle); + Thread::start(internalRun, this, threadPriority, &thread); } bool tryWait() @@ -137,15 +249,11 @@ class ThreadFinishSync void waitForCompletion() { - if (threadHandle) - { - Thread::waitForCompletion(threadHandle); - threadHandle = 0; - } + thread.waitForCompletion(); } private: - Thread::Handle threadHandle; + Thread thread; TA threadArg; ThreadRoutine* threadRoutine; int threadPriority; diff --git a/src/common/classes/Synchronize.cpp b/src/common/classes/Synchronize.cpp index 95a895a6997..bae555b4256 100644 --- a/src/common/classes/Synchronize.cpp +++ b/src/common/classes/Synchronize.cpp @@ -221,7 +221,7 @@ class ThreadSyncInstance : public ThreadSync TLS_DECLARE(ThreadSync*, threadIndex); ThreadSync::ThreadSync(const char* desc) - : threadId(getCurrentThreadId()), nextWaiting(NULL), prevWaiting(NULL), + : threadId(getThreadId()), nextWaiting(NULL), prevWaiting(NULL), lockType(SYNC_NONE), lockGranted(false), lockPending(NULL), locks(NULL), description(desc) { @@ -263,11 +263,6 @@ void ThreadSync::setThread(ThreadSync* thread) TLS_SET(threadIndex, thread); } -ThreadId ThreadSync::getCurrentThreadId() -{ - return getThreadId(); -} - const char* ThreadSync::getWhere() const { if (lockPending && lockPending->where) diff --git a/src/common/classes/Synchronize.h b/src/common/classes/Synchronize.h index c8f8ca7890a..c888437849d 100644 --- a/src/common/classes/Synchronize.h +++ b/src/common/classes/Synchronize.h @@ -84,7 +84,6 @@ friend class SyncObject; static ThreadSync* findThread(); static ThreadSync* getThread(const char* desc); - static ThreadId getCurrentThreadId(); const char* getWhere() const; diff --git a/src/common/classes/TimerImpl.cpp b/src/common/classes/TimerImpl.cpp index b2ad05f3b7e..572478b7ae2 100644 --- a/src/common/classes/TimerImpl.cpp +++ b/src/common/classes/TimerImpl.cpp @@ -53,7 +53,7 @@ void TimerImpl::handler() m_expTime = 0; if (m_onTimer) - m_handlerTid = Thread::getId(); + m_handlerTid = Thread::getCurrentThreadId(); } if (!m_onTimer) @@ -108,7 +108,7 @@ void TimerImpl::stop() MutexLockGuard guard(m_mutex, FB_FUNCTION); // Allow handler() to call stop() - if (m_handlerTid == Thread::getId()) + if (m_handlerTid == Thread::getCurrentThreadId()) return; // hvlad: it could be replaced by condition variable when we have good one for Windows diff --git a/src/common/isc_sync.cpp b/src/common/isc_sync.cpp index 364be0d149d..58aad818fed 100644 --- a/src/common/isc_sync.cpp +++ b/src/common/isc_sync.cpp @@ -328,7 +328,7 @@ class SharedFileInfo : public RefCounted else if (!guard.tryEnter()) return -1; - DEB_FLOCK("%d lock %p %c%c\n", Thread::getId(), this, shared ? 's' : 'X', wait ? 'W' : 't'); + DEB_FLOCK("%d lock %p %c%c\n", Thread::getCurrentThreadId(), this, shared ? 's' : 'X', wait ? 'W' : 't'); while (counter != 0) // file lock belongs to our process { @@ -337,14 +337,14 @@ class SharedFileInfo : public RefCounted { // one more shared lock ++counter; - DEB_FLOCK("%d fast %p c=%d\n", Thread::getId(), this, counter); + DEB_FLOCK("%d fast %p c=%d\n", Thread::getCurrentThreadId(), this, counter); return 0; } - if ((!shared) && counter < 0 && threadId == Thread::getId()) + if ((!shared) && counter < 0 && threadId == Thread::getCurrentThreadId()) { // recursive excl lock --counter; - DEB_FLOCK("%d fast %p c=%d\n", Thread::getId(), this, counter); + DEB_FLOCK("%d fast %p c=%d\n", Thread::getCurrentThreadId(), this, counter); return 0; } @@ -352,11 +352,11 @@ class SharedFileInfo : public RefCounted // wait for another thread to release a lock if (!wait) { - DEB_FLOCK("%d failed internally %p c=%d rc -1\n", Thread::getId(), this, counter); + DEB_FLOCK("%d failed internally %p c=%d rc -1\n", Thread::getCurrentThreadId(), this, counter); return -1; } - DEB_FLOCK("%d wait %p c=%d\n", Thread::getId(), this, counter); + DEB_FLOCK("%d wait %p c=%d\n", Thread::getCurrentThreadId(), this, counter); waitOn.wait(mutex); } @@ -380,13 +380,13 @@ class SharedFileInfo : public RefCounted if (!wait && (rc == EWOULDBLOCK)) rc = -1; #endif - DEB_FLOCK("%d failed on file %p c=%d rc %d\n", Thread::getId(), this, counter, rc); + DEB_FLOCK("%d failed on file %p c=%d rc %d\n", Thread::getCurrentThreadId(), this, counter, rc); return rc; } if (!shared) { - threadId = Thread::getId(); + threadId = Thread::getCurrentThreadId(); // call init() when needed if (init && !shared) @@ -395,7 +395,7 @@ class SharedFileInfo : public RefCounted // mark lock as taken counter = shared ? 1 : -1; - DEB_FLOCK("%d filelock %p c=%d\n", Thread::getId(), this, counter); + DEB_FLOCK("%d filelock %p c=%d\n", Thread::getCurrentThreadId(), this, counter); return 0; } @@ -406,7 +406,7 @@ class SharedFileInfo : public RefCounted MutexEnsureUnlock guard(mutex, FB_FUNCTION); guard.enter(); - DEB_FLOCK("%d UNlock %p c=%d\n", Thread::getId(), this, counter); + DEB_FLOCK("%d UNlock %p c=%d\n", Thread::getCurrentThreadId(), this, counter); if (counter < 0) ++counter; @@ -415,7 +415,7 @@ class SharedFileInfo : public RefCounted if (counter != 0) { - DEB_FLOCK("%d done %p c=%d\n", Thread::getId(), this, counter); + DEB_FLOCK("%d done %p c=%d\n", Thread::getCurrentThreadId(), this, counter); return; } @@ -439,7 +439,7 @@ class SharedFileInfo : public RefCounted iscLogStatus("Unlock error", &local); } - DEB_FLOCK("%d file-done %p\n", Thread::getId(), this); + DEB_FLOCK("%d file-done %p\n", Thread::getCurrentThreadId(), this); waitOn.notifyAll(); } diff --git a/src/iscguard/iscguard.cpp b/src/iscguard/iscguard.cpp index ffc1da5a914..796de0f229d 100644 --- a/src/iscguard/iscguard.cpp +++ b/src/iscguard/iscguard.cpp @@ -92,8 +92,8 @@ static Firebird::GlobalPtr remote_name; static Firebird::GlobalPtr mutex_name; // unsigned short shutdown_flag = FALSE; static log_info* log_entry; -static Thread::Handle watcher_thd = 0; -static Thread::Handle swap_icons_thd = 0; +static Thread watcher_thd; +static Thread swap_icons_thd; int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR lpszCmdLine, int /*nCmdShow*/) @@ -147,11 +147,8 @@ int WINAPI WinMain(HINSTANCE hInstance, CNTL_shutdown_service("StartServiceCtrlDispatcher failed"); } - if (watcher_thd) - { - WaitForSingleObject(watcher_thd, 5000); - CloseHandle(watcher_thd); - } + if (watcher_thd.isValid()) + watcher_thd.waitFor(5000); } else { return WINDOW_main(0); @@ -322,7 +319,7 @@ static THREAD_ENTRY_DECLARE WINDOW_main(THREAD_ENTRY_PARAM) // begin a new thread for calling the start_and_watch_server try { - Thread::start(start_and_watch_server, 0, THREAD_medium, NULL); + Thread::start(start_and_watch_server, 0, THREAD_medium); } catch (const Firebird::Exception&) { @@ -352,11 +349,6 @@ static THREAD_ENTRY_DECLARE WINDOW_main(THREAD_ENTRY_PARAM) { DestroyWindow(hPSDlg); hPSDlg = NULL; - if (swap_icons_thd) - { - CloseHandle(swap_icons_thd); - swap_icons_thd = 0; - }; } if (bPSMsg) continue; @@ -466,13 +458,19 @@ static LRESULT CALLBACK WindowFunc(HWND hWnd, UINT message, WPARAM wParam, LPARA case WM_SWITCHICONS: nRestarts++; { // scope - DWORD thr_exit = 0; - if (swap_icons_thd == 0 || - !GetExitCodeThread(swap_icons_thd, &thr_exit) || - thr_exit != STILL_ACTIVE) + + if (swap_icons_thd.isValid()) { - Thread::start(swap_icons, hWnd, THREAD_medium, &swap_icons_thd); + DWORD thr_exit = 0; + if (!GetExitCodeThread(swap_icons_thd.getHandle(), &thr_exit) || + thr_exit != STILL_ACTIVE) + { + swap_icons_thd.detach(); + } } + + if (!swap_icons_thd.isValid()) + Thread::start(swap_icons, hWnd, THREAD_medium, &swap_icons_thd); } // scope break; diff --git a/src/jrd/CryptoManager.cpp b/src/jrd/CryptoManager.cpp index 27f8b344cae..e1fae9a8e98 100644 --- a/src/jrd/CryptoManager.cpp +++ b/src/jrd/CryptoManager.cpp @@ -59,7 +59,7 @@ namespace THREAD_ENTRY_DECLARE cryptThreadStatic(THREAD_ENTRY_PARAM p) { const auto cryptoManager = (Jrd::CryptoManager*) p; - cryptoManager->cryptThread(); + cryptoManager->cryptThreadRoutine(); return 0; } @@ -320,7 +320,6 @@ namespace Jrd keyConsumers(getPool()), hash(getPool()), dbInfo(FB_NEW DbInfo(this)), - cryptThreadHandle(0), cryptPlugin(NULL), checkFactory(NULL), dbb(*tdbb->getDatabase()), @@ -338,8 +337,7 @@ namespace Jrd CryptoManager::~CryptoManager() { - if (cryptThreadHandle) - Thread::waitForCompletion(cryptThreadHandle); + cryptThread.waitForCompletion(); delete stateLock; delete threadLock; @@ -926,11 +924,8 @@ namespace Jrd void CryptoManager::terminateCryptThread(thread_db*, bool wait) { flDown = true; - if (wait && cryptThreadHandle) - { - Thread::waitForCompletion(cryptThreadHandle); - cryptThreadHandle = 0; - } + if (wait) + cryptThread.waitForCompletion(); } void CryptoManager::stopThreadUsing(thread_db* tdbb, Attachment* att) @@ -988,7 +983,7 @@ namespace Jrd // ready to go guard.leave(); // release in advance to avoid races with cryptThread() - Thread::start(cryptThreadStatic, (THREAD_ENTRY_PARAM) this, THREAD_medium, &cryptThreadHandle); + Thread::start(cryptThreadStatic, (THREAD_ENTRY_PARAM) this, THREAD_medium, &cryptThread); } catch (const Firebird::Exception&) { @@ -1006,7 +1001,7 @@ namespace Jrd } } - void CryptoManager::cryptThread() + void CryptoManager::cryptThreadRoutine() { FbLocalStatus status_vector; bool lckRelease = false; diff --git a/src/jrd/CryptoManager.h b/src/jrd/CryptoManager.h index ebc0dc8ee38..d78b897ade8 100644 --- a/src/jrd/CryptoManager.h +++ b/src/jrd/CryptoManager.h @@ -292,7 +292,7 @@ class CryptoManager final : public Firebird::PermanentStorage, public BarSync::I bool read(thread_db* tdbb, FbStatusVector* sv, Ods::pag* page, IOCallback* io); bool write(thread_db* tdbb, FbStatusVector* sv, Ods::pag* page, IOCallback* io); - void cryptThread(); + void cryptThreadRoutine(); bool checkValidation(Firebird::IDbCryptPlugin* crypt); void setDbInfo(Firebird::IDbCryptPlugin* cp); @@ -301,9 +301,10 @@ class CryptoManager final : public Firebird::PermanentStorage, public BarSync::I UCHAR getCurrentState(thread_db* tdbb) const; const char* getKeyName() const; const char* getPluginName() const; - Thread::Handle getCryptThreadHandle() const + + bool isCryptThreadCurrent() { - return cryptThreadHandle; + return cryptThread.isCurrent(); } private: @@ -382,7 +383,7 @@ class CryptoManager final : public Firebird::PermanentStorage, public BarSync::I AttachmentsRefHolder keyProviders, keyConsumers; Firebird::string hash; Firebird::RefPtr dbInfo; - Thread::Handle cryptThreadHandle; + Thread cryptThread; Firebird::IDbCryptPlugin* cryptPlugin; Factory* checkFactory; Database& dbb; diff --git a/src/jrd/ThreadCollect.h b/src/jrd/ThreadCollect.h index d1566825d0a..497c404c614 100644 --- a/src/jrd/ThreadCollect.h +++ b/src/jrd/ThreadCollect.h @@ -34,95 +34,130 @@ #include "../common/classes/array.h" #include "../common/classes/locks.h" +#include + namespace Jrd { class ThreadCollect { public: - ThreadCollect(MemoryPool& p) + ThreadCollect(Firebird::MemoryPool& p) : threads(p) { } void join() { - if (!threads.hasData()) + if (threads.empty()) return; waitFor(threads); } - void ending(Thread::Handle& h) + // put thread into completion wait queue when it finished running + void ending(Thread&& thd) { - // put thread into completion wait queue when it finished running Firebird::MutexLockGuard g(threadsMutex, FB_FUNCTION); - for (unsigned n = 0; n < threads.getCount(); ++n) + const Thread::Mark mark(thd); + + for (auto& n : threads) { - if (threads[n].hndl == h) + if (n.thread == mark) { - threads[n].ending = true; + n.ending = true; return; } } - Thrd t = {h, true}; - threads.add(t); + threads.push_back(Thrd(std::move(thd), true)); } - void running(Thread::Handle& h) + void ending(Thread::Mark& m) { - // put thread into completion wait queue when it starts running Firebird::MutexLockGuard g(threadsMutex, FB_FUNCTION); - Thrd t = {h, false}; - threads.add(t); + for (auto& n : threads) + { + if (n.thread == m) + { + n.ending = true; + return; + } + } + + fb_assert(!"Marked thread should be present in threads[]"); + } + + // put thread into completion wait queue when it starts running + void running(Thread&& thd) + { + Firebird::MutexLockGuard g(threadsMutex, FB_FUNCTION); + + threads.push_back(Thrd(std::move(thd), false)); } void houseKeeping() { - if (!threads.hasData()) + if (threads.empty()) return; // join finished threads - AllThreads t; + AllThreads finished(threads.get_allocator()); { // mutex scope Firebird::MutexLockGuard g(threadsMutex, FB_FUNCTION); - for (unsigned n = 0; n < threads.getCount(); ) + for (auto n = threads.begin(); n != threads.end(); ) { - if (threads[n].ending) + if (n->ending) { - t.add(threads[n]); - threads.remove(n); + finished.push_back(std::move(*n)); + n = threads.erase(n); } else ++n; } } - waitFor(t); + waitFor(finished); } private: struct Thrd { - Thread::Handle hndl; + Thrd(Thread&& aThread, bool ending) + : thread(std::move(aThread)), + ending(ending) + { } + + Thrd(Thrd&& other) + : thread(std::move(other.thread)), + ending(other.ending) + { } + + Thrd& operator=(Thrd&& other) + { + thread = std::move(other.thread); + ending = other.ending; + return *this; + } + + Thread thread; bool ending; }; - typedef Firebird::HalfStaticArray AllThreads; + + using AllThreads = std::vector>; void waitFor(AllThreads& thr) { Firebird::MutexLockGuard g(threadsMutex, FB_FUNCTION); - while (thr.hasData()) + while (!thr.empty()) { - FB_SIZE_T n = thr.getCount() - 1; - Thrd t = thr[n]; - thr.remove(n); + Thrd t = std::move(thr.back()); + thr.pop_back(); { Firebird::MutexUnlockGuard u(threadsMutex, FB_FUNCTION); - Thread::waitForCompletion(t.hndl); + t.thread.waitForCompletion(); fb_assert(t.ending); } } diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index c59d9f7efaa..0ccc2ed93bb 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -488,7 +488,7 @@ namespace struct AttShutParams { Semaphore thdStartedSem, startCallCompleteSem; - Thread::Handle thrHandle; + Thread thread; AttachmentsRefHolder* attachments; }; @@ -4774,13 +4774,13 @@ void JProvider::shutdown(CheckStatusWrapper* status, unsigned int timeout, const { Semaphore shutdown_semaphore; - Thread::Handle h; - Thread::start(shutdown_thread, &shutdown_semaphore, THREAD_medium, &h); + Thread shutThd; + Thread::start(shutdown_thread, &shutdown_semaphore, THREAD_medium, &shutThd); if (!shutdown_semaphore.tryEnter(0, timeout)) waitForShutdown(shutdown_semaphore); - Thread::waitForCompletion(h); + shutThd.waitForCompletion(); } else { @@ -6876,7 +6876,7 @@ static void check_database(thread_db* tdbb, bool async) } if ((attachment->att_flags & ATT_shutdown) && - (attachment->att_purge_tid != Thread::getId()) || + (attachment->att_purge_tid != Thread::getCurrentThreadId()) || (dbb->isShutdown() && (dbb->isShutdown(shut_mode_full) || !attachment->locksmith(tdbb, ACCESS_SHUTDOWN_DATABASE)))) @@ -7953,15 +7953,11 @@ void release_attachment(thread_db* tdbb, Jrd::Attachment* attachment, XThreadEns XThreadEnsureUnlock* activeThreadGuard = dropGuard; if (!activeThreadGuard) { - if (dbb->dbb_crypto_manager && - Thread::isCurrent(dbb->dbb_crypto_manager->getCryptThreadHandle())) - { + if (dbb->dbb_crypto_manager && dbb->dbb_crypto_manager->isCryptThreadCurrent()) activeThreadGuard = &dummyGuard; - } else - { activeThreadGuard = &threadGuard; - } + activeThreadGuard->enter(); } @@ -8470,7 +8466,7 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign Jrd::Attachment* attachment = sAtt->getHandle(); - if (attachment && attachment->att_purge_tid == Thread::getId()) + if (attachment && attachment->att_purge_tid == Thread::getCurrentThreadId()) { // fb_assert(false); // recursive call - impossible ? return; @@ -8499,7 +8495,7 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign return; fb_assert(attachment->att_flags & ATT_shutdown); - attachment->att_purge_tid = Thread::getId(); + attachment->att_purge_tid = Thread::getCurrentThreadId(); fb_assert(attachment->att_use_count > 0); attachment = sAtt->getHandle(); @@ -9098,12 +9094,12 @@ namespace return 0; } - Thread::Handle th = params->thrHandle; - fb_assert(th); + fb_assert(params->thread.isCurrent()); + Thread::Mark mark(params->thread); try { - shutThreadCollect->running(th); + shutThreadCollect->running(std::move(params->thread)); params->thdStartedSem.release(); MutexLockGuard guard(shutdownMutex, FB_FUNCTION); @@ -9115,7 +9111,7 @@ namespace iscLogException("attachmentShutdownThread", ex); } - shutThreadCollect->ending(th); + shutThreadCollect->ending(mark); return 0; } } // anonymous namespace @@ -9400,7 +9396,7 @@ ISC_STATUS thread_db::getCancelState(ISC_STATUS* secondary) if (tdbb_flags & (TDBB_verb_cleanup | TDBB_dfw_cleanup | TDBB_detaching | TDBB_wait_cancel_disable)) return FB_SUCCESS; - if (attachment && attachment->att_purge_tid != Thread::getId()) + if (attachment && attachment->att_purge_tid != Thread::getCurrentThreadId()) { if (attachment->att_flags & ATT_shutdown) { @@ -9910,7 +9906,7 @@ void JRD_shutdown_attachment(Attachment* attachment) AttShutParams params; params.attachments = queue; - Thread::start(attachmentShutdownThread, ¶ms, THREAD_high, ¶ms.thrHandle); + Thread::start(attachmentShutdownThread, ¶ms, THREAD_high, ¶ms.thread); params.startCallCompleteSem.release(); queue.release(); @@ -9967,7 +9963,7 @@ void JRD_shutdown_attachments(Database* dbb) { AttShutParams params; params.attachments = queue; - Thread::start(attachmentShutdownThread, ¶ms, THREAD_high, ¶ms.thrHandle); + Thread::start(attachmentShutdownThread, ¶ms, THREAD_high, ¶ms.thread); params.startCallCompleteSem.release(); queue.release(); diff --git a/src/jrd/replication/ChangeLog.cpp b/src/jrd/replication/ChangeLog.cpp index ec48f6e8481..735d474df9f 100644 --- a/src/jrd/replication/ChangeLog.cpp +++ b/src/jrd/replication/ChangeLog.cpp @@ -380,7 +380,7 @@ ChangeLog::ChangeLog(MemoryPool& pool, linkSelf(); } - Thread::start(archiver_thread, this, THREAD_medium, 0); + Thread::start(archiver_thread, this, THREAD_medium); m_startupSemaphore.enter(); m_workingSemaphore.release(); } diff --git a/src/jrd/replication/Manager.cpp b/src/jrd/replication/Manager.cpp index a1cfb75f4a9..610fe213d8b 100644 --- a/src/jrd/replication/Manager.cpp +++ b/src/jrd/replication/Manager.cpp @@ -198,7 +198,7 @@ Manager::Manager(const string& dbId, m_replicas.add(FB_NEW_POOL(getPool()) SyncReplica(getPool(), attachment, replicator)); } - Thread::start(writer_thread, this, THREAD_medium, 0); + Thread::start(writer_thread, this, THREAD_medium); m_startupSemaphore.enter(); } diff --git a/src/jrd/svc.cpp b/src/jrd/svc.cpp index b1c12d31007..8ede13e242c 100644 --- a/src/jrd/svc.cpp +++ b/src/jrd/svc.cpp @@ -703,7 +703,7 @@ Service::Service(const TEXT* service_name, USHORT spb_length, const UCHAR* spb_d svc_remote_pid(0), svc_trace_manager(NULL), svc_crypt_callback(crypt_callback), svc_existence(FB_NEW_POOL(*getDefaultMemoryPool()) SvcMutex(this)), svc_stdin_size_requested(0), svc_stdin_buffer(NULL), svc_stdin_size_preload(0), - svc_stdin_preload_requested(0), svc_stdin_user_size(0), svc_thread(0) + svc_stdin_preload_requested(0), svc_stdin_user_size(0) #ifdef DEV_BUILD , svc_debug(false) #endif @@ -1946,12 +1946,11 @@ THREAD_ENTRY_DECLARE Service::run(THREAD_ENTRY_PARAM arg) RefPtr ref(svc->svc_existence); exit_code = svc->svc_service_run->serv_thd(svc); - Thread::Handle thrHandle = svc->svc_thread; svc->started(); svc->unblockQueryGet(); svc->finish(SVC_finished); - threadCollect->ending(thrHandle); + threadCollect->ending(std::move(svc->svc_thread)); } catch (const Exception& ex) { diff --git a/src/jrd/svc.h b/src/jrd/svc.h index aa74d21c46b..4fe3a327fd0 100644 --- a/src/jrd/svc.h +++ b/src/jrd/svc.h @@ -420,8 +420,8 @@ class Service : public Firebird::UtilSvc, public TypedHandle // Size of data, placed into svc_stdin_buffer (set in put) ULONG svc_stdin_user_size; static inline constexpr ULONG PRELOAD_BUFFER_SIZE = SVC_IO_BUFFER_SIZE; - // Handle of a thread to wait for when closing - Thread::Handle svc_thread; + // Thread to wait for when closing + Thread svc_thread; #ifdef DEV_BUILD bool svc_debug; diff --git a/src/jrd/tra.cpp b/src/jrd/tra.cpp index abf2ba81db6..75d5603ab6f 100644 --- a/src/jrd/tra.cpp +++ b/src/jrd/tra.cpp @@ -1713,7 +1713,7 @@ jrd_tra* TRA_start(thread_db* tdbb, ULONG flags, SSHORT lock_timeout, Jrd::jrd_t // are running purge_attachment() because it's needed for // ON DISCONNECT triggers if (dbb->dbb_ast_flags & DBB_shut_tran && - attachment->att_purge_tid != Thread::getId()) + attachment->att_purge_tid != Thread::getCurrentThreadId()) { ERR_post(Arg::Gds(isc_shutinprog) << Arg::Str(attachment->att_filename)); } @@ -1770,7 +1770,7 @@ jrd_tra* TRA_start(thread_db* tdbb, int tpb_length, const UCHAR* tpb, Jrd::jrd_t // are running purge_attachment() because it's needed for // ON DISCONNECT triggers if (dbb->dbb_ast_flags & DBB_shut_tran && - attachment->att_purge_tid != Thread::getId()) + attachment->att_purge_tid != Thread::getCurrentThreadId()) { ERR_post(Arg::Gds(isc_shutinprog) << Arg::Str(attachment->att_filename)); } diff --git a/src/remote/client/interface.cpp b/src/remote/client/interface.cpp index fc4b6d739ac..731b68266ec 100644 --- a/src/remote/client/interface.cpp +++ b/src/remote/client/interface.cpp @@ -6311,8 +6311,7 @@ IEvents* Attachment::queEvents(CheckStatusWrapper* status, IEventCallback* callb port->connect(packet); rem_port* port_async = port->port_async; - port_async->port_events_threadId = - Thread::start(event_thread, port_async, THREAD_high, &port_async->port_events_thread); + Thread::start(event_thread, port_async, THREAD_high, &port_async->port_events_thread); port_async->port_context = rdb; } diff --git a/src/remote/inet.cpp b/src/remote/inet.cpp index 3bba75ef52c..a22027b59f2 100644 --- a/src/remote/inet.cpp +++ b/src/remote/inet.cpp @@ -1804,8 +1804,8 @@ static void disconnect(rem_port* port) SOCLOSE(port->port_channel); } - if (port->port_thread_guard && port->port_events_thread && !port->port_events_threadId.isCurrent()) - port->port_thread_guard->setWait(port->port_events_thread); + if (port->port_thread_guard && port->port_events_thread.isCurrent()) + port->port_thread_guard->setWait(std::move(port->port_events_thread)); else port->releasePort(); diff --git a/src/remote/os/win32/xnet.cpp b/src/remote/os/win32/xnet.cpp index 8e5d8dd4e30..92fbac1a804 100644 --- a/src/remote/os/win32/xnet.cpp +++ b/src/remote/os/win32/xnet.cpp @@ -1071,12 +1071,12 @@ static void cleanup_port(rem_port* port) * **************************************/ - if (port->port_thread_guard && port->port_events_thread && !port->port_events_threadId.isCurrent()) + if (port->port_thread_guard && port->port_events_thread.isCurrent()) { //port->port_thread_guard->setWait(port->port_events_thread); // Do not release XNET structures while event's thread working - Thread::waitForCompletion(port->port_events_thread); + port->port_events_thread.waitForCompletion(); } if (port->port_xcc) diff --git a/src/remote/remote.h b/src/remote/remote.h index d1ba0bd3f07..f5cfcd14881 100644 --- a/src/remote/remote.h +++ b/src/remote/remote.h @@ -1320,8 +1320,7 @@ struct rem_port : public Firebird::GlobalStorage, public Firebird::RefCounted SOCKET port_channel; // handle for connection (from by OS) struct linger port_linger; // linger value as defined by SO_LINGER Rdb* port_context; - Thread::Handle port_events_thread; // handle of thread, handling incoming events - Thread port_events_threadId; + Thread port_events_thread; // thread handling incoming events RemotePortGuard* port_thread_guard; // will close port_events_thread in safe way #ifdef WIN_NT HANDLE port_pipe; // port pipe handle @@ -1485,7 +1484,7 @@ struct rem_port : public Firebird::GlobalStorage, public Firebird::RefCounted port_flags(0), port_partial_data(false), port_z_data(false), port_connect_timeout(0), port_dummy_packet_interval(0), port_dummy_timeout(0), port_handle(INVALID_SOCKET), port_channel(INVALID_SOCKET), port_context(0), - port_events_thread(0), port_thread_guard(0), + port_thread_guard(0), #ifdef WIN_NT port_pipe(INVALID_HANDLE_VALUE), port_event(INVALID_HANDLE_VALUE), #endif @@ -1769,7 +1768,7 @@ class RemotePortGuard { if (waitFlag) { - Thread::waitForCompletion(waitHandle); + thread.waitForCompletion(); fb_assert(asyncPort); @@ -1781,7 +1780,7 @@ class RemotePortGuard } rem_port* asyncPort; - Thread::Handle waitHandle{}; + Thread thread{}; bool waitFlag; }; @@ -1794,9 +1793,9 @@ class RemotePortGuard wThr.asyncPort->port_thread_guard = this; } - void setWait(Thread::Handle& handle) noexcept + void setWait(Thread&& handle) noexcept { - wThr.waitHandle = handle; + wThr.thread = std::move(handle); wThr.waitFlag = true; fb_assert(wThr.asyncPort); wThr.asyncPort->port_thread_guard = nullptr; diff --git a/src/remote/server/ReplServer.cpp b/src/remote/server/ReplServer.cpp index b05b6a4f201..fd7d7a46b95 100644 --- a/src/remote/server/ReplServer.cpp +++ b/src/remote/server/ReplServer.cpp @@ -1054,7 +1054,7 @@ bool REPL_server(CheckStatusWrapper* status, const Replication::Config::ReplicaL for (const auto replica : replicas) { const auto target = FB_NEW Target(replica); - Thread::start(process_thread, target, THREAD_medium, NULL); + Thread::start(process_thread, target, THREAD_medium); ++activeThreads; } diff --git a/src/yvalve/MasterImplementation.cpp b/src/yvalve/MasterImplementation.cpp index 748cafaadc9..d8ec299dbc5 100644 --- a/src/yvalve/MasterImplementation.cpp +++ b/src/yvalve/MasterImplementation.cpp @@ -137,7 +137,7 @@ void abortShutdown() abortShutdownFlag = true; } -Thread::Handle timerThreadHandle = 0; +Thread timerThread; FB_BOOLEAN MasterImplementation::getProcessExiting() { @@ -149,7 +149,7 @@ FB_BOOLEAN MasterImplementation::getProcessExiting() // be terminated already, wait for its handle with zero timeout returns WAIT_TIMEOUT. // Usage of small non-zero timeout seems fixed such cases. - if (timerThreadHandle && WaitForSingleObject(timerThreadHandle, 10) != WAIT_TIMEOUT) + if (timerThread.waitFor(10)) return true; #endif @@ -180,7 +180,7 @@ struct TimerEntry static void init() { - Thread::start(timeThread, 0, THREAD_high, &timerThreadHandle); + Thread::start(timeThread, 0, THREAD_high, &timerThread); } static void cleanup(); @@ -201,7 +201,7 @@ void TimerEntry::cleanup() } timerCleanup->tryEnter(5); - Thread::waitForCompletion(timerThreadHandle); + timerThread.waitForCompletion(); while (timerQueue->hasData()) { diff --git a/src/yvalve/utl.cpp b/src/yvalve/utl.cpp index 25610b6a13e..db2d4161ae2 100644 --- a/src/yvalve/utl.cpp +++ b/src/yvalve/utl.cpp @@ -2973,7 +2973,14 @@ int API_ROUTINE gds__thread_start(FPTR_INT_VOID_PTR* entrypoint, int rc = 0; try { - Thread::start((ThreadEntryPoint*) entrypoint, arg, priority, (Thread::Handle*) thd_id); + Thread thread; + Thread::start((ThreadEntryPoint*) entrypoint, arg, priority, &thread); + + if (thd_id) + { + *static_cast(thd_id) = thread.getHandle(); + thread.detach(false); + } } catch (const status_exception& status) { diff --git a/src/yvalve/why.cpp b/src/yvalve/why.cpp index 035f867327a..65a586bc16e 100644 --- a/src/yvalve/why.cpp +++ b/src/yvalve/why.cpp @@ -836,7 +836,7 @@ class ShutdownInit : ShutdownInit(p) { shutdownSemaphore = &semaphore; - Thread::start(shutdownThread, 0, 0, &handle); + Thread::start(shutdownThread, 0, 0, &thread); procInt = ISC_signal(SIGINT, handlerInt, 0); procTerm = ISC_signal(SIGTERM, handlerTerm, 0); @@ -852,11 +852,11 @@ class ShutdownInit // Must be done to let shutdownThread close. shutdownSemaphore->release(); shutdownSemaphore = NULL; - Thread::waitForCompletion(handle); + thread.waitForCompletion(); } } private: - Thread::Handle handle; + Thread thread; }; #endif // UNIX