Index: pjproject/trunk/pjlib/include/pj/types.h
===================================================================
--- pjproject/trunk/pjlib/include/pj/types.h	(revision 814)
+++ pjproject/trunk/pjlib/include/pj/types.h	(revision 815)
@@ -292,6 +292,26 @@
  * in random string generation, and to initialize operating system dependent
  * functionality (such as WSAStartup() in Windows).
+ *
+ * @return PJ_SUCCESS on success.
  */
 PJ_DECL(pj_status_t) pj_init(void);
+
+
+/**
+ * Shutdown PJLIB.
+ */
+PJ_DECL(void) pj_shutdown(void);
+
+/**
+ * Register cleanup function to be called by PJLIB when pj_shutdown() is 
+ * called.
+ *
+ * @param func	    The function to be registered.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pj_atexit(void (*func)(void));
+
+
 
 /**
Index: pjproject/trunk/pjlib/src/pj/except.c
===================================================================
--- pjproject/trunk/pjlib/src/pj/except.c	(revision 814)
+++ pjproject/trunk/pjlib/src/pj/except.c	(revision 815)
@@ -52,4 +52,12 @@
 }
 
+static void exception_cleanup(void)
+{
+    if (thread_local_id != -1) {
+	pj_thread_local_free(thread_local_id);
+	thread_local_id = -1;
+    }
+}
+
 PJ_DEF(void) pj_push_exception_handler_(struct pj_exception_state_t *rec)
 {
@@ -59,4 +67,5 @@
 	pj_thread_local_alloc(&thread_local_id);
 	pj_assert(thread_local_id != -1);
+	pj_atexit(&exception_cleanup);
     }
     parent_handler = pj_thread_local_get(thread_local_id);
Index: pjproject/trunk/pjlib/src/pj/os_core_unix.c
===================================================================
--- pjproject/trunk/pjlib/src/pj/os_core_unix.c	(revision 814)
+++ pjproject/trunk/pjlib/src/pj/os_core_unix.c	(revision 815)
@@ -148,11 +148,4 @@
     pj_generate_unique_string( &guid );
 
-    /* Initialize exception ID for the pool. 
-     * Must do so after critical section is configured.
-     */
-    rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);
-    if (rc != PJ_SUCCESS)
-        return rc;
-
     /* Startup timestamp */
 #if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0
@@ -170,4 +163,48 @@
     return PJ_SUCCESS;
 }
+
+/*
+ * pj_atexit()
+ */
+PJ_DEF(pj_status_t) pj_atexit(void (*func)(void))
+{
+    if (atexit_count >= PJ_ARRAY_SIZE(atexit_func))
+	return PJ_ETOOMANY;
+
+    atexit_func[atexit_count++] = func;
+    return PJ_SUCCESS;
+}
+
+/*
+ * pj_shutdown(void)
+ */
+PJ_DEF(void) pj_shutdown()
+{
+    int i;
+
+    /* Call atexit() functions */
+    for (i=atexit_count-1; i>=0; --i) {
+	(*atexit_func[i])();
+    }
+    atexit_count = 0;
+
+    /* Free exception ID */
+    if (PJ_NO_MEMORY_EXCEPTION != -1) {
+	pj_exception_id_free(PJ_NO_MEMORY_EXCEPTION);
+	PJ_NO_MEMORY_EXCEPTION = -1;
+    }
+
+#if PJ_HAS_THREADS
+    /* Destroy PJLIB critical section */
+    pj_mutex_destroy(&critical_section);
+
+    /* Free PJLIB TLS */
+    if (thread_tls_id != -1) {
+	pj_thread_local_free(thread_tls_id);
+	thread_tls_id = -1;
+    }
+#endif
+}
+
 
 /*
Index: pjproject/trunk/pjlib/src/pj/os_core_win32.c
===================================================================
--- pjproject/trunk/pjlib/src/pj/os_core_win32.c	(revision 814)
+++ pjproject/trunk/pjlib/src/pj/os_core_win32.c	(revision 815)
@@ -109,7 +109,8 @@
  */
 static pj_thread_desc main_thread;
-static long thread_tls_id;
+static long thread_tls_id = -1;
 static pj_mutex_t critical_section_mutex;
