diff options
author | raf <none@none> | 2007-03-20 19:30:49 -0700 |
---|---|---|
committer | raf <none@none> | 2007-03-20 19:30:49 -0700 |
commit | 1d53067866b073ea6710000ba4dd448441361988 (patch) | |
tree | fbac45aa59a72e34fdd5e5fccc91c5bb1d0f0df5 /usr/src/lib/libmtmalloc/common/mtmalloc.c | |
parent | 84f43ade33b1b00348bdcdfaca9f71f6a0c786eb (diff) | |
download | illumos-gate-1d53067866b073ea6710000ba4dd448441361988.tar.gz |
6533630 all malloc interposition libraries need to be made fork-safe
--HG--
rename : usr/src/lib/libmapmalloc/common/malloc_debug.c => deleted_files/usr/src/lib/libmapmalloc/common/malloc_debug.c
Diffstat (limited to 'usr/src/lib/libmtmalloc/common/mtmalloc.c')
-rw-r--r-- | usr/src/lib/libmtmalloc/common/mtmalloc.c | 191 |
1 files changed, 100 insertions, 91 deletions
diff --git a/usr/src/lib/libmtmalloc/common/mtmalloc.c b/usr/src/lib/libmtmalloc/common/mtmalloc.c index ab502274c5..6dd1970491 100644 --- a/usr/src/lib/libmtmalloc/common/mtmalloc.c +++ b/usr/src/lib/libmtmalloc/common/mtmalloc.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -19,18 +18,21 @@ * * CDDL HEADER END */ + /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" +#include <c_synonyms.h> #include <mtmalloc.h> #include "mtmalloc_impl.h" #include <unistd.h> #include <synch.h> #include <thread.h> +#include <pthread.h> #include <stdio.h> #include <limits.h> #include <errno.h> @@ -116,7 +118,6 @@ #endif static void * morecore(size_t); -static int setup_caches(void); static void create_cache(cache_t *, size_t bufsize, uint_t hunks); static void * malloc_internal(size_t, percpu_t *); static void * oversize(size_t); @@ -136,15 +137,6 @@ static oversize_t *oversize_header_alloc(uintptr_t, size_t); #define HASH_OVERSIZE(caddr) ((uintptr_t)(caddr) % NUM_BUCKETS) oversize_t *ovsz_hashtab[NUM_BUCKETS]; -/* - * Gets a decent "current cpu identifier", to be used to reduce contention. - * Eventually, this should be replaced by an interface to get the actual - * CPU sequence number in libthread/liblwp. - */ -extern uint_t _thr_self(); -#pragma weak _thr_self -#define get_curcpu_func() (curcpu_func)_thr_self - #define ALIGN(x, a) ((((uintptr_t)(x) + ((uintptr_t)(a) - 1)) \ & ~((uintptr_t)(a) - 1))) @@ -195,9 +187,9 @@ static int32_t reinit; static percpu_t *cpu_list; static oversize_t oversize_list; -static mutex_t oversize_lock; +static mutex_t oversize_lock = DEFAULTMUTEX; -static int ncpus; +static int ncpus = 0; #define MTMALLOC_OVERSIZE_MAGIC ((uintptr_t)&oversize_list) #define MTMALLOC_MEMALIGN_MAGIC ((uintptr_t)&oversize_list + 1) @@ -233,20 +225,6 @@ malloc(size_t bytes) percpu_t *list_rotor; uint_t list_index; - /* - * this test is due to linking with libthread. - * There are malloc calls prior to this library - * being initialized. - * - * If setup_caches fails, we set ENOMEM and return NULL - */ - if (cpu_list == (percpu_t *)NULL) { - if (setup_caches() == 0) { - errno = ENOMEM; - return (NULL); - } - } - if (bytes > MAX_CACHED) return (oversize(bytes)); @@ -332,7 +310,7 @@ calloc(size_t nelem, size_t bytes) ptr = malloc(size); if (ptr == NULL) return (NULL); - bzero(ptr, size); + (void) memset(ptr, 0, size); return (ptr); } @@ -753,25 +731,13 @@ mallocctl(int cmd, long value) } /* - * if this function is changed, update the fallback code in setup_caches to - * set ncpus to the number of possible return values. (currently 1) - */ -static uint_t -fallback_curcpu(void) -{ - return (0); -} - -/* - * Returns non-zero on success, zero on failure. - * - * This carefully doesn't set cpu_list until initialization is finished. + * Initialization function, called from the init section of the library. + * No locking is required here because we are single-threaded during + * library initialization. */ -static int +static void setup_caches(void) { - static mutex_t init_lock = DEFAULTMUTEX; - uintptr_t oldbrk; uintptr_t newbrk; @@ -785,21 +751,14 @@ setup_caches(void) uint_t i, j; uintptr_t list_addr; - (void) mutex_lock(&init_lock); - if (cpu_list != NULL) { - (void) mutex_unlock(&init_lock); - return (1); /* success -- already initialized */ - } - - new_curcpu = get_curcpu_func(); - if (new_curcpu == NULL) { - new_curcpu = fallback_curcpu; - ncpus = 1; - } else { - if ((ncpus = 2 * sysconf(_SC_NPROCESSORS_CONF)) <= 0) - ncpus = 4; /* decent default value */ - } - assert(ncpus > 0); + /* + * Get a decent "current cpu identifier", to be used to reduce + * contention. Eventually, this should be replaced by an interface + * to get the actual CPU sequence number in libthread/liblwp. + */ + new_curcpu = (curcpu_func)thr_self; + if ((ncpus = 2 * sysconf(_SC_NPROCESSORS_CONF)) <= 0) + ncpus = 4; /* decent default value */ /* round ncpus up to a power of 2 */ while (ncpus & (ncpus - 1)) @@ -817,10 +776,8 @@ setup_caches(void) * First, make sure sbrk is sane, and store the current brk in oldbrk. */ oldbrk = (uintptr_t)sbrk(0); - if ((void *)oldbrk == (void *)-1) { - (void) mutex_unlock(&init_lock); - return (0); /* sbrk is broken -- we're doomed. */ - } + if ((void *)oldbrk == (void *)-1) + abort(); /* sbrk is broken -- we're doomed. */ /* * Now, align the brk to a multiple of CACHE_COHERENCY_UNIT, so that @@ -830,10 +787,8 @@ setup_caches(void) * so they can be paged out individually. */ newbrk = ALIGN(oldbrk, CACHE_COHERENCY_UNIT); - if (newbrk != oldbrk && (uintptr_t)sbrk(newbrk - oldbrk) != oldbrk) { - (void) mutex_unlock(&init_lock); - return (0); /* someone else sbrked */ - } + if (newbrk != oldbrk && (uintptr_t)sbrk(newbrk - oldbrk) != oldbrk) + abort(); /* sbrk is broken -- we're doomed. */ /* * For each cpu, there is one percpu_t and a list of caches @@ -843,10 +798,8 @@ setup_caches(void) new_cpu_list = (percpu_t *)sbrk(cache_space_needed); if (new_cpu_list == (percpu_t *)-1 || - (uintptr_t)new_cpu_list != newbrk) { - (void) mutex_unlock(&init_lock); - return (0); /* someone else sbrked */ - } + (uintptr_t)new_cpu_list != newbrk) + abort(); /* sbrk is broken -- we're doomed. */ /* * Finally, align the brk to HUNKSIZE so that all hunks are @@ -857,10 +810,8 @@ setup_caches(void) padding = ALIGN(newbrk, HUNKSIZE) - newbrk; - if (padding > 0 && (uintptr_t)sbrk(padding) != newbrk) { - (void) mutex_unlock(&init_lock); - return (0); /* someone else sbrked */ - } + if (padding > 0 && (uintptr_t)sbrk(padding) != newbrk) + abort(); /* sbrk is broken -- we're doomed. */ list_addr = ((uintptr_t)new_cpu_list + (sizeof (percpu_t) * ncpus)); @@ -872,7 +823,8 @@ setup_caches(void) new_cpu_list[i].mt_caches[j].mt_hint = NULL; } - bzero(&new_cpu_list[i].mt_parent_lock, sizeof (mutex_t)); + (void) mutex_init(&new_cpu_list[i].mt_parent_lock, + USYNC_THREAD, NULL); /* get the correct cache list alignment */ list_addr += CACHELIST_SIZE; @@ -889,16 +841,11 @@ setup_caches(void) oversize_list.size = 0; /* sentinal */ /* - * now install the global variables, leaving cpu_list for last, so that - * there aren't any race conditions. + * Now install the global variables. */ curcpu = new_curcpu; cpu_mask = new_cpu_mask; cpu_list = new_cpu_list; - - (void) mutex_unlock(&init_lock); - - return (1); } static void @@ -906,7 +853,7 @@ create_cache(cache_t *cp, size_t size, uint_t chunksize) { long nblocks; - bzero(&cp->mt_cache_lock, sizeof (mutex_t)); + (void) mutex_init(&cp->mt_cache_lock, USYNC_THREAD, NULL); cp->mt_size = size; cp->mt_freelist = ((caddr_t)cp + sizeof (cache_t)); cp->mt_span = chunksize * HUNKSIZE - sizeof (cache_t); @@ -958,11 +905,6 @@ reinit_cpu_list(void) cache_t *thiscache; cache_head_t *cachehead; - if (wp == NULL || cpu_list == NULL) { - reinit = 0; - return; - } - /* Reinitialize free oversize blocks. */ (void) mutex_lock(&oversize_lock); if (debugopt & MTDEBUGPATTERN) @@ -1516,3 +1458,70 @@ oversize_header_alloc(uintptr_t mem, size_t size) ovsz_hdr->addr = (caddr_t)mem; return (ovsz_hdr); } + +static void +malloc_prepare() +{ + percpu_t *cpuptr; + cache_head_t *cachehead; + cache_t *thiscache; + + (void) mutex_lock(&oversize_lock); + for (cpuptr = &cpu_list[0]; cpuptr < &cpu_list[ncpus]; cpuptr++) { + (void) mutex_lock(&cpuptr->mt_parent_lock); + for (cachehead = &cpuptr->mt_caches[0]; + cachehead < &cpuptr->mt_caches[NUM_CACHES]; + cachehead++) { + for (thiscache = cachehead->mt_cache; + thiscache != NULL; + thiscache = thiscache->mt_next) { + (void) mutex_lock( + &thiscache->mt_cache_lock); + } + } + } +} + +static void +malloc_release() +{ + percpu_t *cpuptr; + cache_head_t *cachehead; + cache_t *thiscache; + + for (cpuptr = &cpu_list[ncpus - 1]; cpuptr >= &cpu_list[0]; cpuptr--) { + for (cachehead = &cpuptr->mt_caches[NUM_CACHES - 1]; + cachehead >= &cpuptr->mt_caches[0]; + cachehead--) { + for (thiscache = cachehead->mt_cache; + thiscache != NULL; + thiscache = thiscache->mt_next) { + (void) mutex_unlock( + &thiscache->mt_cache_lock); + } + } + (void) mutex_unlock(&cpuptr->mt_parent_lock); + } + (void) mutex_unlock(&oversize_lock); +} + +#pragma init(malloc_init) +static void +malloc_init(void) +{ + /* + * This works in the init section for this library + * because setup_caches() doesn't call anything in libc + * that calls malloc(). If it did, disaster would ensue. + * + * For this to work properly, this library must be the first + * one to have its init section called (after libc) by the + * dynamic linker. If some other library's init section + * ran first and called malloc(), disaster would ensue. + * Because this is an interposer library for malloc(), the + * dynamic linker arranges for its init section to run first. + */ + (void) setup_caches(); + + (void) pthread_atfork(malloc_prepare, malloc_release, malloc_release); +} |