diff --git a/include/jemalloc/internal/os.h b/include/jemalloc/internal/os.h index 1bf8afb7..73e07625 100644 --- a/include/jemalloc/internal/os.h +++ b/include/jemalloc/internal/os.h @@ -10,12 +10,14 @@ * * os/posix/.h - the default, used by every POSIX platform. * os//.h - an override, present ONLY when an OS specializes - * that module. + * that module (e.g. windows/file.h). * * A dispatcher picks the OS-specific file when one exists and otherwise falls * back to posix/ (guarded by JEMALLOC_OS_POSIX), so any POSIX platform builds * without being enumerated anywhere. A non-POSIX platform with no override - * hits a #error. + * hits a #error. Each os/.h also declares the function prototypes + * its backends must implement, so a backend with a missing or mismatched + * function fails to compile instead of silently diverging. * * Adding OS support for a module (only when existing module headers cannot be * reused): create os//.h (and later a matching src body when @@ -23,4 +25,10 @@ * module: create os/.h + os/posix/.h and #include it below. */ +/* Process */ +#include "jemalloc/internal/os/process.h" + +/* File I/O */ +#include "jemalloc/internal/os/file.h" + #endif /* JEMALLOC_INTERNAL_OS_H */ diff --git a/include/jemalloc/internal/os/file.h b/include/jemalloc/internal/os/file.h new file mode 100644 index 00000000..c4f83d55 --- /dev/null +++ b/include/jemalloc/internal/os/file.h @@ -0,0 +1,36 @@ +#ifndef JEMALLOC_INTERNAL_OS_FILE_H +#define JEMALLOC_INTERNAL_OS_FILE_H + +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/os/detect.h" + +/* + * File I/O interface. + * Default: posix/. Override: Windows (CRT ). + */ + +/* Functions required for implementation in each backend. */ +JEMALLOC_ALWAYS_INLINE ssize_t os_file_write_once(int fd, const void *buf, + size_t bytes); +JEMALLOC_ALWAYS_INLINE ssize_t os_file_read_once(int fd, void *buf, + size_t bytes); +/* + * Full retry-until-bytes-or-error versions of the above: loop over the + * _once primitive until target bytes are transferred or a non-retryable + * error occurs. Retrying on EINTR is a POSIX-only concept (Windows has no + * such signal-interruption semantics for this call), so that decision lives + * entirely in each backend rather than leaking into callers. + */ +JEMALLOC_ALWAYS_INLINE ssize_t os_file_write(int fd, const void *buf, + size_t bytes); +JEMALLOC_ALWAYS_INLINE ssize_t os_file_read(int fd, void *buf, size_t bytes); + +#if defined(_WIN32) +# include "jemalloc/internal/os/windows/file.h" +#elif defined(JEMALLOC_OS_POSIX) +# include "jemalloc/internal/os/posix/file.h" +#else +# error "OS layer: no file backend for this platform; add os//file.h" +#endif + +#endif /* JEMALLOC_INTERNAL_OS_FILE_H */ diff --git a/include/jemalloc/internal/os/posix/file.h b/include/jemalloc/internal/os/posix/file.h new file mode 100644 index 00000000..5a67c952 --- /dev/null +++ b/include/jemalloc/internal/os/posix/file.h @@ -0,0 +1,68 @@ +#ifndef JEMALLOC_INTERNAL_OS_POSIX_FILE_H +#define JEMALLOC_INTERNAL_OS_POSIX_FILE_H + +/* + * POSIX file-I/O backend (read/write syscalls). Direct syscalls where + * available. + */ +#include "jemalloc/internal/jemalloc_preamble.h" + +#ifdef JEMALLOC_USE_SYSCALL +# include +#endif + +JEMALLOC_ALWAYS_INLINE ssize_t +os_file_write_once(int fd, const void *buf, size_t bytes) { +#if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_write) + return (ssize_t)syscall(SYS_write, fd, buf, bytes); +#else + return (ssize_t)write(fd, buf, bytes); +#endif +} + +JEMALLOC_ALWAYS_INLINE ssize_t +os_file_read_once(int fd, void *buf, size_t bytes) { +#if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_read) + return (ssize_t)syscall(SYS_read, fd, buf, bytes); +#else + return (ssize_t)read(fd, buf, bytes); +#endif +} + +JEMALLOC_ALWAYS_INLINE ssize_t +os_file_write(int fd, const void *buf, size_t bytes) { + size_t bytes_written = 0; + do { + ssize_t result = os_file_write_once(fd, + &((const byte_t *)buf)[bytes_written], bytes - bytes_written); + if (result < 0) { + if (errno == EINTR) { + continue; + } + return result; + } + bytes_written += result; + } while (bytes_written < bytes); + return bytes_written; +} + +JEMALLOC_ALWAYS_INLINE ssize_t +os_file_read(int fd, void *buf, size_t bytes) { + size_t bytes_read = 0; + do { + ssize_t result = os_file_read_once( + fd, &((byte_t *)buf)[bytes_read], bytes - bytes_read); + if (result < 0) { + if (errno == EINTR) { + continue; + } + return result; + } else if (result == 0) { + break; + } + bytes_read += result; + } while (bytes_read < bytes); + return bytes_read; +} + +#endif /* JEMALLOC_INTERNAL_OS_POSIX_FILE_H */ diff --git a/include/jemalloc/internal/os/posix/process.h b/include/jemalloc/internal/os/posix/process.h new file mode 100644 index 00000000..63142aed --- /dev/null +++ b/include/jemalloc/internal/os/posix/process.h @@ -0,0 +1,17 @@ +#ifndef JEMALLOC_INTERNAL_OS_POSIX_PROCESS_H +#define JEMALLOC_INTERNAL_OS_POSIX_PROCESS_H + +/* + * POSIX process backend (getpid()). + */ +#include "jemalloc/internal/jemalloc_preamble.h" + +#include +#include + +JEMALLOC_ALWAYS_INLINE int +os_process_id(void) { + return (int)getpid(); +} + +#endif /* JEMALLOC_INTERNAL_OS_POSIX_PROCESS_H */ diff --git a/include/jemalloc/internal/os/process.h b/include/jemalloc/internal/os/process.h new file mode 100644 index 00000000..a67e0041 --- /dev/null +++ b/include/jemalloc/internal/os/process.h @@ -0,0 +1,23 @@ +#ifndef JEMALLOC_INTERNAL_OS_PROCESS_H +#define JEMALLOC_INTERNAL_OS_PROCESS_H + +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/os/detect.h" + +/* + * Process interface. + * Default: posix/. Override: Windows (GetCurrentProcessId). + */ + +/* Functions required for implementation in each backend. */ +JEMALLOC_ALWAYS_INLINE int os_process_id(void); + +#if defined(_WIN32) +# include "jemalloc/internal/os/windows/process.h" +#elif defined(JEMALLOC_OS_POSIX) +# include "jemalloc/internal/os/posix/process.h" +#else +# error "OS layer: no process backend for this platform; add os//process.h" +#endif + +#endif /* JEMALLOC_INTERNAL_OS_PROCESS_H */ diff --git a/include/jemalloc/internal/os/windows/file.h b/include/jemalloc/internal/os/windows/file.h new file mode 100644 index 00000000..a2cc3471 --- /dev/null +++ b/include/jemalloc/internal/os/windows/file.h @@ -0,0 +1,52 @@ +#ifndef JEMALLOC_INTERNAL_OS_WINDOWS_FILE_H +#define JEMALLOC_INTERNAL_OS_WINDOWS_FILE_H + +/* + * Windows file-I/O backend, via the C runtime io.h (_read/_write). + */ +#include "jemalloc/internal/jemalloc_preamble.h" + +#include + +JEMALLOC_ALWAYS_INLINE ssize_t +os_file_write_once(int fd, const void *buf, size_t bytes) { + return (ssize_t)write(fd, buf, (unsigned int)bytes); +} + +JEMALLOC_ALWAYS_INLINE ssize_t +os_file_read_once(int fd, void *buf, size_t bytes) { + return (ssize_t)read(fd, buf, (unsigned int)bytes); +} + +/* No EINTR/signal-interruption semantics on Windows: never retry on error. */ +JEMALLOC_ALWAYS_INLINE ssize_t +os_file_write(int fd, const void *buf, size_t bytes) { + size_t bytes_written = 0; + do { + ssize_t result = os_file_write_once(fd, + &((const byte_t *)buf)[bytes_written], bytes - bytes_written); + if (result < 0) { + return result; + } + bytes_written += result; + } while (bytes_written < bytes); + return bytes_written; +} + +JEMALLOC_ALWAYS_INLINE ssize_t +os_file_read(int fd, void *buf, size_t bytes) { + size_t bytes_read = 0; + do { + ssize_t result = os_file_read_once( + fd, &((byte_t *)buf)[bytes_read], bytes - bytes_read); + if (result < 0) { + return result; + } else if (result == 0) { + break; + } + bytes_read += result; + } while (bytes_read < bytes); + return bytes_read; +} + +#endif /* JEMALLOC_INTERNAL_OS_WINDOWS_FILE_H */ diff --git a/include/jemalloc/internal/os/windows/process.h b/include/jemalloc/internal/os/windows/process.h new file mode 100644 index 00000000..2c1459ec --- /dev/null +++ b/include/jemalloc/internal/os/windows/process.h @@ -0,0 +1,15 @@ +#ifndef JEMALLOC_INTERNAL_OS_WINDOWS_PROCESS_H +#define JEMALLOC_INTERNAL_OS_WINDOWS_PROCESS_H + +#include "jemalloc/internal/jemalloc_preamble.h" + +/* + * Windows process backend (GetCurrentProcessId()). + */ + +JEMALLOC_ALWAYS_INLINE int +os_process_id(void) { + return (int)GetCurrentProcessId(); +} + +#endif /* JEMALLOC_INTERNAL_OS_WINDOWS_PROCESS_H */ diff --git a/src/malloc_io.c b/src/malloc_io.c index 2b8a6564..5514c8ec 100644 --- a/src/malloc_io.c +++ b/src/malloc_io.c @@ -1,6 +1,7 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/malloc_io.h" +#include "jemalloc/internal/os.h" #include "jemalloc/internal/util.h" #ifdef assert @@ -758,79 +759,14 @@ malloc_printf(const char *format, ...) { va_end(ap); } -static ssize_t -malloc_write_fd_syscall(int fd, const void *buf, size_t count) { -#if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_write) - /* - * Use syscall(2) rather than write(2) when possible in order to avoid - * the possibility of memory allocation within libc. This is necessary - * on FreeBSD; most operating systems do not have this problem though. - * - * syscall() returns long or int, depending on platform, so capture the - * result in the widest plausible type to avoid compiler warnings. - */ - return (ssize_t)syscall(SYS_write, fd, buf, count); -#else - return (ssize_t)write(fd, buf, -# ifdef _WIN32 - (unsigned int) -# endif - count); -#endif -} - ssize_t malloc_write_fd(int fd, const void *buf, size_t count) { - size_t bytes_written = 0; - do { - ssize_t result = malloc_write_fd_syscall(fd, - &((const byte_t *)buf)[bytes_written], - count - bytes_written); - if (result < 0) { -#ifndef _WIN32 - if (errno == EINTR) { - continue; - } -#endif - return result; - } - bytes_written += result; - } while (bytes_written < count); - return bytes_written; -} - -static ssize_t -malloc_read_fd_syscall(int fd, void *buf, size_t count) { -#if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_read) - return (ssize_t)syscall(SYS_read, fd, buf, count); -#else - return (ssize_t)read(fd, buf, -# ifdef _WIN32 - (unsigned int) -# endif - count); -#endif + return os_file_write(fd, buf, count); } ssize_t malloc_read_fd(int fd, void *buf, size_t count) { - size_t bytes_read = 0; - do { - ssize_t result = malloc_read_fd_syscall( - fd, &((byte_t *)buf)[bytes_read], count - bytes_read); - if (result < 0) { -#ifndef _WIN32 - if (errno == EINTR) { - continue; - } -#endif - return result; - } else if (result == 0) { - break; - } - bytes_read += result; - } while (bytes_read < count); - return bytes_read; + return os_file_read(fd, buf, count); } /* diff --git a/src/prof_sys.c b/src/prof_sys.c index 0c086bc9..e7257270 100644 --- a/src/prof_sys.c +++ b/src/prof_sys.c @@ -6,6 +6,7 @@ #include "jemalloc/internal/jemalloc_internal_inlines_a.h" #include "jemalloc/internal/malloc_io.h" #include "jemalloc/internal/mutex.h" +#include "jemalloc/internal/os.h" #include "jemalloc/internal/prof.h" #include "jemalloc/internal/prof_data.h" #include "jemalloc/internal/prof_inlines.h" @@ -484,11 +485,7 @@ prof_sys_thread_name_fetch(tsd_t *tsd) { int prof_getpid(void) { -#ifdef _WIN32 - return GetCurrentProcessId(); -#else - return getpid(); -#endif + return os_process_id(); } static long