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