-
+static unsigned atexit_count;
+static void (*atexit_func[32])(void);
 
 /*
@@ -178,4 +179,50 @@
 
 /*
+ * pj_atexit()
+ */
+PJ_DEF(pj_status_t) pj_atexit(void (*func)(void))
+{
+    if (atexit_count >= PJ_ARRAY_SIZE(atexit_func))
+	return PJ_ETOOMANY;
+
+    atexit_func[atexit_count++] = func;
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * pj_shutdown(void)
+ */
+PJ_DEF(void) pj_shutdown()
+{
+    int i;
+
+    /* Call atexit() functions */
+    for (i=atexit_count-1; i>=0; --i) {
+	(*atexit_func[i])();
+    }
+    atexit_count = 0;
+
+    /* Free exception ID */
+    if (PJ_NO_MEMORY_EXCEPTION != -1) {
+	pj_exception_id_free(PJ_NO_MEMORY_EXCEPTION);
+	PJ_NO_MEMORY_EXCEPTION = -1;
+    }
+
+    /* Destroy PJLIB critical section */
+    pj_mutex_destroy(&critical_section_mutex);
+
+    /* Free PJLIB TLS */
+    if (thread_tls_id != -1) {
+	pj_thread_local_free(thread_tls_id);
+	thread_tls_id = -1;
+    }
+
+    /* Shutdown Winsock */
+    WSACleanup();
+}
+
+
+/*
  * pj_getpid(void)
  */
Index: pjproject/trunk/pjlib/src/pj/pool_buf.c
===================================================================
--- pjproject/trunk/pjlib/src/pj/pool_buf.c	(revision 814)
+++ pjproject/trunk/pjlib/src/pj/pool_buf.c	(revision 815)
@@ -30,9 +30,19 @@
 
 static int is_initialized;
-static long tls;
+static long tls = -1;
 static void* stack_alloc(pj_pool_factory *factory, pj_size_t size);
 
-static pj_status_t initialize()
+static void pool_buf_cleanup(void)
 {
+    if (tls != -1) {
+	pj_thread_local_free(tls);
+	tls = -1;
+    }
+}
+
+static pj_status_t pool_buf_initialize()
+{
+    pj_atexit(&pool_buf_cleanup);
+
     stack_based_factory.policy.block_alloc = &stack_alloc;
     return pj_thread_local_alloc(&tls);
@@ -65,5 +75,5 @@
 
     if (!is_initialized) {
-	if (initialize() != PJ_SUCCESS)
+	if (pool_buf_initialize() != PJ_SUCCESS)
 	    return NULL;
 	is_initialized = 1;
Index: pjproject/trunk/pjsip-apps/src/samples/aectest.c
===================================================================
--- pjproject/trunk/pjsip-apps/src/samples/aectest.c	(revision 814)
+++ pjproject/trunk/pjsip-apps/src/samples/aectest.c	(revision 815)
@@ -211,4 +211,6 @@
     pj_caching_pool_destroy( &cp );
 
+    /* Shutdown PJLIB */
+    pj_shutdown();
 
     /* Done. */
Index: pjproject/trunk/pjsip-apps/src/samples/confsample.c
===================================================================
--- pjproject/trunk/pjsip-apps/src/samples/confsample.c	(revision 814)
+++ pjproject/trunk/pjsip-apps/src/samples/confsample.c	(revision 815)
@@ -461,4 +461,6 @@
     pj_caching_pool_destroy( &cp );
 
+    /* Shutdown PJLIB */
+    pj_shutdown();
 
     /* Done. */
Index: pjproject/trunk/pjsip-apps/src/samples/level.c
===================================================================
--- pjproject/trunk/pjsip-apps/src/samples/level.c	(revision 814)
+++ pjproject/trunk/pjsip-apps/src/samples/level.c	(revision 815)
@@ -156,4 +156,7 @@
     pj_caching_pool_destroy( &cp );
 
+    /* Shutdown PJLIB */
+    pj_shutdown();
+
 
     /* Done. */
Index: pjproject/trunk/pjsip-apps/src/samples/pjsip-perf.c
===================================================================
--- pjproject/trunk/pjsip-apps/src/samples/pjsip-perf.c	(revision 814)
+++ pjproject/trunk/pjsip-apps/src/samples/pjsip-perf.c	(revision 815)
@@ -895,4 +895,7 @@
 	pj_caching_pool_destroy(&app.cp);
     }
+
+    /* Shutdown PJLIB */
+    pj_shutdown();
 }
 
Index: pjproject/trunk/pjsip-apps/src/samples/playfile.c
===================================================================
--- pjproject/trunk/pjsip-apps/src/samples/playfile.c	(revision 814)
+++ pjproject/trunk/pjsip-apps/src/samples/playfile.c	(revision 815)
@@ -196,4 +196,7 @@
     pj_caching_pool_destroy( &cp );
 
+    /* Shutdown PJLIB */
+    pj_shutdown();
+
 
     /* Done. */
Index: pjproject/trunk/pjsip-apps/src/samples/playsine.c
===================================================================
--- pjproject/trunk/pjsip-apps/src/samples/playsine.c	(revision 814)
+++ pjproject/trunk/pjsip-apps/src/samples/playsine.c	(revision 815)
@@ -301,4 +301,7 @@
     pj_caching_pool_destroy( &cp );
 
+    /* Shutdown PJLIB */
+    pj_shutdown();
+
 
     /* Done. */
Index: pjproject/trunk/pjsip-apps/src/samples/recfile.c
===================================================================
--- pjproject/trunk/pjsip-apps/src/samples/recfile.c	(revision 814)
+++ pjproject/trunk/pjsip-apps/src/samples/recfile.c	(revision 815)
@@ -191,4 +191,7 @@
     pj_caching_pool_destroy( &cp );
 
+    /* Shutdown PJLIB */
+    pj_shutdown();
+
 
     /* Done. */
Index: pjproject/trunk/pjsip-apps/src/samples/resampleplay.c
===================================================================
--- pjproject/trunk/pjsip-apps/src/samples/resampleplay.c	(revision 814)
+++ pjproject/trunk/pjsip-apps/src/samples/resampleplay.c	(revision 815)
@@ -217,4 +217,7 @@
     pj_caching_pool_destroy( &cp );
 
+    /* Shutdown PJLIB */
+    pj_shutdown();
+
 
     /* Done. */
Index: pjproject/trunk/pjsip-apps/src/samples/siprtp.c
===================================================================
--- pjproject/trunk/pjsip-apps/src/samples/siprtp.c	(revision 814)
+++ pjproject/trunk/pjsip-apps/src/samples/siprtp.c	(revision 815)
@@ -380,4 +380,8 @@
 	app.sip_endpt = NULL;
     }
