[DAPL] missing patch, Do not miss IB completions!
authorstansmith <stansmith@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Tue, 26 Jun 2007 23:16:10 +0000 (23:16 +0000)
committerstansmith <stansmith@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Tue, 26 Jun 2007 23:16:10 +0000 (23:16 +0000)
git-svn-id: svn://openib.tc.cornell.edu/gen1/trunk@717 ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86

ulp/dapl/dapl/common/dapl_evd_wait.c

index 71f3bb8..ac3e3f4 100644 (file)
@@ -1,26 +1,27 @@
 /*\r
  * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved.\r
  *\r
- * This Software is licensed under either one of the following two licenses:\r
+ * This Software is licensed under one of the following licenses:\r
  *\r
  * 1) under the terms of the "Common Public License 1.0" a copy of which is\r
- *    in the file LICENSE.txt in the root directory. The license is also\r
  *    available from the Open Source Initiative, see\r
  *    http://www.opensource.org/licenses/cpl.php.\r
- * OR\r
  *\r
- * 2) under the terms of the "The BSD License" a copy of which is in the file\r
- *    LICENSE2.txt in the root directory. The license is also available from\r
- *    the Open Source Initiative, see\r
+ * 2) under the terms of the "The BSD License" a copy of which is\r
+ *    available from the Open Source Initiative, see\r
  *    http://www.opensource.org/licenses/bsd-license.php.\r
  *\r
- * Licensee has the right to choose either one of the above two licenses.\r
+ * 3) under the terms of the "GNU General Public License (GPL) Version 2" a\r
+ *    copy of which is available from the Open Source Initiative, see\r
+ *    http://www.opensource.org/licenses/gpl-license.php.\r
+ *\r
+ * Licensee has the right to choose one of the above licenses.\r
  *\r
- * Redistributions of source code must retain both the above copyright\r
- * notice and either one of the license notices.\r
+ * Redistributions of source code must retain the above copyright\r
+ * notice and one of the license notices.\r
  *\r
  * Redistributions in binary form must reproduce both the above copyright\r
- * notice, either one of the license notices in the documentation\r
+ * notice, one of the license notices in the documentation\r
  * and/or other materials provided with the distribution.\r
  */\r
 \r
@@ -33,7 +34,7 @@
  * Description: Interfaces in this file are completely defined in \r
  *              the uDAPL 1.1 API specification\r
  *\r
- * $Id$\r
+ * $Id:$\r
  **********************************************************************/\r
 \r
 #include "dapl.h"\r
@@ -73,9 +74,9 @@ DAT_RETURN dapl_evd_wait (
     DAPL_EVD           *evd_ptr;\r
     DAT_RETURN         dat_status;\r
     DAT_EVENT          *local_event;\r
-    DAT_BOOLEAN                waitable,notify_needed;\r
+    DAT_BOOLEAN                notify_requested = DAT_FALSE;\r
+    DAT_BOOLEAN                waitable;\r
     DAPL_EVD_STATE     evd_state;\r
-    DAT_COUNT          total_events,new_events;\r
 \r
     dapl_dbg_log (DAPL_DBG_TYPE_API,\r
                  "dapl_evd_wait (%p, %d, %d, %p, %p)\n", \r
@@ -123,10 +124,11 @@ DAT_RETURN dapl_evd_wait (
     }\r
 \r
     dapl_dbg_log (DAPL_DBG_TYPE_EVD, \r
-                 "dapl_evd_wait: EVD %p, CQ %p, Timeout %d, Threshold %d\n", \r
-              evd_ptr,(void *)evd_ptr->ib_cq_handle, time_out, threshold);\r
+                 "dapl_evd_wait: EVD %p, CQ %p\n", \r
+                  evd_ptr,\r
+                 (void *)evd_ptr->ib_cq_handle);\r
 \r
-       /*\r
+    /*\r
      * Make sure there are no other waiters and the evd is active.\r
      * Currently this means only the OPEN state is allowed.\r
      * Do this atomically.  We need to take a lock to synchronize\r
@@ -143,12 +145,24 @@ DAT_RETURN dapl_evd_wait (
                                        (DAT_COUNT) DAPL_EVD_STATE_OPEN,\r
                                        (DAT_COUNT) DAPL_EVD_STATE_WAITED );\r
     dapl_os_unlock ( &evd_ptr->header.lock );\r
-    if ( evd_state != DAPL_EVD_STATE_OPEN || !waitable)\r
+\r
+    if ( evd_state != DAPL_EVD_STATE_OPEN )\r
     {\r
+       /* Bogus state, bail out */\r
        dat_status = DAT_ERROR (DAT_INVALID_STATE,0);\r
        goto bail;\r
     }\r
 \r
