From 40f782ae3e918c4f3842571ff8064be1c4f54961 Mon Sep 17 00:00:00 2001
From: AlexPeshkoff <peshkoff@mail.ru>
Date: Fri, 13 Jan 2017 14:29:54 +0300
Subject: [PATCH] Backported fix for CORE-5452: Segfault when engine's dynamic
 library is unloaded right after closing worker threads (GC and/or cache
 writer)

---
 src/alice/alice_meta.epp                     |  1 -
 src/burp/burp.h                              |  2 -
 src/common/ThreadStart.h                     | 86 ++++++++++++++++++++++++++++
 src/common/classes/Synchronize.h             |  5 +-
 src/common/classes/misc/class_perf.cpp       |  1 -
 src/common/xdr.cpp                           |  2 -
 src/gpre/boot/gpre_meta_boot.cpp             |  1 -
 src/gpre/std/gpre_meta.epp                   |  1 -
 src/include/fb_exception.h                   |  1 -
 src/include/firebird.h                       |  1 -
 src/isql/OptionsBase.cpp                     |  1 -
 src/isql/extract.epp                         |  1 -
 src/isql/isql.epp                            |  5 --
 src/jrd/Attachment.h                         |  1 +
 src/jrd/Database.h                           |  6 +-
 src/jrd/Mapping.cpp                          | 26 +++++----
 src/jrd/cch.cpp                              | 31 +++++-----
 src/jrd/cch.h                                | 14 ++++-
 src/jrd/event.cpp                            | 13 +++--
 src/jrd/event_proto.h                        |  7 +--
 src/jrd/intl.cpp                             |  1 -
 src/jrd/trace/TraceConfigStorage.h           |  1 +
 src/jrd/vio.cpp                              | 23 ++++----
 src/lock/lock.cpp                            | 29 ++++++----
 src/lock/lock_proto.h                        |  8 +--
 src/qli/command.cpp                          |  1 -
 src/qli/dtr.h                                |  1 -
 src/qli/lex.cpp                              |  4 --
 src/qli/meta.epp                             |  1 -
 src/utilities/gsec/gsecswi.h                 |  1 -
 src/utilities/gstat/dba.epp                  |  1 +
 src/utilities/nbackup/nbkswi.h               |  1 -
 src/utilities/ntrace/os/win32/FileObject.cpp |  1 -
 src/yvalve/gds.cpp                           |  1 +
 src/yvalve/preparse.cpp                      |  1 -
 35 files changed, 182 insertions(+), 99 deletions(-)

diff --git a/src/alice/alice_meta.epp b/src/alice/alice_meta.epp
index d0f59bc..65dc37e 100644
--- a/src/alice/alice_meta.epp
+++ b/src/alice/alice_meta.epp
@@ -30,7 +30,6 @@
 #include "firebird.h"
 #include <stdio.h>
 #include "../jrd/ibase.h"
-//#include "../jrd/license.h"
 #include "../alice/alice.h"
 #include "../alice/alice_meta.h"
 #include "../yvalve/gds_proto.h"
diff --git a/src/burp/burp.h b/src/burp/burp.h
index 293a91f..fe26335 100644
--- a/src/burp/burp.h
+++ b/src/burp/burp.h
@@ -769,8 +769,6 @@ struct burp_meta_obj
 // I need to review if we tolerate different lengths for different OS's here.
 const unsigned int MAX_FILE_NAME_SIZE		= 256;
 
-//#include "../jrd/svc.h"
-
 #include "../burp/std_desc.h"
 
 #ifdef WIN_NT
diff --git a/src/common/ThreadStart.h b/src/common/ThreadStart.h
index 85e6a38..823c5c1 100644
--- a/src/common/ThreadStart.h
+++ b/src/common/ThreadStart.h
@@ -31,6 +31,7 @@
 #define JRD_THREADSTART_H
 
 #include "../common/ThreadData.h"
+#include "../common/classes/semaphore.h"
 
 #ifdef WIN_NT
 #include <windows.h>
@@ -89,4 +90,89 @@ inline ThreadId getThreadId()
 	return Thread::getId();
 }
 
+
+#ifndef USE_POSIX_THREADS
+#define USE_FINI_SEM
+#endif
+
+template <typename TA>
+class ThreadFinishSync
+{
+public:
+	typedef void ThreadRoutine(TA);
+
+	ThreadFinishSync(Firebird::MemoryPool& pool, ThreadRoutine* routine, int priority_arg)
+		:
+#ifdef USE_FINI_SEM
+		  fini(pool),
+#else
+		  threadHandle(0),
+#endif
+		  threadRoutine(routine),
+		  threadPriority(priority_arg)
+	{ }
+
+	void run(TA arg)
+	{
+		threadArg = arg;
+
+		Thread::start(internalRun, this, threadPriority
+#ifndef USE_FINI_SEM
+					, &threadHandle
+#endif
+			);
+	}
+
+	void waitForCompletion()
+	{
+#ifdef USE_FINI_SEM
+		fini.enter();
+#else
+		Thread::waitForCompletion(threadHandle);
+		threadHandle = 0;
+#endif
+	}
+
+private:
+#ifdef USE_FINI_SEM
+	Firebird::Semaphore fini;
+#else
+	Thread::Handle threadHandle;
+#endif
+
+	TA threadArg;
+	ThreadRoutine* threadRoutine;
+	int threadPriority;
+	bool starting;
+
+	static THREAD_ENTRY_DECLARE internalRun(THREAD_ENTRY_PARAM arg)
+	{
+		((ThreadFinishSync*)arg)->internalRun();
+		return 0;
+	}
+
+	void internalRun()
+	{
+		try
+		{
+			threadRoutine(threadArg);
+		}
+		catch (const Firebird::Exception& ex)
+		{
+			threadArg->exceptionHandler(ex, threadRoutine);
+		}
+
+#ifdef USE_FINI_SEM
+		try
+		{
+			fini.release();
+		}
+		catch (const Firebird::Exception& ex)
+		{
+			threadArg->exceptionHandler(ex, threadRoutine);
+		}
+#endif
+	}
+};
+
 #endif // JRD_THREADSTART_H
