]> git.saurik.com Git - redis.git/blame - deps/jemalloc/src/util.c
Sentinel: SENTINEL FAILOVER command implemented.
[redis.git] / deps / jemalloc / src / util.c
CommitLineData
ad4c0b41 1#define assert(e) do { \
2 if (config_debug && !(e)) { \
3 malloc_write("<jemalloc>: Failed assertion\n"); \
4 abort(); \
5 } \
6} while (0)
7
8#define not_reached() do { \
9 if (config_debug) { \
10 malloc_write("<jemalloc>: Unreachable code reached\n"); \
11 abort(); \
12 } \
13} while (0)
14
15#define not_implemented() do { \
16 if (config_debug) { \
17 malloc_write("<jemalloc>: Not implemented\n"); \
18 abort(); \
19 } \
20} while (0)
21
22#define JEMALLOC_UTIL_C_
23#include "jemalloc/internal/jemalloc_internal.h"
24
25/******************************************************************************/
26/* Function prototypes for non-inline static functions. */
27
28static void wrtmessage(void *cbopaque, const char *s);
29#define U2S_BUFSIZE ((1U << (LG_SIZEOF_INTMAX_T + 3)) + 1)
30static char *u2s(uintmax_t x, unsigned base, bool uppercase, char *s,
31 size_t *slen_p);
32#define D2S_BUFSIZE (1 + U2S_BUFSIZE)
33static char *d2s(intmax_t x, char sign, char *s, size_t *slen_p);
34#define O2S_BUFSIZE (1 + U2S_BUFSIZE)
35static char *o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p);
36#define X2S_BUFSIZE (2 + U2S_BUFSIZE)
37static char *x2s(uintmax_t x, bool alt_form, bool uppercase, char *s,
38 size_t *slen_p);
39
40/******************************************************************************/
41
42/* malloc_message() setup. */
43static void
44wrtmessage(void *cbopaque, const char *s)
45{
46
47#ifdef SYS_write
48 /*
49 * Use syscall(2) rather than write(2) when possible in order to avoid
50 * the possibility of memory allocation within libc. This is necessary
51 * on FreeBSD; most operating systems do not have this problem though.
52 */
53 UNUSED int result = syscall(SYS_write, STDERR_FILENO, s, strlen(s));
54#else
55 UNUSED int result = write(STDERR_FILENO, s, strlen(s));
56#endif
57}
58
59JEMALLOC_EXPORT void (*je_malloc_message)(void *, const char *s);
60
61/*
62 * Wrapper around malloc_message() that avoids the need for
63 * je_malloc_message(...) throughout the code.
64 */
65void
66malloc_write(const char *s)
67{
68
69 if (je_malloc_message != NULL)
70 je_malloc_message(NULL, s);
71 else
72 wrtmessage(NULL, s);
73}
74
75/*
76 * glibc provides a non-standard strerror_r() when _GNU_SOURCE is defined, so
77 * provide a wrapper.
78 */
79int
80buferror(char *buf, size_t buflen)
81{
82
83#ifdef _WIN32
84 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
85 (LPSTR)buf, buflen, NULL);
86 return (0);
87#elif defined(_GNU_SOURCE)
88 char *b = strerror_r(errno, buf, buflen);
89 if (b != buf) {
90 strncpy(buf, b, buflen);
91 buf[buflen-1] = '\0';
92 }
93 return (0);
94#else
95 return (strerror_r(errno, buf, buflen));
96#endif
97}
98
99uintmax_t
100malloc_strtoumax(const char *nptr, char **endptr, int base)
101{
102 uintmax_t ret, digit;
103 int b;
104 bool neg;
105 const char *p, *ns;
106
107 if (base < 0 || base == 1 || base > 36) {
108 set_errno(EINVAL);
109 return (UINTMAX_MAX);
110 }
111 b = base;
112
113 /* Swallow leading whitespace and get sign, if any. */
114 neg = false;
115 p = nptr;
116 while (true) {
117 switch (*p) {
118 case '\t': case '\n': case '\v': case '\f': case '\r': case ' ':
119 p++;
120 break;
121 case '-':
122 neg = true;
123 /* Fall through. */
124 case '+':
125 p++;
126 /* Fall through. */
127 default:
128 goto label_prefix;
129 }
130 }
131
132 /* Get prefix, if any. */
133 label_prefix:
134 /*
135 * Note where the first non-whitespace/sign character is so that it is
136 * possible to tell whether any digits are consumed (e.g., " 0" vs.
137 * " -x").
138 */
139 ns = p;
140 if (*p == '0') {
141 switch (p[1]) {
142 case '0': case '1': case '2': case '3': case '4': case '5':
143 case '6': case '7':
144 if (b == 0)
145 b = 8;
146 if (b == 8)
147 p++;
148 break;
149 case 'x':
150 switch (p[2]) {
151 case '0': case '1': case '2': case '3': case '4':
152 case '5': case '6': case '7': case '8': case '9':
153 case 'A': case 'B': case 'C': case 'D': case 'E':
154 case 'F':
155 case 'a': case 'b': case 'c': case 'd': case 'e':
156 case 'f':
157 if (b == 0)
158 b = 16;
159 if (b == 16)
160 p += 2;
161 break;
162 default:
163 break;
164 }
165 break;
166 default:
167 break;
168 }
169 }
170 if (b == 0)
171 b = 10;
172
173 /* Convert. */
174 ret = 0;
175 while ((*p >= '0' && *p <= '9' && (digit = *p - '0') < b)
176 || (*p >= 'A' && *p <= 'Z' && (digit = 10 + *p - 'A') < b)
177 || (*p >= 'a' && *p <= 'z' && (digit = 10 + *p - 'a') < b)) {
178 uintmax_t pret = ret;
179 ret *= b;
180 ret += digit;
181 if (ret < pret) {
182 /* Overflow. */
183 set_errno(ERANGE);
184 return (UINTMAX_MAX);
185 }
186 p++;
187 }
188 if (neg)
189 ret = -ret;
190
191 if (endptr != NULL) {
192 if (p == ns) {
193 /* No characters were converted. */
194 *endptr = (char *)nptr;
195 } else
196 *endptr = (char *)p;
197 }
198
199 return (ret);
200}
201
202static char *
203u2s(uintmax_t x, unsigned base, bool uppercase, char *s, size_t *slen_p)
204{
205 unsigned i;
206
207 i = U2S_BUFSIZE - 1;
208 s[i] = '\0';
209 switch (base) {
210 case 10:
211 do {
212 i--;
213 s[i] = "0123456789"[x % (uint64_t)10];
214 x /= (uint64_t)10;
215 } while (x > 0);
216 break;
217 case 16: {
218 const char *digits = (uppercase)
219 ? "0123456789ABCDEF"
220 : "0123456789abcdef";
221
222 do {
223 i--;
224 s[i] = digits[x & 0xf];
225 x >>= 4;
226 } while (x > 0);
227 break;
228 } default: {
229 const char *digits = (uppercase)
230 ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
231 : "0123456789abcdefghijklmnopqrstuvwxyz";
232
233 assert(base >= 2 && base <= 36);
234 do {
235 i--;
236 s[i] = digits[x % (uint64_t)base];
237 x /= (uint64_t)base;
238 } while (x > 0);
239 }}
240
241 *slen_p = U2S_BUFSIZE - 1 - i;
242 return (&s[i]);
243}
244
245static char *
246d2s(intmax_t x, char sign, char *s, size_t *slen_p)
247{
248 bool neg;
249
250 if ((neg = (x < 0)))
251 x = -x;
252 s = u2s(x, 10, false, s, slen_p);
253 if (neg)
254 sign = '-';
255 switch (sign) {
256 case '-':
257 if (neg == false)
258 break;
259 /* Fall through. */
260 case ' ':
261 case '+':
262 s--;
263 (*slen_p)++;
264 *s = sign;
265 break;
266 default: not_reached();
267 }
268 return (s);
269}
270
271static char *
272o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p)
273{
274
275 s = u2s(x, 8, false, s, slen_p);
276 if (alt_form && *s != '0') {
277 s--;
278 (*slen_p)++;
279 *s = '0';
280 }
281 return (s);
282}
283
284static char *
285x2s(uintmax_t x, bool alt_form, bool uppercase, char *s, size_t *slen_p)
286{
287
288 s = u2s(x, 16, uppercase, s, slen_p);
289 if (alt_form) {
290 s -= 2;
291 (*slen_p) += 2;
292 memcpy(s, uppercase ? "0X" : "0x", 2);
293 }
294 return (s);
295}
296
297int
298malloc_vsnprintf(char *str, size_t size, const char *format, va_list ap)
299{
300 int ret;
301 size_t i;
302 const char *f;
303
304#define APPEND_C(c) do { \
305 if (i < size) \
306 str[i] = (c); \
307 i++; \
308} while (0)
309#define APPEND_S(s, slen) do { \
310 if (i < size) { \
311 size_t cpylen = (slen <= size - i) ? slen : size - i; \
312 memcpy(&str[i], s, cpylen); \
313 } \
314 i += slen; \
315} while (0)
316#define APPEND_PADDED_S(s, slen, width, left_justify) do { \
317 /* Left padding. */ \
318 size_t pad_len = (width == -1) ? 0 : ((slen < (size_t)width) ? \
319 (size_t)width - slen : 0); \
320 if (left_justify == false && pad_len != 0) { \
321 size_t j; \
322 for (j = 0; j < pad_len; j++) \
323 APPEND_C(' '); \
324 } \
325 /* Value. */ \
326 APPEND_S(s, slen); \
327 /* Right padding. */ \
328 if (left_justify && pad_len != 0) { \
329 size_t j; \
330 for (j = 0; j < pad_len; j++) \
331 APPEND_C(' '); \
332 } \
333} while (0)
334#define GET_ARG_NUMERIC(val, len) do { \
335 switch (len) { \
336 case '?': \
337 val = va_arg(ap, int); \
338 break; \
339 case '?' | 0x80: \
340 val = va_arg(ap, unsigned int); \
341 break; \
342 case 'l': \
343 val = va_arg(ap, long); \
344 break; \
345 case 'l' | 0x80: \
346 val = va_arg(ap, unsigned long); \
347 break; \
348 case 'q': \
349 val = va_arg(ap, long long); \
350 break; \
351 case 'q' | 0x80: \
352 val = va_arg(ap, unsigned long long); \
353 break; \
354 case 'j': \
355 val = va_arg(ap, intmax_t); \
356 break; \
357 case 't': \
358 val = va_arg(ap, ptrdiff_t); \
359 break; \
360 case 'z': \
361 val = va_arg(ap, ssize_t); \
362 break; \
363 case 'z' | 0x80: \
364 val = va_arg(ap, size_t); \
365 break; \
366 case 'p': /* Synthetic; used for %p. */ \
367 val = va_arg(ap, uintptr_t); \
368 break; \
369 default: not_reached(); \
370 } \
371} while (0)
372
373 i = 0;
374 f = format;
375 while (true) {
376 switch (*f) {
377 case '\0': goto label_out;
378 case '%': {
379 bool alt_form = false;
380 bool zero_pad = false;
381 bool left_justify = false;
382 bool plus_space = false;
383 bool plus_plus = false;
384 int prec = -1;
385 int width = -1;
386 unsigned char len = '?';
387
388 f++;
389 if (*f == '%') {
390 /* %% */
391 APPEND_C(*f);
392 break;
393 }
394 /* Flags. */
395 while (true) {
396 switch (*f) {
397 case '#':
398 assert(alt_form == false);
399 alt_form = true;
400 break;
401 case '0':
402 assert(zero_pad == false);
403 zero_pad = true;
404 break;
405 case '-':
406 assert(left_justify == false);
407 left_justify = true;
408 break;
409 case ' ':
410 assert(plus_space == false);
411 plus_space = true;
412 break;
413 case '+':
414 assert(plus_plus == false);
415 plus_plus = true;
416 break;
417 default: goto label_width;
418 }
419 f++;
420 }
421 /* Width. */
422 label_width:
423 switch (*f) {
424 case '*':
425 width = va_arg(ap, int);
426 f++;
427 break;
428 case '0': case '1': case '2': case '3': case '4':
429 case '5': case '6': case '7': case '8': case '9': {
430 uintmax_t uwidth;
431 set_errno(0);
432 uwidth = malloc_strtoumax(f, (char **)&f, 10);
433 assert(uwidth != UINTMAX_MAX || get_errno() !=
434 ERANGE);
435 width = (int)uwidth;
436 if (*f == '.') {
437 f++;
438 goto label_precision;
439 } else
440 goto label_length;
441 break;
442 } case '.':
443 f++;
444 goto label_precision;
445 default: goto label_length;
446 }
447 /* Precision. */
448 label_precision:
449 switch (*f) {
450 case '*':
451 prec = va_arg(ap, int);
452 f++;
453 break;
454 case '0': case '1': case '2': case '3': case '4':
455 case '5': case '6': case '7': case '8': case '9': {
456 uintmax_t uprec;
457 set_errno(0);
458 uprec = malloc_strtoumax(f, (char **)&f, 10);
459 assert(uprec != UINTMAX_MAX || get_errno() !=
460 ERANGE);
461 prec = (int)uprec;
462 break;
463 }
464 default: break;
465 }
466 /* Length. */
467 label_length:
468 switch (*f) {
469 case 'l':
470 f++;
471 if (*f == 'l') {
472 len = 'q';
473 f++;
474 } else
475 len = 'l';
476 break;
477 case 'j':
478 len = 'j';
479 f++;
480 break;
481 case 't':
482 len = 't';
483 f++;
484 break;
485 case 'z':
486 len = 'z';
487 f++;
488 break;
489 default: break;
490 }
491 /* Conversion specifier. */
492 switch (*f) {
493 char *s;
494 size_t slen;
495 case 'd': case 'i': {
496 intmax_t val JEMALLOC_CC_SILENCE_INIT(0);
497 char buf[D2S_BUFSIZE];
498
499 GET_ARG_NUMERIC(val, len);
500 s = d2s(val, (plus_plus ? '+' : (plus_space ?
501 ' ' : '-')), buf, &slen);
502 APPEND_PADDED_S(s, slen, width, left_justify);
503 f++;
504 break;
505 } case 'o': {
506 uintmax_t val JEMALLOC_CC_SILENCE_INIT(0);
507 char buf[O2S_BUFSIZE];
508
509 GET_ARG_NUMERIC(val, len | 0x80);
510 s = o2s(val, alt_form, buf, &slen);
511 APPEND_PADDED_S(s, slen, width, left_justify);
512 f++;
513 break;
514 } case 'u': {
515 uintmax_t val JEMALLOC_CC_SILENCE_INIT(0);
516 char buf[U2S_BUFSIZE];
517
518 GET_ARG_NUMERIC(val, len | 0x80);
519 s = u2s(val, 10, false, buf, &slen);
520 APPEND_PADDED_S(s, slen, width, left_justify);
521 f++;
522 break;
523 } case 'x': case 'X': {
524 uintmax_t val JEMALLOC_CC_SILENCE_INIT(0);
525 char buf[X2S_BUFSIZE];
526
527 GET_ARG_NUMERIC(val, len | 0x80);
528 s = x2s(val, alt_form, *f == 'X', buf, &slen);
529 APPEND_PADDED_S(s, slen, width, left_justify);
530 f++;
531 break;
532 } case 'c': {
533 unsigned char val;
534 char buf[2];
535
536 assert(len == '?' || len == 'l');
537 assert_not_implemented(len != 'l');
538 val = va_arg(ap, int);
539 buf[0] = val;
540 buf[1] = '\0';
541 APPEND_PADDED_S(buf, 1, width, left_justify);
542 f++;
543 break;
544 } case 's':
545 assert(len == '?' || len == 'l');
546 assert_not_implemented(len != 'l');
547 s = va_arg(ap, char *);
548 slen = (prec == -1) ? strlen(s) : prec;
549 APPEND_PADDED_S(s, slen, width, left_justify);
550 f++;
551 break;
552 case 'p': {
553 uintmax_t val;
554 char buf[X2S_BUFSIZE];
555
556 GET_ARG_NUMERIC(val, 'p');
557 s = x2s(val, true, false, buf, &slen);
558 APPEND_PADDED_S(s, slen, width, left_justify);
559 f++;
560 break;
561 }
562 default: not_implemented();
563 }
564 break;
565 } default: {
566 APPEND_C(*f);
567 f++;
568 break;
569 }}
570 }
571 label_out:
572 if (i < size)
573 str[i] = '\0';
574 else
575 str[size - 1] = '\0';
576 ret = i;
577
578#undef APPEND_C
579#undef APPEND_S
580#undef APPEND_PADDED_S
581#undef GET_ARG_NUMERIC
582 return (ret);
583}
584
585JEMALLOC_ATTR(format(printf, 3, 4))
586int
587malloc_snprintf(char *str, size_t size, const char *format, ...)
588{
589 int ret;
590 va_list ap;
591
592 va_start(ap, format);
593 ret = malloc_vsnprintf(str, size, format, ap);
594 va_end(ap);
595
596 return (ret);
597}
598
599void
600malloc_vcprintf(void (*write_cb)(void *, const char *), void *cbopaque,
601 const char *format, va_list ap)
602{
603 char buf[MALLOC_PRINTF_BUFSIZE];
604
605 if (write_cb == NULL) {
606 /*
607 * The caller did not provide an alternate write_cb callback
608 * function, so use the default one. malloc_write() is an
609 * inline function, so use malloc_message() directly here.
610 */
611 write_cb = (je_malloc_message != NULL) ? je_malloc_message :
612 wrtmessage;
613 cbopaque = NULL;
614 }
615
616 malloc_vsnprintf(buf, sizeof(buf), format, ap);
617 write_cb(cbopaque, buf);
618}
619
620/*
621 * Print to a callback function in such a way as to (hopefully) avoid memory
622 * allocation.
623 */
624JEMALLOC_ATTR(format(printf, 3, 4))
625void
626malloc_cprintf(void (*write_cb)(void *, const char *), void *cbopaque,
627 const char *format, ...)
628{
629 va_list ap;
630
631 va_start(ap, format);
632 malloc_vcprintf(write_cb, cbopaque, format, ap);
633 va_end(ap);
634}
635
636/* Print to stderr in such a way as to avoid memory allocation. */
637JEMALLOC_ATTR(format(printf, 1, 2))
638void
639malloc_printf(const char *format, ...)
640{
641 va_list ap;
642
643 va_start(ap, format);
644 malloc_vcprintf(NULL, NULL, format, ap);
645 va_end(ap);
646}