4875d914b7f264c2440bb38cf3306bbb855a60ee
[mirror/winof/.git] / core / al / al_common.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  * Portions Copyright (c) 2008 Microsoft Corporation.  All rights reserved.\r
5  *\r
6  * This software is available to you under the OpenIB.org BSD license\r
7  * below:\r
8  *\r
9  *     Redistribution and use in source and binary forms, with or\r
10  *     without modification, are permitted provided that the following\r
11  *     conditions are met:\r
12  *\r
13  *      - Redistributions of source code must retain the above\r
14  *        copyright notice, this list of conditions and the following\r
15  *        disclaimer.\r
16  *\r
17  *      - Redistributions in binary form must reproduce the above\r
18  *        copyright notice, this list of conditions and the following\r
19  *        disclaimer in the documentation and/or other materials\r
20  *        provided with the distribution.\r
21  *\r
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
23  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
24  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
25  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
26  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
27  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
28  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
29  * SOFTWARE.\r
30  *\r
31  * $Id$\r
32  */\r
33 \r
34 #include "al.h"\r
35 #include "al_ci_ca.h"\r
36 #include "al_common.h"\r
37 #include "al_debug.h"\r
38 \r
39 #if defined(EVENT_TRACING)\r
40 #ifdef offsetof\r
41 #undef offsetof\r
42 #endif\r
43 #include "al_common.tmh"\r
44 #endif\r
45 \r
46 #include "al_mgr.h"\r
47 #include <complib/cl_math.h>\r
48 #include "ib_common.h"\r
49 \r
50 \r
51 \r
52 #if AL_OBJ_PRIVATE_ASYNC_PROC\r
53 cl_async_proc_t         *gp_async_obj_mgr = NULL;\r
54 #endif\r
55 \r
56 \r
57 boolean_t\r
58 destroy_obj(\r
59         IN                              struct _al_obj                          *p_obj,\r
60         IN              const   ib_pfn_destroy_cb_t                     pfn_destroy_cb );\r
61 \r
62 \r
63 void\r
64 async_destroy_cb(\r
65         IN                              cl_async_proc_item_t            *p_item );\r
66 \r
67 \r
68 void\r
69 async_destroy_obj(\r
70         IN                              struct _al_obj                          *p_obj,\r
71         IN              const   ib_pfn_destroy_cb_t                     pfn_destroy_cb );\r
72 \r
73 \r
74 void\r
75 sync_destroy_obj(\r
76         IN                              struct _al_obj                          *p_obj,\r
77         IN              const   ib_pfn_destroy_cb_t                     pfn_destroy_cb );\r
78 \r
79 \r
80 \r
81 const char* ib_obj_type_str[] =\r
82 {\r
83         "AL_OBJ_TYPE_UNKNOWN",\r
84         "AL_OBJ_TYPE_H_AL",\r
85         "AL_OBJ_TYPE_H_QP",\r
86         "AL_OBJ_TYPE_H_AV",\r
87         "AL_OBJ_TYPE_H_MR",\r
88         "AL_OBJ_TYPE_H_MW",\r
89         "AL_OBJ_TYPE_H_PD",\r
90         "AL_OBJ_TYPE_H_CA",\r
91         "AL_OBJ_TYPE_H_CQ",\r
92         "AL_OBJ_TYPE_H_CONN",\r
93         "AL_OBJ_TYPE_H_LISTEN",\r
94         "AL_OBJ_TYPE_H_IOC",\r
95         "AL_OBJ_TYPE_H_SVC_ENTRY",\r
96         "AL_OBJ_TYPE_H_PNP",\r
97         "AL_OBJ_TYPE_H_SA_REQ",\r
98         "AL_OBJ_TYPE_H_MCAST",\r
99         "AL_OBJ_TYPE_H_ATTACH",\r
100         "AL_OBJ_TYPE_H_MAD",\r
101         "AL_OBJ_TYPE_H_MAD_POOL",\r
102         "AL_OBJ_TYPE_H_POOL_KEY",\r
103         "AL_OBJ_TYPE_H_MAD_SVC",\r
104         "AL_OBJ_TYPE_CI_CA",\r
105         "AL_OBJ_TYPE_CM",\r
106         "AL_OBJ_TYPE_SMI",\r
107         "AL_OBJ_TYPE_DM",\r
108         "AL_OBJ_TYPE_IOU",\r
109         "AL_OBJ_TYPE_LOADER",\r
110         "AL_OBJ_TYPE_MAD_POOL",\r
111         "AL_OBJ_TYPE_MAD_DISP",\r
112         "AL_OBJ_TYPE_AL_MGR",\r
113         "AL_OBJ_TYPE_PNP_MGR",\r
114         "AL_OBJ_TYPE_IOC_PNP_MGR",\r
115         "AL_OBJ_TYPE_IOC_PNP_SVC",\r
116         "AL_OBJ_TYPE_QUERY_SVC",\r
117         "AL_OBJ_TYPE_MCAST_SVC",\r
118         "AL_OBJ_TYPE_SA_REQ_SVC",\r
119         "AL_OBJ_TYPE_RES_MGR",\r
120         "AL_OBJ_TYPE_H_CA_ATTR",\r
121         "AL_OBJ_TYPE_H_PNP_EVENT",\r
122         "AL_OBJ_TYPE_H_SA_REG",\r
123         "AL_OBJ_TYPE_H_FMR",\r
124         "AL_OBJ_TYPE_H_SRQ",\r
125         "AL_OBJ_TYPE_H_FMR_POOL",\r
126         "AL_OBJ_TYPE_NDI"\r
127 };\r
128 \r
129 \r
130 /*\r
131  * Used to force synchronous destruction of AL objects.\r
132  */\r
133 void\r
134 __sync_destroy_cb(\r
135         IN                              void                                            *context )\r
136 {\r
137         UNUSED_PARAM( context );\r
138 }\r
139 \r
140 \r
141 void\r
142 construct_al_obj(\r
143         IN                              al_obj_t * const                        p_obj,\r
144         IN              const   al_obj_type_t                           obj_type )\r
145 {\r
146         CL_ASSERT( p_obj );\r
147         cl_memclr( p_obj, sizeof( al_obj_t ) );\r
148 \r
149         cl_spinlock_construct( &p_obj->lock );\r
150         p_obj->state = CL_UNINITIALIZED;\r
151         p_obj->type = obj_type;\r
152         p_obj->timeout_ms = AL_DEFAULT_TIMEOUT_MS;\r
153         p_obj->ref_cnt = 1;\r
154         cl_event_construct( &p_obj->event );\r
155 \r
156         /* Insert the object into the global tracking list. */\r
157         if( p_obj != &gp_al_mgr->obj )\r
158         {\r
159                 cl_spinlock_acquire( &gp_al_mgr->lock );\r
160                 cl_qlist_insert_tail( &gp_al_mgr->al_obj_list, &p_obj->list_item );\r
161                 cl_spinlock_release( &gp_al_mgr->lock );\r
162                 ref_al_obj( &gp_al_mgr->obj );\r
163         }\r
164 }\r
165 \r
166 \r
167 \r
168 ib_api_status_t\r
169 init_al_obj(\r
170         IN                              al_obj_t * const                        p_obj,\r
171         IN              const   void* const                                     context,\r
172         IN                              boolean_t                                       async_destroy,\r
173         IN              const   al_pfn_destroying_t                     pfn_destroying,\r
174         IN              const   al_pfn_cleanup_t                        pfn_cleanup,\r
175         IN              const   al_pfn_free_t                           pfn_free )\r
176 {\r
177         cl_status_t                             cl_status;\r
178 \r
179         AL_ENTER( AL_DBG_AL_OBJ );\r
180         CL_ASSERT( p_obj && pfn_free );\r
181         CL_ASSERT( p_obj->state == CL_UNINITIALIZED );\r
182         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_AL_OBJ,\r
183                 ("%p\n", p_obj ) );\r
184 \r
185         /* Initialize the object. */\r
186         p_obj->async_item.pfn_callback = async_destroy_cb;\r
187         p_obj->pfn_free = pfn_free;\r
188 \r
189         p_obj->context = context;\r
190 \r
191         if( async_destroy )\r
192                 p_obj->pfn_destroy = async_destroy_obj;\r
193         else\r
194                 p_obj->pfn_destroy = sync_destroy_obj;\r
195 \r
196         p_obj->pfn_destroying = pfn_destroying;\r
197 \r
198         p_obj->pfn_cleanup = pfn_cleanup;\r
199         p_obj->user_destroy_cb = NULL;\r
200 \r
201         cl_qlist_init( &p_obj->obj_list );\r
202         cl_status = cl_spinlock_init( &p_obj->lock );\r
203         if( cl_status != CL_SUCCESS )\r
204         {\r
205                 return ib_convert_cl_status( cl_status );\r
206         }\r
207 \r
208         cl_status = cl_event_init( &p_obj->event, FALSE );\r
209         if( cl_status != CL_SUCCESS )\r
210         {\r
211                 return ib_convert_cl_status( cl_status );\r
212         }\r
213 \r
214         p_obj->state = CL_INITIALIZED;\r
215 \r
216         /*\r
217          * Hold an extra reference on the object until creation is complete.\r
218          * This prevents a client's destruction of the object during asynchronous\r
219          * event callback processing from deallocating the object before the\r
220          * creation is complete.\r
221          */\r
222         ref_al_obj( p_obj );\r
223 \r
224         AL_EXIT( AL_DBG_AL_OBJ );\r
225         return IB_SUCCESS;\r
226 }\r
227 \r
228 \r
229 void\r
230 reset_al_obj(\r
231         IN                              al_obj_t * const                        p_obj )\r
232 {\r
233         CL_ASSERT( p_obj && (p_obj->ref_cnt == 0) );\r
234         CL_ASSERT( p_obj->state == CL_DESTROYING );\r
235 \r
236         p_obj->ref_cnt = 1;\r
237         p_obj->desc_cnt = 0;\r
238         p_obj->state = CL_INITIALIZED;\r
239         p_obj->h_al = NULL;\r
240         p_obj->hdl = AL_INVALID_HANDLE;\r
241 }\r
242 \r
243 \r
244 \r
245 void\r
246 set_al_obj_timeout(\r
247         IN                              al_obj_t * const                        p_obj,\r
248         IN              const   uint32_t                                        timeout_ms )\r
249 {\r
250         CL_ASSERT( p_obj );\r
251 \r
252         /* Only increase timeout values. */\r
253         p_obj->timeout_ms = MAX( p_obj->timeout_ms, timeout_ms );\r
254 }\r
255 \r
256 \r
257 \r
258 void\r
259 inc_al_obj_desc(\r
260         IN                              al_obj_t * const                        p_obj,\r
261         IN              const   uint32_t                                        desc_cnt )\r
262 {\r
263         CL_ASSERT( p_obj );\r
264 \r
265         /* Increment the number of descendants. */\r
266         p_obj->desc_cnt += desc_cnt;\r
267 }\r
268 \r
269 \r
270 \r
271 ib_api_status_t\r
272 attach_al_obj(\r
273         IN                              al_obj_t * const                        p_parent_obj,\r
274         IN                              al_obj_t * const                        p_child_obj )\r
275 {\r
276         AL_ENTER( AL_DBG_AL_OBJ );\r
277         \r
278         CL_ASSERT( p_child_obj->state == CL_INITIALIZED );\r
279 \r
280         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_AL_OBJ,\r
281                 ("%p(%s) to %p(%s)\n",\r
282                 p_child_obj, ib_get_obj_type( p_child_obj ),\r
283                 p_parent_obj, ib_get_obj_type( p_parent_obj ) ) );\r
284 \r
285         /* Insert the object into the parent's object tracking list. */\r
286         p_child_obj->p_ci_ca = p_parent_obj->p_ci_ca;\r
287         cl_spinlock_acquire( &p_parent_obj->lock );\r
288         if( p_parent_obj->state != CL_INITIALIZED )\r
289         {\r
290                 cl_spinlock_release( &p_parent_obj->lock );\r
291                 return IB_INVALID_STATE;\r
292         }\r
293         cl_qlist_insert_tail( &p_parent_obj->obj_list,\r
294                 (cl_list_item_t*)&p_child_obj->pool_item );\r
295         p_child_obj->p_parent_obj = p_parent_obj;\r
296         cl_spinlock_release( &p_parent_obj->lock );\r
297 \r
298         if( p_parent_obj->h_al )\r
299         {\r
300                 if( !p_child_obj->h_al )\r
301                 {\r
302                         p_child_obj->h_al = p_parent_obj->h_al;\r
303 #ifdef CL_KERNEL\r
304                         p_child_obj->hdl = al_hdl_insert_obj( p_child_obj );\r
305                         if( p_child_obj->hdl == AL_INVALID_HANDLE )\r
306                         {\r
307                                 cl_spinlock_acquire( &p_parent_obj->lock );\r
308                                 cl_qlist_remove_item( &p_parent_obj->obj_list,\r
309                                         (cl_list_item_t*)&p_child_obj->pool_item );\r
310                                 p_child_obj->p_parent_obj = NULL;\r
311                                 cl_spinlock_release( &p_parent_obj->lock );\r
312                                 return IB_INSUFFICIENT_MEMORY;\r
313                         }\r
314 #endif\r
315                 }\r
316                 else\r
317                 {\r
318                         CL_ASSERT( p_child_obj->h_al == p_parent_obj->h_al );\r
319                 }\r
320         }\r
321 \r
322         /* Reference the parent. */\r
323         ref_al_obj( p_parent_obj );\r
324         AL_EXIT( AL_DBG_AL_OBJ );\r
325         return IB_SUCCESS;\r
326 }\r
327 \r
328 \r
329 \r
330 /*\r
331  * Called to release a child object from its parent.\r
332  */\r
333 void\r
334 detach_al_obj(\r
335         IN                              al_obj_t * const                        p_obj )\r
336 {\r
337         al_obj_t                                *p_parent_obj;\r
338 \r
339         AL_ENTER( AL_DBG_AL_OBJ );\r
340         \r
341         p_parent_obj = p_obj->p_parent_obj;\r
342         CL_ASSERT( p_obj );\r
343         CL_ASSERT( p_obj->state == CL_INITIALIZED ||\r
344                 p_obj->state == CL_DESTROYING );\r
345         CL_ASSERT( p_parent_obj );\r
346         CL_ASSERT( p_parent_obj->state == CL_INITIALIZED ||\r
347                 p_parent_obj->state == CL_DESTROYING );\r
348 \r
349         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_AL_OBJ,\r
350                 ("%p(%s) from %p(%s)\n",\r
351                 p_obj, ib_get_obj_type( p_obj ),\r
352                 p_parent_obj, ib_get_obj_type( p_parent_obj ) ) );\r
353 \r
354         /* Remove the object from the parent's list. */\r
355         cl_spinlock_acquire( &p_parent_obj->lock );\r
356         cl_qlist_remove_item( &p_parent_obj->obj_list,\r
357                 (cl_list_item_t*)&p_obj->pool_item );\r
358         cl_spinlock_release( &p_parent_obj->lock );\r
359         AL_EXIT( AL_DBG_AL_OBJ );\r
360 }\r
361 \r
362 \r
363 \r
364 /*\r
365  * Increment a reference count on an object.  This object should not be\r
366  * an object's parent.\r
367  */\r
368 int32_t\r
369 ref_al_obj(\r
370         IN                              al_obj_t * const                        p_obj )\r
371 {\r
372         uint32_t        ref_cnt;\r
373 \r
374         AL_ENTER( AL_DBG_AL_OBJ );\r
375         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_AL_OBJ,\r
376                 ("%p(%s)\n", p_obj, ib_get_obj_type( p_obj ) ) );\r
377         ref_cnt = cl_atomic_inc( &p_obj->ref_cnt );\r
378         CL_ASSERT( ref_cnt != 1 || p_obj->type == AL_OBJ_TYPE_H_CQ );\r
379 \r
380         AL_EXIT( AL_DBG_AL_OBJ );\r
381         return ref_cnt;\r
382 }\r
383 \r
384 \r
385 \r
386 /*\r
387  * Decrement the reference count on an AL object.  Destroy the object if\r
388  * it is no longer referenced.  This object should not be an object's parent.\r
389  */\r
390 int32_t\r
391 deref_al_obj(\r
392         IN                              al_obj_t * const                        p_obj )\r
393 {\r
394         int32_t                 ref_cnt;\r
395 \r
396         AL_ENTER( AL_DBG_AL_OBJ );\r
397 \r
398         CL_ASSERT( p_obj );\r
399         CL_ASSERT( p_obj->state == CL_INITIALIZED ||\r
400                 p_obj->state == CL_DESTROYING );\r
401         CL_ASSERT( p_obj->ref_cnt );\r
402 \r
403         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_AL_OBJ,\r
404                 ("%p(%s)\n", p_obj, ib_get_obj_type( p_obj ) ) );\r
405 \r
406         ref_cnt = cl_atomic_dec( &p_obj->ref_cnt );\r
407 \r
408         /* If the reference count went to 0, the object should be destroyed. */\r
409         if( ref_cnt == 0 )\r
410         {\r
411                 if( p_obj->pfn_destroy == async_destroy_obj &&\r
412                         p_obj->user_destroy_cb != __sync_destroy_cb )\r
413                 {\r
414                         /* Queue the object for asynchronous destruction. */\r
415 #if AL_OBJ_PRIVATE_ASYNC_PROC\r
416                         cl_async_proc_queue( gp_async_obj_mgr, &p_obj->async_item );\r
417 #else\r
418                         cl_async_proc_queue( gp_async_proc_mgr, &p_obj->async_item );\r
419 #endif\r
420                 }\r
421                 else\r
422                 {\r
423                         /* Signal an event for synchronous destruction. */\r
424                         cl_event_signal( &p_obj->event );\r
425                 }\r
426         }\r
427 \r
428         AL_EXIT( AL_DBG_AL_OBJ );\r
429         return ref_cnt;\r
430 }\r
431 \r
432 \r
433 \r
434 /*\r
435  * Called to cleanup all resources allocated by an object.\r
436  */\r
437 void\r
438 destroy_al_obj(\r
439         IN                              al_obj_t * const                        p_obj )\r
440 {\r
441         AL_ENTER( AL_DBG_AL_OBJ );\r
442 \r
443         CL_ASSERT( p_obj );\r
444         CL_ASSERT( p_obj->state == CL_DESTROYING ||\r
445                 p_obj->state == CL_UNINITIALIZED );\r
446         CL_ASSERT( cl_is_qlist_empty( &p_obj->obj_list ) );\r
447 \r
448         /* Remove the object from the global tracking list. */\r
449         if( p_obj != &gp_al_mgr->obj )\r
450         {\r
451                 cl_spinlock_acquire( &gp_al_mgr->lock );\r
452                 cl_qlist_remove_item( &gp_al_mgr->al_obj_list, &p_obj->list_item );\r
453                 cl_spinlock_release( &gp_al_mgr->lock );\r
454                 deref_al_obj( &gp_al_mgr->obj );\r
455         }\r
456 \r
457         cl_event_destroy( &p_obj->event );\r
458         cl_spinlock_destroy( &p_obj->lock );\r
459         p_obj->state = CL_DESTROYED;\r
460 \r
461         AL_EXIT( AL_DBG_AL_OBJ );\r
462 }\r
463 \r
464 \r
465 \r
466 void\r
467 async_destroy_obj(\r
468         IN                              struct _al_obj                          *p_obj,\r
469         IN              const   ib_pfn_destroy_cb_t                     pfn_destroy_cb )\r
470 {\r
471         AL_ENTER( AL_DBG_AL_OBJ );\r
472 \r
473         if( pfn_destroy_cb == ib_sync_destroy )\r
474                 sync_destroy_obj( p_obj, pfn_destroy_cb );\r
475         else if( destroy_obj( p_obj, pfn_destroy_cb ) )\r
476                 deref_al_obj( p_obj );  /* Only destroy the object once. */\r
477 \r
478         AL_EXIT( AL_DBG_AL_OBJ );\r
479 }\r
480 \r
481 \r
482 \r
483 void\r
484 sync_destroy_obj(\r
485         IN                              struct _al_obj                          *p_obj,\r
486         IN              const   ib_pfn_destroy_cb_t                     pfn_destroy_cb )\r
487 {\r
488         cl_status_t             cl_status;\r
489 \r
490         AL_ENTER( AL_DBG_AL_OBJ );\r
491 \r
492         if( !destroy_obj( p_obj, pfn_destroy_cb ) )\r
493         {\r
494                 /* Object is already being destroyed... */\r
495                 AL_EXIT( AL_DBG_AL_OBJ );\r
496                 return;\r
497         }\r
498 \r
499         if( deref_al_obj( p_obj ) )\r
500         {\r
501         #ifdef _DEBUG_\r
502                 uint32_t                wait_us;\r
503                 /*\r
504                  * Wait for all other references to go away.  We wait as long as the\r
505                  * longest child will take, plus an additional amount based on the\r
506                  * number of descendants.\r
507                  */\r
508                 wait_us = (p_obj->timeout_ms * 1000) +\r
509                         (AL_TIMEOUT_PER_DESC_US * p_obj->desc_cnt);\r
510                 wait_us = MIN( wait_us, AL_MAX_TIMEOUT_US );\r
511                 do\r
512                 {\r
513                         cl_status = cl_event_wait_on(\r
514                                 &p_obj->event, wait_us, AL_WAIT_ALERTABLE );\r
515                 } while( cl_status == CL_NOT_DONE );\r
516 \r
517                 if( cl_status != CL_SUCCESS )\r
518                 {\r
519                         AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
520                                 ("Error waiting for references to be released - delaying.\n") );\r
521                         print_al_obj( p_obj );\r
522                         /*\r
523                          * Wait some more to handle really long timeouts by referencing\r
524                          * objects that are not descendants.\r
525                          */\r
526                         do\r
527                         {\r
528                                 cl_status = cl_event_wait_on(\r
529                                         &p_obj->event, AL_MAX_TIMEOUT_US, AL_WAIT_ALERTABLE );\r
530                         } while( cl_status == CL_NOT_DONE );\r
531                 }\r
532         #else\r
533                 do\r
534                 {\r
535                         cl_status = cl_event_wait_on(\r
536                                 &p_obj->event, EVENT_NO_TIMEOUT, AL_WAIT_ALERTABLE );\r
537                 } while( cl_status == CL_NOT_DONE );\r
538         #endif\r
539                 CL_ASSERT( cl_status == CL_SUCCESS );\r
540                 if( cl_status != CL_SUCCESS )\r
541                 {\r
542                         AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
543                                 ("Forcing object destruction.\n") );\r
544                         print_al_obj( p_obj );\r
545                         //print_tail_al_objs();\r
546                         print_al_objs( p_obj->h_al );\r
547                         p_obj->ref_cnt = 0;\r
548                 }\r
549         }\r
550         async_destroy_cb( &p_obj->async_item );\r
551 \r
552         AL_EXIT( AL_DBG_AL_OBJ );\r
553 }\r
554 \r
555 \r
556 \r
557 boolean_t\r
558 destroy_obj(\r
559         IN                              struct _al_obj                          *p_obj,\r
560         IN              const   ib_pfn_destroy_cb_t                     pfn_destroy_cb )\r
561 {\r
562         cl_list_item_t                  *p_list_item;\r
563         al_obj_t                                *p_child_obj;\r
564 \r
565         AL_ENTER( AL_DBG_AL_OBJ );\r
566 \r
567         CL_ASSERT( p_obj );\r
568         CL_ASSERT( p_obj->state == CL_INITIALIZED ||\r
569                 p_obj->state == CL_DESTROYING );\r
570 \r
571         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_AL_OBJ,\r
572                 ("%p(%s)\n", p_obj, ib_get_obj_type( p_obj ) ) );\r
573 \r
574         /*\r
575          * Lock to synchronize with asynchronous event processing.\r
576          * See ci_ca_async_event_cb for more information.\r
577          */\r
578         cl_spinlock_acquire( &p_obj->lock );\r
579         if( p_obj->state == CL_DESTROYING )\r
580         {\r
581                 cl_spinlock_release( &p_obj->lock );\r
582                 deref_al_obj( p_obj );\r
583                 AL_EXIT( AL_DBG_AL_OBJ );\r
584                 return FALSE;\r
585         }\r
586         p_obj->state = CL_DESTROYING;\r
587         cl_spinlock_release( &p_obj->lock );\r
588         deref_al_obj( p_obj );\r
589 \r
590 #ifdef CL_KERNEL\r
591         /*\r
592          * Release this object's handle.  We must do this before calling the\r
593          * destroy callback so that any IOCTLs referencing this object will fail\r
594          */\r
595         if( p_obj->hdl != AL_INVALID_HANDLE )\r
596         {\r
597                 CL_ASSERT( p_obj->h_al );\r
598                 al_hdl_free_obj( p_obj );\r
599         }\r
600 #endif\r
601 \r
602         /* Notify the object that it is being destroyed. */\r
603         if( p_obj->pfn_destroying )\r
604                 p_obj->pfn_destroying( p_obj );\r
605 \r
606         if( p_obj->p_parent_obj )\r
607                 detach_al_obj( p_obj );\r
608 \r
609         /*      Destroy all child resources.  No need to lock during destruction. */\r
610         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_AL_OBJ, ("destroying children\n") );\r
611         p_list_item = cl_qlist_tail( &p_obj->obj_list );\r
612         while( p_list_item != cl_qlist_end( &p_obj->obj_list ) )\r
613         {\r
614                 p_child_obj = PARENT_STRUCT( p_list_item, al_obj_t, pool_item );\r
615                 CL_ASSERT( p_child_obj->pfn_destroy );\r
616                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_AL_OBJ,\r
617                         ("bye bye: %p(%s)\n", p_child_obj,\r
618                         ib_get_obj_type( p_child_obj ) ) );\r
619                 ref_al_obj( p_child_obj );\r
620                 p_child_obj->pfn_destroy( p_child_obj, NULL );\r
621 \r
622                 p_list_item = cl_qlist_tail( &p_obj->obj_list );\r
623         }\r
624 \r
625         /*\r
626          * Update our parent's timeout value.  Ours could have been increased\r
627          * when destroying one of our children's.\r
628          */\r
629         if( p_obj->p_parent_obj )\r
630         {\r
631                 set_al_obj_timeout( p_obj->p_parent_obj, p_obj->timeout_ms );\r
632                 inc_al_obj_desc( p_obj->p_parent_obj, p_obj->desc_cnt + 1 );\r
633         }\r
634 \r
635         if( pfn_destroy_cb == ib_sync_destroy )\r
636                 p_obj->user_destroy_cb = __sync_destroy_cb;\r
637         else\r
638                 p_obj->user_destroy_cb = pfn_destroy_cb;\r
639 \r
640         AL_EXIT( AL_DBG_AL_OBJ );\r
641         return TRUE;\r
642 }\r
643 \r
644 \r
645 \r
646 void\r
647 async_destroy_cb(\r
648         IN                              cl_async_proc_item_t            *p_item )\r
649 {\r
650         al_obj_t                                *p_obj;\r
651         al_obj_t                                *p_parent_obj = NULL;\r
652 \r
653         AL_ENTER( AL_DBG_AL_OBJ );\r
654 \r
655         CL_ASSERT( p_item );\r
656         p_obj = PARENT_STRUCT( p_item, al_obj_t, async_item );\r
657         CL_ASSERT( p_obj );\r
658         CL_ASSERT( p_obj->state == CL_DESTROYING );\r
659         CL_ASSERT( !p_obj->ref_cnt );\r
660 \r
661         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_AL_OBJ,\r
662                 ("%p\n", p_obj ) );\r
663 \r
664         /* Cleanup any hardware related resources. */\r
665         if( p_obj->pfn_cleanup )\r
666         {\r
667                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_AL_OBJ, ("cleaning up\n" ) );\r
668                 p_obj->pfn_cleanup( p_obj );\r
669         }\r
670 \r
671         /* We can now safely dereference the parent. */\r
672         if( p_obj->p_parent_obj )\r
673         {\r
674                 p_parent_obj = p_obj->p_parent_obj;\r
675                 p_obj->p_parent_obj = NULL;\r
676         }\r
677 \r
678         /* Notify the user that we're done. */\r
679         if( p_obj->user_destroy_cb )\r
680         {\r
681                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_AL_OBJ, ("notifying user\n" ) );\r
682                 p_obj->user_destroy_cb( (void*)p_obj->context );\r
683         }\r
684 \r
685         /* Free the resources associated with the object. */\r
686         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_AL_OBJ, ("freeing object\n" ) );\r
687         p_obj->pfn_free( p_obj );\r
688 \r
689         /* Dereference the parent after freeing the child. */\r
690         if( p_parent_obj )\r
691                 deref_al_obj( p_parent_obj );\r
692         AL_EXIT( AL_DBG_AL_OBJ );\r
693 }\r