+    if (!waitable)\r
+    {\r
+       /* This EVD is not waitable, reset the state and bail */\r
+       (void) dapl_os_atomic_assign ((DAPL_ATOMIC *)&evd_ptr->evd_state,\r
+                                       (DAT_COUNT) DAPL_EVD_STATE_WAITED,\r
+                                       evd_state);\r
+       dat_status = DAT_ERROR (DAT_INVALID_STATE, DAT_INVALID_STATE_EVD_UNWAITABLE);\r
+       goto bail;\r
+    }\r
+\r
     /*\r
      * We now own the EVD, even though we don't have the lock anymore,\r
      * because we're in the WAITED state.\r
@@ -156,120 +170,92 @@ DAT_RETURN dapl_evd_wait (
 \r
     evd_ptr->threshold = threshold;\r
 \r
-       for (;;)\r
+    for (;;)\r
     {\r
-               /*\r
-               * Ideally we'd just check the number of entries on the CQ, but\r
-               * we don't have a way to do that.  Because we have to set *nmore\r
-               * at some point in this routine, we'll need to do this copy\r
-               * sometime even if threshold == 1.\r
-               *\r
-               * For connection evd or async evd, the function checks and\r
-               * return right away if the ib_cq_handle associate with these evd\r
-               * equal to IB_INVALID_HANDLE\r
-               */\r
-               /* Logic to prevent missing completion between copy_cq (poll)\r
-                * and completion_notify (re-arm)  \r
-                */\r
-               notify_needed = TRUE;\r
-               new_events = 0;\r
-               while (TRUE)\r
-               {\r
-                       dapls_evd_copy_cq(evd_ptr); /* poll for new completions */\r
-                       total_events = dapls_rbuf_count (&evd_ptr->pending_event_queue); \r
-                       new_events = total_events - new_events;\r
-                       if (total_events >= threshold || \r
-                               (!new_events && notify_needed == FALSE))\r
-                       {\r
-                               break;\r
-                       } \r
-                                                                                               \r
-                       /*\r
-                       * Do not enable the completion notification if this evd is not \r
-                       * a DTO_EVD or RMR_BIND_EVD\r
-                       */\r
-                       if ( (evd_ptr->evd_flags & DAT_EVD_DTO_FLAG) ||\r
-                               (evd_ptr->evd_flags & DAT_EVD_RMR_BIND_FLAG) )\r
-                       {\r
-                           \r
-                               if (evd_ptr->completion_type == DAPL_EVD_STATE_SOLICITED_WAIT) \r
-                               {\r
-                                       dat_status = dapls_ib_completion_notify (\r
-                                               evd_ptr->header.owner_ia->hca_ptr->ib_hca_handle,\r
-                                               evd_ptr->ib_cq_handle,\r
-                                               IB_NOTIFY_ON_SOLIC_COMP); \r
-                               }\r
-                               else\r
-                               {\r
-                                       dat_status = dapls_ib_n_completions_notify (\r
-                                               evd_ptr->header.owner_ia->hca_ptr->ib_hca_handle,\r
-                                               evd_ptr->ib_cq_handle,\r
-                                               threshold - total_events ); \r
-                               }\r
-                               \r
-                               notify_needed = FALSE;\r
-                               new_events = total_events;\r
-                               \r
-                               /* FIXME report error */\r
-                               dapl_os_assert(dat_status == DAT_SUCCESS);\r
-                       } \r
-                       else \r
-                       {\r
-                               break;\r
-                       }\r
-\r
-               } /* while completions < threshold, and rearm needed */\r
-\r
-               if (total_events >= threshold)\r
-               {\r
-                       break;\r
-               }\r
-               \r
-               /*\r
-               * Unused by poster; it has no way to tell how many\r
-               * items are on the queue without copying them over to the\r
-               * EVD queue, and we're the only ones allowed to dequeue\r
-               * from the CQ for synchronization/locking reasons.\r
-               */\r
-               evd_ptr->threshold = threshold; \r
-\r
-               if (evd_ptr->cq_wait_obj_handle)\r
-               {\r
-                       dat_status = dapls_ib_wait_object_wait (\r
-                                                       evd_ptr->cq_wait_obj_handle, time_out );\r
-               }\r
-               else\r
-               {\r
-                       dat_status = dapl_os_wait_object_wait (\r
-                                                       &evd_ptr->wait_object, time_out );\r
-               }\r
-\r
-               /* See if we were awakened by evd_set_unwaitable */\r
-               if ( !evd_ptr->evd_waitable )\r
-               {\r
-                               dat_status = DAT_ERROR (DAT_INVALID_STATE,0);\r
-               }\r
-\r
-               if (dat_status != DAT_SUCCESS)\r
-               {\r
-#if 1\r
-                       dapls_evd_copy_cq(evd_ptr); /* poll */\r
-                       dapl_dbg_log (DAPL_DBG_TYPE_EVD, \r
-                               "dapl_evd_wait: WAKEUP ERROR: EVD %p, CQ %p, events? %d\n", \r
-              evd_ptr,(void *)evd_ptr->ib_cq_handle, \r
-                         dapls_rbuf_count(&evd_ptr->pending_event_queue) );\r
+       /*\r
+        * Ideally we'd just check the number of entries on the CQ, but\r
+        * we don't have a way to do that.  Because we have to set *nmore\r
+        * at some point in this routine, we'll need to do this copy\r
+        * sometime even if threshold == 1.\r
+        *\r
+        * For connection evd or async evd, the function checks and\r
+        * return right away if the ib_cq_handle associate with these evd\r
+        * equal to IB_INVALID_HANDLE\r
+        */\r
+       dapls_evd_copy_cq(evd_ptr);\r
+\r
+       if (dapls_rbuf_count(&evd_ptr->pending_event_queue) >= threshold)\r
+       {\r
+           break;\r
+       }\r
+\r
+       /*\r
+        * Do not enable the completion notification if this evd is not \r
+        * a DTO_EVD or RMR_BIND_EVD\r
+        */\r
+       if ( (!notify_requested) &&\r
+             ((evd_ptr->evd_flags & DAT_EVD_DTO_FLAG) ||\r
+              (evd_ptr->evd_flags & DAT_EVD_RMR_BIND_FLAG)) )\r
+       {\r
+           dat_status = dapls_ib_completion_notify (\r
+               evd_ptr->header.owner_ia->hca_ptr->ib_hca_handle,\r
+               evd_ptr->ib_cq_handle,\r
+               (evd_ptr->completion_type == DAPL_EVD_STATE_SOLICITED_WAIT) ?\r
+                    IB_NOTIFY_ON_SOLIC_COMP : IB_NOTIFY_ON_NEXT_COMP );  \r
+\r
+           DAPL_CNTR(DCNT_EVD_WAIT_CMP_NTFY);\r
+           /* FIXME report error */\r
+           dapl_os_assert(dat_status == DAT_SUCCESS);\r
+\r
+           notify_requested = DAT_TRUE;\r
+\r
+           /* Try again.  */\r
+           continue;\r
+       }\r
+\r
+\r
+       /*\r
+        * Unused by poster; it has no way to tell how many\r
+        * items are on the queue without copying them over to the\r
+        * EVD queue, and we're the only ones allowed to dequeue\r
+        * from the CQ for synchronization/locking reasons.\r
+        */\r
+       evd_ptr->threshold = threshold; \r
+\r
+       DAPL_CNTR(DCNT_EVD_WAIT_BLOCKED);\r
+\r
+#ifdef CQ_WAIT_OBJECT\r
+       if (evd_ptr->cq_wait_obj_handle)\r
+               dat_status = dapls_ib_wait_object_wait (\r
+                               evd_ptr->cq_wait_obj_handle, time_out );\r
+       else\r
 #endif\r
+               dat_status = dapl_os_wait_object_wait (\r
+                               &evd_ptr->wait_object, time_out );\r
+       /*\r
+        * FIXME: if the thread loops around and waits again\r
+        * the time_out value needs to be updated.\r
+        */\r
 \r
-                       /*\r
-                       * If the status is DAT_TIMEOUT, we'll break out of the\r
-                       * loop, *not* dequeue an event (because dat_status\r
-                       * != DAT_SUCCESS), set *nmore (as we should for timeout)\r
-                       * and return DAT_TIMEOUT.\r
-                       */\r
-                       break;\r
-               }\r
-    \r
-       } /* for(;;) */\r
+       notify_requested = DAT_FALSE; /* We've used it up.  */\r
+\r
+       /* See if we were awakened by evd_set_unwaitable */\r
+       if ( !evd_ptr->evd_waitable )\r
+       {\r
+               dat_status = DAT_ERROR (DAT_INVALID_STATE,0);\r
+       }\r
+\r
+       if (dat_status != DAT_SUCCESS)\r
+       {\r
+           /*\r
+            * If the status is DAT_TIMEOUT, we'll break out of the\r
+            * loop, *not* dequeue an event (because dat_status\r
+            * != DAT_SUCCESS), set *nmore (as we should for timeout)\r
+            * and return DAT_TIMEOUT.\r
+            */\r
+           break;\r
+       }\r
+    }\r
            \r
     evd_ptr->evd_state = DAPL_EVD_STATE_OPEN;\r
 \r
@@ -286,7 +272,7 @@ DAT_RETURN dapl_evd_wait (
      */\r
     *nmore = dapls_rbuf_count(&evd_ptr->pending_event_queue);\r
 \r
-bail:\r
+ bail:\r
     dapl_dbg_log (DAPL_DBG_TYPE_RTN,\r
                  "dapl_evd_wait () returns 0x%x\n", \r
                  dat_status);\r