Index: pjproject/trunk/pjlib/build/pjlib.dsp
===================================================================
--- pjproject/trunk/pjlib/build/pjlib.dsp	(revision 362)
+++ pjproject/trunk/pjlib/build/pjlib.dsp	(revision 363)
@@ -234,16 +234,9 @@
 
 SOURCE=..\src\pj\ioqueue_select.c
-# PROP Exclude_From_Build 1
 # End Source File
 # Begin Source File
 
 SOURCE=..\src\pj\ioqueue_winnt.c
-
-!IF  "$(CFG)" == "pjlib - Win32 Release"
-
-!ELSEIF  "$(CFG)" == "pjlib - Win32 Debug"
-
-!ENDIF 
-
+# PROP Exclude_From_Build 1
 # End Source File
 # Begin Source File
Index: pjproject/trunk/pjlib/src/pj/ioqueue_common_abs.c
===================================================================
--- pjproject/trunk/pjlib/src/pj/ioqueue_common_abs.c	(revision 362)
+++ pjproject/trunk/pjlib/src/pj/ioqueue_common_abs.c	(revision 363)
@@ -28,8 +28,23 @@
  */
 
+static long ioqueue_tls_id = -1;
+
+typedef struct key_lock_data {
+    struct key_lock_data *prev;
+    pj_ioqueue_key_t     *key;
+    int			  is_alive;
+} key_lock_data;
+
+
 static void ioqueue_init( pj_ioqueue_t *ioqueue )
 {
     ioqueue->lock = NULL;
     ioqueue->auto_delete_lock = 0;
+
+    if (ioqueue_tls_id == -1) {
+	pj_status_t status;
+	status = pj_thread_local_alloc(&ioqueue_tls_id);
+	pj_thread_local_set(ioqueue_tls_id, NULL);
+    }
 }
 
@@ -93,12 +108,63 @@
         key->fd_type = PJ_SOCK_STREAM;
 
+    key->inside_callback = 0;
+    key->destroy_requested = 0;
+
     /* Create mutex for the key. */
-    rc = pj_mutex_create_simple(pool, NULL, &key->mutex);
+    rc = pj_mutex_create_recursive(pool, NULL, &key->mutex);
     
     return rc;
 }
 
+/* Lock the key and also keep the lock data in thread local storage.
+ * The lock data is used to detect if the key is deleted by application
+ * when we call its callback.
+ */
+static void lock_key(pj_ioqueue_key_t *key, key_lock_data *lck)
+{
+    struct key_lock_data *prev_data;
+
+    pj_mutex_lock(key->mutex);
+    prev_data = (struct key_lock_data *) 
+                    pj_thread_local_get(ioqueue_tls_id);
+    lck->prev = prev_data;
+    lck->key = key;
+    lck->is_alive = 1;
+    pj_thread_local_set(ioqueue_tls_id, lck);
+}
+
+/* Unlock the key only if it is still valid. */
+static void unlock_key(pj_ioqueue_key_t *key, key_lock_data *lck)
+{
+    pj_assert( (void*)pj_thread_local_get(ioqueue_tls_id) == lck);
+    pj_assert( lck->key == key );
+    pj_thread_local_set(ioqueue_tls_id, lck->prev);
+    if (lck->is_alive)
+	pj_mutex_unlock(key->mutex);
+}
+
+/* Destroy key */
 static void ioqueue_destroy_key( pj_ioqueue_key_t *key )
 {
+    key_lock_data *lck;
+
+    /* Make sure that no other threads are doing something with
+     * the key.
+     */
+    pj_mutex_lock(key->mutex);
+    
+    /* Check if this function is called within a callback context.
+     * If so, then we need to inform the callback that the key has
+     * been destroyed so that it doesn't attempt to unlock the
+     * key's mutex.
+     */
+    lck = pj_thread_local_get(ioqueue_tls_id);
+    while (lck) {
+	if (lck->key == key) {
+	    lck->is_alive = 0;
+	}
+	lck = lck->prev;
+    }
+
     pj_mutex_destroy(key->mutex);
 }
@@ -164,6 +230,8 @@
 void ioqueue_dispatch_write_event(pj_ioqueue_t *ioqueue, pj_ioqueue_key_t *h)
 {
+    key_lock_data lck_data;
+
     /* Lock the key. */
-    pj_mutex_lock(h->mutex);
+    lock_key(h, &lck_data);
 
 #if defined(PJ_HAS_TCP) && PJ_HAS_TCP!=0
@@ -179,5 +247,5 @@
 
         /* Unlock; from this point we don't need to hold key's mutex. */
-        pj_mutex_unlock(h->mutex);
+        //pj_mutex_unlock(h->mutex);
 
 #if (defined(PJ_HAS_SO_ERROR) && PJ_HAS_SO_ERROR!=0)
@@ -252,5 +320,5 @@
                 ioqueue_remove_from_set(ioqueue, h->fd, WRITEABLE_EVENT);
 
-            pj_mutex_unlock(h->mutex);
+            //pj_mutex_unlock(h->mutex);
         }
 
@@ -299,5 +367,5 @@
 
                 /* No need to hold mutex anymore */
-                pj_mutex_unlock(h->mutex);
+                //pj_mutex_unlock(h->mutex);
             }
 
@@ -310,5 +378,5 @@
 
         } else {
-            pj_mutex_unlock(h->mutex);
+            //pj_mutex_unlock(h->mutex);
         }
 
@@ -320,14 +388,18 @@
          * able to process the event.
          */
