winverbs: process connect and accept asynchronously
[mirror/winof/.git] / core / complib / cl_memory.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 /*\r
36  * Abstract:\r
37  *      Implementation of memory allocation tracking functions.\r
38  *\r
39  * Environment:\r
40  *      All\r
41  */\r
42 \r
43 \r
44 #include "cl_memtrack.h"\r
45 \r
46 \r
47 cl_mem_tracker_t                *gp_mem_tracker = NULL;\r
48 \r
49 \r
50 /*\r
51  * Allocates memory.\r
52  */\r
53 void*\r
54 __cl_malloc_priv(\r
55         IN      const size_t    size,\r
56         IN      const boolean_t pageable );\r
57 \r
58 \r
59 /*\r
60  * Deallocates memory.\r
61  */\r
62 void\r
63 __cl_free_priv(\r
64         IN      void* const     p_memory );\r
65 \r
66 \r
67 /*\r
68  * Allocate and initialize the memory tracker object.\r
69  */\r
70 static inline void\r
71 __cl_mem_track_start( void )\r
72 {\r
73         cl_status_t                     status;\r
74 \r
75         if( gp_mem_tracker )\r
76                 return;\r
77 \r
78         /* Allocate the memory tracker object. */\r
79         gp_mem_tracker = (cl_mem_tracker_t*)\r
80                 __cl_malloc_priv( sizeof(cl_mem_tracker_t), FALSE );\r
81 \r
82         if( !gp_mem_tracker )\r
83                 return;\r
84 \r
85         /* Initialize the free list. */\r
86         cl_qlist_init( &gp_mem_tracker->free_hdr_list );\r
87         /* Initialize the allocation list. */\r
88         cl_qmap_init( &gp_mem_tracker->alloc_map );\r
89 \r
90         /* Initialize the spin lock to protect list operations. */\r
91         status = cl_spinlock_init( &gp_mem_tracker->lock );\r
92         if( status != CL_SUCCESS )\r
93         {\r
94                 __cl_free_priv( gp_mem_tracker );\r
95                 return;\r
96         }\r
97 }\r
98 \r
99 \r
100 /*\r
101  * Clean up memory tracking.\r
102  */\r
103 static inline void\r
104 __cl_mem_track_stop( void )\r
105 {\r
106         cl_map_item_t   *p_map_item;\r
107         cl_list_item_t  *p_list_item;\r
108 \r
109         if( !gp_mem_tracker )\r
110                 return;\r
111 \r
112         if( cl_qmap_count( &gp_mem_tracker->alloc_map ) )\r
113         {\r
114                 /* There are still items in the list.  Print them out. */\r
115                 cl_mem_display();\r
116         }\r
117 \r
118         /* Free all allocated headers. */\r
119         cl_spinlock_acquire( &gp_mem_tracker->lock );\r
120         while( cl_qmap_count( &gp_mem_tracker->alloc_map ) )\r
121         {\r
122                 p_map_item = cl_qmap_head( &gp_mem_tracker->alloc_map );\r
123                 cl_qmap_remove_item( &gp_mem_tracker->alloc_map, p_map_item );\r
124                 __cl_free_priv(\r
125                         PARENT_STRUCT( p_map_item, cl_malloc_hdr_t, map_item ) );\r
126         }\r
127 \r
128         while( cl_qlist_count( &gp_mem_tracker->free_hdr_list ) )\r
129         {\r
130                 p_list_item = cl_qlist_remove_head( &gp_mem_tracker->free_hdr_list );\r
131                 __cl_free_priv( PARENT_STRUCT(\r
132                         p_list_item, cl_malloc_hdr_t, map_item.pool_item.list_item ) );\r
133         }\r
134         cl_spinlock_release( &gp_mem_tracker->lock );\r
135 \r
136         /* Destory all objects in the memory tracker object. */\r
137         cl_spinlock_destroy( &gp_mem_tracker->lock );\r
138 \r
139         /* Free the memory allocated for the memory tracker object. */\r
140         __cl_free_priv( gp_mem_tracker );\r
141         gp_mem_tracker = NULL;\r
142 }\r
143 \r
144 \r
145 /*\r
146  * Enables memory allocation tracking.\r
147  */\r
148 void\r
149 __cl_mem_track(\r
150         IN      const boolean_t start )\r
151 {\r
152         if( start )\r
153                 __cl_mem_track_start();\r
154         else\r
155                 __cl_mem_track_stop();\r
156 }\r
157 \r
158 \r
159 /*\r
160  * Display memory usage.\r
161  */\r
162 void\r
163 cl_mem_display( void )\r
164 {\r
165         cl_map_item_t           *p_map_item;\r
166         cl_malloc_hdr_t         *p_hdr;\r
167 \r
168         if( !gp_mem_tracker )\r
169                 return;\r
170 \r
171         cl_spinlock_acquire( &gp_mem_tracker->lock );\r
172         cl_msg_out( "\n\n\n*** Memory Usage ***\n" );\r
173         p_map_item = cl_qmap_head( &gp_mem_tracker->alloc_map );\r
174         while( p_map_item != cl_qmap_end( &gp_mem_tracker->alloc_map ) )\r
175         {\r
176                 /*\r
177                  * Get the pointer to the header.  Note that the object member of the\r
178                  * list item will be used to store the pointer to the user's memory.\r
179                  */\r
180                 p_hdr = PARENT_STRUCT( p_map_item, cl_malloc_hdr_t, map_item );\r
181 \r
182                 cl_msg_out( "\tMemory block at %p allocated in file %s line %d\n",\r
183                         p_hdr->p_mem, p_hdr->file_name, p_hdr->line_num );\r
184 \r
185                 p_map_item = cl_qmap_next( p_map_item );\r
186         }\r
187         cl_msg_out( "*** End of Memory Usage ***\n\n" );\r
188         cl_spinlock_release( &gp_mem_tracker->lock );\r
189 }\r
190 \r
191 \r
192 /*\r
193  * Allocates memory and stores information about the allocation in a list.\r
194  * The contents of the list can be printed out by calling the function\r
195  * "MemoryReportUsage".  Memory allocation will succeed even if the list\r
196  * cannot be created.\r
197  */\r
198 void*\r
199 __cl_malloc_trk(\r
200         IN      const char* const       p_file_name,\r
201         IN      const int32_t           line_num,\r
202         IN      const size_t            size,\r
203         IN      const boolean_t         pageable )\r
204 {\r
205         cl_malloc_hdr_t *p_hdr;\r
206         cl_list_item_t  *p_list_item;\r
207         void                    *p_mem;\r
208         uint64_t                temp_buf[FILE_NAME_LENGTH/sizeof(uint64_t)];\r
209         int32_t                 temp_line;\r
210 \r
211         /*\r
212          * Allocate the memory first, so that we give the user's allocation\r
213          * priority over the the header allocation.\r
214          */\r
215         p_mem = __cl_malloc_priv( size, pageable );\r
216 \r
217         if( !p_mem )\r
218                 return( NULL );\r
219 \r
220         if( !gp_mem_tracker )\r
221                 return( p_mem );\r
222 \r
223         /*\r
224          * Make copies of the file name and line number in case those\r
225          * parameters are in paged pool.\r
226          */\r
227         temp_line = line_num;\r
228         strncpy( (char*)temp_buf, p_file_name, FILE_NAME_LENGTH );\r
229         /* Make sure the string is null terminated. */\r
230         ((char*)temp_buf)[FILE_NAME_LENGTH - 1] = '\0';\r
231 \r
232         cl_spinlock_acquire( &gp_mem_tracker->lock );\r
233 \r
234         /* Get a header from the free header list. */\r
235         p_list_item = cl_qlist_remove_head( &gp_mem_tracker->free_hdr_list );\r
236         if( p_list_item != cl_qlist_end( &gp_mem_tracker->free_hdr_list ) )\r
237         {\r
238                 /* Set the header pointer to the header retrieved from the list. */\r
239                 p_hdr = PARENT_STRUCT( p_list_item, cl_malloc_hdr_t,\r
240                         map_item.pool_item.list_item );\r
241         }\r
242         else\r
243         {\r
244                 /* We failed to get a free header.  Allocate one. */\r
245                 p_hdr = __cl_malloc_priv( sizeof(cl_malloc_hdr_t), FALSE );\r
246                 if( !p_hdr )\r
247                 {\r
248                         /* We failed to allocate the header.  Return the user's memory. */\r
249                         cl_spinlock_release( &gp_mem_tracker->lock );\r
250                         return( p_mem );\r
251                 }\r
252         }\r
253         cl_memcpy( p_hdr->file_name, temp_buf, FILE_NAME_LENGTH );\r
254         p_hdr->line_num = temp_line;\r
255         /*\r
256          * We store the pointer to the memory returned to the user.  This allows\r
257          * searching the list of allocated memory even if the buffer allocated is\r
258          * not in the list without dereferencing memory we do not own.\r
259          */\r
260         p_hdr->p_mem = p_mem;\r
261 \r
262         /* Insert the header structure into our allocation list. */\r
263         cl_qmap_insert( &gp_mem_tracker->alloc_map, (uintn_t)p_mem, &p_hdr->map_item );\r
264         cl_spinlock_release( &gp_mem_tracker->lock );\r
265 \r
266         return( p_mem );\r
267 }\r
268 \r
269 \r
270 /*\r
271  * Allocate non-tracked memory.\r
272  */\r
273 void*\r
274 __cl_malloc_ntrk(\r
275         IN      const size_t    size,\r
276         IN      const boolean_t pageable )\r
277 {\r
278         return( __cl_malloc_priv( size, pageable ) );\r
279 }\r
280 \r
281 \r
282 void*\r
283 __cl_zalloc_trk(\r
284         IN      const char* const       p_file_name,\r
285         IN      const int32_t           line_num,\r
286         IN      const size_t            size,\r
287         IN      const boolean_t         pageable )\r
288 {\r
289         void    *p_buffer;\r
290 \r
291         p_buffer = __cl_malloc_trk( p_file_name, line_num, size, pageable );\r
292         if( p_buffer )\r
293                 cl_memclr( p_buffer, size );\r
294 \r
295         return( p_buffer );\r
296 }\r
297 \r
298 \r
299 void*\r
300 __cl_zalloc_ntrk(\r
301         IN      const size_t    size,\r
302         IN      const boolean_t pageable )\r
303 {\r
304         void    *p_buffer;\r
305 \r
306         p_buffer = __cl_malloc_priv( size, pageable );\r
307         if( p_buffer )\r
308                 cl_memclr( p_buffer, size );\r
309 \r
310         return( p_buffer );\r
311 }\r
312 \r
313 \r
314 void\r
315 __cl_free_trk(\r
316         IN      void* const     p_memory )\r
317 {\r
318         cl_malloc_hdr_t         *p_hdr;\r
319         cl_map_item_t           *p_map_item;\r
320 \r
321         if( gp_mem_tracker )\r
322         {\r
323                 cl_spinlock_acquire( &gp_mem_tracker->lock );\r
324 \r
325                 /*\r
326                  * Removes an item from the allocation tracking list given a pointer\r
327                  * To the user's data and returns the pointer to header referencing the\r
328                  * allocated memory block.\r
329                  */\r
330                 p_map_item = cl_qmap_get( &gp_mem_tracker->alloc_map, (uintn_t)p_memory );\r
331                 if( p_map_item != cl_qmap_end( &gp_mem_tracker->alloc_map ) )\r
332                 {\r
333                         /* Get the pointer to the header. */\r
334                         p_hdr = PARENT_STRUCT( p_map_item, cl_malloc_hdr_t, map_item );\r
335                         /* Remove the item from the list. */\r
336                         cl_qmap_remove_item( &gp_mem_tracker->alloc_map, p_map_item );\r
337 \r
338                         /* Return the header to the free header list. */\r
339                         cl_qlist_insert_head( &gp_mem_tracker->free_hdr_list,\r
340                                 &p_hdr->map_item.pool_item.list_item );\r
341                 }\r
342                 cl_spinlock_release( &gp_mem_tracker->lock );\r
343         }\r
344         __cl_free_priv( p_memory );\r
345 }\r
346 \r
347 \r
348 void\r
349 __cl_free_ntrk(\r
350         IN      void* const     p_memory )\r
351 {\r
352         __cl_free_priv( p_memory );\r
353 }\r