1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved.
24 */
25
26 /*
27 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
29 */
30
31 /*
32 *
33 * MODULE: dapl_evd_wait.c
34 *
35 * PURPOSE: EVENT management
36 *
37 * Description: Interfaces in this file are completely defined in
38 * the uDAPL 1.1 API specification
39 *
40 * $Id: dapl_evd_wait.c,v 1.22 2003/08/20 13:18:36 sjs2 Exp $
41 */
42
43 #include "dapl.h"
44 #include "dapl_evd_util.h"
45 #include "dapl_ring_buffer_util.h"
46 #include "dapl_adapter_util.h"
47
48 /*
49 * dapl_evd_wait
50 *
51 * UDAPL Requirements Version xxx,
52 *
53 * Wait, up to specified timeout, for notification event on EVD.
54 * Then return first available event.
55 *
56 * Input:
57 * evd_handle
58 * timeout
59 *
60 * Output:
61 * event
62 *
63 * Returns:
64 * DAT_SUCCESS
65 * DAT_INVALID_PARAMETER
66 * DAT_INVALID_STATE
67 */
dapl_evd_wait(IN DAT_EVD_HANDLE evd_handle,IN DAT_TIMEOUT time_out,IN DAT_COUNT threshold,OUT DAT_EVENT * event,OUT DAT_COUNT * nmore)68 DAT_RETURN dapl_evd_wait(
69 IN DAT_EVD_HANDLE evd_handle,
70 IN DAT_TIMEOUT time_out,
71 IN DAT_COUNT threshold,
72 OUT DAT_EVENT *event,
73 OUT DAT_COUNT *nmore)
74
75 {
76 DAPL_EVD *evd_ptr;
77 DAT_RETURN dat_status;
78 DAT_EVENT *local_event;
79 DAT_BOOLEAN waitable;
80 DAPL_EVD_STATE evd_state;
81
82 dapl_dbg_log(DAPL_DBG_TYPE_API,
83 "dapl_evd_wait (%p, %d, %d, %p, %p)\n",
84 evd_handle,
85 time_out,
86 threshold,
87 event,
88 nmore);
89
90 evd_ptr = (DAPL_EVD *)evd_handle;
91 dat_status = DAT_SUCCESS;
92
93 if (DAPL_BAD_HANDLE(evd_ptr, DAPL_MAGIC_EVD)) {
94 /*
95 * We return directly rather than bailing because
96 * bailing attempts to update the evd, and we don't have
97 * one.
98 */
99 dat_status = DAT_ERROR(DAT_INVALID_HANDLE, 0);
100 goto bail;
101 }
102 if (!event) {
103 dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG4);
104 goto bail;
105 }
106 if (!nmore) {
107 dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG5);
108 goto bail;
109 }
110 if (threshold <= 0 ||
111 (threshold > 1 &&
112 evd_ptr->completion_type != DAPL_EVD_STATE_THRESHOLD)) {
113 dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG3);
114 goto bail;
115 }
116 if (evd_ptr->catastrophic_overflow) {
117 dat_status = DAT_ERROR(DAT_INVALID_STATE, 0);
118 goto bail;
119 }
120
121 dapl_dbg_log(DAPL_DBG_TYPE_EVD,
122 "dapl_evd_wait: EVD %p, CQ %p\n",
123 evd_ptr,
124 (void *)evd_ptr->ib_cq_handle);
125
126 /*
127 * Make sure there are no other waiters and the evd is active.
128 * Currently this means only the OPEN state is allowed.
129 * We need to take a lock to synchronize with dapl_evd_dequeue().
130 */
131
132 dapl_os_lock(&evd_ptr->header.lock);
133 waitable = evd_ptr->evd_waitable;
134 evd_state = evd_ptr->evd_state;
135 if (evd_state != DAPL_EVD_STATE_OPEN || !waitable) {
136 dapl_os_unlock(&evd_ptr->header.lock);
137 dat_status = DAT_ERROR(DAT_INVALID_STATE, 0);
138 goto bail;
139 }
140 evd_ptr->evd_state = DAPL_EVD_STATE_WAITED;
141 dapl_os_unlock(&evd_ptr->header.lock);
142
143 /*
144 * We now own the EVD, we don't have the lock anymore,
145 * because we're in the WAITED state.
146 */
147
148 evd_ptr->threshold = threshold;
149
150 /* return pending events immediately without further polling */
151 if (dapls_rbuf_count(&evd_ptr->pending_event_queue) > 0) {
152 evd_ptr->evd_state = DAPL_EVD_STATE_OPEN;
153 dat_status = DAT_SUCCESS;
154 } else {
155 dat_status = dapls_evd_copy_events(evd_ptr, time_out);
156 evd_ptr->evd_state = DAPL_EVD_STATE_OPEN;
157 if (DAT_GET_TYPE(dat_status) == DAT_INTERRUPTED_CALL) {
158 goto bail;
159 }
160 if (!evd_ptr->evd_waitable) {
161 /* See if we were awakened by evd_set_unwaitable */
162 dat_status = DAT_ERROR(DAT_INVALID_STATE, 0);
163 goto bail;
164 }
165 if (dapls_rbuf_count(&evd_ptr->pending_event_queue) == 0) {
166 dat_status = DAT_ERROR(DAT_TIMEOUT_EXPIRED, 0);
167 }
168 }
169
170 if (dat_status == DAT_SUCCESS) {
171 local_event = dapls_rbuf_remove(&evd_ptr->pending_event_queue);
172 *event = *local_event;
173 dat_status = dapls_rbuf_add(&evd_ptr->free_event_queue,
174 local_event);
175 dapl_os_assert(dat_status == DAT_SUCCESS);
176 }
177
178 /*
179 * Valid if dat_status == DAT_SUCCESS || dat_status == DAT_TIMEOUT
180 * Undefined otherwise, so ok to set it.
181 */
182 *nmore = dapls_rbuf_count(&evd_ptr->pending_event_queue);
183
184 bail:
185 dapl_dbg_log(DAPL_DBG_TYPE_RTN,
186 "dapl_evd_wait () returns 0x%x\n",
187 dat_status);
188
189 return (dat_status);
190 }
191