merge the formfield patch from ooo-build
[ooovba.git] / dmake / dbug / malloc / malloc.c
blob8e496792108d20bb5a2ca6e9877004c53ca24240
1 /*
2 * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
3 * You may copy, distribute, and use this software as long as this
4 * copyright statement is not removed.
5 */
6 #include <stdio.h>
7 #include <fcntl.h>
8 #include "malloc.h"
9 #include "tostring.h"
12 * Function: malloc()
14 * Purpose: memory allocator
16 * Arguments: size - size of data area needed
18 * Returns: pointer to allocated area, or NULL if unable
19 * to allocate addtional data.
21 * Narrative:
24 #ifndef lint
25 static
26 char rcs_hdr[] = "$Id: malloc.c,v 1.2 2006-07-25 10:08:36 rt Exp $";
27 #endif
29 extern int malloc_checking;
30 char * malloc_data_start;
31 char * malloc_data_end;
32 struct mlist * malloc_end;
33 int malloc_errfd = 2;
34 int malloc_errno;
35 int malloc_fatal_level = M_HANDLE_CORE;
36 struct mlist malloc_start;
37 int malloc_warn_level;
38 void malloc_memset();
40 char *
41 malloc(size)
42 unsigned int size;
44 char * func = "malloc";
45 char * getenv();
46 void malloc_fatal();
47 void malloc_init();
48 void malloc_split();
49 void malloc_warning();
50 unsigned int need;
51 struct mlist * oldptr;
52 struct mlist * ptr;
53 char * sbrk();
56 * If this is the first call to malloc...
58 if( malloc_data_start == (char *) 0 )
60 malloc_init();
64 * If malloc chain checking is on, go do it.
66 if( malloc_checking )
68 (void) malloc_chain_check(1);
72 * always make sure there is at least on extra byte in the malloc
73 * area so that we can verify that the user does not overrun the
74 * data area.
76 size++;
79 * Now look for a free area of memory of size bytes...
81 oldptr = NULL;
82 for(ptr = &malloc_start; ; ptr = ptr->next)
85 * Since the malloc chain is a forward only chain, any
86 * pointer that we get should always be positioned in
87 * memory following the previous pointer. If this is not
88 * so, we must have a corrupted chain.
90 if( ptr )
92 if( ptr<oldptr )
94 malloc_errno = M_CODE_CHAIN_BROKE;
95 malloc_fatal(func);
96 return(NULL);
98 oldptr = ptr;
100 else if( oldptr != malloc_end )
103 * This should never happen. If it does, then
104 * we got a real problem.
106 malloc_errno = M_CODE_NO_END;
107 malloc_fatal(func);
108 return(NULL);
113 * if this element is already in use...
115 if( ptr && ((ptr->flag & M_INUSE) != 0) )
117 continue;
121 * if there isn't room for this block..
123 if( ptr && (ptr->s.size < size) )
125 continue;
129 * If ptr is null, we have run out of memory and must sbrk more
131 if( ptr == NULL )
133 need = (size + M_SIZE) * (size > 10*1024 ? 1:2);
134 if( need < M_BLOCKSIZE )
136 need = M_BLOCKSIZE;
138 else if( need & (M_BLOCKSIZE-1) )
140 need &= ~(M_BLOCKSIZE-1);
141 need += M_BLOCKSIZE;
143 ptr = (struct mlist *) sbrk((int)need);
144 if( ptr == (struct mlist *) -1 )
146 malloc_errno = M_CODE_NOMORE_MEM;
147 malloc_fatal(func);
149 malloc_data_end = sbrk((int)0);
151 ptr->prev = oldptr;
152 ptr->next = (struct mlist *) 0;
153 ptr->s.size = need - M_SIZE;
154 ptr->flag = M_MAGIC;
156 oldptr->next = ptr;
157 malloc_end = ptr;
160 } /* if( ptr ==... */
163 * Now ptr points to a memory location that can store
164 * this data, so lets go to work.
167 ptr->r_size = size; /* save requested size */
168 ptr->flag |= M_INUSE;
171 * split off unneeded data area in this block, if possible...
173 malloc_split(ptr);
176 * re-adjust the requested size so that it is what the user
177 * actually requested...
180 ptr->r_size--;
183 * just to make sure that noone is misusing malloced
184 * memory without initializing it, lets set it to
185 * all '\01's. We call local_memset() because memset()
186 * may be checking for malloc'd ptrs and this isn't
187 * a malloc'd ptr yet.
189 malloc_memset(ptr->data,M_FILL,(int)ptr->s.size);
191 return( ptr->data);
193 } /* for(... */
195 } /* malloc(... */
198 * Function: malloc_split()
200 * Purpose: to split a malloc segment if there is enough room at the
201 * end of the segment that isn't being used
203 * Arguments: ptr - pointer to segment to split
205 * Returns: nothing of any use.
207 * Narrative:
208 * get the needed size of the module
209 * round the size up to appropriat boundry
210 * calculate amount of left over space
211 * if there is enough left over space
212 * create new malloc block out of remainder
213 * if next block is free
214 * join the two blocks together
215 * fill new empty block with free space filler
216 * re-adjust pointers and size of current malloc block
220 * Mod History:
221 * 90/01/27 cpcahil Initial revision.
223 void
224 malloc_split(ptr)
225 struct mlist * ptr;
227 extern struct mlist * malloc_end;
228 void malloc_join();
229 int rest;
230 int size;
231 struct mlist * tptr;
233 size = ptr->r_size;
236 * roundup size to the appropriate boundry
239 M_ROUNDUP(size);
242 * figure out how much room is left in the array.
243 * if there is enough room, create a new mlist
244 * structure there.
247 if( ptr->s.size > size )
249 rest = ptr->s.size - size;
251 else
253 rest = 0;
256 if( rest > (M_SIZE+M_RND) )
258 tptr = (struct mlist *) (ptr->data+size);
259 tptr->prev = ptr;
260 tptr->next = ptr->next;
261 tptr->flag = M_MAGIC;
262 tptr->s.size = rest - M_SIZE;
265 * If possible, join this segment with the next one
268 malloc_join(tptr, tptr->next,0,0);
270 if( tptr->next )
272 tptr->next->prev = tptr;
275 malloc_memset(tptr->data,M_FREE_FILL, (int)tptr->s.size);
277 ptr->next = tptr;
278 ptr->s.size = size;
280 if( malloc_end == ptr )
282 malloc_end = tptr;
286 } /* malloc_split(... */
289 * Function: malloc_join()
291 * Purpose: to join two malloc segments together (if possible)
293 * Arguments: ptr - pointer to segment to join to.
294 * nextptr - pointer to next segment to join to ptr.
296 * Returns: nothing of any values.
298 * Narrative:
300 * Mod History:
301 * 90/01/27 cpcahil Initial revision.
303 void
304 malloc_join(ptr,nextptr, inuse_override, fill_flag)
305 struct mlist * ptr;
306 struct mlist * nextptr;
307 int inuse_override;
308 int fill_flag;
310 unsigned int newsize;
312 if( ptr && ! (inuse_override || (ptr->flag & M_INUSE)) &&
313 nextptr && ! (nextptr->flag & M_INUSE) &&
314 ((ptr->data+ptr->s.size) == (char *) nextptr) )
316 if( malloc_end == nextptr )
318 malloc_end = ptr;
320 ptr->next = nextptr->next;
321 newsize = nextptr->s.size + M_SIZE;
324 * if we are to fill and this segment is in use,
325 * fill in with M_FILL newly added space...
328 if(fill_flag && (ptr->flag & M_INUSE) )
330 malloc_memset(ptr->data+ptr->s.size,
331 M_FILL, (int)(nextptr->s.size + M_SIZE));
334 ptr->s.size += newsize;
335 if( ptr->next )
337 ptr->next->prev = ptr;
341 } /* malloc_join(... */
345 * The following mess is just to ensure that the versions of these functions in
346 * the current library are included (to make sure that we don't accidentaly get
347 * the libc versions. (This is the lazy man's -u ld directive)
350 void free();
351 int strcmp();
352 int memcmp();
353 char * realloc();
355 void (*malloc_void_funcs[])() =
357 free,
360 int (*malloc_int_funcs[])() =
362 strcmp,
363 memcmp,
366 char * (*malloc_char_star_funcs[])() =
368 realloc,
372 * This is malloc's own memset which is used without checking the parameters.
375 void
376 malloc_memset(ptr,byte,len)
377 char * ptr;
378 char byte;
379 int len;
382 while(len-- > 0)
384 *ptr++ = byte;
387 } /* malloc_memset(... */
390 * Function: malloc_fatal()
392 * Purpose: to display fatal error message and take approrpriate action
394 * Arguments: funcname - name of function calling this routine
396 * Returns: nothing of any value
398 * Narrative:
400 * Notes: This routine does not make use of any libc functions to build
401 * and/or disply the error message. This is due to the fact that
402 * we are probably at a point where malloc is having a real problem
403 * and we don't want to call any function that may use malloc.
405 void
406 malloc_fatal(funcname)
407 char * funcname;
409 char errbuf[128];
410 void exit();
411 void malloc_err_handler();
412 extern char * malloc_err_strings[];
413 extern int malloc_errno;
414 extern int malloc_fatal_level;
415 char * s;
416 char * t;
418 s = errbuf;
419 t = "Fatal error: ";
420 while( *s = *t++)
422 s++;
424 t = funcname;
425 while( *s = *t++)
427 s++;
430 t = "(): ";
431 while( *s = *t++)
433 s++;
436 t = malloc_err_strings[malloc_errno];
437 while( *s = *t++)
439 s++;
442 *(s++) = '\n';
444 if( write(malloc_errfd,errbuf,(unsigned)(s-errbuf)) != (s-errbuf))
446 (void) write(2,"I/O error to error file\n",(unsigned)24);
447 exit(110);
449 malloc_err_handler(malloc_fatal_level);
451 } /* malloc_fatal(... */
454 * Function: malloc_warning()
456 * Purpose: to display warning error message and take approrpriate action
458 * Arguments: funcname - name of function calling this routine
460 * Returns: nothing of any value
462 * Narrative:
464 * Notes: This routine does not make use of any libc functions to build
465 * and/or disply the error message. This is due to the fact that
466 * we are probably at a point where malloc is having a real problem
467 * and we don't want to call any function that may use malloc.
469 void
470 malloc_warning(funcname)
471 char * funcname;
473 char errbuf[128];
474 void exit();
475 void malloc_err_handler();
476 extern char * malloc_err_strings[];
477 extern int malloc_errno;
478 extern int malloc_warn_level;
479 char * s;
480 char * t;
482 s = errbuf;
483 t = "Warning: ";
484 while( *s = *t++)
486 s++;
488 t = funcname;
489 while( *s = *t++)
491 s++;
494 t = "(): ";
495 while( *s = *t++)
497 s++;
500 t = malloc_err_strings[malloc_errno];
501 while( *s = *t++)
503 s++;
506 *(s++) = '\n';
508 if( write(malloc_errfd,errbuf,(unsigned)(s-errbuf)) != (s-errbuf))
510 (void) write(2,"I/O error to error file\n",(unsigned)24);
511 exit(110);
514 malloc_err_handler(malloc_warn_level);
516 } /* malloc_warning(... */
519 * Function: malloc_err_handler()
521 * Purpose: to take the appropriate action for warning and/or fatal
522 * error conditions.
524 * Arguments: level - error handling level
526 * Returns: nothing of any value
528 * Narrative:
530 * Notes: This routine does not make use of any libc functions to build
531 * and/or disply the error message. This is due to the fact that
532 * we are probably at a point where malloc is having a real problem
533 * and we don't want to call any function that may use malloc.
535 void
536 malloc_err_handler(level)
538 void exit();
539 void malloc_dump();
540 extern int malloc_errfd;
542 if( level & M_HANDLE_DUMP )
544 malloc_dump(malloc_errfd);
547 switch( level & ~M_HANDLE_DUMP )
550 * If we are to drop a core file and exit
552 case M_HANDLE_ABORT:
553 (void) abort();
554 break;
557 * If we are to exit..
559 case M_HANDLE_EXIT:
560 exit(200);
561 break;
563 #ifndef __MSDOS__
565 * If we are to dump a core, but keep going on our merry way
567 case M_HANDLE_CORE:
569 int pid;
572 * fork so child can abort (and dump core)
574 if( (pid = fork()) == 0 )
576 (void) write(2,"Child dumping core\n",
577 (unsigned)9);
578 (void) abort();
582 * wait for child to finish dumping core
584 while( wait((int *)0) != pid)
589 * Move core file to core.pid.cnt so
590 * multiple cores don't overwrite each
591 * other.
593 if( access("core",0) == 0 )
595 static int corecnt;
596 char filenam[32];
597 filenam[0] = 'c';
598 filenam[1] = 'o';
599 filenam[2] = 'r';
600 filenam[3] = 'e';
601 filenam[4] = '.';
602 (void)tostring(filenam+5,getpid(),
603 5, B_DEC, '0');
604 filenam[10] = '.';
605 (void)tostring(filenam+11,corecnt++,
606 3, B_DEC, '0');
607 filenam[14] = '\0';
608 (void) unlink(filenam);
609 if( link("core",filenam) == 0)
611 (void) unlink("core");
615 #endif
619 * If we are to just ignore the error and keep on processing
621 case M_HANDLE_IGNORE:
622 break;
624 } /* switch(... */
626 } /* malloc_err_handler(... */