Ticket #913: Concurrency problem in select ioqueue may corrupt descriptor set
 - fixed the concurrency problem
 - also fixed ioqueue unregister test in pjlib-test


git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@2826 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjlib/src/pj/ioqueue_common_abs.c b/pjlib/src/pj/ioqueue_common_abs.c
index e965b14..cccabc8 100644
--- a/pjlib/src/pj/ioqueue_common_abs.c
+++ b/pjlib/src/pj/ioqueue_common_abs.c
@@ -687,6 +687,14 @@
     read_op->flags = flags;
 
     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);
     pj_mutex_unlock(key->mutex);
@@ -755,6 +763,14 @@
     read_op->rmt_addrlen = addrlen;
 
     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);
     pj_mutex_unlock(key->mutex);
@@ -861,6 +877,14 @@
     write_op->flags = flags;
     
     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);
     pj_mutex_unlock(key->mutex);
@@ -978,6 +1002,14 @@
     write_op->rmt_addrlen = addrlen;
     
     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);
     pj_mutex_unlock(key->mutex);
@@ -1047,6 +1079,14 @@
     accept_op->local_addr = local;
 
     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);
     pj_mutex_unlock(key->mutex);
@@ -1083,6 +1123,13 @@
 	if (status == PJ_STATUS_FROM_OS(PJ_BLOCKING_CONNECT_ERROR_VAL)) {
 	    /* 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);
             ioqueue_add_to_set(key->ioqueue, key, EXCEPTION_EVENT);