[IBBUS] remove duplicate FDO extension fields [p_port_mgr,p_iou_mgr] and use same...
[mirror/winof/.git] / core / complib / cl_reqmgr.c
1 /*\r
2  * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.\r
3  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. \r
4  *\r
5  * This software is available to you under the OpenIB.org BSD license\r
6  * below:\r
7  *\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
11  *\r
12  *      - Redistributions of source code must retain the above\r
13  *        copyright notice, this list of conditions and the following\r
14  *        disclaimer.\r
15  *\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
20  *\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
28  * SOFTWARE.\r
29  *\r
30  * $Id$\r
31  */\r
32 \r
33 \r
34 /*\r
35  * Abstract:\r
36  *      Implementation of asynchronous request manager.\r
37  *\r
38  * Environment:\r
39  *      All\r
40  */\r
41 \r
42 \r
43 #include <complib/cl_reqmgr.h>\r
44 #include <complib/cl_memory.h>\r
45 \r
46 \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
51 \r
52 \r
53 /****i* Component Library: Request Manager/cl_request_object_t\r
54 * NAME\r
55 *       cl_request_object_t\r
56 *\r
57 * DESCRIPTION\r
58 *       Request manager structure.\r
59 *\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
62 *\r
63 * SYNOPSIS\r
64 */\r
65 typedef struct _cl_request_object\r
66 {\r
67         cl_pool_item_t  pool_item;\r
68         size_t                  count;\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
73 \r
74 } cl_request_object_t;\r
75 /*\r
76 * FIELDS\r
77 *       pool_item\r
78 *               Pool item to store request in a pool or list.\r
79 *\r
80 *       count\r
81 *               Number of items requested.\r
82 *\r
83 *       partial_ok\r
84 *               Is it okay to return some of the items.\r
85 *\r
86 *       pfn_callback\r
87 *               Notification routine when completed.\r
88 *\r
89 *       context1\r
90 *               Callback context information.\r
91 *\r
92 *       context2\r
93 *               Callback context information.\r
94 *\r
95 * SEE ALSO\r
96 *       Overview\r
97 *********/\r
98 \r
99 \r
100 void\r
101 cl_req_mgr_construct(\r
102         IN      cl_req_mgr_t* const     p_req_mgr )\r
103 {\r
104         CL_ASSERT( p_req_mgr );\r
105 \r
106         /* Clear the structure. */\r
107         cl_memclr( p_req_mgr, sizeof(cl_req_mgr_t) );\r
108 \r
109         /* Initialize the state of the free request stack. */\r
110         cl_qpool_construct( &p_req_mgr->request_pool );\r
111 }\r
112 \r
113 \r
114 cl_status_t\r
115 cl_req_mgr_init(\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
119 {\r
120         cl_status_t             status;\r
121 \r
122         CL_ASSERT( p_req_mgr );\r
123         CL_ASSERT( pfn_get_count );\r
124 \r
125         cl_qlist_init( &p_req_mgr->request_queue );\r
126 \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
129 \r
130         if( status != CL_SUCCESS )\r
131                 return( status );\r
132 \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
136 \r
137         return( CL_SUCCESS );\r
138 }\r
139 \r
140 \r
141 void\r
142 cl_req_mgr_destroy(\r
143         IN      cl_req_mgr_t* const     p_req_mgr )\r
144 {\r
145         CL_ASSERT( p_req_mgr );\r
146 \r
147         /* Return all requests to the grow pool. */\r
148         if( cl_is_qpool_inited( &p_req_mgr->request_pool ) )\r
149         {\r
150                 cl_qpool_put_list( &p_req_mgr->request_pool,\r
151                         &p_req_mgr->request_queue );\r
152         }\r
153 \r
154         cl_qpool_destroy( &p_req_mgr->request_pool );\r
155 }\r
156 \r
157 \r
158 cl_status_t\r
159 cl_req_mgr_get(\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
166 {\r
167         size_t                                  available_count;\r
168         size_t                                  count;\r
169         cl_request_object_t             *p_request;\r
170 \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
175 \r
176         /* Get the number of available objects in the grow pool. */\r
177         available_count =\r
178                 p_req_mgr->pfn_get_count( (void*)p_req_mgr->get_context );\r
179 \r
180         /*\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
183          */\r
184         if( cl_is_qlist_empty( &p_req_mgr->request_queue ) &&\r
185                 *p_count <= available_count )\r
186         {\r
187                 return( CL_SUCCESS );\r
188         }\r
189 \r
190         if( req_type == REQ_GET_SYNC )\r
191                 return( CL_INSUFFICIENT_RESOURCES );\r
192 \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
196 \r
197         if( !p_request )\r
198                 return( CL_INSUFFICIENT_MEMORY );\r
199 \r
200         /*\r
201          * We can return the available number of objects but we still need\r
202          * to queue a request for the remainder.\r
203          */\r
204         if( req_type == REQ_GET_PARTIAL_OK &&\r
205                 cl_is_qlist_empty( &p_req_mgr->request_queue ) )\r
206         {\r
207                 count = *p_count - available_count;\r
208                 *p_count = available_count;\r
209                 p_request->partial_ok = TRUE;\r
210         }\r
211         else\r
212         {\r
213                 /*\r
214                  * We cannot return any objects.  We queue a request for\r
215                  * all of them.\r
216                  */\r
217                 count = *p_count;\r
218                 *p_count = 0;\r
219                 p_request->partial_ok = FALSE;\r
220         }\r
221 \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
227 \r
228         cl_qlist_insert_tail( &p_req_mgr->request_queue,\r
229                 &p_request->pool_item.list_item );\r
230 \r
231         return( CL_PENDING );\r
232 }\r
233 \r
234 \r
235 cl_status_t\r
236 cl_req_mgr_resume(\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
242 {\r
243         size_t                                  available_count;\r
244         cl_request_object_t             *p_queued_request;\r
245 \r
246         CL_ASSERT( p_req_mgr );\r
247         CL_ASSERT( cl_is_qpool_inited( &p_req_mgr->request_pool ) );\r
248 \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
252 \r
253         /*\r
254          * Get the item at the head of the request queue,\r
255          * but do not remove it yet.\r
256          */\r
257         p_queued_request = (cl_request_object_t*)\r
258                 cl_qlist_head( &p_req_mgr->request_queue );\r
259 \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
263 \r
264         available_count =\r
265                 p_req_mgr->pfn_get_count( (void*)p_req_mgr->get_context );\r
266 \r
267         /* See if the request can be fulfilled. */\r
268         if( p_queued_request->count > available_count )\r
269         {\r
270                 if( !p_queued_request->partial_ok )\r
271                         return( CL_INSUFFICIENT_RESOURCES );\r
272 \r
273                 p_queued_request->count -= available_count;\r
274 \r
275                 *p_count = available_count;\r
276                 return( CL_PENDING );\r
277         }\r
278 \r
279         *p_count = p_queued_request->count;\r
280 \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
283 \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
288 }\r