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