From 32c6baecf91773ad5419460ffdcf5da2530ddc35 Mon Sep 17 00:00:00 2001 From: otto <> Date: Mon, 14 Mar 2016 17:20:26 +0000 Subject: [PATCH] small step towards multiple pools: move two globls into the struct dir_info ok @stefan armani@ --- src/lib/libc/stdlib/malloc.c | 238 ++++++++++++++++++----------------- 1 file changed, 126 insertions(+), 112 deletions(-) diff --git a/src/lib/libc/stdlib/malloc.c b/src/lib/libc/stdlib/malloc.c index 24b22854..0fa0d39b 100644 --- a/src/lib/libc/stdlib/malloc.c +++ b/src/lib/libc/stdlib/malloc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: malloc.c,v 1.183 2016/03/13 18:34:21 guenther Exp $ */ +/* $OpenBSD: malloc.c,v 1.184 2016/03/14 17:20:26 otto Exp $ */ /* * Copyright (c) 2008, 2010, 2011 Otto Moerbeek * Copyright (c) 2012 Matthew Dempsky @@ -93,13 +93,13 @@ #define MQUERY(a, sz) mquery((a), (size_t)(sz), PROT_READ | PROT_WRITE, \ MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, (off_t)0) -#define _MALLOC_LEAVE() if (__isthreaded) do { \ - malloc_active--; \ +#define _MALLOC_LEAVE(d) if (__isthreaded) do { \ + (d)->active--; \ _MALLOC_UNLOCK(); \ } while (0) -#define _MALLOC_ENTER() if (__isthreaded) do { \ +#define _MALLOC_ENTER(d) if (__isthreaded) do { \ _MALLOC_LOCK(); \ - malloc_active++; \ + (d)->active++; \ } while (0) struct region_info { @@ -114,6 +114,7 @@ LIST_HEAD(chunk_head, chunk_info); struct dir_info { u_int32_t canary1; + int active; /* status of malloc */ struct region_info *r; /* region slots */ size_t regions_total; /* number of region slots */ size_t regions_free; /* number of free slots */ @@ -127,6 +128,7 @@ struct dir_info { /* delayed free chunk slots */ void *delayed_chunks[MALLOC_DELAYED_CHUNK_MASK + 1]; size_t rbytesused; /* random bytes used */ + char *func; /* current function */ u_char rbytes[32]; /* random bytes */ u_short chunk_start; #ifdef MALLOC_STATS @@ -203,8 +205,6 @@ static union { #define getpool() mopts.malloc_pool char *malloc_options; /* compile-time options */ -static char *malloc_func; /* current function */ -static int malloc_active; /* status of malloc */ static u_char getrbyte(struct dir_info *d); @@ -241,7 +241,7 @@ hash(void *p) } static void -wrterror(char *msg, void *p) +wrterror(struct dir_info *d, char *msg, void *p) { char *q = " error: "; struct iovec iov[7]; @@ -254,8 +254,13 @@ wrterror(char *msg, void *p) iov[1].iov_base = pidbuf; snprintf(pidbuf, sizeof(pidbuf), "(%d) in ", getpid()); iov[1].iov_len = strlen(pidbuf); - iov[2].iov_base = malloc_func; - iov[2].iov_len = strlen(malloc_func); + if (d != NULL) { + iov[2].iov_base = d->func; + iov[2].iov_len = strlen(d->func); + } else { + iov[2].iov_base = "unknown"; + iov[2].iov_len = 7; + } iov[3].iov_base = q; iov[3].iov_len = strlen(q); iov[4].iov_base = msg; @@ -316,14 +321,14 @@ unmap(struct dir_info *d, void *p, size_t sz) u_int i, offset; if (sz != PAGEROUND(sz)) { - wrterror("munmap round", NULL); + wrterror(d, "munmap round", NULL); return; } if (psz > mopts.malloc_cache) { i = munmap(p, sz); if (i) - wrterror("munmap", p); + wrterror(d, "munmap", p); STATS_SUB(d->malloc_used, sz); return; } @@ -337,7 +342,7 @@ unmap(struct dir_info *d, void *p, size_t sz) if (r->p != NULL) { rsz = r->size << MALLOC_PAGESHIFT; if (munmap(r->p, rsz)) - wrterror("munmap", r->p); + wrterror(d, "munmap", r->p); r->p = NULL; if (tounmap > r->size) tounmap -= r->size; @@ -349,7 +354,7 @@ unmap(struct dir_info *d, void *p, size_t sz) } } if (tounmap > 0) - wrterror("malloc cache underflow", NULL); + wrterror(d, "malloc cache underflow", NULL); for (i = 0; i < mopts.malloc_cache; i++) { r = &d->free_regions[(i + offset) & (mopts.malloc_cache - 1)]; if (r->p == NULL) { @@ -364,9 +369,9 @@ unmap(struct dir_info *d, void *p, size_t sz) } } if (i == mopts.malloc_cache) - wrterror("malloc free slot lost", NULL); + wrterror(d, "malloc free slot lost", NULL); if (d->free_regions_size > mopts.malloc_cache) - wrterror("malloc cache overflow", NULL); + wrterror(d, "malloc cache overflow", NULL); } static void @@ -381,7 +386,7 @@ zapcacheregion(struct dir_info *d, void *p, size_t len) if (r->p >= p && r->p <= (void *)((char *)p + len)) { rsz = r->size << MALLOC_PAGESHIFT; if (munmap(r->p, rsz)) - wrterror("munmap", r->p); + wrterror(d, "munmap", r->p); r->p = NULL; d->free_regions_size -= r->size; r->size = 0; @@ -400,15 +405,15 @@ map(struct dir_info *d, void *hint, size_t sz, int zero_fill) if (mopts.malloc_canary != (d->canary1 ^ (u_int32_t)(uintptr_t)d) || d->canary1 != ~d->canary2) - wrterror("internal struct corrupt", NULL); + wrterror(d, "internal struct corrupt", NULL); if (sz != PAGEROUND(sz)) { - wrterror("map round", NULL); + wrterror(d, "map round", NULL); return MAP_FAILED; } if (!hint && psz > d->free_regions_size) { - _MALLOC_LEAVE(); + _MALLOC_LEAVE(d); p = MMAP(sz); - _MALLOC_ENTER(); + _MALLOC_ENTER(d); if (p != MAP_FAILED) STATS_ADD(d->malloc_used, sz); /* zero fill not needed */ @@ -458,10 +463,10 @@ map(struct dir_info *d, void *hint, size_t sz, int zero_fill) if (hint) return MAP_FAILED; if (d->free_regions_size > mopts.malloc_cache) - wrterror("malloc cache", NULL); - _MALLOC_LEAVE(); + wrterror(d, "malloc cache", NULL); + _MALLOC_LEAVE(d); p = MMAP(sz); - _MALLOC_ENTER(); + _MALLOC_ENTER(d); if (p != MAP_FAILED) STATS_ADD(d->malloc_used, sz); /* zero fill not needed */ @@ -652,7 +657,7 @@ omalloc_init(struct dir_info **dp) regioninfo_size = d->regions_total * sizeof(struct region_info); d->r = MMAP(regioninfo_size); if (d->r == MAP_FAILED) { - wrterror("malloc init mmap failed", NULL); + wrterror(NULL, "malloc init mmap failed", NULL); d->regions_total = 0; return 1; } @@ -715,7 +720,7 @@ omalloc_grow(struct dir_info *d) } /* avoid pages containing meta info to end up in cache */ if (munmap(d->r, d->regions_total * sizeof(struct region_info))) - wrterror("munmap", d->r); + wrterror(d, "munmap", d->r); else STATS_SUB(d->malloc_used, d->regions_total * sizeof(struct region_info)); @@ -803,7 +808,7 @@ find(struct dir_info *d, void *p) if (mopts.malloc_canary != (d->canary1 ^ (u_int32_t)(uintptr_t)d) || d->canary1 != ~d->canary2) - wrterror("internal struct corrupt", NULL); + wrterror(d, "internal struct corrupt", NULL); p = MASK_POINTER(p); index = hash(p) & mask; r = d->r[index].p; @@ -826,9 +831,9 @@ delete(struct dir_info *d, struct region_info *ri) size_t i, j, r; if (d->regions_total & (d->regions_total - 1)) - wrterror("regions_total not 2^x", NULL); + wrterror(d, "regions_total not 2^x", NULL); d->regions_free++; - STATS_INC(getpool()->deletes); + STATS_INC(d->deletes); i = ri - d->r; for (;;) { @@ -844,7 +849,7 @@ delete(struct dir_info *d, struct region_info *ri) (j < i && i <= r)) continue; d->r[j] = d->r[i]; - STATS_INC(getpool()->delete_moves); + STATS_INC(d->delete_moves); break; } @@ -910,7 +915,7 @@ omalloc_make_chunks(struct dir_info *d, int bits, int listnum) bits++; if ((uintptr_t)pp & bits) - wrterror("pp & bits", pp); + wrterror(d, "pp & bits", pp); insert(d, (void *)((uintptr_t)pp | bits), (uintptr_t)bp, NULL); return bp; @@ -930,7 +935,7 @@ malloc_bytes(struct dir_info *d, size_t size, void *f) if (mopts.malloc_canary != (d->canary1 ^ (u_int32_t)(uintptr_t)d) || d->canary1 != ~d->canary2) - wrterror("internal struct corrupt", NULL); + wrterror(d, "internal struct corrupt", NULL); /* Don't bother with anything less than this */ /* unless we have a malloc(0) requests */ if (size != 0 && size < MALLOC_MINSIZE) @@ -955,7 +960,7 @@ malloc_bytes(struct dir_info *d, size_t size, void *f) } if (bp->canary != d->canary1) - wrterror("chunk info corrupted", NULL); + wrterror(d, "chunk info corrupted", NULL); i = d->chunk_start; if (bp->free > 1) @@ -1018,25 +1023,25 @@ find_chunknum(struct dir_info *d, struct region_info *r, void *ptr) info = (struct chunk_info *)r->size; if (info->canary != d->canary1) - wrterror("chunk info corrupted", NULL); + wrterror(d, "chunk info corrupted", NULL); if (mopts.malloc_canaries && info->size > 0) { char *end = (char *)ptr + info->size; uintptr_t *canary = (uintptr_t *)(end - mopts.malloc_canaries); if (*canary != (mopts.malloc_chunk_canary ^ hash(canary))) - wrterror("chunk canary corrupted", ptr); + wrterror(d, "chunk canary corrupted", ptr); } /* Find the chunk number on the page */ chunknum = ((uintptr_t)ptr & MALLOC_PAGEMASK) >> info->shift; if ((uintptr_t)ptr & ((1U << (info->shift)) - 1)) { - wrterror("modified chunk-pointer", ptr); + wrterror(d, "modified chunk-pointer", ptr); return -1; } if (info->bits[chunknum / MALLOC_BITS] & (1U << (chunknum % MALLOC_BITS))) { - wrterror("chunk is already free", ptr); + wrterror(d, "chunk is already free", ptr); return -1; } return chunknum; @@ -1092,9 +1097,8 @@ free_bytes(struct dir_info *d, struct region_info *r, void *ptr) static void * -omalloc(size_t sz, int zero_fill, void *f) +omalloc(struct dir_info *pool, size_t sz, int zero_fill, void *f) { - struct dir_info *pool = getpool(); void *p; size_t psz; @@ -1118,7 +1122,7 @@ omalloc(size_t sz, int zero_fill, void *f) if (mopts.malloc_guard) { if (mprotect((char *)p + psz - mopts.malloc_guard, mopts.malloc_guard, PROT_NONE)) - wrterror("mprotect", NULL); + wrterror(pool, "mprotect", NULL); STATS_ADD(pool->malloc_guarded, mopts.malloc_guard); } @@ -1161,15 +1165,15 @@ omalloc(size_t sz, int zero_fill, void *f) * potentially worse. */ static void -malloc_recurse(void) +malloc_recurse(struct dir_info *d) { static int noprint; if (noprint == 0) { noprint = 1; - wrterror("recursive call", NULL); + wrterror(d, "recursive call", NULL); } - malloc_active--; + d->active--; _MALLOC_UNLOCK(); errno = EDEADLK; } @@ -1180,7 +1184,7 @@ malloc_init(void) if (omalloc_init(&mopts.malloc_pool)) { _MALLOC_UNLOCK(); if (mopts.malloc_xmalloc) - wrterror("out of memory", NULL); + wrterror(NULL, "out of memory", NULL); errno = ENOMEM; return -1; } @@ -1191,26 +1195,29 @@ void * malloc(size_t size) { void *r; + struct dir_info *d; int saved_errno = errno; _MALLOC_LOCK(); - malloc_func = "malloc():"; - if (getpool() == NULL) { + d = getpool(); + if (d == NULL) { if (malloc_init() != 0) return NULL; + d = getpool(); } + d->func = "malloc():"; - if (malloc_active++) { - malloc_recurse(); + if (d->active++) { + malloc_recurse(d); return NULL; } if (size > 0 && size <= MALLOC_MAXCHUNK) size += mopts.malloc_canaries; - r = omalloc(size, 0, CALLER); - malloc_active--; + r = omalloc(d, size, 0, CALLER); + d->active--; _MALLOC_UNLOCK(); if (r == NULL && mopts.malloc_xmalloc) { - wrterror("out of memory", NULL); + wrterror(d, "out of memory", NULL); errno = ENOMEM; } if (r != NULL) @@ -1220,16 +1227,15 @@ malloc(size_t size) /*DEF_STRONG(malloc);*/ static void -validate_junk(void *p) { +validate_junk(struct dir_info *pool, void *p) { struct region_info *r; - struct dir_info *pool = getpool(); size_t byte, sz; if (p == NULL) return; r = find(pool, p); if (r == NULL) { - wrterror("bogus pointer in validate_junk", p); + wrterror(pool, "bogus pointer in validate_junk", p); return; } REALSIZE(sz, r); @@ -1239,22 +1245,21 @@ validate_junk(void *p) { sz = 32; for (byte = 0; byte < sz; byte++) { if (((unsigned char *)p)[byte] != SOME_FREEJUNK) { - wrterror("use after free", p); + wrterror(pool, "use after free", p); return; } } } static void -ofree(void *p) +ofree(struct dir_info *pool, void *p) { - struct dir_info *pool = getpool(); struct region_info *r; size_t sz; r = find(pool, p); if (r == NULL) { - wrterror("bogus pointer (double free?)", p); + wrterror(pool, "bogus pointer (double free?)", p); return; } REALSIZE(sz, r); @@ -1262,7 +1267,7 @@ ofree(void *p) if (sz - mopts.malloc_guard >= MALLOC_PAGESIZE - MALLOC_LEEWAY) { if (r->p != p) { - wrterror("bogus pointer", p); + wrterror(pool, "bogus pointer", p); return; } } else { @@ -1277,12 +1282,12 @@ ofree(void *p) } if (mopts.malloc_guard) { if (sz < mopts.malloc_guard) - wrterror("guard size", NULL); + wrterror(pool, "guard size", NULL); if (!mopts.malloc_freeunmap) { if (mprotect((char *)p + PAGEROUND(sz) - mopts.malloc_guard, mopts.malloc_guard, PROT_READ | PROT_WRITE)) - wrterror("mprotect", NULL); + wrterror(pool, "mprotect", NULL); } STATS_SUB(pool->malloc_guarded, mopts.malloc_guard); } @@ -1306,17 +1311,17 @@ ofree(void *p) tmp = p; p = pool->delayed_chunks[i]; if (tmp == p) { - wrterror("double free", p); + wrterror(pool, "double free", p); return; } if (mopts.malloc_junk) - validate_junk(p); + validate_junk(pool, p); pool->delayed_chunks[i] = tmp; } if (p != NULL) { r = find(pool, p); if (r == NULL) { - wrterror("bogus pointer (double free?)", p); + wrterror(pool, "bogus pointer (double free?)", p); return; } free_bytes(pool, r, p); @@ -1327,6 +1332,7 @@ ofree(void *p) void free(void *ptr) { + struct dir_info *d; int saved_errno = errno; /* This is legal. */ @@ -1334,18 +1340,19 @@ free(void *ptr) return; _MALLOC_LOCK(); - malloc_func = "free():"; - if (getpool() == NULL) { + d = getpool(); + if (d == NULL) { _MALLOC_UNLOCK(); - wrterror("free() called before allocation", NULL); + wrterror(d, "free() called before allocation", NULL); return; } - if (malloc_active++) { - malloc_recurse(); + d->func = "free():"; + if (d->active++) { + malloc_recurse(d); return; } - ofree(ptr); - malloc_active--; + ofree(d, ptr); + d->active--; _MALLOC_UNLOCK(); errno = saved_errno; } @@ -1353,19 +1360,18 @@ free(void *ptr) static void * -orealloc(void *p, size_t newsz, void *f) +orealloc(struct dir_info *pool, void *p, size_t newsz, void *f) { - struct dir_info *pool = getpool(); struct region_info *r; size_t oldsz, goldsz, gnewsz; void *q; if (p == NULL) - return omalloc(newsz, 0, f); + return omalloc(pool, newsz, 0, f); r = find(pool, p); if (r == NULL) { - wrterror("bogus pointer (double free?)", p); + wrterror(pool, "bogus pointer (double free?)", p); return NULL; } if (newsz >= SIZE_MAX - mopts.malloc_guard - MALLOC_PAGESIZE) { @@ -1377,7 +1383,7 @@ orealloc(void *p, size_t newsz, void *f) goldsz = oldsz; if (oldsz > MALLOC_MAXCHUNK) { if (oldsz < mopts.malloc_guard) - wrterror("guard size", NULL); + wrterror(pool, "guard size", NULL); oldsz -= mopts.malloc_guard; } @@ -1416,7 +1422,7 @@ gotit: return p; } else if (q != MAP_FAILED) { if (munmap(q, needed)) - wrterror("munmap", q); + wrterror(pool, "munmap", q); } } } else if (rnewsz < roldsz) { @@ -1424,11 +1430,11 @@ gotit: if (mprotect((char *)p + roldsz - mopts.malloc_guard, mopts.malloc_guard, PROT_READ | PROT_WRITE)) - wrterror("mprotect", NULL); + wrterror(pool, "mprotect", NULL); if (mprotect((char *)p + rnewsz - mopts.malloc_guard, mopts.malloc_guard, PROT_NONE)) - wrterror("mprotect", NULL); + wrterror(pool, "mprotect", NULL); } unmap(pool, (char *)p + rnewsz, roldsz - rnewsz); r->size = gnewsz; @@ -1454,7 +1460,7 @@ gotit: STATS_SETF(r, f); return p; } else if (newsz != oldsz || mopts.malloc_realloc) { - q = omalloc(newsz, 0, f); + q = omalloc(pool, newsz, 0, f); if (q == NULL) return NULL; if (newsz != 0 && oldsz != 0) { @@ -1463,7 +1469,7 @@ gotit: copysz -= mopts.malloc_canaries; memcpy(q, p, copysz); } - ofree(p); + ofree(pool, p); return q; } else { STATS_SETF(r, f); @@ -1474,27 +1480,30 @@ gotit: void * realloc(void *ptr, size_t size) { + struct dir_info *d; void *r; int saved_errno = errno; _MALLOC_LOCK(); - malloc_func = "realloc():"; - if (getpool() == NULL) { + d = getpool(); + if (d == NULL) { if (malloc_init() != 0) return NULL; + d = getpool(); } - if (malloc_active++) { - malloc_recurse(); + d->func = "realloc():"; + if (d->active++) { + malloc_recurse(d); return NULL; } if (size > 0 && size <= MALLOC_MAXCHUNK) size += mopts.malloc_canaries; - r = orealloc(ptr, size, CALLER); + r = orealloc(d, ptr, size, CALLER); - malloc_active--; + d->active--; _MALLOC_UNLOCK(); if (r == NULL && mopts.malloc_xmalloc) { - wrterror("out of memory", NULL); + wrterror(d, "out of memory", NULL); errno = ENOMEM; } if (r != NULL) @@ -1513,38 +1522,41 @@ realloc(void *ptr, size_t size) void * calloc(size_t nmemb, size_t size) { + struct dir_info *d; void *r; int saved_errno = errno; _MALLOC_LOCK(); - malloc_func = "calloc():"; - if (getpool() == NULL) { + d = getpool(); + if (d == NULL) { if (malloc_init() != 0) return NULL; + d = getpool(); } + d->func = "calloc():"; if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && nmemb > 0 && SIZE_MAX / nmemb < size) { _MALLOC_UNLOCK(); if (mopts.malloc_xmalloc) - wrterror("out of memory", NULL); + wrterror(d, "out of memory", NULL); errno = ENOMEM; return NULL; } - if (malloc_active++) { - malloc_recurse(); + if (d->active++) { + malloc_recurse(d); return NULL; } size *= nmemb; if (size > 0 && size <= MALLOC_MAXCHUNK) size += mopts.malloc_canaries; - r = omalloc(size, 1, CALLER); + r = omalloc(d, size, 1, CALLER); - malloc_active--; + d->active--; _MALLOC_UNLOCK(); if (r == NULL && mopts.malloc_xmalloc) { - wrterror("out of memory", NULL); + wrterror(d, "out of memory", NULL); errno = ENOMEM; } if (r != NULL) @@ -1559,11 +1571,11 @@ mapalign(struct dir_info *d, size_t alignment, size_t sz, int zero_fill) char *p, *q; if (alignment < MALLOC_PAGESIZE || ((alignment - 1) & alignment) != 0) { - wrterror("mapalign bad alignment", NULL); + wrterror(d, "mapalign bad alignment", NULL); return MAP_FAILED; } if (sz != PAGEROUND(sz)) { - wrterror("mapalign round", NULL); + wrterror(d, "mapalign round", NULL); return MAP_FAILED; } @@ -1582,19 +1594,18 @@ mapalign(struct dir_info *d, size_t alignment, size_t sz, int zero_fill) q = (char *)(((uintptr_t)p + alignment - 1) & ~(alignment - 1)); if (q != p) { if (munmap(p, q - p)) - wrterror("munmap", p); + wrterror(d, "munmap", p); } if (munmap(q + sz, alignment - (q - p))) - wrterror("munmap", q + sz); + wrterror(d, "munmap", q + sz); STATS_SUB(d->malloc_used, alignment); return q; } static void * -omemalign(size_t alignment, size_t sz, int zero_fill, void *f) +omemalign(struct dir_info *pool, size_t alignment, size_t sz, int zero_fill, void *f) { - struct dir_info *pool = getpool(); size_t psz; void *p; @@ -1605,7 +1616,7 @@ omemalign(size_t alignment, size_t sz, int zero_fill, void *f) */ if (sz < alignment) sz = alignment; - return omalloc(sz, zero_fill, f); + return omalloc(pool, sz, zero_fill, f); } if (sz >= SIZE_MAX - mopts.malloc_guard - MALLOC_PAGESIZE) { @@ -1631,7 +1642,7 @@ omemalign(size_t alignment, size_t sz, int zero_fill, void *f) if (mopts.malloc_guard) { if (mprotect((char *)p + psz - mopts.malloc_guard, mopts.malloc_guard, PROT_NONE)) - wrterror("mprotect", NULL); + wrterror(pool, "mprotect", NULL); STATS_ADD(pool->malloc_guarded, mopts.malloc_guard); } @@ -1649,6 +1660,7 @@ omemalign(size_t alignment, size_t sz, int zero_fill, void *f) int posix_memalign(void **memptr, size_t alignment, size_t size) { + struct dir_info *d; int res, saved_errno = errno; void *r; @@ -1657,23 +1669,25 @@ posix_memalign(void **memptr, size_t alignment, size_t size) return EINVAL; _MALLOC_LOCK(); - malloc_func = "posix_memalign():"; - if (getpool() == NULL) { + d = getpool(); + if (d == NULL) { if (malloc_init() != 0) goto err; + d = getpool(); } - if (malloc_active++) { - malloc_recurse(); + d->func = "posix_memalign():"; + if (d->active++) { + malloc_recurse(d); goto err; } if (size > 0 && size <= MALLOC_MAXCHUNK) size += mopts.malloc_canaries; - r = omemalign(alignment, size, 0, CALLER); - malloc_active--; + r = omemalign(d, alignment, size, 0, CALLER); + d->active--; _MALLOC_UNLOCK(); if (r == NULL) { if (mopts.malloc_xmalloc) { - wrterror("out of memory", NULL); + wrterror(d, "out of memory", NULL); errno = ENOMEM; } goto err; @@ -1925,7 +1939,7 @@ malloc_dump(int fd) continue; r = find(pool, p); if (r == NULL) { - wrterror("bogus pointer in malloc_dump", p); + wrterror(pool, "bogus pointer in malloc_dump", p); continue; } free_bytes(pool, r, p);