On Mon, Mar 28, 2016 at 11:27:32AM +0200, Otto Moerbeek wrote: > On Wed, Mar 23, 2016 at 08:00:19AM +0100, Otto Moerbeek wrote: > > > Hi, > > > > first diff that seems to work. Tested on amd64 and compile tested on > > sparc64. > > > > It is alo available at http://www.drijf.net/openbsd/malloc > > > > Form the README: > > > > The diff should be applied while in /usr/src/lib, it will patch > > both librthreads as as well as libc. > > > > THIS IS WORK IN PROGRESS. It contains multiple things that should > > be improved. To name a few things: > > > > - Curently fixed at 4 pools with a fixed thread -> pool mapping. > > - All pools are always initialized, even for single threaded programs, where > > only one pool is used. > > - Especially realloc gets quite a bit uglier. > > - I'm pondering storing the thread -> pool mapping in the thread > > struct instead of computing it each time from the tcb address. > > > > -Otto > > > > Second diff. Only one person (Stefan Kempf, thanks!) gave feedback... > > A race condition was fixed in the init code. But there remain race > problems in the init code. I will be working on that the coming time. > > Please be aware that to make this code ready for commit, I need > feedback/tests/reviews. There's no way this code will end up in the tree > without those. > > -Otto >
Been running this in a VM since this weekend, no issues seen. (amd64). -ml > > Index: libc/include/thread_private.h > =================================================================== > RCS file: /cvs/src/lib/libc/include/thread_private.h,v > retrieving revision 1.26 > diff -u -p -r1.26 thread_private.h > --- libc/include/thread_private.h 7 Apr 2015 01:27:07 -0000 1.26 > +++ libc/include/thread_private.h 28 Mar 2016 08:22:31 -0000 > @@ -17,6 +17,8 @@ > */ > extern int __isthreaded; > > +#define _MALLOC_MUTEXES 4 > + > /* > * Weak symbols are used in libc so that the thread library can > * efficiently wrap libc functions. > @@ -136,16 +138,16 @@ extern void *__THREAD_NAME(serv_mutex); > /* > * malloc lock/unlock prototypes and definitions > */ > -void _thread_malloc_lock(void); > -void _thread_malloc_unlock(void); > +void _thread_malloc_lock(int); > +void _thread_malloc_unlock(int); > > -#define _MALLOC_LOCK() do { > \ > +#define _MALLOC_LOCK(n) do { > \ > if (__isthreaded) \ > - _thread_malloc_lock(); \ > + _thread_malloc_lock(n); \ > } while (0) > -#define _MALLOC_UNLOCK() do { \ > +#define _MALLOC_UNLOCK(n) do { \ > if (__isthreaded) \ > - _thread_malloc_unlock();\ > + _thread_malloc_unlock(n);\ > } while (0) > > void _thread_atexit_lock(void); > Index: libc/stdlib/malloc.c > =================================================================== > RCS file: /cvs/src/lib/libc/stdlib/malloc.c,v > retrieving revision 1.185 > diff -u -p -r1.185 malloc.c > --- libc/stdlib/malloc.c 17 Mar 2016 17:55:33 -0000 1.185 > +++ libc/stdlib/malloc.c 28 Mar 2016 08:22:31 -0000 > @@ -1,6 +1,6 @@ > /* $OpenBSD: malloc.c,v 1.185 2016/03/17 17:55:33 mmcc Exp $ */ > /* > - * Copyright (c) 2008, 2010, 2011 Otto Moerbeek <o...@drijf.net> > + * Copyright (c) 2008, 2010, 2011, 2016 Otto Moerbeek <o...@drijf.net> > * Copyright (c) 2012 Matthew Dempsky <matt...@openbsd.org> > * Copyright (c) 2008 Damien Miller <d...@openbsd.org> > * Copyright (c) 2000 Poul-Henning Kamp <p...@freebsd.org> > @@ -43,6 +43,7 @@ > #endif > > #include "thread_private.h" > +#include <machine/tcb.h> > > #if defined(__sparc__) && !defined(__sparcv9__) > #define MALLOC_PAGESHIFT (13U) > @@ -95,10 +96,10 @@ > > #define _MALLOC_LEAVE(d) do { if (__isthreaded) { \ > (d)->active--; \ > - _MALLOC_UNLOCK(); } \ > + _MALLOC_UNLOCK(d->mutex); } \ > } while (0) > #define _MALLOC_ENTER(d) do { if (__isthreaded) { \ > - _MALLOC_LOCK(); \ > + _MALLOC_LOCK(d->mutex); \ > (d)->active++; } \ > } while (0) > > @@ -129,6 +130,7 @@ struct dir_info { > void *delayed_chunks[MALLOC_DELAYED_CHUNK_MASK + 1]; > size_t rbytesused; /* random bytes used */ > char *func; /* current function */ > + int mutex; > u_char rbytes[32]; /* random bytes */ > u_short chunk_start; > #ifdef MALLOC_STATS > @@ -178,7 +180,7 @@ struct chunk_info { > }; > > struct malloc_readonly { > - struct dir_info *malloc_pool; /* Main bookkeeping information */ > + struct dir_info *malloc_pool[_MALLOC_MUTEXES]; /* Main bookkeeping > information */ > int malloc_freenow; /* Free quickly - disable chunk rnd */ > int malloc_freeunmap; /* mprotect free pages PROT_NONE? */ > int malloc_hint; /* call madvice on free pages? */ > @@ -202,14 +204,13 @@ static union { > u_char _pad[MALLOC_PAGESIZE]; > } malloc_readonly __attribute__((aligned(MALLOC_PAGESIZE))); > #define mopts malloc_readonly.mopts > -#define getpool() mopts.malloc_pool > > char *malloc_options; /* compile-time options */ > > static u_char getrbyte(struct dir_info *d); > > #ifdef MALLOC_STATS > -void malloc_dump(int); > +void malloc_dump(int, struct dir_info *); > PROTO_NORMAL(malloc_dump); > static void malloc_exit(void); > #define CALLER __builtin_return_address(0) > @@ -240,6 +241,18 @@ hash(void *p) > return sum; > } > > +static inline > +struct dir_info *getpool(void) > +{ > + //return mopts.malloc_pool[0]; > + if (!__isthreaded) > + return mopts.malloc_pool[0]; > + else > + return mopts.malloc_pool[hash(TCB_GET()) & > + (_MALLOC_MUTEXES - 1)]; > +} > + > + > static void > wrterror(struct dir_info *d, char *msg, void *p) > { > @@ -247,7 +260,7 @@ wrterror(struct dir_info *d, char *msg, > struct iovec iov[7]; > char pidbuf[20]; > char buf[20]; > - int saved_errno = errno; > + int saved_errno = errno, i; > > iov[0].iov_base = __progname; > iov[0].iov_len = strlen(__progname); > @@ -278,7 +291,8 @@ wrterror(struct dir_info *d, char *msg, > > #ifdef MALLOC_STATS > if (mopts.malloc_stats) > - malloc_dump(STDERR_FILENO); > + for (i = 0; i < _MALLOC_MUTEXES; i++) > + malloc_dump(STDERR_FILENO, mopts.malloc_pool[i]); > #endif /* MALLOC_STATS */ > > errno = saved_errno; > @@ -565,16 +579,11 @@ omalloc_parseopt(char opt) > } > } > > -/* > - * Initialize a dir_info, which should have been cleared by caller > - */ > -static int > -omalloc_init(struct dir_info **dp) > +static void > +omalloc_init(void) > { > char *p, *q, b[64]; > int i, j; > - size_t d_avail, regioninfo_size; > - struct dir_info *d; > > /* > * Default options > @@ -637,6 +646,18 @@ omalloc_init(struct dir_info **dp) > > arc4random_buf(&mopts.malloc_chunk_canary, > sizeof(mopts.malloc_chunk_canary)); > +} > + > +/* > + * Initialize a dir_info, which should have been cleared by caller > + */ > +static int > +omalloc_poolinit(struct dir_info **dp) > +{ > + void *p; > + size_t d_avail, regioninfo_size; > + struct dir_info *d; > + int i, j; > > /* > * Allocate dir_info with a guard page on either side. Also > @@ -644,7 +665,7 @@ omalloc_init(struct dir_info **dp) > * lies (subject to alignment by 1 << MALLOC_MINSHIFT) > */ > if ((p = MMAP(DIR_INFO_RSZ + (MALLOC_PAGESIZE * 2))) == MAP_FAILED) > - return -1; > + return 1; > mprotect(p, MALLOC_PAGESIZE, PROT_NONE); > mprotect(p + MALLOC_PAGESIZE + DIR_INFO_RSZ, > MALLOC_PAGESIZE, PROT_NONE); > @@ -672,13 +693,6 @@ omalloc_init(struct dir_info **dp) > > *dp = d; > > - /* > - * Options have been set and will never be reset. > - * Prevent further tampering with them. > - */ > - if (((uintptr_t)&malloc_readonly & MALLOC_PAGEMASK) == 0) > - mprotect(&malloc_readonly, sizeof(malloc_readonly), PROT_READ); > - > return 0; > } > > @@ -1174,20 +1188,41 @@ malloc_recurse(struct dir_info *d) > wrterror(d, "recursive call", NULL); > } > d->active--; > - _MALLOC_UNLOCK(); > + _MALLOC_UNLOCK(d->mutex); > errno = EDEADLK; > } > > static int > malloc_init(void) > { > - if (omalloc_init(&mopts.malloc_pool)) { > - _MALLOC_UNLOCK(); > - if (mopts.malloc_xmalloc) > - wrterror(NULL, "out of memory", NULL); > - errno = ENOMEM; > - return -1; > + int i; > + struct dir_info *d; > + > + _MALLOC_LOCK(0); > + if (mopts.malloc_pool[0]) { > + _MALLOC_UNLOCK(0); > + return 0; > + } > + omalloc_init(); > + for (i = 0; i < _MALLOC_MUTEXES; i++) { > + if (omalloc_poolinit(&d)) { > + _MALLOC_UNLOCK(0); > + if (mopts.malloc_xmalloc) > + wrterror(NULL, "out of memory", NULL); > + errno = ENOMEM; > + return -1; > + } > + d->mutex = i; > + mopts.malloc_pool[i] = d; > } > + > + /* > + * Options have been set and will never be reset. > + * Prevent further tampering with them. > + */ > + if (((uintptr_t)&malloc_readonly & MALLOC_PAGEMASK) == 0) > + mprotect(&malloc_readonly, sizeof(malloc_readonly), PROT_READ); > + _MALLOC_UNLOCK(0); > return 0; > } > > @@ -1198,13 +1233,13 @@ malloc(size_t size) > struct dir_info *d; > int saved_errno = errno; > > - _MALLOC_LOCK(); > d = getpool(); > if (d == NULL) { > if (malloc_init() != 0) > return NULL; > d = getpool(); > } > + _MALLOC_LOCK(d->mutex); > d->func = "malloc():"; > > if (d->active++) { > @@ -1215,7 +1250,7 @@ malloc(size_t size) > size += mopts.malloc_canaries; > r = omalloc(d, size, 0, CALLER); > d->active--; > - _MALLOC_UNLOCK(); > + _MALLOC_UNLOCK(d->mutex); > if (r == NULL && mopts.malloc_xmalloc) { > wrterror(d, "out of memory", NULL); > errno = ENOMEM; > @@ -1252,23 +1287,41 @@ validate_junk(struct dir_info *pool, voi > } > > static void > -ofree(struct dir_info *pool, void *p) > +ofree(struct dir_info *argpool, void *p) > { > + struct dir_info *pool; > struct region_info *r; > size_t sz; > + int i; > > + pool = argpool; > r = find(pool, p); > if (r == NULL) { > - wrterror(pool, "bogus pointer (double free?)", p); > - return; > + for (i = 0; i < _MALLOC_MUTEXES; i++) { > + if (i == pool->mutex) > + continue; > + pool->active--; > + _MALLOC_UNLOCK(pool->mutex); > + pool = mopts.malloc_pool[i]; > + _MALLOC_LOCK(pool->mutex); > + pool->active++; > + r = find(pool, p); > + if (r != NULL) > + break; > + } > + if (r == NULL) { > + wrterror(pool, "bogus pointer (double free?)", p); > + goto done; > + } > } > + > REALSIZE(sz, r); > if (sz > MALLOC_MAXCHUNK) { > if (sz - mopts.malloc_guard >= MALLOC_PAGESIZE - > MALLOC_LEEWAY) { > if (r->p != p) { > wrterror(pool, "bogus pointer", p); > - return; > + goto done; > } > } else { > #if notyetbecause_of_realloc > @@ -1306,13 +1359,13 @@ ofree(struct dir_info *pool, void *p) > memset(p, SOME_FREEJUNK, sz - mopts.malloc_canaries); > if (!mopts.malloc_freenow) { > if (find_chunknum(pool, r, p) == -1) > - return; > + goto done; > i = getrbyte(pool) & MALLOC_DELAYED_CHUNK_MASK; > tmp = p; > p = pool->delayed_chunks[i]; > if (tmp == p) { > wrterror(pool, "double free", p); > - return; > + goto done; > } > if (mopts.malloc_junk) > validate_junk(pool, p); > @@ -1322,11 +1375,18 @@ ofree(struct dir_info *pool, void *p) > r = find(pool, p); > if (r == NULL) { > wrterror(pool, "bogus pointer (double free?)", > p); > - return; > + goto done; > } > free_bytes(pool, r, p); > } > } > +done: > + if (argpool != pool) { > + pool->active--; > + _MALLOC_UNLOCK(pool->mutex); > + _MALLOC_LOCK(argpool->mutex); > + argpool->active++; > + } > } > > void > @@ -1339,13 +1399,12 @@ free(void *ptr) > if (ptr == NULL) > return; > > - _MALLOC_LOCK(); > d = getpool(); > if (d == NULL) { > - _MALLOC_UNLOCK(); > wrterror(d, "free() called before allocation", NULL); > return; > } > + _MALLOC_LOCK(d->mutex); > d->func = "free():"; > if (d->active++) { > malloc_recurse(d); > @@ -1353,30 +1412,50 @@ free(void *ptr) > } > ofree(d, ptr); > d->active--; > - _MALLOC_UNLOCK(); > + _MALLOC_UNLOCK(d->mutex); > errno = saved_errno; > } > /*DEF_STRONG(free);*/ > > > static void * > -orealloc(struct dir_info *pool, void *p, size_t newsz, void *f) > +orealloc(struct dir_info *argpool, void *p, size_t newsz, void *f) > { > + struct dir_info *pool; > struct region_info *r; > size_t oldsz, goldsz, gnewsz; > - void *q; > + void *q, *ret; > + int i; > + > + pool = argpool; > > if (p == NULL) > return omalloc(pool, newsz, 0, f); > > r = find(pool, p); > if (r == NULL) { > - wrterror(pool, "bogus pointer (double free?)", p); > - return NULL; > + for (i = 0; i < _MALLOC_MUTEXES; i++) { > + if (i == pool->mutex) > + continue; > + pool->active--; > + _MALLOC_UNLOCK(pool->mutex); > + pool = mopts.malloc_pool[i]; > + _MALLOC_LOCK(pool->mutex); > + pool->active++; > + r = find(pool, p); > + if (r != NULL) > + break; > + } > + if (r == NULL) { > + wrterror(pool, "bogus pointer (double free?)", p); > + ret = NULL; > + goto done; > + } > } > if (newsz >= SIZE_MAX - mopts.malloc_guard - MALLOC_PAGESIZE) { > errno = ENOMEM; > - return NULL; > + ret = NULL; > + goto done; > } > > REALSIZE(oldsz, r); > @@ -1419,7 +1498,8 @@ gotit: > r->size = newsz; > STATS_SETF(r, f); > STATS_INC(pool->cheap_reallocs); > - return p; > + ret = p; > + goto done; > } else if (q != MAP_FAILED) { > if (munmap(q, needed)) > wrterror(pool, "munmap", q); > @@ -1439,14 +1519,16 @@ gotit: > unmap(pool, (char *)p + rnewsz, roldsz - rnewsz); > r->size = gnewsz; > STATS_SETF(r, f); > - return p; > + ret = p; > + goto done; > } else { > if (newsz > oldsz && mopts.malloc_junk == 2) > memset((char *)p + newsz, SOME_JUNK, > rnewsz - mopts.malloc_guard - newsz); > r->size = gnewsz; > STATS_SETF(r, f); > - return p; > + ret = p; > + goto done; > } > } > if (newsz <= oldsz && newsz > oldsz / 2 && !mopts.malloc_realloc) { > @@ -1458,11 +1540,13 @@ gotit: > memset((char *)p + newsz, SOME_JUNK, > usable_oldsz - newsz); > } > STATS_SETF(r, f); > - return p; > + ret = p; > } else if (newsz != oldsz || mopts.malloc_realloc) { > q = omalloc(pool, newsz, 0, f); > - if (q == NULL) > - return NULL; > + if (q == NULL) { > + ret = NULL; > + goto done; > + } > if (newsz != 0 && oldsz != 0) { > size_t copysz = oldsz < newsz ? oldsz : newsz; > if (copysz <= MALLOC_MAXCHUNK) > @@ -1470,11 +1554,19 @@ gotit: > memcpy(q, p, copysz); > } > ofree(pool, p); > - return q; > + ret = q; > } else { > STATS_SETF(r, f); > - return p; > + ret = p; > + } > +done: > + if (argpool != pool) { > + pool->active--; > + _MALLOC_UNLOCK(pool->mutex); > + _MALLOC_LOCK(argpool->mutex); > + argpool->active++; > } > + return ret; > } > > void * > @@ -1484,13 +1576,13 @@ realloc(void *ptr, size_t size) > void *r; > int saved_errno = errno; > > - _MALLOC_LOCK(); > d = getpool(); > if (d == NULL) { > if (malloc_init() != 0) > return NULL; > d = getpool(); > } > + _MALLOC_LOCK(d->mutex); > d->func = "realloc():"; > if (d->active++) { > malloc_recurse(d); > @@ -1501,7 +1593,7 @@ realloc(void *ptr, size_t size) > r = orealloc(d, ptr, size, CALLER); > > d->active--; > - _MALLOC_UNLOCK(); > + _MALLOC_UNLOCK(d->mutex); > if (r == NULL && mopts.malloc_xmalloc) { > wrterror(d, "out of memory", NULL); > errno = ENOMEM; > @@ -1526,17 +1618,17 @@ calloc(size_t nmemb, size_t size) > void *r; > int saved_errno = errno; > > - _MALLOC_LOCK(); > d = getpool(); > if (d == NULL) { > if (malloc_init() != 0) > return NULL; > d = getpool(); > } > + _MALLOC_LOCK(d->mutex); > d->func = "calloc():"; > if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && > nmemb > 0 && SIZE_MAX / nmemb < size) { > - _MALLOC_UNLOCK(); > + _MALLOC_UNLOCK(d->mutex); > if (mopts.malloc_xmalloc) > wrterror(d, "out of memory", NULL); > errno = ENOMEM; > @@ -1554,7 +1646,7 @@ calloc(size_t nmemb, size_t size) > r = omalloc(d, size, 1, CALLER); > > d->active--; > - _MALLOC_UNLOCK(); > + _MALLOC_UNLOCK(d->mutex); > if (r == NULL && mopts.malloc_xmalloc) { > wrterror(d, "out of memory", NULL); > errno = ENOMEM; > @@ -1668,13 +1760,13 @@ posix_memalign(void **memptr, size_t ali > if (((alignment - 1) & alignment) != 0 || alignment < sizeof(void *)) > return EINVAL; > > - _MALLOC_LOCK(); > d = getpool(); > if (d == NULL) { > if (malloc_init() != 0) > goto err; > d = getpool(); > } > + _MALLOC_LOCK(d->mutex); > d->func = "posix_memalign():"; > if (d->active++) { > malloc_recurse(d); > @@ -1684,7 +1776,7 @@ posix_memalign(void **memptr, size_t ali > size += mopts.malloc_canaries; > r = omemalign(d, alignment, size, 0, CALLER); > d->active--; > - _MALLOC_UNLOCK(); > + _MALLOC_UNLOCK(d->mutex); > if (r == NULL) { > if (mopts.malloc_xmalloc) { > wrterror(d, "out of memory", NULL); > @@ -1923,9 +2015,8 @@ malloc_dump1(int fd, struct dir_info *d) > } > > void > -malloc_dump(int fd) > +malloc_dump(int fd, struct dir_info *pool) > { > - struct dir_info *pool = getpool(); > int i; > void *p; > struct region_info *r; > @@ -1956,11 +2047,12 @@ static void > malloc_exit(void) > { > static const char q[] = "malloc() warning: Couldn't dump stats\n"; > - int save_errno = errno, fd; > + int save_errno = errno, fd, i; > > fd = open("malloc.out", O_RDWR|O_APPEND); > if (fd != -1) { > - malloc_dump(fd); > + for (i = 0; i < _MALLOC_MUTEXES; i++) > + malloc_dump(fd, mopts.malloc_pool[i]); > close(fd); > } else > write(STDERR_FILENO, q, sizeof(q) - 1); > Index: libc/thread/unithread_malloc_lock.c > =================================================================== > RCS file: /cvs/src/lib/libc/thread/unithread_malloc_lock.c,v > retrieving revision 1.9 > diff -u -p -r1.9 unithread_malloc_lock.c > --- libc/thread/unithread_malloc_lock.c 7 Apr 2015 01:27:07 -0000 > 1.9 > +++ libc/thread/unithread_malloc_lock.c 28 Mar 2016 08:22:31 -0000 > @@ -28,13 +28,13 @@ WEAK_ALIAS(_thread_arc4_lock); > WEAK_ALIAS(_thread_arc4_unlock); > > void > -WEAK_NAME(_thread_malloc_lock)(void) > +WEAK_NAME(_thread_malloc_lock)(int n) > { > return; > } > > void > -WEAK_NAME(_thread_malloc_unlock)(void) > +WEAK_NAME(_thread_malloc_unlock)(int n) > { > return; > } > Index: librthread/rthread_fork.c > =================================================================== > RCS file: /cvs/src/lib/librthread/rthread_fork.c,v > retrieving revision 1.15 > diff -u -p -r1.15 rthread_fork.c > --- librthread/rthread_fork.c 27 Jan 2016 08:40:05 -0000 1.15 > +++ librthread/rthread_fork.c 28 Mar 2016 08:22:31 -0000 > @@ -55,6 +55,7 @@ _dofork(int is_vfork) > pthread_t me; > pid_t (*sys_fork)(void); > pid_t newid; > + int i; > > sys_fork = is_vfork ? &_thread_sys_vfork : &_thread_sys_fork; > > @@ -76,7 +77,8 @@ _dofork(int is_vfork) > #endif > > _thread_atexit_lock(); > - _thread_malloc_lock(); > + for (i = 0; i < _MALLOC_MUTEXES; i++) > + _thread_malloc_lock(i); > _thread_arc4_lock(); > > newid = sys_fork(); > @@ -85,7 +87,8 @@ _dofork(int is_vfork) > if (newid == 0) > _thread_malloc_reinit(); > else > - _thread_malloc_unlock(); > + for (i = 0; i < _MALLOC_MUTEXES; i++) > + _thread_malloc_unlock(i); > _thread_atexit_unlock(); > > if (newid == 0) { > Index: librthread/rthread_libc.c > =================================================================== > RCS file: /cvs/src/lib/librthread/rthread_libc.c,v > retrieving revision 1.13 > diff -u -p -r1.13 rthread_libc.c > --- librthread/rthread_libc.c 27 Jan 2016 08:40:05 -0000 1.13 > +++ librthread/rthread_libc.c 28 Mar 2016 08:22:31 -0000 > @@ -152,35 +152,50 @@ _thread_mutex_destroy(void **mutex) > /* > * the malloc lock > */ > -static struct pthread_mutex malloc_lock = { > - _SPINLOCK_UNLOCKED, > - TAILQ_HEAD_INITIALIZER(malloc_lock.lockers), > - PTHREAD_MUTEX_DEFAULT, > - NULL, > - 0, > - -1 > +#define MALLOC_LOCK_INITIALZER(n) { \ > + _SPINLOCK_UNLOCKED, \ > + TAILQ_HEAD_INITIALIZER(malloc_lock[n].lockers), \ > + PTHREAD_MUTEX_DEFAULT, \ > + NULL, \ > + 0, \ > + -1 } \ > + > +static struct pthread_mutex malloc_lock[_MALLOC_MUTEXES] = { > + MALLOC_LOCK_INITIALZER(0), > + MALLOC_LOCK_INITIALZER(1), > + MALLOC_LOCK_INITIALZER(2), > + MALLOC_LOCK_INITIALZER(3) > +}; > +static pthread_mutex_t malloc_mutex[_MALLOC_MUTEXES] = { > + &malloc_lock[0], > + &malloc_lock[1], > + &malloc_lock[2], > + &malloc_lock[3] > }; > -static pthread_mutex_t malloc_mutex = &malloc_lock; > > void > -_thread_malloc_lock(void) > +_thread_malloc_lock(int i) > { > - pthread_mutex_lock(&malloc_mutex); > + pthread_mutex_lock(&malloc_mutex[i]); > } > > void > -_thread_malloc_unlock(void) > +_thread_malloc_unlock(int i) > { > - pthread_mutex_unlock(&malloc_mutex); > + pthread_mutex_unlock(&malloc_mutex[i]); > } > > void > _thread_malloc_reinit(void) > { > - malloc_lock.lock = _SPINLOCK_UNLOCKED_ASSIGN; > - TAILQ_INIT(&malloc_lock.lockers); > - malloc_lock.owner = NULL; > - malloc_lock.count = 0; > + int i; > + > + for (i = 0; i < _MALLOC_MUTEXES; i++) { > + malloc_lock[i].lock = _SPINLOCK_UNLOCKED_ASSIGN; > + TAILQ_INIT(&malloc_lock[i].lockers); > + malloc_lock[i].owner = NULL; > + malloc_lock[i].count = 0; > + } > } > > /* >