diff --git a/src/common/classes/Synchronize.h b/src/common/classes/Synchronize.h
index 198de44..3788541 100644
--- a/src/common/classes/Synchronize.h
+++ b/src/common/classes/Synchronize.h
@@ -33,10 +33,7 @@
 #define CLASSES_SYNCHRONIZE_H
 
 #include "../common/classes/SyncObject.h"
-
-#ifndef WIN_NT
-#include "fb_pthread.h"
-#endif
+#include "../common/ThreadStart.h"
 
 
 namespace Firebird {
diff --git a/src/common/classes/misc/class_perf.cpp b/src/common/classes/misc/class_perf.cpp
index 97b7bb3..142bfde 100644
--- a/src/common/classes/misc/class_perf.cpp
+++ b/src/common/classes/misc/class_perf.cpp
@@ -28,7 +28,6 @@
 
 #include "tree.h"
 #include "alloc.h"
-//#include "../memory/memory_pool.h"
 #include <stdio.h>
 #include <time.h>
 #include <set>
diff --git a/src/common/xdr.cpp b/src/common/xdr.cpp
index b9f9f4d..1dfff76 100644
--- a/src/common/xdr.cpp
+++ b/src/common/xdr.cpp
@@ -26,9 +26,7 @@
 
 #include "firebird.h"
 #include <string.h>
-//#include "../remote/remote.h"
 #include "../common/xdr.h"
-//#include "../remote/proto_proto.h"
 #include "../common/xdr_proto.h"
 #include "../yvalve/gds_proto.h"
 #include "../common/gdsassert.h"
diff --git a/src/gpre/boot/gpre_meta_boot.cpp b/src/gpre/boot/gpre_meta_boot.cpp
index 0fde018..1f302c6 100644
--- a/src/gpre/boot/gpre_meta_boot.cpp
+++ b/src/gpre/boot/gpre_meta_boot.cpp
@@ -32,7 +32,6 @@
 #include <string.h>
 #include "../jrd/ibase.h"
 #include "../gpre/gpre.h"
-//#include "../jrd/license.h"
 #include "../jrd/intl.h"
 #include "../gpre/gpre_proto.h"
 #include "../gpre/hsh_proto.h"
diff --git a/src/gpre/std/gpre_meta.epp b/src/gpre/std/gpre_meta.epp
index 34ff932..0780dd4 100644
--- a/src/gpre/std/gpre_meta.epp
+++ b/src/gpre/std/gpre_meta.epp
@@ -32,7 +32,6 @@
 #include <string.h>
 #include "../jrd/ibase.h"
 #include "../gpre/gpre.h"
-//#include "../jrd/license.h"
 #include "../jrd/intl.h"
 #include "../gpre/gpre_proto.h"
 #include "../gpre/hsh_proto.h"
diff --git a/src/include/fb_exception.h b/src/include/fb_exception.h
index 030cf94..c4c1df4 100644
--- a/src/include/fb_exception.h
+++ b/src/include/fb_exception.h
@@ -43,7 +43,6 @@
 
 #include "fb_types.h"
 #include "firebird/Interface.h"
-#include "../common/ThreadStart.h"
 
 namespace Firebird
 {
diff --git a/src/include/firebird.h b/src/include/firebird.h
index 3d74354..87f0a11 100644
--- a/src/include/firebird.h
+++ b/src/include/firebird.h
@@ -68,7 +68,6 @@
 
 #ifdef __cplusplus
 #include "../common/common.h"
-//#include "fb_exception.h"
 #endif
 
 #ifndef NULL
diff --git a/src/isql/OptionsBase.cpp b/src/isql/OptionsBase.cpp
index 5a78540..0974fa3 100644
--- a/src/isql/OptionsBase.cpp
+++ b/src/isql/OptionsBase.cpp
@@ -24,7 +24,6 @@
 
 #include "firebird.h"
 #include "OptionsBase.h"
-//#include "../common/utils_proto.h"  // strnicmp
 #include "../common/gdsassert.h"
 
 
diff --git a/src/isql/extract.epp b/src/isql/extract.epp
index ec2ddb1..99e821c 100644
--- a/src/isql/extract.epp
+++ b/src/isql/extract.epp
@@ -59,7 +59,6 @@
 #include "../jrd/ods.h"
 #include "../common/utils_proto.h"
 #include "../jrd/constants.h"
-//#include "../common/classes/ImplementHelper.h"
 
 using MsgFormat::SafeArg;
 
diff --git a/src/isql/isql.epp b/src/isql/isql.epp
index ccadce2..98b37bb 100644
--- a/src/isql/isql.epp
+++ b/src/isql/isql.epp
@@ -46,7 +46,6 @@
 #include "firebird.h"
 #include <stdio.h>
 #include "../yvalve/keywords.h"
-//#include "../yvalve/gds_proto.h"
 #include "../jrd/intl.h"
 #include <stdlib.h>
 #include <stdarg.h>
@@ -79,10 +78,6 @@
 #include <locale.h>
 #endif
 
-//#ifdef HAVE_IO_H
-//#include <io.h> // mktemp
-//#endif
-
 #ifdef HAVE_EDITLINE_H
 // This is a local file included in our distribution - but not always
 // compiled into the system
diff --git a/src/jrd/Attachment.h b/src/jrd/Attachment.h
index 2807db3..e71610e 100644
--- a/src/jrd/Attachment.h
+++ b/src/jrd/Attachment.h
@@ -39,6 +39,7 @@
 #include "../common/classes/array.h"
 #include "../common/classes/stack.h"
 #include "../common/classes/timestamp.h"
+#include "../common/ThreadStart.h"
 
 #include "../jrd/EngineInterface.h"
 
diff --git a/src/jrd/Database.h b/src/jrd/Database.h
index 0eab40d..f0f44d3 100644
--- a/src/jrd/Database.h
+++ b/src/jrd/Database.h
@@ -440,7 +440,7 @@ public:
 	GarbageCollector*	dbb_garbage_collector;	// GarbageCollector class
 	Firebird::Semaphore dbb_gc_sem;		// Event to wake up garbage collector
 	Firebird::Semaphore dbb_gc_init;	// Event for initialization garbage collector
-	Firebird::Semaphore dbb_gc_fini;	// Event for finalization garbage collector
+	ThreadFinishSync<Database*> dbb_gc_fini;	// Sync for finalization garbage collector
 
 	Firebird::MemoryStats dbb_memory_stats;
 	RuntimeStatistics dbb_stats;
@@ -511,6 +511,7 @@ private:
 		dbb_owner(*p),
 		dbb_pools(*p, 4),
 		dbb_sort_buffers(*p),
+		dbb_gc_fini(*p, garbage_collector, THREAD_medium),
 		dbb_stats(*p),
 		dbb_lock_owner_id(getLockOwnerId()),
 		dbb_tip_cache(NULL),
@@ -560,6 +561,9 @@ public:
 	// reset sweep flags and release sweep lock
 	void clearSweepFlags(thread_db* tdbb);
 
+	static void garbage_collector(Database* dbb);
+	void exceptionHandler(const Firebird::Exception& ex, ThreadFinishSync<Database*>::ThreadRoutine* routine);
+
 private:
 	//static int blockingAstSharedCounter(void*);
 	static int blocking_ast_sweep(void* ast_object);
diff --git a/src/jrd/Mapping.cpp b/src/jrd/Mapping.cpp
index c1bcf0e..8df7e2f 100644
--- a/src/jrd/Mapping.cpp
+++ b/src/jrd/Mapping.cpp
@@ -581,7 +581,8 @@ class MappingIpc FB_FINAL : public Firebird::IpcObject
 
 public:
 	explicit MappingIpc(MemoryPool&)
-		: processId(getpid())
+		: processId(getpid()),
+		  cleanupSync(*getDefaultMemoryPool(), clearDelivery, THREAD_high)
 	{ }
 
 	~MappingIpc()
@@ -602,7 +603,7 @@ public:
 		sMem->process[process].flags &= ~MappingHeader::FLAG_ACTIVE;
 		(void)  // Ignore errors in cleanup
             sharedMemory->eventPost(&sMem->process[process].notifyEvent);
-		cleanupSemaphore.tryEnter(5);
+		cleanupSync.waitForCompletion();
 
 		// Ignore errors in cleanup
 		sharedMemory->eventFini(&sMem->process[process].notifyEvent);
@@ -755,7 +756,7 @@ public:
 
 		try
 		{
-			Thread::start(clearDelivery, this, THREAD_high);
+			cleanupSync.run(this);
 		}
 		catch (const Exception&)
 		{
@@ -764,6 +765,12 @@ public:
 		}
 	}
 
+	void exceptionHandler(const Exception& ex, ThreadFinishSync<MappingIpc*>::ThreadRoutine*)
+	{
+		iscLogException("Fatal error in clearDeliveryThread", ex);
+		fb_utils::logAndDie("Fatal error in clearDeliveryThread");
+	}
+
 private:
 	void clearDeliveryThread()
 	{
@@ -801,13 +808,10 @@ private:
 			}
 			if (startup)
 				startupSemaphore.release();
-
-			cleanupSemaphore.release();
 		}
 		catch (const Exception& ex)
 		{
-			iscLogException("Fatal error in clearDeliveryThread", ex);
-			fb_utils::logAndDie("Fatal error in clearDeliveryThread");
+			exceptionHandler(ex, NULL);
 		}
 	}
 
