Index: pjproject/trunk/pjlib/src/pj/ioqueue_common_abs.c
===================================================================
--- pjproject/trunk/pjlib/src/pj/ioqueue_common_abs.c	(revision 2825)
+++ pjproject/trunk/pjlib/src/pj/ioqueue_common_abs.c	(revision 2826)
@@ -688,4 +688,12 @@
 
     pj_mutex_lock(key->mutex);
+    /* Check again. Handle may have been closed after the previous check
+     * in multithreaded app. If we add bad handle to the set it will
+     * corrupt the ioqueue set. See #913
+     */
+    if (IS_CLOSING(key)) {
+	pj_mutex_unlock(key->mutex);
+	return PJ_ECANCELLED;
+    }
     pj_list_insert_before(&key->read_list, read_op);
     ioqueue_add_to_set(key->ioqueue, key, READABLE_EVENT);
@@ -756,4 +764,12 @@
 
     pj_mutex_lock(key->mutex);
+    /* Check again. Handle may have been closed after the previous check
+     * in multithreaded app. If we add bad handle to the set it will
+     * corrupt the ioqueue set. See #913
+     */
+    if (IS_CLOSING(key)) {
+	pj_mutex_unlock(key->mutex);
+	return PJ_ECANCELLED;
+    }
     pj_list_insert_before(&key->read_list, read_op);
     ioqueue_add_to_set(key->ioqueue, key, READABLE_EVENT);
@@ -862,4 +878,12 @@
     
     pj_mutex_lock(key->mutex);
+    /* Check again. Handle may have been closed after the previous check
+     * in multithreaded app. If we add bad handle to the set it will
+     * corrupt the ioqueue set. See #913
+     */
+    if (IS_CLOSING(key)) {
+	pj_mutex_unlock(key->mutex);
+	return PJ_ECANCELLED;
+    }
     pj_list_insert_before(&key->write_list, write_op);
     ioqueue_add_to_set(key->ioqueue, key, WRITEABLE_EVENT);
@@ -979,4 +1003,12 @@
     
     pj_mutex_lock(key->mutex);
+    /* Check again. Handle may have been closed after the previous check
+     * in multithreaded app. If we add bad handle to the set it will
+     * corrupt the ioqueue set. See #913
+     */
+    if (IS_CLOSING(key)) {
+	pj_mutex_unlock(key->mutex);
+	return PJ_ECANCELLED;
+    }
     pj_list_insert_before(&key->write_list, write_op);
     ioqueue_add_to_set(key->ioqueue, key, WRITEABLE_EVENT);
@@ -1048,4 +1080,12 @@
 
     pj_mutex_lock(key->mutex);
+    /* Check again. Handle may have been closed after the previous check
+     * in multithreaded app. If we add bad handle to the set it will
+     * corrupt the ioqueue set. See #913
+     */
+    if (IS_CLOSING(key)) {
+	pj_mutex_unlock(key->mutex);
+	return PJ_ECANCELLED;
+    }
     pj_list_insert_before(&key->accept_list, accept_op);
     ioqueue_add_to_set(key->ioqueue, key, READABLE_EVENT);
@@ -1084,4 +1124,11 @@
 	    /* Pending! */
             pj_mutex_lock(key->mutex);
+	    /* Check again. Handle may have been closed after the previous 
+	     * check in multithreaded app. See #913
+	     */
+	    if (IS_CLOSING(key)) {
+		pj_mutex_unlock(key->mutex);
+		return PJ_ECANCELLED;
+	    }
 	    key->connecting = PJ_TRUE;
             ioqueue_add_to_set(key->ioqueue, key, WRITEABLE_EVENT);
Index: pjproject/trunk/pjlib/src/pjlib-test/ioq_unreg.c
===================================================================
--- pjproject/trunk/pjlib/src/pjlib-test/ioq_unreg.c	(revision 2825)
+++ pjproject/trunk/pjlib/src/pjlib-test/ioq_unreg.c	(revision 2826)
@@ -94,7 +94,4 @@
 	    sock_data.unregistered = 1;
 	    pj_ioqueue_unregister(key);
