1 mday 1.1 //%//////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2000 - 2002 The Open group, BMC Software, Tivoli Systems, IBM
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to
7 // deal in the Software without restriction, including without limitation the
8 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 // sell copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
13 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
14 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
15 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
16 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
18 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
19 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 //
21 //==============================================================================
22 mday 1.1 //
23 // Author: Mike Day (mdday@us.ibm.com)
24 //
25 // Modified By:
26 //
27 //%/////////////////////////////////////////////////////////////////////////////
28
29 #include <Pegasus/Common/suballoc.h>
30 #include <Pegasus/Common/Tracer.h>
31 #include <new.h>
32 PEGASUS_NAMESPACE_BEGIN
33
34 peg_suballocator *peg_suballocator::_suballoc_instance = 0;
35
36 PEGASUS_SUBALLOC_LINKAGE peg_suballocator *peg_suballocator::get_instance(void)
37 {
38 if(peg_suballocator::_suballoc_instance == 0)
39 {
40 peg_suballocator::_suballoc_instance = new((void *)malloc(sizeof(peg_suballocator))) peg_suballocator(true);
41 }
42 return peg_suballocator::_suballoc_instance;
43 mday 1.1 }
44
45 #if defined(PEGASUS_DEBUG_MEMORY)
46 PEGASUS_SUBALLOC_LINKAGE void * pegasus_alloc(size_t size,
47 void * handle,
48 int type,
49 const Sint8 *classname,
50 Sint8 *file,
51 Uint32 line)
52 {
53 return peg_suballocator::get_instance()->vs_malloc(size,
54 ((handle == NULL) ? &(peg_suballocator::get_instance()->get_handle()) : handle),
55 type,
56 classname,
57 file,
58 line) ;
59 }
60
61 PEGASUS_SUBALLOC_LINKAGE void pegasus_free(void * dead,
62 void * handle,
63 int type,
64 mday 1.1 Sint8 *classname,
65 Sint8 * file,
66 Uint32 line)
67 {
68 if ( dead == 0 )
69 return;
70
71 peg_suballocator::get_instance()->vs_free(dead,
72 ((handle == NULL) ? &(peg_suballocator::get_instance()->get_handle()) : handle),
73 type,
74 classname,
75 file,
76 line);
77 }
78
79 #else
80
81 PEGASUS_SUBALLOC_LINKAGE void * pegasus_alloc(size_t size)
82 {
83 return peg_suballocator::get_instance()->vs_malloc(size);
84 }
85 mday 1.1
86 PEGASUS_SUBALLOC_LINKAGE void pegasus_free(void *dead)
87 {
88 peg_suballocator::get_instance()->vs_free(dead);
89 }
90
91 #endif
92
93 PEGASUS_NAMESPACE_END
94
95 PEGASUS_USING_PEGASUS;
96
97 void * operator new(size_t size) throw(PEGASUS_STD(bad_alloc))
98 {
99 if( size == 0 )
100 size = 1;
101 void *p;
102
103 while(1)
104 {
105 #if defined(PEGASUS_DEBUG_MEMORY)
106 mday 1.1 p = peg_suballocator::get_instance()->vs_malloc(size,
107 &(peg_suballocator::get_instance()->get_handle()),
108 NORMAL,
109 "BUILTIN NEW",
110 __FILE__, __LINE__) ;
111
112
113 #else
114 p = peg_suballocator::get_instance()->vs_malloc(size);
115 #endif
116 if( p )
117 return p;
118 new_handler global = set_new_handler(0);
119 set_new_handler(global);
120 if( global)
121 (*global)();
122 else
123 throw PEGASUS_STD(bad_alloc());
124 }
125 }
126
127 mday 1.1
128 void operator delete(void *dead) throw()
129 {
130 if( dead == 0 )
131 return;
132 #if defined(PEGASUS_DEBUG_MEMORY)
133 peg_suballocator::get_instance()->vs_free(dead,
134 &(peg_suballocator::get_instance()->get_handle()),
135 NORMAL,
136 "internal",
137 __FILE__,
138 __LINE__);
139 free(dead);
140
141
142 #else
143 peg_suballocator::get_instance()->vs_free(dead);
144 #endif
145 return;
146 }
147
148 mday 1.1 void * operator new [] (size_t size) throw(PEGASUS_STD(bad_alloc))
149 {
150 if( size == 0 )
151 size = 1;
152 void *p;
153
154 while(1)
155 {
156 #if defined(PEGASUS_DEBUG_MEMORY)
157 p = peg_suballocator::get_instance()->vs_malloc(size,
158 &(peg_suballocator::get_instance()->get_handle()),
159 ARRAY,
160 "BUILTIN ARRAY NEW",
161 __FILE__, __LINE__) ;
162
163 #else
164 p = peg_suballocator::get_instance()->vs_malloc(size);
165 #endif
166 if( p )
167 return p;
168 new_handler global = set_new_handler(0);
169 mday 1.1 set_new_handler(global);
170 if( global)
171 (*global)();
172 else
173 throw PEGASUS_STD(bad_alloc());
174 }
175 }
176
177 void operator delete [] (void *dead) throw()
178 {
179 if( dead == 0 )
180 return;
181 #if defined(PEGASUS_DEBUG_MEMORY)
182 peg_suballocator::get_instance()->vs_free(dead,
183 &(peg_suballocator::get_instance()->get_handle()),
184 ARRAY,
185 "internal",
186 __FILE__,
187 __LINE__);
188
189 #else
190 mday 1.1 peg_suballocator::get_instance()->vs_free(dead);
191 #endif
192 return;
193 }
194
195
196 PEGASUS_NAMESPACE_BEGIN
197
198 #if defined(PEGASUS_DEBUG_MEMORY)
199 const Uint8 peg_suballocator::guard[] = {0x01, 0x02, 0x03, 0x04, 0x05,
200 0x06, 0x07, 0x08, 0x09, 0x09,
201 0x08, 0x07, 0x06, 0x05, 0x04,
202 0x03};
203 const Uint8 peg_suballocator::alloc_pattern = 0xaa;
204 const Uint8 peg_suballocator::delete_pattern = 0xee;
205 #endif
206
207 const Sint32 peg_suballocator::nodeSizes[3][16] =
208 {
209 {
210 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80,
211 mday 1.1 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff
212 },
213 {
214 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700,
215 0x800, 0x900, 0xa00, 0xb00, 0xc00, 0xd00, 0xe00,
216 0xf00, 0xfff
217 },
218 {
219 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000,
220 0x7000, 0x8000, 0x9000, 0xa000, 0xb000, 0xc000,
221 0xd000, 0xe000, 0xf000,
222 2 * sizeof(void *)
223 }
224 };
225
226
227 // prototypes that begin with an underscore do not attempt to
228 // gain ownership of semaphores and can be safely called
229 // by a process that owns a semaphore
230
231
232 mday 1.1 const Uint32 peg_suballocator::preAlloc[3][16] =
233 {
234 {20, 20, 20, 20, 20, 20, 20, 10, 10, 10, 10, 10, 10, 10, 10, 10 },
235 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
236 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
237 };
238
239 const Uint32 peg_suballocator::step[3][16] =
240 {
241 {20, 20, 20, 20, 20, 20, 20, 10, 10, 10, 10, 10, 10, 10, 10, 10 },
242 {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 },
243 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
244 };
245
246 peg_suballocator::peg_suballocator(void)
247 : debug_mode(true),
248 abort_on_error(true),
249 check_for_leaks(false),
250 internal_handle("internal_suballoc_log")
251
252 {
253 mday 1.1 sprintf(internal_handle.classname, "internal");
254 InitializeSubAllocator();
255 return;
256 }
257
258 peg_suballocator::peg_suballocator(Boolean mode)
259 : debug_mode(mode),
260 abort_on_error(true),
261 check_for_leaks(false),
262 internal_handle("internal_suballoc_log")
263
264 {
265 sprintf(internal_handle.classname, "internal");
266 InitializeSubAllocator();
267 return;
268 }
269
270 peg_suballocator::~peg_suballocator(void)
271 {
272 DeInitSubAllocator(&internal_handle);
273 }
274 mday 1.1
275 peg_suballocator::SUBALLOC_HANDLE *peg_suballocator::InitializeProcessHeap(Sint8 *f)
276 {
277 return new SUBALLOC_HANDLE(f);
278 }
279
280 /****************************************************************
281 * InitializeSubAllocator
282 *
283 *
284 * PARAMETERS: none
285 *
286 * DESCRIPTION: If suballocator is already initialized, returns
287 * true immediately. Otherwise, allocates node list
288 * heads and performs pre-allocations.
289 *
290 * RETURNS: true if successful, false otherwise
291 *
292 ***************************************************************/
293 Boolean peg_suballocator::InitializeSubAllocator(void)
294 {
295 mday 1.1 SUBALLOC_NODE *temp;
296 Sint32 i, o;
297 Boolean ccode = true;
298 Sint32 waitCode;
299
300 if(initialized)
301 return true;
302
303 if(CREATE_MUTEX(&globalSemHandle))
304 return(false);
305
306 WAIT_MUTEX(&globalSemHandle, 1000, &waitCode);
307
308 // check to see if we are already initialized
309 // gain ownership of global semaphore here
310
311 for (o = 0; o < 3; o++)
312 {
313 for (i = 0; i < 16; i++)
314 {
315 // allocate our list heads
316 mday 1.1 if (0 == ((Sint32)(CREATE_MUTEX(&(semHandles[o][i])))))
317 {
318 nodeListHeads[o][i] = (SUBALLOC_NODE *)calloc(1, sizeof (SUBALLOC_NODE));
319 if ( nodeListHeads[o][i] == NULL )
320 {
321 while (o >= 0)
322 {
323 while (i >= 0)
324 {
325 if (nodeListHeads[o][i] != NULL)
326 {
327 free(nodeListHeads[o][i]);
328 nodeListHeads[o][i] = NULL;
329 }
330 CLOSE_MUTEX(&(semHandles[o][i]));
331 i--;
332 }
333 o--;
334 }
335 RELEASE_MUTEX(&globalSemHandle);
336 RELEASE_MUTEX(&init_mutex);
337 mday 1.1
338 return(false);
339 }
340
341 temp = nodeListHeads[o][i];
342 temp->next = temp->prev = temp;
343 temp->flags |= (IS_HEAD_NODE );
344 #if defined(PEGASUS_DEBUG_MEMORY)
345 memcpy(temp->guardPre, guard, GUARD_SIZE);
346 #endif
347 if (preAlloc[o][i])
348 ccode = _Allocate(o, i, PRE_ALLOCATE);
349
350 if (ccode == false)
351 {
352 while (o >= 0)
353 {
354 while (i >= 0)
355 {
356 if (nodeListHeads[o][i] != NULL)
357 {
358 mday 1.1 free(nodeListHeads[o][i]);
359 nodeListHeads[o][i] = NULL;
360 }
361
362 CLOSE_MUTEX(&(semHandles[o][i]));
363
364 i--;
365 }
366 o--;
367 }
368 RELEASE_MUTEX(&globalSemHandle);
369 RELEASE_MUTEX(&init_mutex);
370 return(false);
371 }
372 }
373 }
374 }
375 initialized = 1;
376 // release global concurrency semaphore here
377 RELEASE_MUTEX(&globalSemHandle);
378 return(true);
379 mday 1.1 }
380
381
382 /****************************************************************
383 * _Allocate
384 *
385 *
386 * PARAMETERS: IN index is a selector for the correct
387 * node head.
388 * IN code is a control code that determines if we
389 * are doing a pre-allocation or a step-allocation.
390 *
391 * DESCRIPTION: Creates new memory nodes, initializes them,
392 * and links them to the appropriate list head.
393 * A pre-allocation creates nodes at init time, while
394 * a step-allocation creates nodes at run time when all
395 * existing nodes are unavailable.
396 *
397 * INTERNAL CALL ONLY - caller must own the semaphore
398 * for the list indicated by index; or, alternatively,
399 * caller must own the global semaphore.
400 mday 1.1 *
401 * RETURNS: true if successful, false otherwise
402 *
403 ***************************************************************/
404 Boolean peg_suballocator::_Allocate(Sint32 vector, Sint32 index, Sint32 code)
405 {
406
407
408 // no semaphores - this internal routine must only be
409 // called by threads owning the list head indicated by index
410 SUBALLOC_NODE *temp, *temp2;
411 Sint32 i;
412 Sint8 *g;
413
414 temp = nodeListHeads[vector][index];
415 if (code == PRE_ALLOCATE) // this is a preallocation
416 i = preAlloc[vector][index];
417 else
418 i = step[vector][index]; // this is a step allocation
419 #if defined(PEGASUS_DEBUG_MEMORY)
420 size_t chunk_size = (i * (sizeof(SUBALLOC_NODE) + GUARD_SIZE + nodeSizes[vector][index]));
421 mday 1.1 #else
422 size_t chunk_size = (i * (sizeof(SUBALLOC_NODE) + nodeSizes[vector][index]));
423 #endif
424
425 temp2 = (SUBALLOC_NODE *)malloc(chunk_size);
426 if(temp2 == NULL)
427 return false;
428 for ( ; i > 0; i--)
429 {
430 temp2->flags |= AVAIL;
431 temp2->concurrencyHandle = &internal_handle;
432
433 #if defined(PEGASUS_DEBUG_MEMORY)
434 memcpy(temp2->guardPre, guard, GUARD_SIZE);
435 #endif
436 g = (Sint8 *)temp2;
437 g+= sizeof(SUBALLOC_NODE);
438 g+= nodeSizes[vector][index];
439 #if defined(PEGASUS_DEBUG_MEMORY)
440 memcpy(g, guard, GUARD_SIZE);
441 g += GUARD_SIZE;
442 mday 1.1 #endif
443 INSERT(temp2, temp);
444 temp2 = (SUBALLOC_NODE *)g;
445 }
446 return(true);
447 }
448
449 /****************************************************************
450 * DeInitSubAllocator
451 *
452 *
453 * PARAMETERS:
454 *
455 * DESCRIPTION: Locks suballocator and destroys all of its data
456 * structures. Checks for unfreed nodes, which
457 * represent memory leaks.
458 *
459 * RETURNS:
460 *
461 ***************************************************************/
462 void peg_suballocator::DeInitSubAllocator(void *handle)
463 mday 1.1 {
464 Sint32 i, o, waitCode;
465 assert(handle != 0);
466 // _UnfreedNodes(handle);
467 if( handle != (void *) &internal_handle)
468 free((void *)handle);
469
470 init_count--;
471 if (! init_count)
472 {
473 initialized = 0;
474 WAIT_MUTEX(&globalSemHandle, 1000, &waitCode);
475 for (o = 0; o < 3; o++)
476 {
477 for (i = 0; i < 16; i++)
478 {
479 WAIT_MUTEX(&(semHandles[o][i]), 1000, &waitCode);
480 CLOSE_MUTEX(&(semHandles[o][i]));
481 _DeAllocate(o, i);
482 free(nodeListHeads[o][i]);
483 nodeListHeads[o][i] = NULL;
484 mday 1.1 }
485 }
486 CLOSE_MUTEX(&(globalSemHandle));
487 initialized = 0;
488 }
489
490 return;
491 }
492
493 /****************************************************************
494 * _DeAllocate
495 *
496 *
497 * PARAMETERS: IN index is a selector for the correct
498 * list to destroy
499 *
500 * DESCRIPTION: INTERNAL CALL ONLY - caller must own the semaphore
501 * for the list head, or, alternatively, the
502 * global semaphore.
503 * After calling this function, be certain to close
504 * the semaphore handle corresponding to index.
505 mday 1.1 *
506 * RETURNS:
507 *
508 ***************************************************************/
509 void peg_suballocator::_DeAllocate(Sint32 vector, Sint32 index)
510 {
511 // caller owns semHandles[vector][index]
512 SUBALLOC_NODE *temp, *temp2;
513 temp = nodeListHeads[vector][index];
514 while ( ! IS_EMPTY(temp) )
515 {
516 temp2 = temp->next;
517 _DELETE(temp2);
518 free(temp2);
519 }
520 return;
521 }
522
523 /****************************************************************
524 * GetNode
525 *
526 mday 1.1 *
527 * PARAMETERS: IN index is a selector for the listHead from which
528 * we want to get a node.
529 *
530 * DESCRIPTION: Allocates a node from the selected list. If the
531 * list is fully utilized, allocates some new nodes
532 * and returns one of those.
533 *
534 * RETURNS: pointer to an allocated node. the node remains linked
535 * its list but is marked as not being available.
536 *
537 ***************************************************************/
538 peg_suballocator::SUBALLOC_NODE *peg_suballocator::GetNode(Sint32 vector, Sint32 index)
539 {
540 SUBALLOC_NODE *temp;
541 Sint32 waitCode;
542 if(initialized == 0 )
543 {
544 InitializeSubAllocator();
545 }
546 WAIT_MUTEX(&(semHandles[vector][index]), 1000, &waitCode);
547 mday 1.1 temp = (nodeListHeads[vector][index])->next;
548 // if list is empty we will fall through
549
550 while (! IS_HEAD(temp) )
551 {
552 if ((temp->flags & AVAIL) && (false == IS_HEAD(temp)))
553 {
554 temp->flags &= ~(AVAIL) ;
555 // release semHandles[index]
556 RELEASE_MUTEX(&(semHandles[vector][index]));
557 return(temp);
558 }
559 temp = temp->next;
560 }
561 // the list is either empty or fully allocated
562 if (! _Allocate(vector, index, STEP_ALLOCATE))
563 {
564 // release semHandles[index];
565 RELEASE_MUTEX(&(semHandles[vector][index]));
566 return(NULL);
567 }
568 mday 1.1 // Allocate always links new nodes at the front of the list
569 // we can just grab the first node and go
570 temp = (nodeListHeads[vector][index])->next;
571 temp->flags &= ~(AVAIL);
572 if( check_for_leaks == true )
573 temp->flags |= CHECK_LEAK;
574
575 // release semHandles[vector][index];
576 RELEASE_MUTEX(&(semHandles[vector][index]));
577 return(temp);
578 }
579
580 /****************************************************************
581 * GetHugeNode
582 *
583 *
584 * PARAMETERS: IN size is the amount of memory requested by the
585 * caller.
586 *
587 * DESCRIPTION: Allocates a node from the "huge" list. This list is
588 * maintained specifically for memory allocations that
589 mday 1.1 * are greater than 32K bytes. If the list is fully
590 * utilized, will allocate some new nodes and return
591 * one of those.
592 *
593 * RETURNS: pointer to an allocated node. the node remains linked
594 * its list but is marked as not being available.
595 *
596 ***************************************************************/
597 peg_suballocator::SUBALLOC_NODE * peg_suballocator::GetHugeNode(Sint32 size)
598 {
599 SUBALLOC_NODE *temp;
600 Sint8 *g;
601
602
603 Sint32 waitCode;
604 if(initialized == 0 )
605 {
606 InitializeSubAllocator();
607 }
608
609
610 mday 1.1 WAIT_MUTEX(&(semHandles[2][15]), 1000, &waitCode);
611 temp = (nodeListHeads[2][15])->next;
612 while (! IS_HEAD(temp) )
613 {
614 if ((temp->flags & AVAIL) && (false == IS_HEAD(temp)))
615 {
616 if(temp->nodeSize >= (Uint32)size)
617 {
618 temp->flags &= ~(AVAIL) ;
619 temp->allocSize = size;
620 break;
621 }
622 }
623 temp = temp->next;
624 }
625
626 if( IS_HEAD(temp))
627 {
628 #if defined(PEGASUS_DEBUG_MEMORY)
629 size_t chunk_size = (sizeof(SUBALLOC_NODE) + GUARD_SIZE + size);
630 #else
631 mday 1.1 size_t chunk_size = (sizeof(SUBALLOC_NODE) + size);
632 #endif
633 temp = (SUBALLOC_NODE *)malloc(chunk_size);
634 if(temp == NULL)
635 {
636 RELEASE_MUTEX(&(semHandles[2][15]));
637 return temp;
638 }
639
640 temp->allocSize = temp->nodeSize = size;
641 INSERT(temp, nodeListHeads[2][15]);
642 }
643 temp->concurrencyHandle = &internal_handle;
644 #if defined(PEGASUS_DEBUG_MEMORY)
645 memcpy(temp->guardPre, guard, GUARD_SIZE);
646 #endif
647
648 RELEASE_MUTEX(&(semHandles[2][15]));
649 return(temp);
650 }
651
652 mday 1.1 /****************************************************************
653 * PutNode
654 *
655 *
656 * PARAMETERS: IN index is a selector for the correct listhead.
657 * IN node is the node that we need to "put" back
658 * on to the list.
659 *
660 * DESCRIPTION: "put" is a misnomer because the node never
661 * leaves its list. However, we do unlink the node
662 * and insert it at the front of the list before marking
663 * it as being available. We do this to speed up allocation
664 * of the node next time someone needs it. We want
665 * to keep all available nodes at the front of the list.
666 *
667 * RETURNS:
668 *
669 ***************************************************************/
670 void peg_suballocator::PutNode(Sint32 vector, Sint32 index, SUBALLOC_NODE *node)
671 {
672 Sint32 waitCode;
673 mday 1.1 WAIT_MUTEX(&(semHandles[vector][index]), 1000, &waitCode);
674
675 // mark the node as available, unlink it, and relink it
676 // to the front of the list
677 assert(node != NULL);
678 // gain ownership of semHandles[index];
679 // delete insert the node at the front of the list -
680 // this will make it faster to get the node
681 _DELETE(node);
682 node->concurrencyHandle = &internal_handle;
683 node->flags |= AVAIL;
684 INSERT(node, nodeListHeads[vector][index]);
685 RELEASE_MUTEX(&(semHandles[vector][index]));
686 return;
687 }
688
689 /****************************************************************
690 * PutHugeNode
691 *
692 *
693 * PARAMETERS: IN node is the node that we need to "put" back
694 mday 1.1 * on to the "huge" list.
695 *
696 * DESCRIPTION: "put" is a misnomer because the node never
697 * leaves its list. However, we do unlink the node
698 * and insert it at the front of the list before marking
699 * it as being available. We do this to speed up allocation
700 * of the node next time someone needs it. We want
701 * to keep all available nodes at the front of the list.
702 *
703 * RETURNS:
704 *
705 ***************************************************************/
706 void peg_suballocator::PutHugeNode(SUBALLOC_NODE *node)
707 {
708 // mark the node as available, unlink it, and relink it
709 // to the front of the list
710 PutNode(2, 15, node);
711 }
712
713
714 /****************************************************************
715 mday 1.1 * vs_malloc
716 *
717 *
718 * PARAMETERS: IN size is the amount of memory requested
719 *
720 * DESCRIPTION: initializes the suballocator if neccesary.
721 * gets an appropriately sized memory node and
722 * returns a pointer to the caller.
723 *
724 * RETURNS: pointer to memory available for use by the caller,
725 * or NULL.
726 *
727 ***************************************************************/
728
729 #if defined(PEGASUS_DEBUG_MEMORY)
730 void *peg_suballocator::vs_malloc(size_t size, void *handle, int type, const Sint8 *classname, const Sint8 *f, Uint32 l)
731 {
732 // we don't need to grab any semaphores,
733 // called routines will do that for us
734 SUBALLOC_NODE *temp;
735 Sint8 *g;
736 mday 1.1
737 assert(size != 0);
738
739 if (! (size >> 8))
740 {
741 temp = GetNode(0, (size >> 4));
742 }
743 else if (! (size >> 12))
744 {
745 temp = GetNode(1, (size >> 8));
746 }
747 else if (! (size >> 16))
748 {
749 temp = GetNode(2, (size >> 12));
750 }
751 else
752 {
753 temp = GetHugeNode(size);
754 }
755
756 temp->allocSize = size;
757 mday 1.1 temp->concurrencyHandle = (void *)handle;
758 if(type == ARRAY)
759 temp->flags |= ARRAY_NODE;
760 if(classname)
761 strncpy(temp->classname, classname, MAX_CLASS_LEN);
762 else
763 temp->classname[0] = 0x00;
764
765 if(f)
766 strncpy(temp->file, f, MAX_PATH_LEN);
767 else
768 temp->file[0] = 0x00;
769
770 if(l)
771 sprintf(temp->line, "%d", l);
772 else
773 temp->line[0] = 0x00;
774 g = (Sint8 *)temp;
775 g += sizeof(SUBALLOC_NODE);
776 memcpy(g + size, guard, GUARD_SIZE);
777 return((void *)g);
778 mday 1.1 }
779 #else
780 void *peg_suballocator::vs_malloc(size_t size)
781 {
782 SUBALLOC_NODE *temp;
783 Sint8 *g;
784 assert(size != 0);
785
786 if (! (size >> 8))
787 {
788 temp = GetNode(0, (size >> 4));
789 }
790 else if (! (size >> 12))
791 {
792 temp = GetNode(1, (size >> 8));
793 }
794 else if (! (size >> 16))
795 {
796 temp = GetNode(2, (size >> 12));
797 }
798 else
799 mday 1.1 temp = GetHugeNode(size);
800 temp->allocSize = size;
801 temp->concurrencyHandle = (void *)&internal_handle;
802 g = (Sint8 *)temp;
803 g += sizeof(SUBALLOC_NODE);
804 return((void *)g);
805 }
806 #endif
807
808
809 /****************************************************************
810 * vs_calloc
811 *
812 *
813 * PARAMETERS: IN num is the number of memory units requested.
814 * IN size is the size of each memory unit. result
815 * is a contigious area of memory that is
816 * num * size bytes.
817 *
818 * DESCRIPTION: initializes the suballocator if neccesary.
819 * gets an appropriately sized memory node, zeros
820 mday 1.1 * caller's memory block and returns a
821 * pointer to the caller.
822 *
823 * RETURNS: pointer to zero'ed memory available for use by the
824 * caller, or NULL.
825 ***************************************************************/
826
827 #if defined(PEGASUS_DEBUG_MEMORY)
828 void *peg_suballocator::vs_calloc(size_t num, size_t s, void *handle, int type, Sint8 *f, Uint32 l)
829 {
830 void *g = vs_malloc((unsigned)num * s, handle, type, "internal", f, l);
831 memset(g, 0x00, num * s);
832 return(g);
833 }
834
835 #else
836
837 void *peg_suballocator::vs_calloc(size_t num, size_t s)
838 {
839 void *g = vs_malloc((unsigned)num * s);
840 memset(g, 0x00, num * s);
841 mday 1.1 return(g);
842 }
843
844
845 #endif
846
847 /****************************************************************
848 * vs_free
849 *
850 *
851 * PARAMETERS: IN pointer to memory that the caller wants freed.
852 *
853 * DESCRIPTION: marks the node as available. in debug mode,
854 * checks for memory under and over -writes.
855 *
856 * RETURNS:
857 *
858 ***************************************************************/
859
860 #if defined(PEGASUS_DEBUG_MEMORY)
861 void peg_suballocator::vs_free(void *m,
862 mday 1.1 void *handle,
863 int type ,
864 Sint8 *classname,
865 Sint8* file,
866 Uint32 line)
867 {
868 // we don't need to grab any semaphores -
869 // called routines will do that for us
870 assert( m != NULL);
871
872 SUBALLOC_NODE *temp = _CheckNode(m, type, file, line);
873 memset(temp->d_classname, 0x00, MAX_CLASS_LEN + 1);
874 strncpy(temp->d_classname, classname, MAX_CLASS_LEN);
875 memset(temp->d_file, 0x00, MAX_PATH_LEN + 1);
876 strncpy(temp->d_file, file, MAX_PATH_LEN);
877 memset(temp->d_line, 0x00, MAX_LINE_LEN + 1);
878 sprintf(temp->d_line, "%d", line);
879
880 if (! (temp->allocSize >> 8))
881 {
882 PutNode(0, (temp->allocSize >> 4), temp);
883 mday 1.1 }
884 else if (! (temp->allocSize >> 12))
885 {
886 PutNode(1, (temp->allocSize >> 8), temp);
887 }
888 else if (! (temp->allocSize >> 16))
889 {
890 PutNode(2, (temp->allocSize >> 12), temp);
891 }
892 else
893 PutHugeNode(temp);
894 return;
895 }
896
897 #else
898 void peg_suballocator::vs_free(void *m)
899 {
900 // we don't need to grab any semaphores -
901 // called routines will do that for us
902 assert( m != 0 );
903 SUBALLOC_NODE *temp = (SUBALLOC_NODE *)m;
904 mday 1.1 temp--;
905
906 if (! (temp->allocSize >> 8))
907 {
908 PutNode(0, (temp->allocSize >> 4), temp);
909 }
910 else if (! (temp->allocSize >> 12))
911 {
912 PutNode(1, (temp->allocSize >> 8), temp);
913 }
914 else if (! (temp->allocSize >> 16))
915 {
916 PutNode(2, (temp->allocSize >> 12), temp);
917 }
918 else
919 PutHugeNode(temp);
920 return;
921 }
922
923 #endif
924
925 mday 1.1
926 #if defined(PEGASUS_DEBUG_MEMORY)
927
928 void *peg_suballocator::vs_realloc(void *pblock, size_t newsize, void *handle, int type, Sint8 *f, Uint32 l)
929 {
930 if (pblock == NULL) {
931 return(vs_malloc(newsize, handle, type, 0, f, l));
932 }
933 if (newsize == 0) {
934 vs_free(pblock, handle, type, "INTERNAL", f, l);
935 return(NULL);
936 }
937
938 {
939 void *newblock;
940 newblock = vs_calloc(newsize, sizeof(char), handle, type, f, l);
941 if (newblock != NULL) {
942 SUBALLOC_NODE *temp;
943 Sint8 *g;
944 int copysize;
945 temp = (SUBALLOC_NODE *)pblock;
946 mday 1.1 temp--;
947 if(newsize > temp->allocSize)
948 copysize = temp->allocSize;
949 else
950 copysize = newsize;
951
952 /* get the actual data size of the old block - only copy that much */
953 /* if newsize is smaller than oldsize, only copy newsize */
954 memcpy(newblock, pblock, copysize);
955 vs_free(pblock, handle, type, "INTERNAL", f, l);
956 return(newblock);
957 }
958 else
959 return(pblock);
960 }
961 }
962
963 #else
964
965 void *peg_suballocator::vs_realloc(void *pblock, size_t newsize)
966 {
967 mday 1.1 if (pblock == NULL) {
968 return(vs_malloc(newsize));
969 }
970 if (newsize == 0) {
971 vs_free(pblock);
972 return(NULL);
973 }
974
975 {
976 void *newblock;
977 newblock = vs_calloc(newsize, sizeof(char));
978 if (newblock != NULL) {
979 SUBALLOC_NODE *temp;
980 Sint8 *g;
981 int copysize;
982 temp = (SUBALLOC_NODE *)pblock;
983 temp--;
984 if(newsize > temp->allocSize)
985 copysize = temp->allocSize;
986 else
987 copysize = newsize;
988 mday 1.1
989 /* get the actual data size of the old block - only copy that much */
990 /* if newsize is smaller than oldsize, only copy newsize */
991 memcpy(newblock, pblock, copysize);
992 vs_free(pblock);
993 return(newblock);
994 }
995 else
996 return(pblock);
997 }
998 }
999
1000 #endif
1001
1002
1003 #if defined(PEGASUS_DEBUG_MEMORY)
1004 Sint8 * peg_suballocator::vs_strdup(const Sint8 *string, void *handle, int type, Sint8 *f, Uint32 l)
1005 {
1006
1007 Sint8 *memory;
1008
1009 mday 1.1 if (!string)
1010 return(NULL);
1011 if ((memory = (Sint8 *)vs_malloc(strlen(string) + 1, handle, type, 0, f, l)))
1012 return(strcpy(memory,string));
1013
1014 return(NULL);
1015 }
1016
1017 #else
1018
1019 Sint8 * peg_suballocator::vs_strdup(const Sint8 *string)
1020 {
1021
1022 Sint8 *memory;
1023
1024 if (!string)
1025 return(NULL);
1026 if ((memory = (Sint8 *)vs_malloc(strlen(string) + 1)))
1027 return(strcpy(memory,string));
1028 return(NULL);
1029 }
1030 mday 1.1 #endif
1031
1032
1033 /****************************************************************
1034 * _UnfreedNodes
1035 *
1036 *
1037 * PARAMETERS: IN index is a selector for the correct listhead.
1038 *
1039 * DESCRIPTION: Checks the list for unfreed nodes. These are nodes
1040 * that are marked as available. Call this routine
1041 * to check for memory leaks.
1042 * INTERNAL call only - caller must own the semaphore
1043 * for the list indicated by index.
1044 *
1045 * RETURNS: true if there are unfreed nodes on the list,
1046 * false otherwise
1047 *
1048 ***************************************************************/
1049 #if defined(PEGASUS_DEBUG_MEMORY)
1050 Boolean peg_suballocator::_UnfreedNodes(void * handle)
1051 mday 1.1 {
1052 Sint8 i, y;
1053 Sint32 waitCode;
1054 SUBALLOC_NODE *temp;
1055 Boolean ccode = false;
1056 SUBALLOC_HANDLE *h = (SUBALLOC_HANDLE *)handle;
1057
1058 WAIT_MUTEX(&(globalSemHandle), 1000, &waitCode);
1059 for (y = 0; y < 3; y++ )
1060 {
1061 for (i = 0; i < 16; i++)
1062 {
1063 WAIT_MUTEX(&(semHandles[y][i]), 1000, &waitCode);
1064 temp = (nodeListHeads[y][i])->next;
1065 // if list is empty we will fall through
1066 while (! IS_HEAD(temp) )
1067 {
1068 if (!(temp->flags & AVAIL) && temp->concurrencyHandle == (void *)handle)
1069 {
1070 if( temp->flags & CHECK_LEAK)
1071 {
1072 mday 1.1 h = (SUBALLOC_HANDLE *)temp->concurrencyHandle;
1073 RELEASE_MUTEX(&(semHandles[y][i]));
1074 Tracer::trace(__FILE__, __LINE__, TRC_MEMORY, Tracer::LEVEL2,
1075 "Memory Leak: %d bytes class %s allocated memory in source file %s at " \
1076 "line %s", temp->allocSize, temp->classname, temp->file, temp->line);
1077 WAIT_MUTEX(&(semHandles[y][i]), 1000, &waitCode);
1078 ccode = true;
1079 }
1080 }
1081 temp = temp->next;
1082 }
1083 RELEASE_MUTEX(&(semHandles[y][i]));
1084 }
1085 }
1086 RELEASE_MUTEX(&(globalSemHandle));
1087 return(ccode);
1088 }
1089
1090 /****************************************************************
1091 * _CheckGuard
1092 *
1093 mday 1.1 *
1094 * PARAMETERS: IN node is a node that we want to check for
1095 * under and over -writes.
1096 *
1097 * DESCRIPTION: checks node for under and over -writes
1098 *
1099 * NOTE: only available in debug mode.
1100 *
1101 * RETURNS: true if node is intact, false if node has been
1102 * stomped upon.
1103 *
1104 ***************************************************************/
1105 Boolean peg_suballocator::_CheckGuard(SUBALLOC_NODE *node)
1106 {
1107 Sint32 ccode;
1108
1109 ccode = memcmp(node->guardPre, guard, GUARD_SIZE);
1110 if (ccode == 0)
1111 {
1112 Sint8 *g = (Sint8 *)node;
1113 g += sizeof(SUBALLOC_NODE);
1114 mday 1.1 g += node->allocSize;
1115 ccode = memcmp(g, guard, GUARD_SIZE);
1116 if (ccode == 0)
1117 {
1118 return(true);
1119 }
1120 }
1121 return(false);
1122 }
1123
1124 Uint32 peg_suballocator::CheckMemory(void *m)
1125 {
1126 return _CheckNode(m);
1127 }
1128
1129 Uint32 peg_suballocator::_CheckNode(void *m)
1130 {
1131 assert(m != NULL);
1132 SUBALLOC_NODE *temp = (SUBALLOC_NODE *)m;
1133 temp--;
1134
1135 mday 1.1 if(temp->flags & AVAIL)
1136 return ALREADY_DELETED;
1137 if(false == _CheckGuard(temp))
1138 return OVERWRITE;
1139 return 0;
1140 }
1141
1142 peg_suballocator::SUBALLOC_NODE *peg_suballocator::_CheckNode(void *m,
1143 int type,
1144 Sint8 *file,
1145 Uint32 line)
1146 {
1147 assert(m != NULL);
1148 SUBALLOC_NODE *temp = (SUBALLOC_NODE *)m;
1149 temp--;
1150 if( (temp->flags & AVAIL ) )
1151 {
1152 Tracer::trace(file, line, TRC_MEMORY, Tracer::LEVEL2,
1153 "Doubly freed memory, already deleted by class %s at " \
1154 "source file %s line number %s; this deletion is from " \
1155 "source file %s line number %d",
1156 mday 1.1 temp->d_classname, temp->d_file, temp->d_line, file, line);
1157 temp->flags |= CHECK_FAILED;
1158 if( abort_on_error)
1159 abort();
1160 }
1161 if( type == ARRAY )
1162 {
1163 if( false == IS_ARRAY(temp))
1164 {
1165 Tracer::trace(file, line, TRC_MEMORY, Tracer::LEVEL2,
1166 "Array delete called with non-array object at " \
1167 "source file %s line number %d. Object was originally allocated " \
1168 " by class %s in source file %s at line number %s",
1169 file, line, temp->classname, temp->file, temp->line);
1170 temp->flags |= CHECK_FAILED;
1171 if( abort_on_error)
1172 abort();
1173 }
1174 }
1175 else if( true == IS_ARRAY(temp))
1176 {
1177 mday 1.1 Tracer::trace(file, line, TRC_MEMORY, Tracer::LEVEL2,
1178 "Normal delete called with array object at " \
1179 "source file %s line number %d. Object was originally allocated " \
1180 " by class %s in source file %s at line number %s",
1181 file, line, temp->classname, temp->file, temp->line);
1182 temp->flags |= CHECK_FAILED;
1183 if( abort_on_error)
1184 abort();
1185 }
1186 if(false == _CheckGuard(temp))
1187 {
1188 Tracer::trace(file, line, TRC_MEMORY, Tracer::LEVEL2,
1189 "Memory overwritten. Allocated by %s in source file %s at line number %s",
1190 temp->classname, temp->file, temp->line);
1191 temp->flags |= CHECK_FAILED;
1192 if( abort_on_error)
1193 abort();
1194 }
1195 return temp;
1196 }
1197
1198 mday 1.1 #endif
1199
1200
1201
1202
1203 PEGASUS_NAMESPACE_END
|