@@ -862,11 +866,9 @@ private:
 		MappingIpc* const data;
 	};
 
-	static THREAD_ENTRY_DECLARE clearDelivery(THREAD_ENTRY_PARAM par)
+	static void clearDelivery(MappingIpc* mapping)
 	{
-		MappingIpc* m = (MappingIpc*)par;
-		m->clearDeliveryThread();
-		return 0;
+		mapping->clearDeliveryThread();
 	}
 
 	AutoPtr<SharedMemory<MappingHeader> > sharedMemory;
@@ -874,7 +876,7 @@ private:
 	const SLONG processId;
 	unsigned process;
 	Semaphore startupSemaphore;
-	Semaphore cleanupSemaphore;
+	ThreadFinishSync<MappingIpc*> cleanupSync;
 };
 
 GlobalPtr<MappingIpc, InstanceControl::PRIORITY_DELETE_FIRST> mappingIpc;
diff --git a/src/jrd/cch.cpp b/src/jrd/cch.cpp
index e1d403b..1bf714f 100644
--- a/src/jrd/cch.cpp
+++ b/src/jrd/cch.cpp
@@ -120,14 +120,11 @@ static BufferDesc* alloc_bdb(thread_db*, BufferControl*, UCHAR **);
 static Lock* alloc_page_lock(Jrd::thread_db*, BufferDesc*);
 static int blocking_ast_bdb(void*);
 #ifdef CACHE_READER