-        pj_mutex_unlock(h->mutex);
-    }
+        //pj_mutex_unlock(h->mutex);
+    }
+
+    /* Finally unlock key */
+    unlock_key(h, &lck_data);
 }
 
 void ioqueue_dispatch_read_event( pj_ioqueue_t *ioqueue, pj_ioqueue_key_t *h )
 {
+    key_lock_data lck_data;
     pj_status_t rc;
 
     /* Lock the key. */
-    pj_mutex_lock(h->mutex);
+    lock_key(h, &lck_data);
 
 #   if PJ_HAS_TCP
@@ -346,5 +418,5 @@
 
         /* Unlock; from this point we don't need to hold key's mutex. */
-        pj_mutex_unlock(h->mutex);
+        //pj_mutex_unlock(h->mutex);
 
 	rc=pj_sock_accept(h->fd, accept_op->accept_fd, 
@@ -379,5 +451,7 @@
 
         /* Unlock; from this point we don't need to hold key's mutex. */
-        pj_mutex_unlock(h->mutex);
+	//Crash as of revision 353 (since we added pjmedia socket to
+	//main ioqueue).
+        //pj_mutex_unlock(h->mutex);
 
         bytes_read = read_op->size;
@@ -456,6 +530,9 @@
          * able to process the event.
          */
-        pj_mutex_unlock(h->mutex);
-    }
+        //pj_mutex_unlock(h->mutex);
+    }
+
+    /* Unlock handle. */
+    unlock_key(h, &lck_data);
 }
 
@@ -464,5 +541,7 @@
                                        pj_ioqueue_key_t *h )
 {
-    pj_mutex_lock(h->mutex);
+    key_lock_data lck_data;
+
+    lock_key(h, &lck_data);
 
     if (!h->connecting) {
@@ -471,5 +550,6 @@
          * it has been processed by other thread.
          */
-        pj_mutex_unlock(h->mutex);
+        //pj_mutex_unlock(h->mutex);
+	unlock_key(h, &lck_data);
         return;
     }
@@ -478,5 +558,5 @@
     h->connecting = 0;
 
-    pj_mutex_unlock(h->mutex);
+    //pj_mutex_unlock(h->mutex);
 
     ioqueue_remove_from_set(ioqueue, h->fd, WRITEABLE_EVENT);
@@ -486,4 +566,6 @@
     if (h->cb.on_connect_complete)
 	(*h->cb.on_connect_complete)(h, -1);
+
+    unlock_key(h, &lck_data);
 }
 
@@ -905,4 +987,5 @@
 {
     struct generic_operation *op_rec;
+    key_lock_data lck_data;
 
     /*
@@ -910,5 +993,5 @@
      * really make sure that it's still there; then call the callback.
      */
-    pj_mutex_lock(key->mutex);
+    lock_key(key, &lck_data);
 
     /* Find the operation in the pending read list. */
@@ -918,7 +1001,9 @@
             pj_list_erase(op_rec);
             op_rec->op = 0;
-            pj_mutex_unlock(key->mutex);
+            //pj_mutex_unlock(key->mutex);
 
             (*key->cb.on_read_complete)(key, op_key, bytes_status);
+
+	    unlock_key(key, &lck_data);
             return PJ_SUCCESS;
         }
@@ -932,7 +1017,9 @@
             pj_list_erase(op_rec);
             op_rec->op = 0;
-            pj_mutex_unlock(key->mutex);
+            //pj_mutex_unlock(key->mutex);
 
             (*key->cb.on_write_complete)(key, op_key, bytes_status);
+
+	    unlock_key(key, &lck_data);
             return PJ_SUCCESS;
         }
@@ -946,9 +1033,11 @@
             pj_list_erase(op_rec);
             op_rec->op = 0;
-            pj_mutex_unlock(key->mutex);
+            //pj_mutex_unlock(key->mutex);
 
             (*key->cb.on_accept_complete)(key, op_key, 
                                           PJ_INVALID_SOCKET,
                                           bytes_status);
+
+	    unlock_key(key, &lck_data);
             return PJ_SUCCESS;
         }
@@ -956,5 +1045,5 @@
     }
 
-    pj_mutex_unlock(key->mutex);
+    unlock_key(key, &lck_data);
     
     return PJ_EINVALIDOP;
Index: pjproject/trunk/pjlib/src/pj/ioqueue_common_abs.h
===================================================================
--- pjproject/trunk/pjlib/src/pj/ioqueue_common_abs.h	(revision 362)
+++ pjproject/trunk/pjlib/src/pj/ioqueue_common_abs.h	(revision 363)
@@ -92,4 +92,6 @@
     pj_ioqueue_t           *ioqueue;                \
     pj_mutex_t             *mutex;                  \
+    pj_bool_t		    inside_callback;	    \
+    pj_bool_t		    destroy_requested;	    \
     pj_sock_t		    fd;                     \
     int                     fd_type;                \
Index: pjproject/trunk/pjlib/src/pjlib-test/ioq_perf.c
===================================================================
--- pjproject/trunk/pjlib/src/pjlib-test/ioq_perf.c	(revision 362)
+++ pjproject/trunk/pjlib/src/pjlib-test/ioq_perf.c	(revision 363)
@@ -392,5 +392,4 @@
 	TRACE_((THIS_FILE, "      join thread %d..", i));
         pj_thread_join(thread[i]);
-        pj_thread_destroy(thread[i]);
     }
 
@@ -429,5 +428,5 @@
     *p_bandwidth = (pj_uint32_t)bandwidth;
 
-    PJ_LOG(3,(THIS_FILE, "   %.4s    %d         %d        %8d KB/s",
+    PJ_LOG(3,(THIS_FILE, "   %.4s    %2d        %2d       %8d KB/s",
               type_name, thread_cnt, sockpair_cnt,
               *p_bandwidth));