-	    pj_mutex_destroy(sock_data.mutex);
-	    pj_pool_release(sock_data.pool);
-	    sock_data.pool = NULL;
 	    return;
 	}
@@ -244,4 +241,5 @@
     for (;;) {
 	pj_time_val now, timeout;
+	int n;
 
 	pj_gettimeofday(&now);
@@ -249,15 +247,11 @@
 	if (test_method == UNREGISTER_IN_APP && 
 	    PJ_TIME_VAL_GTE(now, time_to_unregister) &&
-	    sock_data.pool) 
+	    !sock_data.unregistered) 
 	{
-	    //Can't do this otherwise it'll deadlock
-	    //pj_mutex_lock(sock_data.mutex);
-
 	    sock_data.unregistered = 1;
+	    /* Wait (as much as possible) for callback to complete */
+	    pj_mutex_lock(sock_data.mutex);
+	    pj_mutex_unlock(sock_data.mutex);
 	    pj_ioqueue_unregister(sock_data.key);
-	    //pj_mutex_unlock(sock_data.mutex);
-	    pj_mutex_destroy(sock_data.mutex);
-	    pj_pool_release(sock_data.pool);
-	    sock_data.pool = NULL;
 	}
 
@@ -266,7 +260,9 @@
 
 	timeout.sec = 0; timeout.msec = 10;
-	pj_ioqueue_poll(ioqueue, &timeout);
-	//pj_thread_sleep(1);
-
+	n = pj_ioqueue_poll(ioqueue, &timeout);
+	if (n < 0) {
+	    app_perror("pj_ioqueue_poll error", -n);
+	    pj_thread_sleep(1);
+	}
     }
 
@@ -277,4 +273,9 @@
 	pj_thread_destroy(thread[i]);
     }
+
+    /* Destroy data */
+    pj_mutex_destroy(sock_data.mutex);
+    pj_pool_release(sock_data.pool);
+    sock_data.pool = NULL;
 
     if (other_socket) {
@@ -315,5 +316,5 @@
     }
 
-    PJ_LOG(3, (THIS_FILE, "...ioqueue unregister stress test 0/3 (%s)", 
+    PJ_LOG(3, (THIS_FILE, "...ioqueue unregister stress test 0/3, unregister in app (%s)", 
 	       pj_ioqueue_name()));
     for (i=0; i<LOOP; ++i) {
@@ -325,5 +326,5 @@
 
 
-    PJ_LOG(3, (THIS_FILE, "...ioqueue unregister stress test 1/3 (%s)",
+    PJ_LOG(3, (THIS_FILE, "...ioqueue unregister stress test 1/3, unregister in app (%s)",
 	       pj_ioqueue_name()));
     for (i=0; i<LOOP; ++i) {
@@ -336,5 +337,5 @@
     test_method = UNREGISTER_IN_CALLBACK;
 
-    PJ_LOG(3, (THIS_FILE, "...ioqueue unregister stress test 2/3 (%s)", 
+    PJ_LOG(3, (THIS_FILE, "...ioqueue unregister stress test 2/3, unregister in cb (%s)", 
 	       pj_ioqueue_name()));
     for (i=0; i<LOOP; ++i) {
@@ -346,5 +347,5 @@
 
 
-    PJ_LOG(3, (THIS_FILE, "...ioqueue unregister stress test 3/3 (%s)", 
+    PJ_LOG(3, (THIS_FILE, "...ioqueue unregister stress test 3/3, unregister in cb (%s)", 
 	       pj_ioqueue_name()));
     for (i=0; i<LOOP; ++i) {
@@ -367,5 +368,5 @@
     rc = udp_ioqueue_unreg_test_imp(PJ_TRUE);
     if (rc != 0)
-	return rc;
+    	return rc;
 
     rc = udp_ioqueue_unreg_test_imp(PJ_FALSE);
