mirror of
https://github.com/microsoft/mimalloc.git
synced 2024-12-27 13:33:18 +08:00
add libc primitives to reduce dependencies
This commit is contained in:
parent
4a85f32f8e
commit
e10467f673
@ -189,7 +189,10 @@ bool _mi_free_delayed_block(mi_block_t* block);
|
||||
void _mi_free_generic(const mi_segment_t* segment, mi_page_t* page, bool is_local, void* p) mi_attr_noexcept; // for runtime integration
|
||||
void _mi_padding_shrink(const mi_page_t* page, const mi_block_t* block, const size_t min_size);
|
||||
|
||||
// libc.c, c primitives
|
||||
// "libc.c"
|
||||
#include <stdarg.h>
|
||||
void _mi_vsnprintf(char* buf, size_t bufsize, const char* fmt, va_list args);
|
||||
void _mi_snprintf(char* buf, size_t buflen, const char* fmt, ...);
|
||||
char _mi_toupper(char c);
|
||||
int _mi_strnicmp(const char* s, const char* t, size_t n);
|
||||
void _mi_strlcpy(char* dest, const char* src, size_t dest_size);
|
||||
|
247
src/libc.c
Normal file
247
src/libc.c
Normal file
@ -0,0 +1,247 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
Copyright (c) 2018-2023, Microsoft Research, Daan Leijen
|
||||
This is free software; you can redistribute it and/or modify it under the
|
||||
terms of the MIT license. A copy of the license can be found in the file
|
||||
"LICENSE" at the root of this distribution.
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
// --------------------------------------------------------
|
||||
// This module defines various std libc functions to reduce
|
||||
// the dependency on libc, and also prevent errors caused
|
||||
// by some libc implementations when called before `main`
|
||||
// executes (due to malloc redirection)
|
||||
// --------------------------------------------------------
|
||||
|
||||
#include "mimalloc.h"
|
||||
#include "mimalloc/internal.h"
|
||||
#include "mimalloc/prim.h" // mi_prim_getenv
|
||||
|
||||
char _mi_toupper(char c) {
|
||||
if (c >= 'a' && c <= 'z') return (c - 'a' + 'A');
|
||||
else return c;
|
||||
}
|
||||
|
||||
int _mi_strnicmp(const char* s, const char* t, size_t n) {
|
||||
if (n == 0) return 0;
|
||||
for (; *s != 0 && *t != 0 && n > 0; s++, t++, n--) {
|
||||
if (_mi_toupper(*s) != _mi_toupper(*t)) break;
|
||||
}
|
||||
return (n == 0 ? 0 : *s - *t);
|
||||
}
|
||||
|
||||
void _mi_strlcpy(char* dest, const char* src, size_t dest_size) {
|
||||
if (dest==NULL || src==NULL || dest_size == 0) return;
|
||||
// copy until end of src, or when dest is (almost) full
|
||||
while (*src != 0 && dest_size > 1) {
|
||||
*dest++ = *src++;
|
||||
dest_size--;
|
||||
}
|
||||
// always zero terminate
|
||||
*dest = 0;
|
||||
}
|
||||
|
||||
void _mi_strlcat(char* dest, const char* src, size_t dest_size) {
|
||||
if (dest==NULL || src==NULL || dest_size == 0) return;
|
||||
// find end of string in the dest buffer
|
||||
while (*dest != 0 && dest_size > 1) {
|
||||
dest++;
|
||||
dest_size--;
|
||||
}
|
||||
// and catenate
|
||||
_mi_strlcpy(dest, src, dest_size);
|
||||
}
|
||||
|
||||
size_t _mi_strlen(const char* s) {
|
||||
if (s==NULL) return 0;
|
||||
size_t len = 0;
|
||||
while(s[len] != 0) { len++; }
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t _mi_strnlen(const char* s, size_t max_len) {
|
||||
if (s==NULL) return 0;
|
||||
size_t len = 0;
|
||||
while(s[len] != 0 && len < max_len) { len++; }
|
||||
return len;
|
||||
}
|
||||
|
||||
#ifdef MI_NO_GETENV
|
||||
bool _mi_getenv(const char* name, char* result, size_t result_size) {
|
||||
MI_UNUSED(name);
|
||||
MI_UNUSED(result);
|
||||
MI_UNUSED(result_size);
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
bool _mi_getenv(const char* name, char* result, size_t result_size) {
|
||||
if (name==NULL || result == NULL || result_size < 64) return false;
|
||||
return _mi_prim_getenv(name,result,result_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
// --------------------------------------------------------
|
||||
// Define our own limited `_vsnprintf`
|
||||
// --------------------------------------------------------
|
||||
|
||||
static void mi_outc(char c, char** out, char* end) {
|
||||
char* p = *out;
|
||||
if (p >= end) return;
|
||||
*p = c;
|
||||
*out = p + 1;
|
||||
}
|
||||
|
||||
static void mi_outs(const char* s, char** out, char* end) {
|
||||
if (s == NULL) return;
|
||||
char* p = *out;
|
||||
while (*s != 0 && p < end) {
|
||||
*p++ = *s++;
|
||||
}
|
||||
*out = p;
|
||||
}
|
||||
|
||||
static void mi_out_fill(char fill, size_t len, char** out, char* end) {
|
||||
char* p = *out;
|
||||
for (size_t i = 0; i < len && p < end; i++) {
|
||||
*p++ = fill;
|
||||
}
|
||||
*out = p;
|
||||
}
|
||||
|
||||
static void mi_out_alignright(char fill, char* start, size_t len, size_t extra, char* end) {
|
||||
if (len == 0 || extra == 0) return;
|
||||
if (start + len + extra >= end) return;
|
||||
// move `len` characters to the right (in reverse since it can overlap)
|
||||
for (size_t i = 1; i <= len; i++) {
|
||||
start[len + extra - i] = start[len - i];
|
||||
}
|
||||
// and fill the start
|
||||
for (size_t i = 0; i < extra; i++) {
|
||||
start[i] = fill;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void mi_out_num(uintptr_t x, size_t base, char prefix, char** out, char* end)
|
||||
{
|
||||
if (x == 0 || base == 0 || base > 16) {
|
||||
if (prefix != 0) { mi_outc(prefix, out, end); }
|
||||
mi_outc('0',out,end);
|
||||
}
|
||||
else {
|
||||
// output digits in reverse
|
||||
char* start = *out;
|
||||
while (x > 0) {
|
||||
char digit = (char)(x % base);
|
||||
mi_outc((digit <= 9 ? '0' + digit : 'A' + digit - 10),out,end);
|
||||
x = x / base;
|
||||
}
|
||||
if (prefix != 0) {
|
||||
mi_outc(prefix, out, end);
|
||||
}
|
||||
size_t len = *out - start;
|
||||
// and reverse in-place
|
||||
for (size_t i = 0; i < (len / 2); i++) {
|
||||
char c = start[len - i - 1];
|
||||
start[len - i - 1] = start[i];
|
||||
start[i] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define MI_NEXTC() c = *in; if (c==0) break; in++;
|
||||
|
||||
void _mi_vsnprintf(char* buf, size_t bufsize, const char* fmt, va_list args) {
|
||||
if (buf == NULL || bufsize == 0 || fmt == NULL) return;
|
||||
buf[bufsize - 1] = 0;
|
||||
char* const end = buf + (bufsize - 1);
|
||||
const char* in = fmt;
|
||||
char* out = buf;
|
||||
while (true) {
|
||||
if (out >= end) break;
|
||||
char c;
|
||||
MI_NEXTC();
|
||||
if (c != '%') {
|
||||
mi_outc(c,&out,end);
|
||||
}
|
||||
else {
|
||||
MI_NEXTC();
|
||||
char fill = ' ';
|
||||
size_t width = 0;
|
||||
char numtype = 'd';
|
||||
char numplus = 0;
|
||||
bool alignright = true;
|
||||
if (c == '+' || c == ' ') { numplus = c; MI_NEXTC(); }
|
||||
if (c == '-') { alignright = false; MI_NEXTC(); }
|
||||
if (c == '0') { fill = '0'; MI_NEXTC(); }
|
||||
if (c >= '1' && c <= '9') {
|
||||
width = (c - '0'); MI_NEXTC();
|
||||
while (c >= '0' && c <= '9') {
|
||||
width = (10 * width) + (c - '0'); MI_NEXTC();
|
||||
}
|
||||
if (c == 0) break; // extra check due to while
|
||||
}
|
||||
if (c == 'z' || c == 'l') { numtype = c; MI_NEXTC(); }
|
||||
|
||||
char* const start = out;
|
||||
if (c == 's') {
|
||||
// string
|
||||
const char* s = va_arg(args, const char*);
|
||||
mi_outs(s, &out, end);
|
||||
}
|
||||
else if (c == 'p' || c == 'x' || c == 'u') {
|
||||
// unsigned
|
||||
uintptr_t x = 0;
|
||||
if (c == 'x' || c == 'u') {
|
||||
if (numtype == 'z') x = va_arg(args, size_t);
|
||||
else x = va_arg(args, unsigned long);
|
||||
}
|
||||
else if (c == 'p') {
|
||||
x = va_arg(args, uintptr_t);
|
||||
mi_outs("0x", &out, end);
|
||||
if (width == 0) {
|
||||
width = 2 * sizeof(void*);
|
||||
fill = '0';
|
||||
}
|
||||
}
|
||||
mi_out_num(x, (c == 'x' || c == 'p' ? 16 : 10), numplus, &out, end);
|
||||
}
|
||||
else if (c == 'i' || c == 'd') {
|
||||
// signed
|
||||
long x = va_arg(args, long);
|
||||
char pre = 0;
|
||||
if (x < 0) {
|
||||
pre = '-';
|
||||
x = -x;
|
||||
}
|
||||
else if (numplus != 0) {
|
||||
pre = numplus;
|
||||
}
|
||||
mi_out_num((size_t)x, 10, pre, &out, end);
|
||||
}
|
||||
else if (c >= ' ' && c < '~') {
|
||||
mi_outc(c, &out, end);
|
||||
}
|
||||
|
||||
// fill & align
|
||||
mi_assert_internal(out <= end);
|
||||
mi_assert_internal(out >= start);
|
||||
const size_t len = out - start;
|
||||
if (len < width) {
|
||||
mi_out_fill(fill, width - len, &out, end);
|
||||
if (alignright && out <= end) {
|
||||
mi_out_alignright(fill, start, len, width - len, end);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mi_assert_internal(out <= end);
|
||||
*out = 0;
|
||||
}
|
||||
|
||||
void _mi_snprintf(char* buf, size_t buflen, const char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
_mi_vsnprintf(buf, buflen, fmt, args);
|
||||
va_end(args);
|
||||
}
|
@ -9,9 +9,9 @@ terms of the MIT license. A copy of the license can be found in the file
|
||||
#include "mimalloc/atomic.h"
|
||||
#include "mimalloc/prim.h" // mi_prim_out_stderr
|
||||
|
||||
#include <stdio.h> // FILE
|
||||
#include <stdio.h> // stdin/stdout
|
||||
#include <stdlib.h> // abort
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
|
||||
static long mi_max_error_count = 16; // stop outputting errors after this (use < 0 for no limit)
|
||||
@ -312,12 +312,12 @@ void _mi_fputs(mi_output_fun* out, void* arg, const char* prefix, const char* me
|
||||
}
|
||||
|
||||
// Define our own limited `fprintf` that avoids memory allocation.
|
||||
// We do this using `snprintf` with a limited buffer.
|
||||
// We do this using `_mi_vsnprintf` with a limited buffer.
|
||||
static void mi_vfprintf( mi_output_fun* out, void* arg, const char* prefix, const char* fmt, va_list args ) {
|
||||
char buf[512];
|
||||
if (fmt==NULL) return;
|
||||
if (!mi_recurse_enter()) return;
|
||||
vsnprintf(buf,sizeof(buf)-1,fmt,args);
|
||||
_mi_vsnprintf(buf, sizeof(buf)-1, fmt, args);
|
||||
mi_recurse_exit();
|
||||
_mi_fputs(out,arg,prefix,buf);
|
||||
}
|
||||
@ -332,7 +332,7 @@ void _mi_fprintf( mi_output_fun* out, void* arg, const char* fmt, ... ) {
|
||||
static void mi_vfprintf_thread(mi_output_fun* out, void* arg, const char* prefix, const char* fmt, va_list args) {
|
||||
if (prefix != NULL && _mi_strnlen(prefix,33) <= 32 && !_mi_is_main_thread()) {
|
||||
char tprefix[64];
|
||||
snprintf(tprefix, sizeof(tprefix), "%sthread 0x%llx: ", prefix, (unsigned long long)_mi_thread_id());
|
||||
_mi_snprintf(tprefix, sizeof(tprefix), "%sthread 0x%zx: ", prefix, (size_t)_mi_thread_id());
|
||||
mi_vfprintf(out, arg, tprefix, fmt, args);
|
||||
}
|
||||
else {
|
||||
|
@ -476,8 +476,6 @@ int _mi_prim_alloc_huge_os_pages(void* hint_addr, size_t size, int numa_node, bo
|
||||
|
||||
#if defined(__linux__)
|
||||
|
||||
#include <stdio.h> // snprintf
|
||||
|
||||
size_t _mi_prim_numa_node(void) {
|
||||
#if defined(MI_HAS_SYSCALL_H) && defined(SYS_getcpu)
|
||||
unsigned long node = 0;
|
||||
@ -495,7 +493,7 @@ size_t _mi_prim_numa_node_count(void) {
|
||||
unsigned node = 0;
|
||||
for(node = 0; node < 256; node++) {
|
||||
// enumerate node entries -- todo: it there a more efficient way to do this? (but ensure there is no allocation)
|
||||
snprintf(buf, 127, "/sys/devices/system/node/node%u", node + 1);
|
||||
_mi_snprintf(buf, 127, "/sys/devices/system/node/node%u", node + 1);
|
||||
if (mi_prim_access(buf,R_OK) != 0) break;
|
||||
}
|
||||
return (node+1);
|
||||
|
@ -9,7 +9,6 @@ terms of the MIT license. A copy of the license can be found in the file
|
||||
#include "mimalloc/atomic.h"
|
||||
#include "mimalloc/prim.h"
|
||||
|
||||
#include <stdio.h> // snprintf
|
||||
#include <string.h> // memset
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1920)
|
||||
@ -146,7 +145,7 @@ static void mi_printf_amount(int64_t n, int64_t unit, mi_output_fun* out, void*
|
||||
const int64_t pos = (n < 0 ? -n : n);
|
||||
if (pos < base) {
|
||||
if (n!=1 || suffix[0] != 'B') { // skip printing 1 B for the unit column
|
||||
snprintf(buf, len, "%d %-3s", (int)n, (n==0 ? "" : suffix));
|
||||
_mi_snprintf(buf, len, "%d %-3s", (int)n, (n==0 ? "" : suffix));
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -158,8 +157,8 @@ static void mi_printf_amount(int64_t n, int64_t unit, mi_output_fun* out, void*
|
||||
const long whole = (long)(tens/10);
|
||||
const long frac1 = (long)(tens%10);
|
||||
char unitdesc[8];
|
||||
snprintf(unitdesc, 8, "%s%s%s", magnitude, (base==1024 ? "i" : ""), suffix);
|
||||
snprintf(buf, len, "%ld.%ld %-3s", whole, (frac1 < 0 ? -frac1 : frac1), unitdesc);
|
||||
_mi_snprintf(unitdesc, 8, "%s%s%s", magnitude, (base==1024 ? "i" : ""), suffix);
|
||||
_mi_snprintf(buf, len, "%ld.%ld %-3s", whole, (frac1 < 0 ? -frac1 : frac1), unitdesc);
|
||||
}
|
||||
_mi_fprintf(out, arg, (fmt==NULL ? "%12s" : fmt), buf);
|
||||
}
|
||||
@ -255,7 +254,7 @@ static void mi_stats_print_bins(const mi_stat_count_t* bins, size_t max, const c
|
||||
if (bins[i].allocated > 0) {
|
||||
found = true;
|
||||
int64_t unit = _mi_bin_size((uint8_t)i);
|
||||
snprintf(buf, 64, "%s %3lu", fmt, (long)i);
|
||||
_mi_snprintf(buf, 64, "%s %3lu", fmt, (long)i);
|
||||
mi_stat_print(&bins[i], buf, unit, out, arg);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user