-static THREAD_ENTRY_DECLARE cache_reader(THREAD_ENTRY_PARAM);
-
 static void prefetch_epilogue(Prefetch*, FbStatusVector *);
 static void prefetch_init(Prefetch*, thread_db*);
 static void prefetch_io(Prefetch*, FbStatusVector *);
 static void prefetch_prologue(Prefetch*, SLONG *);
 #endif
-static THREAD_ENTRY_DECLARE cache_writer(THREAD_ENTRY_PARAM);
 static void check_precedence(thread_db*, WIN*, PageNumber);
 static void clear_precedence(thread_db*, BufferDesc*);
 static BufferDesc* dealloc_bdb(BufferDesc*);
@@ -1438,7 +1435,7 @@ void CCH_init2(thread_db* tdbb)
 
 		try
 		{
-			Thread::start(cache_writer, dbb, THREAD_medium);
+			bcb->bcb_writer_fini.run(bcb);
 		}
 		catch (const Exception&)
 		{
@@ -2017,7 +2014,7 @@ void CCH_shutdown(thread_db* tdbb)
 	{
 		bcb->bcb_flags &= ~BCB_cache_writer;
 		bcb->bcb_writer_sem.release(); // Wake up running thread
-		bcb->bcb_writer_fini.enter();
+		bcb->bcb_writer_fini.waitForCompletion();
 	}
 
 	SyncLockGuard bcbSync(&bcb->bcb_syncObject, SYNC_EXCLUSIVE, "CCH_shutdown");
@@ -2692,7 +2689,7 @@ static void flushAll(thread_db* tdbb, USHORT flush_flag)
 
 
 #ifdef CACHE_READER
-static THREAD_ENTRY_DECLARE cache_reader(THREAD_ENTRY_PARAM arg)
+void BufferControl::cache_reader(BufferControl* bcb)
 {
 /**************************************
  *
@@ -2706,7 +2703,7 @@ static THREAD_ENTRY_DECLARE cache_reader(THREAD_ENTRY_PARAM arg)
  *	busy at a time.
  *
  **************************************/
-	Database* dbb = (Database*) arg;
+	Database* dbb = bcb->bcb_database;
 	Database::SyncGuard dsGuard(dbb);
 
 	FbLocalStatus status_vector;
@@ -2846,7 +2843,7 @@ static THREAD_ENTRY_DECLARE cache_reader(THREAD_ENTRY_PARAM arg)
 #endif
 
 
-static THREAD_ENTRY_DECLARE cache_writer(THREAD_ENTRY_PARAM arg)
+void BufferControl::cache_writer(BufferControl* bcb)
 {
 /**************************************
  *
@@ -2859,8 +2856,7 @@ static THREAD_ENTRY_DECLARE cache_writer(THREAD_ENTRY_PARAM arg)
  *
  **************************************/
 	FbLocalStatus status_vector;
-	Database* const dbb = (Database*) arg;
-	BufferControl* const bcb = dbb->dbb_bcb;
+	Database* const dbb = bcb->bcb_database;
 
 	try
 	{
@@ -2964,8 +2960,7 @@ static THREAD_ENTRY_DECLARE cache_writer(THREAD_ENTRY_PARAM arg)
 	}	// try
 	catch (const Firebird::Exception& ex)
 	{
-		ex.stuffException(&status_vector);
-		iscDbLogStatus(dbb->dbb_filename.c_str(), &status_vector);
+		bcb->exceptionHandler(ex, cache_writer);
 	}
 
 	bcb->bcb_flags &= ~BCB_cache_writer;
@@ -2977,15 +2972,19 @@ static THREAD_ENTRY_DECLARE cache_writer(THREAD_ENTRY_PARAM arg)
 			bcb->bcb_flags &= ~BCB_writer_start;
 			bcb->bcb_writer_init.release();
 		}
-		bcb->bcb_writer_fini.release();
 	}
 	catch (const Firebird::Exception& ex)
 	{
-		ex.stuffException(&status_vector);
-		iscDbLogStatus(dbb->dbb_filename.c_str(), &status_vector);
+		bcb->exceptionHandler(ex, cache_writer);
 	}
+}
 
