summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2020-06-10 19:41:27 -0400
committerRich Felker <dalias@aerifal.cx>2020-06-10 20:34:34 -0400
commit28f64fa6caeb621780bf116bc8cae7d7a48b477e (patch)
treef0ac98c4c7f415fb704ddeea84310be8f3317ec3 /src
parent384c0131ccda2656dec23a0416ad3f14101151a7 (diff)
downloadmusl-28f64fa6caeb621780bf116bc8cae7d7a48b477e.tar.gz
switch to a common calloc implementation
abstractly, calloc is completely malloc-implementation-independent; it's malloc followed by memset, or as we do it, a "conditional memset" that avoids touching fresh zero pages. previously, calloc was kept separate for the bump allocator, which can always skip memset, and the version of calloc provided with the full malloc conditionally skipped the clearing for large direct-mmapped allocations. the latter is a moderately attractive optimization, and can be added back if needed. however, further consideration to make it correct under malloc replacement would be needed. commit b4b1e10364c8737a632be61582e05a8d3acf5690 documented the contract for malloc replacement as allowing omission of calloc, and indeed that worked for dynamic linking, but for static linking it was possible to get the non-clearing definition from the bump allocator; if not for that, it would have been a link error trying to pull in malloc.o. the conditional-clearing code for the new common calloc is taken from mal0_clear in oldmalloc, but drops the need to access actual page size and just uses a fixed value of 4096. this avoids potentially needing access to global data for the sake of an optimization that at best marginally helps archs with offensively-large page sizes.
Diffstat (limited to 'src')
-rw-r--r--src/malloc/calloc.c37
-rw-r--r--src/malloc/lite_malloc.c11
-rw-r--r--src/malloc/oldmalloc/malloc.c36
3 files changed, 37 insertions, 47 deletions
diff --git a/src/malloc/calloc.c b/src/malloc/calloc.c
new file mode 100644
index 00000000..322193ca
--- /dev/null
+++ b/src/malloc/calloc.c
@@ -0,0 +1,37 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+
+static size_t mal0_clear(char *p, size_t n)
+{
+ const size_t pagesz = 4096; /* arbitrary */
+ if (n < pagesz) return n;
+#ifdef __GNUC__
+ typedef uint64_t __attribute__((__may_alias__)) T;
+#else
+ typedef unsigned char T;
+#endif
+ char *pp = p + n;
+ size_t i = (uintptr_t)pp & (pagesz - 1);
+ for (;;) {
+ pp = memset(pp - i, 0, i);
+ if (pp - p < pagesz) return pp - p;
+ for (i = pagesz; i; i -= 2*sizeof(T), pp -= 2*sizeof(T))
+ if (((T *)pp)[-1] | ((T *)pp)[-2])
+ break;
+ }
+}
+
+void *calloc(size_t m, size_t n)
+{
+ if (n && m > (size_t)-1/n) {
+ errno = ENOMEM;
+ return 0;
+ }
+ n *= m;
+ void *p = malloc(n);
+ if (!p) return p;
+ n = mal0_clear(p, n);
+ return memset(p, 0, n);
+}
diff --git a/src/malloc/lite_malloc.c b/src/malloc/lite_malloc.c
index c3f0c129..f8931ba5 100644
--- a/src/malloc/lite_malloc.c
+++ b/src/malloc/lite_malloc.c
@@ -101,14 +101,3 @@ static void *__simple_malloc(size_t n)
}
weak_alias(__simple_malloc, malloc);
-
-static void *__simple_calloc(size_t m, size_t n)
-{
- if (n && m > (size_t)-1/n) {
- errno = ENOMEM;
- return 0;
- }
- return __simple_malloc(n * m);
-}
-
-weak_alias(__simple_calloc, calloc);
diff --git a/src/malloc/oldmalloc/malloc.c b/src/malloc/oldmalloc/malloc.c
index df3ea1be..afa75722 100644
--- a/src/malloc/oldmalloc/malloc.c
+++ b/src/malloc/oldmalloc/malloc.c
@@ -341,42 +341,6 @@ void *malloc(size_t n)
return CHUNK_TO_MEM(c);
}
-static size_t mal0_clear(char *p, size_t pagesz, size_t n)
-{
-#ifdef __GNUC__
- typedef uint64_t __attribute__((__may_alias__)) T;
-#else
- typedef unsigned char T;
-#endif
- char *pp = p + n;
- size_t i = (uintptr_t)pp & (pagesz - 1);
- for (;;) {
- pp = memset(pp - i, 0, i);
- if (pp - p < pagesz) return pp - p;
- for (i = pagesz; i; i -= 2*sizeof(T), pp -= 2*sizeof(T))
- if (((T *)pp)[-1] | ((T *)pp)[-2])
- break;
- }
-}
-
-void *calloc(size_t m, size_t n)
-{
- if (n && m > (size_t)-1/n) {
- errno = ENOMEM;
- return 0;
- }
- n *= m;
- void *p = malloc(n);
- if (!p) return p;
- if (!__malloc_replaced) {
- if (IS_MMAPPED(MEM_TO_CHUNK(p)))
- return p;
- if (n >= PAGE_SIZE)
- n = mal0_clear(p, PAGE_SIZE, n);
- }
- return memset(p, 0, n);
-}
-
void *realloc(void *p, size_t n)
{
struct chunk *self, *next;