Alloc.c revision 249c3046
1/***********************************************************
2Copyright (c) 1993, Oracle and/or its affiliates. All rights reserved.
3
4Permission is hereby granted, free of charge, to any person obtaining a
5copy of this software and associated documentation files (the "Software"),
6to deal in the Software without restriction, including without limitation
7the rights to use, copy, modify, merge, publish, distribute, sublicense,
8and/or sell copies of the Software, and to permit persons to whom the
9Software is furnished to do so, subject to the following conditions:
10
11The above copyright notice and this permission notice (including the next
12paragraph) shall be included in all copies or substantial portions of the
13Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21DEALINGS IN THE SOFTWARE.
22
23Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
24
25                        All Rights Reserved
26
27Permission to use, copy, modify, and distribute this software and its
28documentation for any purpose and without fee is hereby granted,
29provided that the above copyright notice appear in all copies and that
30both that copyright notice and this permission notice appear in
31supporting documentation, and that the name of Digital not be
32used in advertising or publicity pertaining to distribution of the
33software without specific, written prior permission.
34
35DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
36ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
37DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
38ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
39WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
40ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
41SOFTWARE.
42
43******************************************************************/
44
45/*
46
47Copyright 1987, 1988, 1998  The Open Group
48
49Permission to use, copy, modify, distribute, and sell this software and its
50documentation for any purpose is hereby granted without fee, provided that
51the above copyright notice appear in all copies and that both that
52copyright notice and this permission notice appear in supporting
53documentation.
54
55The above copyright notice and this permission notice shall be included in
56all copies or substantial portions of the Software.
57
58THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
61OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
62AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
63CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
64
65Except as contained in this notice, the name of The Open Group shall not be
66used in advertising or otherwise to promote the sale, use or other dealings
67in this Software without prior written authorization from The Open Group.
68
69*/
70
71/*
72 * X Toolkit Memory Allocation Routines
73 *
74 * Uses Xlib memory management, which is spec'd to be re-entrant.
75 */
76
77#ifdef HAVE_CONFIG_H
78#include <config.h>
79#endif
80#include "IntrinsicI.h"
81#include "InitialI.h"
82#undef _XBCOPYFUNC
83
84#include <stdlib.h>
85
86#define Xmalloc(size) malloc((size))
87#define Xrealloc(ptr, size) realloc((ptr), (size))
88#define Xcalloc(nelem, elsize) calloc((nelem), (elsize))
89#define Xfree(ptr) free(ptr)
90
91#ifdef _XNEEDBCOPYFUNC
92void _XtBcopy(
93    char *src, char *dst,
94    int length)
95{
96    if (src < dst) {
97	dst += length;
98	src += length;
99	while (length--)
100	    *--dst = *--src;
101    } else {
102	while (length--)
103	    *dst++ = *src++;
104    }
105}
106#endif
107
108void _XtAllocError(
109    String type)
110{
111    Cardinal num_params = 1;
112    if (type == NULL) type = "local memory allocation";
113    XtErrorMsg("allocError", type, XtCXtToolkitError,
114	       "Cannot perform %s", &type, &num_params);
115}
116
117void _XtHeapInit(
118    Heap*	heap)
119{
120    heap->start = NULL;
121    heap->bytes_remaining = 0;
122}
123
124#ifndef XTTRACEMEMORY
125
126char *XtMalloc(
127    unsigned size)
128{
129    char *ptr;
130
131#if defined(MALLOC_0_RETURNS_NULL) && defined(XTMALLOC_BC)
132    /* preserve this (broken) behavior until everyone fixes their apps */
133    if (!size) size = 1;
134#endif
135    if ((ptr = Xmalloc(size)) == NULL)
136        _XtAllocError("malloc");
137
138    return(ptr);
139}
140
141char *XtRealloc(
142    char     *ptr,
143    unsigned size)
144{
145   if (ptr == NULL) {
146#ifdef MALLOC_0_RETURNS_NULL
147	if (!size) size = 1;
148#endif
149	return(XtMalloc(size));
150   } else if ((ptr = Xrealloc(ptr, size)) == NULL
151#ifdef MALLOC_0_RETURNS_NULL
152		&& size
153#endif
154	)
155	_XtAllocError("realloc");
156
157   return(ptr);
158}
159
160char *XtCalloc(
161    unsigned num, unsigned size)
162{
163    char *ptr;
164
165#if defined(MALLOC_0_RETURNS_NULL) && defined(XTMALLOC_BC)
166    /* preserve this (broken) behavior until everyone fixes their apps */
167    if (!size) num = size = 1;
168#endif
169    if ((ptr = Xcalloc(num, size)) == NULL)
170	_XtAllocError("calloc");
171
172    return(ptr);
173}
174
175void XtFree(
176    char *ptr)
177{
178    if (ptr != NULL) Xfree(ptr);
179}
180
181char* __XtMalloc(
182    unsigned size)
183{
184#ifdef MALLOC_0_RETURNS_NULL
185    if (!size) size = 1;
186#endif
187    return XtMalloc (size);
188}
189
190char* __XtCalloc(
191    unsigned num, unsigned size)
192{
193#ifdef MALLOC_0_RETURNS_NULL
194    if (!size) num = size = 1;
195#endif
196    return XtCalloc(num, size);
197}
198
199#ifndef HEAP_SEGMENT_SIZE
200#define HEAP_SEGMENT_SIZE 1492
201#endif
202
203char* _XtHeapAlloc(
204    Heap*	heap,
205    Cardinal	bytes)
206{
207    register char* heap_loc;
208    if (heap == NULL) return XtMalloc(bytes);
209    if (heap->bytes_remaining < (int)bytes) {
210	if ((bytes + sizeof(char*)) >= (HEAP_SEGMENT_SIZE>>1)) {
211	    /* preserve current segment; insert this one in front */
212#ifdef _TRACE_HEAP
213	    printf( "allocating large segment (%d bytes) on heap %#x\n",
214		    bytes, heap );
215#endif
216	    heap_loc = XtMalloc(bytes + sizeof(char*));
217	    if (heap->start) {
218		*(char**)heap_loc = *(char**)heap->start;
219		*(char**)heap->start = heap_loc;
220	    }
221	    else {
222		*(char**)heap_loc = NULL;
223		heap->start = heap_loc;
224	    }
225	    return heap_loc + sizeof(char*);
226	}
227	/* else discard remainder of this segment */
228#ifdef _TRACE_HEAP
229	printf( "allocating new segment on heap %#x\n", heap );
230#endif
231	heap_loc = XtMalloc((unsigned)HEAP_SEGMENT_SIZE);
232	*(char**)heap_loc = heap->start;
233	heap->start = heap_loc;
234	heap->current = heap_loc + sizeof(char*);
235	heap->bytes_remaining = HEAP_SEGMENT_SIZE - sizeof(char*);
236    }
237    bytes = (bytes + (sizeof(long) - 1)) & (~(sizeof(long) - 1));
238    heap_loc = heap->current;
239    heap->current += bytes;
240    heap->bytes_remaining -= bytes; /* can be negative, if rounded */
241    return heap_loc;
242}
243
244void _XtHeapFree(
245    Heap*	heap)
246{
247    char* segment = heap->start;
248    while (segment != NULL) {
249	char* next_segment = *(char**)segment;
250	XtFree(segment);
251	segment = next_segment;
252    }
253    heap->start = NULL;
254    heap->bytes_remaining = 0;
255}
256
257#else
258
259/*
260 * X Toolkit Memory Trace Allocation Routines
261 */
262
263#undef XtMalloc
264#undef XtRealloc
265#undef XtCalloc
266#undef XtFree
267
268typedef struct _Stats *StatsPtr;
269typedef struct _Stats {
270    StatsPtr prev, next;
271    char *file;
272    int line;
273    unsigned size;
274    unsigned long seq;
275    XtPointer heap;
276} Stats;
277
278static StatsPtr XtMemory = (StatsPtr)NULL;
279static unsigned long ActiveXtMemory = 0;
280static unsigned long XtSeqId = 0;
281static unsigned long XtSeqBreakpoint = ~0;
282
283#define StatsSize(n) ((((n) + (sizeof(long) - 1)) & ~(sizeof(long) - 1)) + sizeof(Stats))
284#define ToStats(ptr) ((StatsPtr)(ptr - sizeof(Stats)))
285#define ToMem(ptr) (((char *)ptr) + sizeof(Stats))
286
287#define CHAIN(ptr,len,hp) \
288    ptr->next = XtMemory; \
289    if (XtMemory) \
290        XtMemory->prev = ptr; \
291    XtMemory = ptr; \
292    ptr->prev = (StatsPtr)NULL; \
293    ptr->file = file; \
294    ptr->line = line; \
295    ptr->size = len; \
296    ptr->heap = hp; \
297    if (file) \
298	ActiveXtMemory += len; \
299    ptr->seq = XtSeqId; \
300    if (XtSeqId == XtSeqBreakpoint) \
301	_XtBreakpoint(ptr); \
302    XtSeqId++
303
304/*ARGUSED*/
305static void _XtBreakpoint(
306    StatsPtr mem)
307{
308    mem->seq = XtSeqId; /* avoid being optimized out of existence */
309}
310
311char *_XtMalloc(
312    unsigned size,
313    char *file,
314    int line)
315{
316    StatsPtr ptr;
317    unsigned newsize;
318    char* retval = NULL;
319
320    LOCK_PROCESS;
321    newsize = StatsSize(size);
322    if ((ptr = (StatsPtr)Xmalloc(newsize)) == NULL)
323        _XtAllocError("malloc");
324    CHAIN(ptr, size, NULL);
325    retval = (ToMem(ptr));
326    UNLOCK_PROCESS;
327    return retval;
328}
329
330char *XtMalloc(
331    unsigned size)
332{
333    return _XtMalloc(size, (char *)NULL, 0);
334}
335
336char *_XtRealloc(
337    char     *ptr,
338    unsigned size,
339    char *file,
340    int line)
341{
342   char *newptr;
343
344   LOCK_PROCESS;
345   newptr = _XtMalloc(size, file, line);
346   if (ptr) {
347       unsigned copysize = ToStats(ptr)->size;
348       if (copysize > size) copysize = size;
349       memmove(newptr, ptr, copysize);
350       _XtFree(ptr);
351   }
352   UNLOCK_PROCESS;
353   return(newptr);
354}
355
356char *XtRealloc(
357    char     *ptr,
358    unsigned size)
359{
360    return _XtRealloc(ptr, size, (char *)NULL, 0);
361}
362
363char *_XtCalloc(
364    unsigned num, unsigned size,
365    char *file,
366    int line)
367{
368    StatsPtr ptr;
369    unsigned total, newsize;
370    char* retval = NULL;
371
372    LOCK_PROCESS;
373    total = num * size;
374    newsize = StatsSize(total);
375    if ((ptr = (StatsPtr)Xcalloc(newsize, 1)) == NULL)
376        _XtAllocError("calloc");
377    CHAIN(ptr, total, NULL);
378    retval = (ToMem(ptr));
379    UNLOCK_PROCESS;
380    return retval;
381}
382
383char *XtCalloc(
384    unsigned num, unsigned size)
385{
386    return _XtCalloc(num, size, (char *)NULL, 0);
387}
388
389Boolean _XtIsValidPointer(
390    char *ptr)
391{
392    register StatsPtr mem;
393    register StatsPtr stp = ToStats(ptr);
394
395    LOCK_PROCESS;
396    for (mem = XtMemory; mem; mem = mem->next) {
397	if (mem == stp) {
398	    UNLOCK_PROCESS;
399	    return True;
400	}
401    }
402    UNLOCK_PROCESS;
403    return False;
404}
405
406Boolean _XtValidateMemory = False;
407
408void _XtFree(
409    char *ptr)
410{
411   register StatsPtr stp;
412
413   LOCK_PROCESS;
414   if (ptr) {
415       if (_XtValidateMemory && !_XtIsValidPointer(ptr))
416	   abort();
417       stp = ToStats(ptr);
418       if (stp->file)
419	   ActiveXtMemory -= stp->size;
420       if (stp->prev)
421	   stp->prev->next = stp->next;
422       else
423	   XtMemory = stp->next;
424       if (stp->next)
425	   stp->next->prev = stp->prev;
426       Xfree((char *)stp);
427   }
428   UNLOCK_PROCESS;
429}
430
431void XtFree(char *ptr)
432{
433   _XtFree(ptr);
434}
435
436char *_XtHeapMalloc(
437    Heap *heap,
438    Cardinal size,
439    char *file,
440    int line)
441{
442    StatsPtr ptr;
443    unsigned newsize;
444    XtPointer hp = (XtPointer) heap;
445    char* retval = NULL;
446
447    LOCK_PROCESS;
448    newsize = StatsSize(size);
449    if ((ptr = (StatsPtr)Xmalloc(newsize)) == NULL)
450        _XtAllocError("malloc");
451    CHAIN(ptr, size, hp);
452    retval = (ToMem(ptr));
453    UNLOCK_PROCESS;
454    return retval;
455}
456
457void _XtHeapFree(register XtPointer heap)
458{
459    register StatsPtr mem, next;
460
461    LOCK_PROCESS;
462    for (mem = XtMemory; mem; mem = next) {
463	next = mem->next;
464	if (mem->heap == heap) {
465	    if (mem->file)
466		ActiveXtMemory -= mem->size;
467	    if (mem->prev)
468		mem->prev->next = next;
469	    else
470		XtMemory = next;
471	    if (next)
472		next->prev = mem->prev;
473	    Xfree((char *)mem);
474	}
475    }
476    UNLOCK_PROCESS;
477}
478
479#include <stdio.h>
480
481void _XtPrintMemory(char * filename)
482{
483    register StatsPtr mem;
484    FILE *f;
485
486    if (filename == NULL)
487	f = stderr;
488    else
489	f = fopen(filename, "w");
490    LOCK_PROCESS;
491    fprintf(f, "total size: %d\n", ActiveXtMemory);
492    for (mem = XtMemory; mem; mem = mem->next) {
493	if (mem->file)
494	    fprintf(f, "size: %6d  seq: %5d  %12s(%4d)  %s\n",
495		    mem->size, mem->seq,
496		    mem->file, mem->line, mem->heap ? "heap" : "");
497    }
498    UNLOCK_PROCESS;
499    if (filename) fclose(f);
500}
501
502#endif  /* XTTRACEMEMORY */
503