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