2 * Copyright (c) 2005 SilverStorm Technologies. All rights reserved.
\r
3 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
\r
5 * This software is available to you under the OpenIB.org BSD license
\r
8 * Redistribution and use in source and binary forms, with or
\r
9 * without modification, are permitted provided that the following
\r
10 * conditions are met:
\r
12 * - Redistributions of source code must retain the above
\r
13 * copyright notice, this list of conditions and the following
\r
16 * - Redistributions in binary form must reproduce the above
\r
17 * copyright notice, this list of conditions and the following
\r
18 * disclaimer in the documentation and/or other materials
\r
19 * provided with the distribution.
\r
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
\r
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
\r
23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
\r
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
\r
25 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
\r
26 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
27 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
\r
36 * Implementation of asynchronous request manager.
\r
43 #include <complib/cl_reqmgr.h>
\r
44 #include <complib/cl_memory.h>
\r
47 /* minimum number of objects to allocate */
\r
48 #define REQ_MGR_START_SIZE 10
\r
49 /* minimum number of objects to grow */
\r
50 #define REQ_MGR_GROW_SIZE 10
\r
53 /****i* Component Library: Request Manager/cl_request_object_t
\r
55 * cl_request_object_t
\r
58 * Request manager structure.
\r
60 * The cl_request_object_t structure should be treated as opaque and should be
\r
61 * manipulated only through the provided functions.
\r
65 typedef struct _cl_request_object
\r
67 cl_pool_item_t pool_item;
\r
69 boolean_t partial_ok;
\r
70 cl_pfn_req_cb_t pfn_callback;
\r
71 const void *context1;
\r
72 const void *context2;
\r
74 } cl_request_object_t;
\r
78 * Pool item to store request in a pool or list.
\r
81 * Number of items requested.
\r
84 * Is it okay to return some of the items.
\r
87 * Notification routine when completed.
\r
90 * Callback context information.
\r
93 * Callback context information.
\r
101 cl_req_mgr_construct(
\r
102 IN cl_req_mgr_t* const p_req_mgr )
\r
104 CL_ASSERT( p_req_mgr );
\r
106 /* Clear the structure. */
\r
107 cl_memclr( p_req_mgr, sizeof(cl_req_mgr_t) );
\r
109 /* Initialize the state of the free request stack. */
\r
110 cl_qpool_construct( &p_req_mgr->request_pool );
\r
116 IN cl_req_mgr_t* const p_req_mgr,
\r
117 IN cl_pfn_reqmgr_get_count_t pfn_get_count,
\r
118 IN const void* const get_context )
\r
120 cl_status_t status;
\r
122 CL_ASSERT( p_req_mgr );
\r
123 CL_ASSERT( pfn_get_count );
\r
125 cl_qlist_init( &p_req_mgr->request_queue );
\r
127 status = cl_qpool_init( &p_req_mgr->request_pool, REQ_MGR_START_SIZE, 0,
\r
128 REQ_MGR_GROW_SIZE, sizeof(cl_request_object_t), NULL, NULL, NULL );
\r
130 if( status != CL_SUCCESS )
\r
133 /* Store callback information for the count function. */
\r
134 p_req_mgr->pfn_get_count = pfn_get_count;
\r
135 p_req_mgr->get_context = get_context;
\r
137 return( CL_SUCCESS );
\r
142 cl_req_mgr_destroy(
\r
143 IN cl_req_mgr_t* const p_req_mgr )
\r
145 CL_ASSERT( p_req_mgr );
\r
147 /* Return all requests to the grow pool. */
\r
148 if( cl_is_qpool_inited( &p_req_mgr->request_pool ) )
\r
150 cl_qpool_put_list( &p_req_mgr->request_pool,
\r
151 &p_req_mgr->request_queue );
\r
154 cl_qpool_destroy( &p_req_mgr->request_pool );
\r
160 IN cl_req_mgr_t* const p_req_mgr,
\r
161 IN OUT size_t* const p_count,
\r
162 IN const cl_req_type_t req_type,
\r
163 IN cl_pfn_req_cb_t pfn_callback,
\r
164 IN const void* const context1,
\r
165 IN const void* const context2 )
\r
167 size_t available_count;
\r
169 cl_request_object_t *p_request;
\r
171 CL_ASSERT( p_req_mgr );
\r
172 CL_ASSERT( cl_is_qpool_inited( &p_req_mgr->request_pool ) );
\r
173 CL_ASSERT( p_count );
\r
174 CL_ASSERT( *p_count );
\r
176 /* Get the number of available objects in the grow pool. */
\r
178 p_req_mgr->pfn_get_count( (void*)p_req_mgr->get_context );
\r
181 * Check to see if there is nothing on the queue, and there are
\r
182 * enough items to satisfy the whole request.
\r
184 if( cl_is_qlist_empty( &p_req_mgr->request_queue ) &&
\r
185 *p_count <= available_count )
\r
187 return( CL_SUCCESS );
\r
190 if( req_type == REQ_GET_SYNC )
\r
191 return( CL_INSUFFICIENT_RESOURCES );
\r
193 /* We need a request object to place on the request queue. */
\r
194 p_request = (cl_request_object_t*)
\r
195 cl_qpool_get( &p_req_mgr->request_pool );
\r
198 return( CL_INSUFFICIENT_MEMORY );
\r
201 * We can return the available number of objects but we still need
\r
202 * to queue a request for the remainder.
\r
204 if( req_type == REQ_GET_PARTIAL_OK &&
\r
205 cl_is_qlist_empty( &p_req_mgr->request_queue ) )
\r
207 count = *p_count - available_count;
\r
208 *p_count = available_count;
\r
209 p_request->partial_ok = TRUE;
\r
214 * We cannot return any objects. We queue a request for
\r
219 p_request->partial_ok = FALSE;
\r
222 /* Set the request fields and enqueue it. */
\r
223 p_request->pfn_callback = pfn_callback;
\r
224 p_request->context1 = context1;
\r
225 p_request->context2 = context2;
\r
226 p_request->count = count;
\r
228 cl_qlist_insert_tail( &p_req_mgr->request_queue,
\r
229 &p_request->pool_item.list_item );
\r
231 return( CL_PENDING );
\r
237 IN cl_req_mgr_t* const p_req_mgr,
\r
238 OUT size_t* const p_count,
\r
239 OUT cl_pfn_req_cb_t* const ppfn_callback,
\r
240 OUT const void** const p_context1,
\r
241 OUT const void** const p_context2 )
\r
243 size_t available_count;
\r
244 cl_request_object_t *p_queued_request;
\r
246 CL_ASSERT( p_req_mgr );
\r
247 CL_ASSERT( cl_is_qpool_inited( &p_req_mgr->request_pool ) );
\r
249 /* If no requests are pending, there's nothing to return. */
\r
250 if( cl_is_qlist_empty( &p_req_mgr->request_queue ) )
\r
251 return( CL_NOT_DONE );
\r
254 * Get the item at the head of the request queue,
\r
255 * but do not remove it yet.
\r
257 p_queued_request = (cl_request_object_t*)
\r
258 cl_qlist_head( &p_req_mgr->request_queue );
\r
260 *ppfn_callback = p_queued_request->pfn_callback;
\r
261 *p_context1 = p_queued_request->context1;
\r
262 *p_context2 = p_queued_request->context2;
\r
265 p_req_mgr->pfn_get_count( (void*)p_req_mgr->get_context );
\r
267 /* See if the request can be fulfilled. */
\r
268 if( p_queued_request->count > available_count )
\r
270 if( !p_queued_request->partial_ok )
\r
271 return( CL_INSUFFICIENT_RESOURCES );
\r
273 p_queued_request->count -= available_count;
\r
275 *p_count = available_count;
\r
276 return( CL_PENDING );
\r
279 *p_count = p_queued_request->count;
\r
281 /* The entire request can be met. Remove it from the request queue. */
\r
282 cl_qlist_remove_head( &p_req_mgr->request_queue );
\r
284 /* Return the internal request object to the free stack. */
\r
285 cl_qpool_put( &p_req_mgr->request_pool,
\r
286 &p_queued_request->pool_item );
\r
287 return( CL_SUCCESS );
\r