diff --git a/include/jemalloc/internal/os.h b/include/jemalloc/internal/os.h index d232eb71..b66a1943 100644 --- a/include/jemalloc/internal/os.h +++ b/include/jemalloc/internal/os.h @@ -49,4 +49,11 @@ /* VM */ #include "jemalloc/internal/os/vm.h" +/* + * Error codes. util.h includes os/error.h directly (not via this umbrella) + * since it's reachable too early in the include graph for the full os.h. + * Included here too for discoverability. + */ +#include "jemalloc/internal/os/error.h" + #endif /* JEMALLOC_INTERNAL_OS_H */ diff --git a/include/jemalloc/internal/os/error.h b/include/jemalloc/internal/os/error.h new file mode 100644 index 00000000..ad46f938 --- /dev/null +++ b/include/jemalloc/internal/os/error.h @@ -0,0 +1,35 @@ +#ifndef JEMALLOC_INTERNAL_OS_ERROR_H +#define JEMALLOC_INTERNAL_OS_ERROR_H + +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/os/detect.h" + +/* + * Error-code interface: get/set the calling thread's last-error value, and + * render an error code to a human-readable string. + * Default: posix/. Override: Windows. + * + * Included directly by util.h (not via the os.h umbrella): util.h is itself + * transitively included very early. assert.h includes malloc_io.h then + * util.h, before either has any reason to know about mutex.h/base.h. Thus, + * pulling in the full os.h from util.h would risk the same circular-include + * failure worked around in the VM module (base.h -> mutex.h -> os.h -> + * os/vm.h -> base.h). This module's backends need nothing beyond libc/CRT + * error primitives and malloc_io.h's malloc_snprintf, so including it alone + * from util.h is safe. + */ + +/* Functions required for implementation in each backend. */ +JEMALLOC_ALWAYS_INLINE int os_errno_get(void); +JEMALLOC_ALWAYS_INLINE void os_errno_set(int errnum); +JEMALLOC_ALWAYS_INLINE int os_strerror(int err, char *buf, size_t buflen); + +#if defined(_WIN32) +# include "jemalloc/internal/os/windows/error.h" +#elif defined(JEMALLOC_OS_POSIX) +# include "jemalloc/internal/os/posix/error.h" +#else +# error "OS layer: no error backend for this platform; add os//error.h" +#endif + +#endif /* JEMALLOC_INTERNAL_OS_ERROR_H */ diff --git a/include/jemalloc/internal/os/posix/error.h b/include/jemalloc/internal/os/posix/error.h new file mode 100644 index 00000000..1fceb856 --- /dev/null +++ b/include/jemalloc/internal/os/posix/error.h @@ -0,0 +1,38 @@ +#ifndef JEMALLOC_INTERNAL_OS_POSIX_ERROR_H +#define JEMALLOC_INTERNAL_OS_POSIX_ERROR_H + +/* + * POSIX error backend (errno, strerror_r). + */ +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/malloc_io.h" + +JEMALLOC_ALWAYS_INLINE int +os_errno_get(void) { + return errno; +} + +JEMALLOC_ALWAYS_INLINE void +os_errno_set(int errnum) { + errno = errnum; +} + +/* + * glibc provides a non-standard strerror_r() when _GNU_SOURCE is defined, so + * provide a wrapper. + */ +JEMALLOC_ALWAYS_INLINE int +os_strerror(int err, char *buf, size_t buflen) { +#if defined(JEMALLOC_STRERROR_R_RETURNS_CHAR_WITH_GNU_SOURCE) \ + && defined(_GNU_SOURCE) + char *b = strerror_r(err, buf, buflen); + if (b != buf) { + malloc_snprintf(buf, buflen, "%s", b); + } + return 0; +#else + return strerror_r(err, buf, buflen); +#endif +} + +#endif /* JEMALLOC_INTERNAL_OS_POSIX_ERROR_H */ diff --git a/include/jemalloc/internal/os/windows/error.h b/include/jemalloc/internal/os/windows/error.h new file mode 100644 index 00000000..00d6c5ab --- /dev/null +++ b/include/jemalloc/internal/os/windows/error.h @@ -0,0 +1,26 @@ +#ifndef JEMALLOC_INTERNAL_OS_WINDOWS_ERROR_H +#define JEMALLOC_INTERNAL_OS_WINDOWS_ERROR_H + +/* + * Windows error backend (GetLastError/SetLastError, FormatMessageA). + */ +#include "jemalloc/internal/jemalloc_preamble.h" + +JEMALLOC_ALWAYS_INLINE int +os_errno_get(void) { + return GetLastError(); +} + +JEMALLOC_ALWAYS_INLINE void +os_errno_set(int errnum) { + SetLastError(errnum); +} + +JEMALLOC_ALWAYS_INLINE int +os_strerror(int err, char *buf, size_t buflen) { + FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, (LPSTR)buf, + (DWORD)buflen, NULL); + return 0; +} + +#endif /* JEMALLOC_INTERNAL_OS_WINDOWS_ERROR_H */ diff --git a/include/jemalloc/internal/util.h b/include/jemalloc/internal/util.h index 6465144c..2c994594 100644 --- a/include/jemalloc/internal/util.h +++ b/include/jemalloc/internal/util.h @@ -3,6 +3,7 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_types.h" +#include "jemalloc/internal/os/error.h" #define UTIL_INLINE static inline @@ -66,21 +67,13 @@ max_zu(size_t a, size_t b) { /* Set error code. */ UTIL_INLINE void set_errno(int errnum) { -#ifdef _WIN32 - SetLastError(errnum); -#else - errno = errnum; -#endif + os_errno_set(errnum); } /* Get last error code. */ UTIL_INLINE int get_errno(void) { -#ifdef _WIN32 - return GetLastError(); -#else - return errno; -#endif + return os_errno_get(); } #ifdef _MSC_VER diff --git a/src/malloc_io.c b/src/malloc_io.c index 5514c8ec..3b8c88e4 100644 --- a/src/malloc_io.c +++ b/src/malloc_io.c @@ -91,26 +91,9 @@ malloc_write(const char *s) { } } -/* - * glibc provides a non-standard strerror_r() when _GNU_SOURCE is defined, so - * provide a wrapper. - */ int buferror(int err, char *buf, size_t buflen) { -#ifdef _WIN32 - FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, (LPSTR)buf, - (DWORD)buflen, NULL); - return 0; -#elif defined(JEMALLOC_STRERROR_R_RETURNS_CHAR_WITH_GNU_SOURCE) \ - && defined(_GNU_SOURCE) - char *b = strerror_r(err, buf, buflen); - if (b != buf) { - malloc_snprintf(buf, buflen, "%s", b); - } - return 0; -#else - return strerror_r(err, buf, buflen); -#endif + return os_strerror(err, buf, buflen); } uintmax_t