-	return 0;
+
+void BufferControl::exceptionHandler(const Firebird::Exception& ex, BcbSync::ThreadRoutine* /*routine*/)
+{
+	FbLocalStatus status_vector;
+	ex.stuffException(&status_vector);
+	iscDbLogStatus(bcb_database->dbb_filename.c_str(), &status_vector);
 }
 
 
diff --git a/src/jrd/cch.h b/src/jrd/cch.h
index b920566..b7f8486 100644
--- a/src/jrd/cch.h
+++ b/src/jrd/cch.h
@@ -29,6 +29,7 @@
 #include "../common/classes/RefCounted.h"
 #include "../common/classes/semaphore.h"
 #include "../common/classes/SyncObject.h"
+#include "../common/ThreadStart.h"
 #ifdef SUPERSERVER_V2
 #include "../jrd/sbm.h"
 #include "../jrd/pag.h"
@@ -85,7 +86,8 @@ class BufferControl : public pool_alloc<type_bcb>
 	BufferControl(MemoryPool& p, Firebird::MemoryStats& parentStats)
 		: bcb_bufferpool(&p),
 		  bcb_memory_stats(&parentStats),
-		  bcb_memory(p)
+		  bcb_memory(p),
+		  bcb_writer_fini(p, cache_writer, THREAD_medium)
 	{
 		bcb_database = NULL;
 		QUE_INIT(bcb_in_use);
@@ -144,18 +146,24 @@ public:
 	Firebird::SyncObject	bcb_syncLRU;
 	//Firebird::SyncObject	bcb_syncPageWrite;
 
+	typedef ThreadFinishSync<BufferControl*> BcbSync;
+
+	static void cache_writer(BufferControl* bcb);
 	Firebird::Semaphore bcb_writer_sem;		// Wake up cache writer
 	Firebird::Semaphore bcb_writer_init;	// Cache writer initialization
-	Firebird::Semaphore bcb_writer_fini;	// Cache writer finalization
+	BcbSync bcb_writer_fini;				// Cache writer finalization
 #ifdef SUPERSERVER_V2
+	static void cache_reader(BufferControl* bcb);
 	// the code in cch.cpp is not tested for semaphore instead event !!!
 	Firebird::Semaphore bcb_reader_sem;		// Wake up cache reader
 	Firebird::Semaphore bcb_reader_init;	// Cache reader initialization
-	Firebird::Semaphore bcb_reader_fini;	// Cache reader finalization
+	BcbSync bcb_reader_fini;				// Cache reader finalization
 
 	PageBitmap*	bcb_prefetch;		// Bitmap of pages to prefetch
 #endif
 
+	void exceptionHandler(const Firebird::Exception& ex, BcbSync::ThreadRoutine* routine);
+
 	bcb_repeat*	bcb_rpt;
 };
 
diff --git a/src/jrd/event.cpp b/src/jrd/event.cpp
index 3a6bf28..cb6dc33 100644
--- a/src/jrd/event.cpp
+++ b/src/jrd/event.cpp
@@ -126,6 +126,7 @@ EventManager::EventManager(const Firebird::string& id, Firebird::RefPtr<Config>
 	  m_processOffset(0),
 	  m_dbId(getPool(), id),
 	  m_config(conf),
+	  m_cleanupSync(getPool(), watcher_thread, THREAD_medium),
 	  m_sharedFileCreated(false),
 	  m_exiting(false)
 {
@@ -146,7 +147,7 @@ EventManager::~EventManager()
 		// Terminate the event watcher thread
 		m_startupSemaphore.tryEnter(5);
 		(void) m_sharedMemory->eventPost(&m_process->prb_event);
-		m_cleanupSemaphore.tryEnter(5);
+		m_cleanupSync.waitForCompletion();
 
 #ifdef HAVE_OBJECT_MAP
 		m_sharedMemory->unmapObject(&localStatus, &m_process);
@@ -697,7 +698,7 @@ void EventManager::create_process()
 
 	release_shmem();
 
-	Thread::start(watcher_thread, this, THREAD_medium);
+	m_cleanupSync.run(this);
 }
 
 
@@ -1414,12 +1415,16 @@ void EventManager::watcher_thread()
 		{
 			m_startupSemaphore.release();
 		}
-		m_cleanupSemaphore.release();
 	}
 	catch (const Firebird::Exception& ex)
 	{
-		iscLogException("Error closing event watcher thread\n", ex);
+		exceptionHandler(ex, NULL);
 	}
 }
 
+void EventManager::exceptionHandler(const Firebird::Exception& ex, ThreadFinishSync<EventManager*>::ThreadRoutine*)
+{
+	iscLogException("Error closing event watcher thread\n", ex);
+}
+
 } // namespace
