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