Alloc.c revision bdf0f55d
1/***********************************************************
2Copyright (c) 1993, 2011, 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#include <stdio.h>
86#include <stdarg.h>
87
88#define Xmalloc(size) malloc((size))
89#define Xrealloc(ptr, size) realloc((ptr), (size))
90#define Xcalloc(nelem, elsize) calloc((nelem), (elsize))
91#define Xfree(ptr) free(ptr)
92
93#ifdef _XNEEDBCOPYFUNC
94void _XtBcopy(
95    char *src, char *dst,
96    int length)
97{
98    if (src < dst) {
99	dst += length;
100	src += length;
101	while (length--)
102	    *--dst = *--src;
103    } else {
104	while (length--)
105	    *dst++ = *src++;
106    }
107}
108#endif
109
110void _XtAllocError(
111    String type)
112{
113    Cardinal num_params = 1;
114    if (type == NULL) type = "local memory allocation";
115    XtErrorMsg("allocError", type, XtCXtToolkitError,
116	       "Cannot perform %s", &type, &num_params);
117}
118
119void _XtHeapInit(
120    Heap*	heap)
121{
122    heap->start = NULL;
123    heap->bytes_remaining = 0;
124}
125
126/* Version of asprintf() using XtMalloc
127 * Not currently available in XTTRACEMEMORY version, since that would
128 * require varargs macros everywhere, which are only standard in C99 & later.
129 */
130Cardinal XtAsprintf(
131    String *new_string,
132    _Xconst char * _X_RESTRICT_KYWD format,
133    ...)
134{
135    char buf[256];
136    Cardinal len;
137    va_list ap;
138
139    va_start(ap, format);
140    len = vsnprintf(buf, sizeof(buf), format, ap);
141    va_end(ap);
142
143    if (len < 0)
144	_XtAllocError("vsnprintf");
145
146    *new_string = XtMalloc(len + 1); /* snprintf doesn't count trailing '\0' */
147    if (len < sizeof(buf))
148    {
149	strncpy(*new_string, buf, len);
150	(*new_string)[len] = '\0';
151    }
152    else
153    {
154	va_start(ap, format);
155	if (vsnprintf(*new_string, len + 1, format, ap) < 0)
156	    _XtAllocError("vsnprintf");
157	va_end(ap);
158    }
159    return len;
160}
161
162
163#ifndef XTTRACEMEMORY
164
165char *XtMalloc(
166    unsigned size)
167{
168    char *ptr;
169
170#if defined(MALLOC_0_RETURNS_NULL) && defined(XTMALLOC_BC)
171    /* preserve this (broken) behavior until everyone fixes their apps */
172    if (!size) size = 1;
173#endif
174    if ((ptr = Xmalloc(size)) == NULL)
175        _XtAllocError("malloc");
176
177    return(ptr);
178}
179
180char *XtRealloc(
181    char     *ptr,
182    unsigned size)
183{
184   if (ptr == NULL) {
185#ifdef MALLOC_0_RETURNS_NULL
186	if (!size) size = 1;
187#endif
188	return(XtMalloc(size));
189   } else if ((ptr = Xrealloc(ptr, size)) == NULL
190#ifdef MALLOC_0_RETURNS_NULL
191		&& size
192#endif
193	)
194	_XtAllocError("realloc");
195
196   return(ptr);
197}
198
199char *XtCalloc(
200    unsigned num, unsigned size)
201{
202    char *ptr;
203
204#if defined(MALLOC_0_RETURNS_NULL) && defined(XTMALLOC_BC)
205    /* preserve this (broken) behavior until everyone fixes their apps */
206    if (!size) num = size = 1;
207#endif
208    if ((ptr = Xcalloc(num, size)) == NULL)
209	_XtAllocError("calloc");
210
211    return(ptr);
212}
213
214void XtFree(
215    char *ptr)
216{
217    if (ptr != NULL) Xfree(ptr);
218}
219
220char* __XtMalloc(
221    unsigned size)
222{
223#ifdef MALLOC_0_RETURNS_NULL
224    if (!size) size = 1;
225#endif
226    return XtMalloc (size);
227}
228
229char* __XtCalloc(
230    unsigned num, unsigned size)
231{
232#ifdef MALLOC_0_RETURNS_NULL
233    if (!size) num = size = 1;
234#endif
235    return XtCalloc(num, size);
236}
237
238#ifndef HEAP_SEGMENT_SIZE
239#define HEAP_SEGMENT_SIZE 1492
240#endif
241
242char* _XtHeapAlloc(
243    Heap*	heap,
244    Cardinal	bytes)
245{
246    register char* heap_loc;
247    if (heap == NULL) return XtMalloc(bytes);
248    if (heap->bytes_remaining < (int)bytes) {
249	if ((bytes + sizeof(char*)) >= (HEAP_SEGMENT_SIZE>>1)) {
250	    /* preserve current segment; insert this one in front */
251#ifdef _TRACE_HEAP
252	    printf( "allocating large segment (%d bytes) on heap %#x\n",
253		    bytes, heap );
254#endif
255	    heap_loc = XtMalloc(bytes + sizeof(char*));
256	    if (heap->start) {
257		*(char**)heap_loc = *(char**)heap->start;
258		*(char**)heap->start = heap_loc;
259	    }
260	    else {
261		*(char**)heap_loc = NULL;
262		heap->start = heap_loc;
263	    }
264	    return heap_loc + sizeof(char*);
265	}
266	/* else discard remainder of this segment */
267#ifdef _TRACE_HEAP
268	printf( "allocating new segment on heap %#x\n", heap );
269#endif
270	heap_loc = XtMalloc((unsigned)HEAP_SEGMENT_SIZE);
271	*(char**)heap_loc = heap->start;
272	heap->start = heap_loc;
273	heap->current = heap_loc + sizeof(char*);
274	heap->bytes_remaining = HEAP_SEGMENT_SIZE - sizeof(char*);
275    }
276    bytes = (bytes + (sizeof(long) - 1)) & (~(sizeof(long) - 1));
277    heap_loc = heap->current;
278    heap->current += bytes;
279    heap->bytes_remaining -= bytes; /* can be negative, if rounded */
280    return heap_loc;
281}
282
283void _XtHeapFree(
284    Heap*	heap)
285{
286    char* segment = heap->start;
287    while (segment != NULL) {
288	char* next_segment = *(char**)segment;
289	XtFree(segment);
290	segment = next_segment;
291    }
292    heap->start = NULL;
293    heap->bytes_remaining = 0;
294}
295
296#else
297
298/*
299 * X Toolkit Memory Trace Allocation Routines
300 */
301
302#undef XtMalloc
303#undef XtRealloc
304#undef XtCalloc
305#undef XtFree
306
307typedef struct _Stats *StatsPtr;
308typedef struct _Stats {
309    StatsPtr prev, next;
310    char *file;
311    int line;
312    unsigned size;
313    unsigned long seq;
314    XtPointer heap;
315} Stats;
316
317static StatsPtr XtMemory = (StatsPtr)NULL;
318static unsigned long ActiveXtMemory = 0;
319static unsigned long XtSeqId = 0;
320static unsigned long XtSeqBreakpoint = ~0;
321
322#define StatsSize(n) ((((n) + (sizeof(long) - 1)) & ~(sizeof(long) - 1)) + sizeof(Stats))
323#define ToStats(ptr) ((StatsPtr)(ptr - sizeof(Stats)))
324#define ToMem(ptr) (((char *)ptr) + sizeof(Stats))
325
326#define CHAIN(ptr,len,hp) \
327    ptr->next = XtMemory; \
328    if (XtMemory) \
329        XtMemory->prev = ptr; \
330    XtMemory = ptr; \
331    ptr->prev = (StatsPtr)NULL; \
332    ptr->file = file; \
333    ptr->line = line; \
334    ptr->size = len; \
335    ptr->heap = hp; \
336    if (file) \
337	ActiveXtMemory += len; \
338    ptr->seq = XtSeqId; \
339    if (XtSeqId == XtSeqBreakpoint) \
340	_XtBreakpoint(ptr); \
341    XtSeqId++
342
343/*ARGUSED*/
344static void _XtBreakpoint(
345    StatsPtr mem)
346{
347    mem->seq = XtSeqId; /* avoid being optimized out of existence */
348}
349
350char *_XtMalloc(
351    unsigned size,
352    char *file,
353    int line)
354{
355    StatsPtr ptr;
356    unsigned newsize;
357    char* retval = NULL;
358
359    LOCK_PROCESS;
360    newsize = StatsSize(size);
361    if ((ptr = (StatsPtr)Xmalloc(newsize)) == NULL)
362        _XtAllocError("malloc");
363    CHAIN(ptr, size, NULL);
364    retval = (ToMem(ptr));
365    UNLOCK_PROCESS;
366    return retval;
367}
368
369char *XtMalloc(
370    unsigned size)
371{
372    return _XtMalloc(size, (char *)NULL, 0);
373}
374
375char *_XtRealloc(
376    char     *ptr,
377    unsigned size,
378    char *file,
379    int line)
380{
381   char *newptr;
382
383   LOCK_PROCESS;
384   newptr = _XtMalloc(size, file, line);
385   if (ptr) {
386       unsigned copysize = ToStats(ptr)->size;
387       if (copysize > size) copysize = size;
388       memmove(newptr, ptr, copysize);
389       _XtFree(ptr);
390   }
391   UNLOCK_PROCESS;
392   return(newptr);
393}
394
395char *XtRealloc(
396    char     *ptr,
397    unsigned size)
398{
399    return _XtRealloc(ptr, size, (char *)NULL, 0);
400}
401
402char *_XtCalloc(
403    unsigned num, unsigned size,
404    char *file,
405    int line)
406{
407    StatsPtr ptr;
408    unsigned total, newsize;
409    char* retval = NULL;
410
411    LOCK_PROCESS;
412    total = num * size;
413    newsize = StatsSize(total);
414    if ((ptr = (StatsPtr)Xcalloc(newsize, 1)) == NULL)
415        _XtAllocError("calloc");
416    CHAIN(ptr, total, NULL);
417    retval = (ToMem(ptr));
418    UNLOCK_PROCESS;
419    return retval;
420}
421
422char *XtCalloc(
423    unsigned num, unsigned size)
424{
425    return _XtCalloc(num, size, (char *)NULL, 0);
426}
427
428Boolean _XtIsValidPointer(
429    char *ptr)
430{
431    register StatsPtr mem;
432    register StatsPtr stp = ToStats(ptr);
433
434    LOCK_PROCESS;
435    for (mem = XtMemory; mem; mem = mem->next) {
436	if (mem == stp) {
437	    UNLOCK_PROCESS;
438	    return True;
439	}
440    }
441    UNLOCK_PROCESS;
442    return False;
443}
444
445Boolean _XtValidateMemory = False;
446
447void _XtFree(
448    char *ptr)
449{
450   register StatsPtr stp;
451
452   LOCK_PROCESS;
453   if (ptr) {
454       if (_XtValidateMemory && !_XtIsValidPointer(ptr))
455	   abort();
456       stp = ToStats(ptr);
457       if (stp->file)
458	   ActiveXtMemory -= stp->size;
459       if (stp->prev)
460	   stp->prev->next = stp->next;
461       else
462	   XtMemory = stp->next;
463       if (stp->next)
464	   stp->next->prev = stp->prev;
465       Xfree((char *)stp);
466   }
467   UNLOCK_PROCESS;
468}
469
470void XtFree(char *ptr)
471{
472   _XtFree(ptr);
473}
474
475char *_XtHeapMalloc(
476    Heap *heap,
477    Cardinal size,
478    char *file,
479    int line)
480{
481    StatsPtr ptr;
482    unsigned newsize;
483    XtPointer hp = (XtPointer) heap;
484    char* retval = NULL;
485
486    LOCK_PROCESS;
487    newsize = StatsSize(size);
488    if ((ptr = (StatsPtr)Xmalloc(newsize)) == NULL)
489        _XtAllocError("malloc");
490    CHAIN(ptr, size, hp);
491    retval = (ToMem(ptr));
492    UNLOCK_PROCESS;
493    return retval;
494}
495
496void _XtHeapFree(register XtPointer heap)
497{
498    register StatsPtr mem, next;
499
500    LOCK_PROCESS;
501    for (mem = XtMemory; mem; mem = next) {
502	next = mem->next;
503	if (mem->heap == heap) {
504	    if (mem->file)
505		ActiveXtMemory -= mem->size;
506	    if (mem->prev)
507		mem->prev->next = next;
508	    else
509		XtMemory = next;
510	    if (next)
511		next->prev = mem->prev;
512	    Xfree((char *)mem);
513	}
514    }
515    UNLOCK_PROCESS;
516}
517
518#include <stdio.h>
519
520void _XtPrintMemory(char * filename)
521{
522    register StatsPtr mem;
523    FILE *f;
524
525    if (filename == NULL)
526	f = stderr;
527    else
528	f = fopen(filename, "w");
529    LOCK_PROCESS;
530    fprintf(f, "total size: %d\n", ActiveXtMemory);
531    for (mem = XtMemory; mem; mem = mem->next) {
532	if (mem->file)
533	    fprintf(f, "size: %6d  seq: %5d  %12s(%4d)  %s\n",
534		    mem->size, mem->seq,
535		    mem->file, mem->line, mem->heap ? "heap" : "");
536    }
537    UNLOCK_PROCESS;
538    if (filename) fclose(f);
539}
540
541#endif  /* XTTRACEMEMORY */
542