diff --git a/src/jrd/event_proto.h b/src/jrd/event_proto.h
index 3301203..9bfd20e 100644
--- a/src/jrd/event_proto.h
+++ b/src/jrd/event_proto.h
@@ -63,6 +63,7 @@ public:
 
 	bool initialize(Firebird::SharedMemoryBase*, bool);
 	void mutexBug(int osErrorCode, const char* text);
+	void exceptionHandler(const Firebird::Exception& ex, ThreadFinishSync<EventManager*>::ThreadRoutine* routine);
 
 private:
 	void acquire_shmem();
@@ -91,11 +92,9 @@ private:
 	void detach_shared_file();
 	void get_shared_file_name(Firebird::PathName&) const;
 
-	static THREAD_ENTRY_DECLARE watcher_thread(THREAD_ENTRY_PARAM arg)
+	static void watcher_thread(EventManager* eventMgr)
 	{
-		EventManager* const eventMgr = static_cast<EventManager*>(arg);
 		eventMgr->watcher_thread();
-		return 0;
 	}
 
 	static void mutex_bugcheck(const TEXT*, int);
@@ -109,7 +108,7 @@ private:
 	Firebird::AutoPtr<Firebird::SharedMemory<evh> > m_sharedMemory;
 
 	Firebird::Semaphore m_startupSemaphore;
-	Firebird::Semaphore m_cleanupSemaphore;
+	ThreadFinishSync<EventManager*> m_cleanupSync;
 
 	bool m_sharedFileCreated;
 	bool m_exiting;
diff --git a/src/jrd/intl.cpp b/src/jrd/intl.cpp
index 6666c5f..b0e662b 100644
--- a/src/jrd/intl.cpp
+++ b/src/jrd/intl.cpp
@@ -104,7 +104,6 @@
 #include "../intl/charsets.h"
 #include "../intl/country_codes.h"
 #include "../common/gdsassert.h"
-//#include "../jrd/license.h"
 #ifdef INTL_BUILTIN
 #include "../intl/ld_proto.h"
 #endif
diff --git a/src/jrd/trace/TraceConfigStorage.h b/src/jrd/trace/TraceConfigStorage.h
index ca973c0..3d08143 100644
--- a/src/jrd/trace/TraceConfigStorage.h
+++ b/src/jrd/trace/TraceConfigStorage.h
@@ -32,6 +32,7 @@
 #include "../../common/classes/fb_string.h"
 #include "../../common/classes/init.h"
 #include "../../common/isc_s_proto.h"
+#include "../../common/ThreadStart.h"
 #include "../../jrd/trace/TraceSession.h"
 #include "../../common/classes/RefCounted.h"
 
diff --git a/src/jrd/vio.cpp b/src/jrd/vio.cpp
index 02c5809..8ca9f66 100644
--- a/src/jrd/vio.cpp
+++ b/src/jrd/vio.cpp
@@ -107,7 +107,6 @@ static bool dfw_should_know(record_param* org_rpb, record_param* new_rpb,
 	USHORT irrelevant_field, bool void_update_is_relevant = false);
 static void garbage_collect(thread_db*, record_param*, ULONG, RecordStack&);
 static void garbage_collect_idx(thread_db*, record_param*, Record*, Record*);
-static THREAD_ENTRY_DECLARE garbage_collector(THREAD_ENTRY_PARAM);
 
 
 #ifdef VIO_DEBUG
@@ -1958,7 +1957,7 @@ void VIO_fini(thread_db* tdbb)
 	{
 		dbb->dbb_flags &= ~DBB_garbage_collector;
 		dbb->dbb_gc_sem.release(); // Wake up running thread
-		dbb->dbb_gc_fini.enter();
+		dbb->dbb_gc_fini.waitForCompletion();
 	}
 }
 
@@ -2420,7 +2419,7 @@ void VIO_init(thread_db* tdbb)
 			{
 				try
 				{
-					Thread::start(garbage_collector, dbb, THREAD_medium);
+					dbb->dbb_gc_fini.run(dbb);
 				}
 				catch (const Exception&)
 				{
@@ -4741,7 +4740,7 @@ static void garbage_collect_idx(thread_db* tdbb,
 }
 
 
-static THREAD_ENTRY_DECLARE garbage_collector(THREAD_ENTRY_PARAM arg)
+void Database::garbage_collector(Database* dbb)
 {
 /**************************************
  *
@@ -4758,7 +4757,6 @@ static THREAD_ENTRY_DECLARE garbage_collector(THREAD_ENTRY_PARAM arg)
  *
  **************************************/
 	FbLocalStatus status_vector;
-	Database* const dbb = (Database*) arg;
 
 	try
 	{
@@ -4989,8 +4987,7 @@ static THREAD_ENTRY_DECLARE garbage_collector(THREAD_ENTRY_PARAM arg)
 	}	// try
 	catch (const Firebird::Exception& ex)
 	{
-		ex.stuffException(&status_vector);
-		iscDbLogStatus(dbb->dbb_filename.c_str(), &status_vector);
+		dbb->exceptionHandler(ex, NULL);
 	}
 
 	dbb->dbb_flags &= ~(DBB_garbage_collector | DBB_gc_active | DBB_gc_pending);
@@ -5003,15 +5000,19 @@ static THREAD_ENTRY_DECLARE garbage_collector(THREAD_ENTRY_PARAM arg)
 			dbb->dbb_flags &= ~DBB_gc_starting;
 			dbb->dbb_gc_init.release();
 		}
-		dbb->dbb_gc_fini.release();
 	}
 	catch (const Firebird::Exception& ex)
 	{
-		ex.stuffException(&status_vector);
-		iscDbLogStatus(dbb->dbb_filename.c_str(), &status_vector);
+		dbb->exceptionHandler(ex, NULL);
 	}
+}
+
 
