/*\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
* 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
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
}\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
(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
\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
*/\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