diff --git a/innobase/include/os0sync.h b/innobase/include/os0sync.h
index d52444d02ec34140075209bb22fe54eb3da0660c..3096c9256ed1577ac4443daf5bb75745eba9e6d8 100644
--- a/innobase/include/os0sync.h
+++ b/innobase/include/os0sync.h
@@ -10,15 +10,16 @@ Created 9/6/1995 Heikki Tuuri
 #define os0sync_h
 
 #include "univ.i"
+#include "ut0lst.h"
 
 #ifdef __WIN__
-
 #define os_fast_mutex_t CRITICAL_SECTION
-typedef void*		os_event_t;
-
+typedef HANDLE          os_event_t;
 #else
-
 typedef pthread_mutex_t	os_fast_mutex_t;
+
+typedef struct os_event_struct os_event_struct_t;
+typedef os_event_struct_t*     os_event_t;
 struct os_event_struct {
 	os_fast_mutex_t	os_mutex;	/* this mutex protects the next
 					fields */
@@ -26,9 +27,9 @@ struct os_event_struct {
 					not reserved */
 	pthread_cond_t	cond_var;	/* condition variable is used in
 					waiting for the event */
+	UT_LIST_NODE_T(os_event_struct_t) os_event_list;
+					/* list of all created events */
 };
-typedef struct os_event_struct os_event_struct_t;
-typedef os_event_struct_t*     os_event_t;
 #endif
 
 typedef struct os_mutex_struct	os_mutex_str_t;
@@ -38,13 +39,30 @@ typedef os_mutex_str_t*		os_mutex_t;
 
 #define OS_SYNC_TIME_EXCEEDED	1
 
-/* Mutex protecting the thread count */
-extern os_mutex_t			os_thread_count_mutex;
+/* Mutex protecting the thread count and event and OS 'slow' mutex lists */
+extern os_mutex_t	os_sync_mutex;
 
 /* This is incremented by 1 in os_thread_create and decremented by 1 in
 os_thread_exit */
-extern ulint				os_thread_count;
+extern ulint		os_thread_count;
 
+/* The following are approximate counters for debugging in Unix */
+extern ulint		os_event_count;
+extern ulint		os_mutex_count;
+
+/*************************************************************
+Initializes global event and OS 'slow' mutex lists. */
+
+void
+os_sync_init(void);
+/*==============*/
+/*************************************************************
+Frees created events (not in Windows) and OS 'slow' mutexes. OS 'fast'
+mutexes must be freed with sync_free() before this. */
+
+void
+os_sync_free(void);
+/*==============*/
 /*************************************************************
 Creates an event semaphore, i.e., a semaphore which may
 just have two states: signaled and nonsignaled.
diff --git a/innobase/include/srv0srv.h b/innobase/include/srv0srv.h
index 8355496762ce4ae7d04fa9fd00696cda2c3ac8df..24e692dedabe7550d77931cd63798ae9a3320515 100644
--- a/innobase/include/srv0srv.h
+++ b/innobase/include/srv0srv.h
@@ -209,6 +209,12 @@ void
 srv_init(void);
 /*==========*/
 /*************************************************************************
+Frees the OS fast mutex created in srv_init(). */
+
+void
+srv_free(void);
+/*==========*/
+/*************************************************************************
 Initializes the synchronization primitives, memory system, and the thread
 local storage. */
 
diff --git a/innobase/include/srv0start.h b/innobase/include/srv0start.h
index aec3ebfeea9472dccba3e7a3057046cf44e58185..8d2c3fa12c520306a19a9801f92e6b1d62d943f7 100644
--- a/innobase/include/srv0start.h
+++ b/innobase/include/srv0start.h
@@ -86,11 +86,12 @@ extern	ibool	srv_startup_is_before_trx_rollback_phase;
 extern	ibool	srv_is_being_shut_down;
 
 /* At a shutdown the value first climbs from 0 to SRV_SHUTDOWN_CLEANUP
-and then to SRV_SHUTDOWN_LAST_PHASE */
+and then to SRV_SHUTDOWN_LAST_PHASE, and so on */
 
 extern  ulint   srv_shutdown_state;
 
-#define SRV_SHUTDOWN_CLEANUP	1
-#define SRV_SHUTDOWN_LAST_PHASE	2
+#define SRV_SHUTDOWN_CLEANUP	   1
+#define SRV_SHUTDOWN_LAST_PHASE	   2
+#define SRV_SHUTDOWN_EXIT_THREADS  3
 
 #endif
diff --git a/innobase/os/os0sync.c b/innobase/os/os0sync.c
index abcfa25471027da838f2f67768b1ba1d091d67fb..ce9f21ec9a1554989193a6551e3a105dd881c6d4 100644
--- a/innobase/os/os0sync.c
+++ b/innobase/os/os0sync.c
@@ -28,14 +28,74 @@ struct os_mutex_struct{
 				do not assume that the OS mutex
 				supports recursive locking, though
 				NT seems to do that */
+	UT_LIST_NODE_T(os_mutex_str_t) os_mutex_list;
+				/* list of all 'slow' OS mutexes created */
 };
 
-/* Mutex protecting the thread count */
-os_mutex_t			os_thread_count_mutex;
+/* Mutex protecting the thread count and the lists of OS mutexes
+and events */
+os_mutex_t	os_sync_mutex;
+ibool		os_sync_mutex_inited	= FALSE;
 
 /* This is incremented by 1 in os_thread_create and decremented by 1 in
 os_thread_exit */
-ulint				os_thread_count		= 0;
+ulint		os_thread_count		= 0;
+
+/* The list of all events created (not in Windows) */
+UT_LIST_BASE_NODE_T(os_event_struct_t)	os_event_list;
+
+/* The list of all OS 'slow' mutexes */
+UT_LIST_BASE_NODE_T(os_mutex_str_t)	os_mutex_list;
+
+/* The following are approximate counters for debugging in Unix */
+ulint		os_event_count		= 0;
+ulint		os_mutex_count		= 0;
+
+
+/*************************************************************
+Initializes global event and OS 'slow' mutex lists. */
+
+void
+os_sync_init(void)
+/*==============*/
+{
+	UT_LIST_INIT(os_event_list);
+	UT_LIST_INIT(os_mutex_list);
+
+	os_sync_mutex = os_mutex_create(NULL);
+
+	os_sync_mutex_inited = TRUE;
+}
+
+/*************************************************************
+Frees created events (not in Windows) and OS 'slow' mutexes. OS 'fast'
+mutexes must be freed with sync_free() before this. */
+
+void
+os_sync_free(void)
+/*==============*/
+{
+	os_event_t	event;
+	os_mutex_t	mutex;
+
+	event = UT_LIST_GET_FIRST(os_event_list);
+
+	while (event) {
+
+	      os_event_free(event);
+
+	      event = UT_LIST_GET_FIRST(os_event_list);
+	}
+
+	mutex = UT_LIST_GET_FIRST(os_mutex_list);
+
+	while (mutex) {
+
+	      os_mutex_free(mutex);
+
+	      mutex = UT_LIST_GET_FIRST(os_mutex_list);
+	}
+}
 
 /*************************************************************
 Creates an event semaphore, i.e., a semaphore which may
@@ -51,8 +111,8 @@ os_event_create(
 			the event is created without a name */
 {
 #ifdef __WIN__
-	HANDLE	event;
-	
+        os_event_t event;
+
 	event = CreateEvent(NULL,	/* No security attributes */
 			TRUE,		/* Manual reset */
 			FALSE,		/* Initial state nonsignaled */
@@ -83,6 +143,14 @@ os_event_create(
 #endif
 	event->is_set = FALSE;
 
+	os_mutex_enter(os_sync_mutex);
+
+	UT_LIST_ADD_FIRST(os_event_list, os_event_list, event);
+
+	os_event_count++;
+
+	os_mutex_exit(os_sync_mutex);
+
 	return(event);
 #endif
 }
@@ -100,7 +168,7 @@ os_event_create_auto(
 			the event is created without a name */
 {
 #ifdef __WIN__
-	HANDLE	event;
+        os_event_t event;
 
 	event = CreateEvent(NULL,	/* No security attributes */
 			FALSE,		/* Auto-reset */
@@ -114,6 +182,8 @@ os_event_create_auto(
 
 	UT_NOT_USED(name);
 
+	ut_a(0);
+
 	return(NULL);
 #endif
 }
@@ -193,6 +263,14 @@ os_event_free(
 	os_fast_mutex_free(&(event->os_mutex));
 	ut_a(0 == pthread_cond_destroy(&(event->cond_var)));
 
+	os_mutex_enter(os_sync_mutex);
+
+	UT_LIST_REMOVE(os_event_list, os_event_list, event);
+
+	os_event_count--;
+
+	os_mutex_exit(os_sync_mutex);
+
 	ut_free(event);
 #endif
 }
@@ -310,8 +388,7 @@ os_event_wait_multiple(
 	ut_a(event_array);
 	ut_a(n > 0);
 
-	index = WaitForMultipleObjects(n,
-					event_array,
+	index = WaitForMultipleObjects(n, event_array,
 					FALSE,	   /* Wait for any 1 event */
 					INFINITE); /* Infinite wait time
 						   limit */
@@ -360,6 +437,16 @@ os_mutex_create(
 	mutex_str->handle = mutex;
 	mutex_str->count = 0;
 
+	if (os_sync_mutex_inited) {
+	        os_mutex_enter(os_sync_mutex);
+	}
+
+	UT_LIST_ADD_FIRST(os_mutex_list, os_mutex_list, mutex_str);
+
+	if (os_sync_mutex_inited) {
+		os_mutex_exit(os_sync_mutex);
+	}
+
 	return(mutex_str);
 #else
 	os_fast_mutex_t*	os_mutex;
@@ -376,6 +463,16 @@ os_mutex_create(
 	mutex_str->handle = os_mutex;
 	mutex_str->count = 0;
 
+	if (os_sync_mutex_inited) {
+	        os_mutex_enter(os_sync_mutex);
+	}
+
+	UT_LIST_ADD_FIRST(os_mutex_list, os_mutex_list, mutex_str);
+
+	if (os_sync_mutex_inited) {
+		os_mutex_exit(os_sync_mutex);
+	}
+
 	return(mutex_str);
 #endif	
 }
@@ -447,9 +544,22 @@ os_mutex_free(
 #ifdef __WIN__
 	ut_a(mutex);
 
+	os_mutex_enter(os_sync_mutex);
+
+	UT_LIST_REMOVE(os_mutex_list, os_mutex_list, mutex);
+
+	os_mutex_exit(os_sync_mutex);
+
 	ut_a(CloseHandle(mutex->handle));
+
 	ut_free(mutex);
 #else
+	os_mutex_enter(os_sync_mutex);
+
+	UT_LIST_REMOVE(os_mutex_list, os_mutex_list, mutex);
+
+	os_mutex_exit(os_sync_mutex);
+
 	os_fast_mutex_free(mutex->handle);
 	ut_free(mutex->handle);
 	ut_free(mutex);
@@ -474,6 +584,7 @@ os_fast_mutex_init(
 #else
 	ut_a(0 == pthread_mutex_init(fast_mutex, MY_MUTEX_INIT_FAST));
 #endif
+	os_mutex_count++;
 #endif
 }
 
@@ -521,5 +632,6 @@ os_fast_mutex_free(
 	DeleteCriticalSection((LPCRITICAL_SECTION) fast_mutex);
 #else
 	ut_a(0 == pthread_mutex_destroy(fast_mutex));
+	os_mutex_count--;
 #endif
 }
diff --git a/innobase/os/os0thread.c b/innobase/os/os0thread.c
index a68f6a3b8bc1c3b6cbf0ba4c39574b1f87bbdeba..1722051a841a0ce89412ae85eda98d5d5d2166fd 100644
--- a/innobase/os/os0thread.c
+++ b/innobase/os/os0thread.c
@@ -101,9 +101,9 @@ os_thread_create(
 	os_thread_t	thread;
 	ulint           win_thread_id;
 
-	os_mutex_enter(os_thread_count_mutex);
+	os_mutex_enter(os_sync_mutex);
 	os_thread_count++;
-	os_mutex_exit(os_thread_count_mutex);
+	os_mutex_exit(os_sync_mutex);
 
 	thread = CreateThread(NULL,	/* no security attributes */
 				0,	/* default size stack */
@@ -147,9 +147,9 @@ os_thread_create(
 		 exit(1);
 	}
 #endif
-	os_mutex_enter(os_thread_count_mutex);
+	os_mutex_enter(os_sync_mutex);
 	os_thread_count++;
-	os_mutex_exit(os_thread_count_mutex);
+	os_mutex_exit(os_sync_mutex);
 
 #if defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10)
 	ret = pthread_create(&pthread, pthread_attr_default, start_f, arg);
@@ -185,9 +185,9 @@ os_thread_exit(
 	void*	exit_value)	/* in: exit value; in Windows this void*
 				is cast as a DWORD */
 {
-	os_mutex_enter(os_thread_count_mutex);
+	os_mutex_enter(os_sync_mutex);
 	os_thread_count--;
-	os_mutex_exit(os_thread_count_mutex);
+	os_mutex_exit(os_sync_mutex);
 
 #ifdef __WIN__
         ExitThread((DWORD)exit_value);
diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c
index a44bc0147e4e9bce71cc433644716576b99b0ebd..da2966a7124e42fc96ae143452146a6ddc33726c 100644
--- a/innobase/srv/srv0srv.c
+++ b/innobase/srv/srv0srv.c
@@ -1693,80 +1693,33 @@ srv_init(void)
 		ut_a(conc_slot->event);
 	}
 }	
-	
+
 /*************************************************************************
-Initializes the synchronization primitives, memory system, and the thread
-local storage. */
+Frees the OS fast mutex created in srv_init(). */
 
 void
-srv_general_init(void)
-/*==================*/
+srv_free(void)
+/*==========*/
 {
-	os_thread_count_mutex = os_mutex_create(NULL);
-
-	sync_init();
-	mem_init(srv_mem_pool_size);
-	thr_local_init();
+	os_fast_mutex_free(&srv_conc_mutex);
 }
 
-
-#if defined(__NETWARE__) || defined(SAFE_MUTEX_DETECT_DESTROY)
-/* NetWare requires some cleanup of mutexes */
-
 /*************************************************************************
-Deinitializes the synchronization primitives, memory system, and the thread
+Initializes the synchronization primitives, memory system, and the thread
 local storage. */
 
 void
-srv_general_free(void)
+srv_general_init(void)
 /*==================*/
 {
-  sync_close();
-
-  os_mutex_free(os_thread_count_mutex);
+	os_sync_init();
+	sync_init();
+	mem_init(srv_mem_pool_size);
+	thr_local_init();
 }
-#endif /* __NETWARE__ */
-
 
 /*======================= InnoDB Server FIFO queue =======================*/
 
-#if defined(__NETWARE__) || defined(SAFE_MUTEX_DETECT_DESTROY)
-/* NetWare requires some cleanup of mutexes */
-
-/*************************************************************************
-Deinitializes the server. */
-
-void
-srv_free(void)
-/*==========*/
-{
-  srv_conc_slot_t* conc_slot;
-  srv_slot_t* slot;
-  ulint i;
-
-  for (i = 0; i < OS_THREAD_MAX_N; i++)
-  {
-    slot = srv_table_get_nth_slot(i);
-    os_event_free(slot->event);
-  }
-
-  /* TODO: free(srv_sys->threads); */
-
-  for (i = 0; i < OS_THREAD_MAX_N; i++)
-  {
-    slot = srv_mysql_table + i;
-    os_event_free(slot->event);
-  }
-
-  /* TODO: free(srv_mysql_table); */
-
-  for (i = 0; i < OS_THREAD_MAX_N; i++)
-  {
-    conc_slot = srv_conc_slots + i;
-    os_event_free(conc_slot->event);
-  }
-}
-#endif /* __NETWARE__ */
 
 /*************************************************************************
 Puts an OS thread to wait if there are too many concurrent threads
diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c
index d34c18b1a25e6f5db8192b09a2004cfd41464446..f03355b825c5ae3a56d647257f965c2fdad72fd4 100644
--- a/innobase/srv/srv0start.c
+++ b/innobase/srv/srv0start.c
@@ -1442,9 +1442,7 @@ innobase_start_or_create_for_mysql(void)
 
 	os_fast_mutex_unlock(&srv_os_test_mutex);
 
-#if defined(__NETWARE__) || defined(SAFE_MUTEX_DETECT_DESTROY)
-	os_fast_mutex_free(&srv_os_test_mutex);  /* all platforms? */
-#endif /* __NETWARE__ */
+	os_fast_mutex_free(&srv_os_test_mutex);
 
 	if (srv_print_verbose_log) {
 	  	ut_print_timestamp(stderr);
@@ -1484,7 +1482,7 @@ innobase_shutdown_for_mysql(void)
 	  	return(DB_SUCCESS);
 	}
 
-	/* Flush buffer pool to disk, write the current lsn to
+	/* 1. Flush buffer pool to disk, write the current lsn to
 	the tablespace header(s), and copy all log data to archive */
 
 	logs_empty_and_mark_files_at_shutdown();
@@ -1496,7 +1494,7 @@ innobase_shutdown_for_mysql(void)
 		srv_conc_n_threads);
 	}
 
-	/* Now we will exit all threads InnoDB created */
+	/* 2. Make all threads created by InnoDB to exit */
 
 	srv_shutdown_state = SRV_SHUTDOWN_EXIT_THREADS;
 
@@ -1521,7 +1519,7 @@ innobase_shutdown_for_mysql(void)
 
 		os_aio_wake_all_threads_at_shutdown();
 
-		os_mutex_enter(os_thread_count_mutex);
+		os_mutex_enter(os_sync_mutex);
 
 		if (os_thread_count == 0) {
 		        /* All the threads have exited or are just exiting;
@@ -1530,14 +1528,14 @@ innobase_shutdown_for_mysql(void)
 			they have exited? Now we just sleep 0.1 seconds and
 			hope that is enough! */
 
-			os_mutex_exit(os_thread_count_mutex);
+			os_mutex_exit(os_sync_mutex);
 
 			os_thread_sleep(100000);
 
 			break;
 		}
 
-		os_mutex_exit(os_thread_count_mutex);
+		os_mutex_exit(os_sync_mutex);
 
 		os_thread_sleep(100000);
 	}
@@ -1548,19 +1546,21 @@ innobase_shutdown_for_mysql(void)
 		      os_thread_count);
 	}
 
-#if defined(__NETWARE__) || defined(SAFE_MUTEX_DETECT_DESTROY)
+	/* 3. Free all InnoDB's own mutexes */
+
+	sync_close();
+
+	/* 4. Free all OS synchronization primitives (in Windows currently
+	events are not freed) */
 
-	/* TODO: Where should this be called? */
 	srv_free();
+	os_sync_free();
 
-	/* TODO: Where should this be called? */
-	srv_general_free();
-#endif
+	/* 5. Free all allocated memory (and the os_fast_mutex created in
+	ut0mem.c */
 
-#if defined(NOT_WORKING_YET) || defined(__NETWARE__) || defined(SAFE_MUTEX_DETECT_DESTROY)
-        /* NetWare requires this free */
         ut_free_all_mem();
-#endif 
+
 	if (srv_print_verbose_log) {
 	        ut_print_timestamp(stderr);
 	        fprintf(stderr, "  InnoDB: Shutdown completed\n");
diff --git a/innobase/sync/sync0sync.c b/innobase/sync/sync0sync.c
index 20d68ba5a9f4e6188be71a04762592aaffe65105..32615ce88ac3d3cc7d1842b7229cd14c59289fad 100644
--- a/innobase/sync/sync0sync.c
+++ b/innobase/sync/sync0sync.c
@@ -235,8 +235,7 @@ mutex_create_func(
 	mutex->cline = cline;
 	
 	/* Check that lock_word is aligned; this is important on Intel */
-
-	ut_a(((ulint)(&(mutex->lock_word))) % 4 == 0);
+	ut_ad(((ulint)(&(mutex->lock_word))) % 4 == 0);
 
 	/* NOTE! The very first mutexes are not put to the mutex list */
 
@@ -266,11 +265,14 @@ mutex_free(
 	ut_a(mutex_get_lock_word(mutex) == 0);
 	ut_a(mutex_get_waiters(mutex) == 0);
 	
-	mutex_enter(&mutex_list_mutex);
+	if (mutex != &mutex_list_mutex && mutex != &sync_thread_mutex) {
 
-	UT_LIST_REMOVE(list, mutex_list, mutex);
+	        mutex_enter(&mutex_list_mutex);
 
-	mutex_exit(&mutex_list_mutex);
+	        UT_LIST_REMOVE(list, mutex_list, mutex);
+
+		mutex_exit(&mutex_list_mutex);
+	}
 
 #if !defined(_WIN32) || !defined(UNIV_CAN_USE_X86_ASSEMBLER) 
 	os_fast_mutex_free(&(mutex->os_fast_mutex));
@@ -1230,13 +1232,26 @@ sync_init(void)
 }
 
 /**********************************************************************
-Frees the resources in synchronization data structures. */
+Frees the resources in InnoDB's own synchronization data structures. Use
+os_sync_free() after calling this. */
 
 void
 sync_close(void)
 /*===========*/
 {
+	mutex_t*	mutex;
+
 	sync_array_free(sync_primary_wait_array);
+
+	mutex = UT_LIST_GET_FIRST(mutex_list);
+
+	while (mutex) {
+	        mutex_free(mutex);
+		mutex = UT_LIST_GET_FIRST(mutex_list);
+	}
+
+	mutex_free(&mutex_list_mutex);
+	mutex_free(&sync_thread_mutex);	
 }
 
 /***********************************************************************
diff --git a/innobase/ut/ut0mem.c b/innobase/ut/ut0mem.c
index dbd3e7e47375652b3f71a80a1283cd27ff13871e..174ae4cc6bb2467d78d0cfeabe2a4ec13ad3d86d 100644
--- a/innobase/ut/ut0mem.c
+++ b/innobase/ut/ut0mem.c
@@ -190,6 +190,8 @@ ut_free_all_mem(void)
 	os_fast_mutex_unlock(&ut_list_mutex);
 
 	ut_a(ut_total_allocated_memory == 0);
+
+        os_fast_mutex_free(&ut_list_mutex);
 }
 
 /**************************************************************************