-	return 0;
+void Database::exceptionHandler(const Firebird::Exception& ex, ThreadFinishSync<Database*>::ThreadRoutine* /*routine*/)
+{
+	FbLocalStatus status_vector;
+	ex.stuffException(&status_vector);
+	iscDbLogStatus(dbb_filename.c_str(), &status_vector);
 }
 
 
diff --git a/src/lock/lock.cpp b/src/lock/lock.cpp
index 89eb4c5..2ab3358 100644
--- a/src/lock/lock.cpp
+++ b/src/lock/lock.cpp
@@ -214,6 +214,7 @@ LockManager::LockManager(const Firebird::string& id, RefPtr<Config> conf)
 	  m_sharedFileCreated(false),
 	  m_process(NULL),
 	  m_processOffset(0),
+	  m_cleanupSync(getPool(), blocking_action_thread, THREAD_high),
 	  m_sharedMemory(NULL),
 	  m_blockage(false),
 	  m_dbId(getPool(), id),
@@ -259,7 +260,7 @@ LockManager::~LockManager()
 			m_sharedMemory->eventPost(&m_process->prc_blocking);
 
 			// Wait for the AST thread to finish cleanup or for 5 seconds
-			m_cleanupSemaphore.tryEnter(5);
+			m_cleanupSync.waitForCompletion();
 		}
 
 #ifdef HAVE_OBJECT_MAP
@@ -1548,16 +1549,22 @@ void LockManager::blocking_action_thread()
 	{
 		iscLogException("Error in blocking action thread\n", x);
 	}
+}
 
-	try
-	{
-		// Wakeup the main thread waiting for our exit
-		m_cleanupSemaphore.release();
-	}
-	catch (const Firebird::Exception& x)
-	{
-		iscLogException("Error closing blocking action thread\n", x);
-	}
+
+void LockManager::exceptionHandler(const Firebird::Exception& ex, ThreadFinishSync<LockManager*>::ThreadRoutine* /*routine*/)
+{
+/**************************************
+ *
+ *   e x c e p t i o n H a n d l e r
+ *
+ **************************************
+ *
+ * Functional description
+ *	Handler for blocking thread close bugs.
+ *
+ **************************************/
+	iscLogException("Error closing blocking action thread\n", ex);
 }
 
 
