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