+
+    /* Shutdown PJLIB */
+    pj_shutdown();
+
 }
 
Index: pjproject/trunk/pjsip-apps/src/samples/sndinfo.c
===================================================================
--- pjproject/trunk/pjsip-apps/src/samples/sndinfo.c	(revision 814)
+++ pjproject/trunk/pjsip-apps/src/samples/sndinfo.c	(revision 815)
@@ -286,4 +286,7 @@
     }
 
+    /* Shutdown PJLIB */
+    pj_shutdown();
+
     return 0;
 }
Index: pjproject/trunk/pjsip-apps/src/samples/streamutil.c
===================================================================
--- pjproject/trunk/pjsip-apps/src/samples/streamutil.c	(revision 814)
+++ pjproject/trunk/pjsip-apps/src/samples/streamutil.c	(revision 815)
@@ -517,4 +517,7 @@
     /* Destroy pool factory */
     pj_caching_pool_destroy( &cp );
+
+    /* Shutdown PJLIB */
+    pj_shutdown();
 
 
Index: pjproject/trunk/pjsip-apps/src/samples/tonegen.c
===================================================================
--- pjproject/trunk/pjsip-apps/src/samples/tonegen.c	(revision 814)
+++ pjproject/trunk/pjsip-apps/src/samples/tonegen.c	(revision 815)
@@ -147,4 +147,7 @@
     pj_caching_pool_destroy( &cp );
 
+    /* Shutdown PJLIB */
+    pj_shutdown();
+
 
     /* Done. */
Index: pjproject/trunk/pjsip/src/pjsip/sip_endpoint.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip/sip_endpoint.c	(revision 814)
+++ pjproject/trunk/pjsip/src/pjsip/sip_endpoint.c	(revision 815)
@@ -581,4 +581,7 @@
     /* Delete endpoint mutex. */
     pj_mutex_destroy(endpt->mutex);
+
+    /* Delete module's mutex */
+    pj_rwmutex_destroy(endpt->mod_mutex);
 
     /* Finally destroy pool. */
Index: pjproject/trunk/pjsip/src/pjsip/sip_transaction.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip/sip_transaction.c	(revision 814)
+++ pjproject/trunk/pjsip/src/pjsip/sip_transaction.c	(revision 815)
@@ -675,4 +675,7 @@
     pjsip_endpt_release_pool(mod_tsx_layer.endpt, mod_tsx_layer.pool);
 
+    /* Free TLS */
+    pj_thread_local_free(pjsip_tsx_lock_tls_id);
+
     /* Mark as unregistered. */
     mod_tsx_layer.endpt = NULL;
Index: pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 814)
+++ pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 815)
@@ -708,4 +708,7 @@
     }
 
+    /* Shutdown PJLIB */
+    pj_shutdown();
+
     /* Done. */
     return PJ_SUCCESS;
Index: pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 814)
+++ pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 815)
@@ -475,4 +475,7 @@
     }
 
+    /* Deinitialize sound subsystem */
+    pjmedia_snd_deinit();
+
     return PJ_SUCCESS;
 }