@@ -1815,7 +1822,7 @@ bool LockManager::create_process(CheckStatusWrapper* statusVector)
 	{
 		try
 		{
-			Thread::start(blocking_action_thread, this, THREAD_high);
+			m_cleanupSync.run(this);
 		}
 		catch (const Exception& ex)
 		{
diff --git a/src/lock/lock_proto.h b/src/lock/lock_proto.h
index d991c1e..2faec49 100644
--- a/src/lock/lock_proto.h
+++ b/src/lock/lock_proto.h
@@ -418,6 +418,8 @@ public:
 	SINT64 readData2(USHORT, const UCHAR*, USHORT, SRQ_PTR);
 	SINT64 writeData(SRQ_PTR, SINT64);
 
+	void exceptionHandler(const Firebird::Exception& ex, ThreadFinishSync<LockManager*>::ThreadRoutine* routine);
+
 private:
 	explicit LockManager(const Firebird::string&, Firebird::RefPtr<Config>);
 	~LockManager();
@@ -471,11 +473,9 @@ private:
 	void detach_shared_file(Firebird::CheckStatusWrapper*);
 	void get_shared_file_name(Firebird::PathName&, ULONG extend = 0) const;
 
-	static THREAD_ENTRY_DECLARE blocking_action_thread(THREAD_ENTRY_PARAM arg)
+	static void blocking_action_thread(LockManager* lockMgr)
 	{
-		LockManager* const lockMgr = static_cast<LockManager*>(arg);
 		lockMgr->blocking_action_thread();
-		return 0;
 	}
 
 	bool initialize(Firebird::SharedMemoryBase* sm, bool init);
@@ -490,7 +490,7 @@ private:
 	Firebird::RWLock m_remapSync;
 	Firebird::AtomicCounter m_waitingOwners;
 
-	Firebird::Semaphore m_cleanupSemaphore;
+	ThreadFinishSync<LockManager*> m_cleanupSync;
 	Firebird::Semaphore m_startupSemaphore;
 
 public:
diff --git a/src/qli/command.cpp b/src/qli/command.cpp
index 5f949f3..fbbf4fb 100644
--- a/src/qli/command.cpp
+++ b/src/qli/command.cpp
@@ -30,7 +30,6 @@
 #include "../qli/parse.h"
 #include "../qli/compile.h"
 #include "../qli/exe.h"
-//#include "../jrd/license.h"
 #include "../qli/all_proto.h"
 #include "../qli/err_proto.h"
 #include "../qli/exe_proto.h"
diff --git a/src/qli/dtr.h b/src/qli/dtr.h
index ba5cd64..e246ef4 100644
--- a/src/qli/dtr.h
+++ b/src/qli/dtr.h
@@ -480,7 +480,6 @@ struct qli_fun
 };
 
 // Program wide globals
-//#include <setjmp.h>
 
 #ifdef QLI_MAIN
 #define EXTERN
diff --git a/src/qli/lex.cpp b/src/qli/lex.cpp
index c20d1f9..9e26046 100644
--- a/src/qli/lex.cpp
+++ b/src/qli/lex.cpp
@@ -50,10 +50,6 @@ using MsgFormat::SafeArg;
 #include <unistd.h>
 #endif
 
-//#ifdef HAVE_CTYPES_H
-//#include <ctypes.h>
-//#endif
-
 #ifdef HAVE_IO_H
 #include <io.h> // isatty
 #endif
diff --git a/src/qli/meta.epp b/src/qli/meta.epp
index a7f222c..2d55716 100644
--- a/src/qli/meta.epp
+++ b/src/qli/meta.epp
@@ -28,7 +28,6 @@
 #include "../qli/dtr.h"
 #include "../qli/compile.h"
 #include "../qli/exe.h"
-//#include "../jrd/license.h"
 #include "../jrd/flags.h"
 #include "../jrd/ibase.h"
 #include "../qli/reqs.h"
diff --git a/src/utilities/gsec/gsecswi.h b/src/utilities/gsec/gsecswi.h
index b8519f5..9b560e3 100644
--- a/src/utilities/gsec/gsecswi.h
+++ b/src/utilities/gsec/gsecswi.h
@@ -24,7 +24,6 @@
 #ifndef GSEC_GSECSWI_H
 #define GSEC_GSECSWI_H
 
-//#include "../common/common.h"
 #include "../jrd/constants.h"
 
 /* Switch handling constants.  Note that the first IN_SW_DATA_ITEMS
diff --git a/src/utilities/gstat/dba.epp b/src/utilities/gstat/dba.epp
index 379b418..19b99d1 100644
--- a/src/utilities/gstat/dba.epp
+++ b/src/utilities/gstat/dba.epp
@@ -56,6 +56,7 @@
 #include "../common/classes/UserBlob.h"
 #include "../common/os/os_utils.h"
 #include "../common/StatusHolder.h"
+#include "../common/ThreadStart.h"
 
 using MsgFormat::SafeArg;
 
diff --git a/src/utilities/nbackup/nbkswi.h b/src/utilities/nbackup/nbkswi.h
index 4326c3d..b8d43da 100644
--- a/src/utilities/nbackup/nbkswi.h
+++ b/src/utilities/nbackup/nbkswi.h
@@ -27,7 +27,6 @@
 #ifndef NBACKUP_NBKSWI_H
 #define NBACKUP_NBKSWI_H
 
-//#include "../common/common.h"
 #include "../jrd/constants.h"
 
 // Switch handling constants
diff --git a/src/utilities/ntrace/os/win32/FileObject.cpp b/src/utilities/ntrace/os/win32/FileObject.cpp
index 73ed38f..53fbfc0 100644
--- a/src/utilities/ntrace/os/win32/FileObject.cpp
+++ b/src/utilities/ntrace/os/win32/FileObject.cpp
@@ -27,7 +27,6 @@
 
 #include "firebird.h"
 #include "../FileObject.h"
-//#include "../common/classes/locks.h"
 
 using namespace Firebird;
 Firebird::Mutex open_mutex;
diff --git a/src/yvalve/gds.cpp b/src/yvalve/gds.cpp
index c851f7c..998bbde 100644
--- a/src/yvalve/gds.cpp
+++ b/src/yvalve/gds.cpp
@@ -57,6 +57,7 @@
 #include "../common/classes/init.h"
 #include "../common/classes/TempFile.h"
 #include "../common/utils_proto.h"
+#include "../common/ThreadStart.h"
 
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
diff --git a/src/yvalve/preparse.cpp b/src/yvalve/preparse.cpp
index b2335a5..e742784 100644
--- a/src/yvalve/preparse.cpp
+++ b/src/yvalve/preparse.cpp
@@ -25,7 +25,6 @@
 #include "firebird.h"
 #include <stdlib.h>
 #include <string.h>
-//#include "../dsql/chars.h"
 #include "../yvalve/prepa_proto.h"
 #include "../yvalve/gds_proto.h"
 #include "../yvalve/YObjects.h"
--- a/src/common/isc_sync.cpp
+++ b/src/common/isc_sync.cpp
@@ -67,6 +67,7 @@
 #include "../common/classes/RefMutex.h"
 #include "../common/classes/array.h"
 #include "../common/StatusHolder.h"
+#include "../common/ThreadStart.h"
 
 static int process_id;
 
-- 
2.9.3