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.
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.
26 char rcs_hdr
[] = "$Id: malloc.c,v 1.2 2006-07-25 10:08:36 rt Exp $";
29 extern int malloc_checking
;
30 char * malloc_data_start
;
31 char * malloc_data_end
;
32 struct mlist
* malloc_end
;
35 int malloc_fatal_level
= M_HANDLE_CORE
;
36 struct mlist malloc_start
;
37 int malloc_warn_level
;
44 char * func
= "malloc";
49 void malloc_warning();
51 struct mlist
* oldptr
;
56 * If this is the first call to malloc...
58 if( malloc_data_start
== (char *) 0 )
64 * If malloc chain checking is on, go do it.
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
79 * Now look for a free area of memory of size bytes...
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.
94 malloc_errno
= M_CODE_CHAIN_BROKE
;
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
;
113 * if this element is already in use...
115 if( ptr
&& ((ptr
->flag
& M_INUSE
) != 0) )
121 * if there isn't room for this block..
123 if( ptr
&& (ptr
->s
.size
< size
) )
129 * If ptr is null, we have run out of memory and must sbrk more
133 need
= (size
+ M_SIZE
) * (size
> 10*1024 ? 1:2);
134 if( need
< M_BLOCKSIZE
)
138 else if( need
& (M_BLOCKSIZE
-1) )
140 need
&= ~(M_BLOCKSIZE
-1);
143 ptr
= (struct mlist
*) sbrk((int)need
);
144 if( ptr
== (struct mlist
*) -1 )
146 malloc_errno
= M_CODE_NOMORE_MEM
;
149 malloc_data_end
= sbrk((int)0);
152 ptr
->next
= (struct mlist
*) 0;
153 ptr
->s
.size
= need
- M_SIZE
;
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...
176 * re-adjust the requested size so that it is what the user
177 * actually requested...
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
);
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.
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
221 * 90/01/27 cpcahil Initial revision.
227 extern struct mlist
* malloc_end
;
236 * roundup size to the appropriate boundry
242 * figure out how much room is left in the array.
243 * if there is enough room, create a new mlist
247 if( ptr
->s
.size
> size
)
249 rest
= ptr
->s
.size
- size
;
256 if( rest
> (M_SIZE
+M_RND
) )
258 tptr
= (struct mlist
*) (ptr
->data
+size
);
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);
272 tptr
->next
->prev
= tptr
;
275 malloc_memset(tptr
->data
,M_FREE_FILL
, (int)tptr
->s
.size
);
280 if( malloc_end
== ptr
)
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.
301 * 90/01/27 cpcahil Initial revision.
304 malloc_join(ptr
,nextptr
, inuse_override
, fill_flag
)
306 struct mlist
* nextptr
;
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
)
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
;
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)
355 void (*malloc_void_funcs
[])() =
360 int (*malloc_int_funcs
[])() =
366 char * (*malloc_char_star_funcs
[])() =
372 * This is malloc's own memset which is used without checking the parameters.
376 malloc_memset(ptr
,byte
,len
)
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
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.
406 malloc_fatal(funcname
)
411 void malloc_err_handler();
412 extern char * malloc_err_strings
[];
413 extern int malloc_errno
;
414 extern int malloc_fatal_level
;
436 t
= malloc_err_strings
[malloc_errno
];
444 if( write(malloc_errfd
,errbuf
,(unsigned)(s
-errbuf
)) != (s
-errbuf
))
446 (void) write(2,"I/O error to error file\n",(unsigned)24);
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
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.
470 malloc_warning(funcname
)
475 void malloc_err_handler();
476 extern char * malloc_err_strings
[];
477 extern int malloc_errno
;
478 extern int malloc_warn_level
;
500 t
= malloc_err_strings
[malloc_errno
];
508 if( write(malloc_errfd
,errbuf
,(unsigned)(s
-errbuf
)) != (s
-errbuf
))
510 (void) write(2,"I/O error to error file\n",(unsigned)24);
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
524 * Arguments: level - error handling level
526 * Returns: nothing of any value
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.
536 malloc_err_handler(level
)
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
557 * If we are to exit..
565 * If we are to dump a core, but keep going on our merry way
572 * fork so child can abort (and dump core)
574 if( (pid
= fork()) == 0 )
576 (void) write(2,"Child dumping core\n",
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
593 if( access("core",0) == 0 )
602 (void)tostring(filenam
+5,getpid(),
605 (void)tostring(filenam
+11,corecnt
++,
608 (void) unlink(filenam
);
609 if( link("core",filenam
) == 0)
611 (void) unlink("core");
619 * If we are to just ignore the error and keep on processing
621 case M_HANDLE_IGNORE
:
626 } /* malloc_err_handler(... */