diff --git a/main.cpp b/main.cpp index aee1fbaf8..4b2afa54d 100644 --- a/main.cpp +++ b/main.cpp @@ -1,9 +1,9 @@ #include "ggml.h" #include "utils.h" +#include "mmap.h" #include -#include #include #include #include @@ -207,27 +207,6 @@ void *memalign(size_t a, size_t n) { return p; } -int posix_memalign(void **pp, size_t a, size_t n) { - int e; - void *m; - size_t q, r; - q = a / sizeof(void *); - r = a % sizeof(void *); - if (!r && q && IS2POW(q)) { - e = errno; - m = memalign(a, n); - if (m) { - *pp = m; - return 0; - } else { - errno = e; - return ENOMEM; - } - } else { - return EINVAL; - } -} - void *malloc(size_t n) { return memalign(MAGIC_ALGN, n); } diff --git a/mmap.h b/mmap.h new file mode 100644 index 000000000..3559f51a3 --- /dev/null +++ b/mmap.h @@ -0,0 +1,263 @@ +#pragma once + +// portable mmap() implementation +// +// - supports win32 (needs vista+) +// - supports posix.1 (no map_anonymous) +// +// notes on windows +// +// - no errno support +// - not designed to support mprotect() +// - very poor support for memory intervals + +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) || defined(__MINGW32__) +#ifndef __MINGW32__ +#include +#else +#include +#endif +#include +#include +#include + +#ifndef PROT_READ +#define PROT_READ 1 +#endif +#ifndef PROT_WRITE +#define PROT_WRITE 2 +#endif +#ifndef PROT_EXEC +#define PROT_EXEC 4 +#endif + +#ifndef MAP_SHARED +#define MAP_SHARED 1 +#endif +#ifndef MAP_PRIVATE +#define MAP_PRIVATE 2 +#endif +#ifndef MAP_FIXED +#define MAP_FIXED 16 +#endif +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS 32 +#endif +#ifndef MAP_FAILED +#define MAP_FAILED ((void*)-1) +#endif + +#ifndef O_RDONLY +#define O_RDONLY _O_RDWR // intentional smudge for mmap() +#endif +#ifndef O_WRONLY +#define O_WRONLY _O_WRONLY +#endif +#ifndef O_RDWR +#define O_RDWR _O_RDWR +#endif +#ifndef O_CREAT +#define O_CREAT _O_CREAT +#endif +#ifndef O_TRUNC +#define O_TRUNC _O_TRUNC +#endif +#ifndef O_EXCL +#define O_EXCL _O_EXCL +#endif + +#ifndef MADV_NORMAL +#define MADV_NORMAL 0 +#endif +#ifndef MADV_DONTNEED +#define MADV_DONTNEED 4 +#endif +#ifndef MADV_RANDOM +#define MADV_RANDOM 1 +#endif +#ifndef MADV_SEQUENTIAL +#define MADV_SEQUENTIAL 2 +#endif +#ifndef MADV_WILLNEED +#define MADV_WILLNEED 3 +#endif + +#ifndef mmap +#define mmap WinMap +#endif +#ifndef munmap +#define munmap WinUnmap +#endif +#ifndef open +#define open _open +#endif +#ifndef close +#define close _close +#endif +#ifndef fstat +#define fstat _fstat +#endif +#ifndef madvise +#define madvise WinMadvise +#endif +#ifndef ftruncate +#define ftruncate WinFtruncate +#endif + +static std::atomic g_winlock; +static std::map g_winmap; + +static void WinLock(void) { + while (!g_winlock.exchange(1, std::memory_order_acquire)); +} + +static void WunLock(void) { + g_winlock.store(0, std::memory_order_release); +} + +static int WinMadvise(int fd, size_t length, int flags) { + return 0; +} + +static int WinFtruncate(int fd, uint64_t length) { + return _chsize_s(fd, length) ? -1 : 0; +} + +static int WinUnmap(void *addr, size_t length) { + HANDLE hand; + WinLock(); + hand = g_winmap[addr]; + g_winmap[addr] = 0; + WunLock(); + if (hand) { + UnmapViewOfFile(addr); + CloseHandle(hand); + return 0; + } else { + return -1; + } +} + +static void *WinMap(void *addr, size_t length, int prot, + int flags, int fd, uint64_t offset) { + HANDLE hFile; + DWORD winprot; + DWORD access = 0; + HANDLE hand = NULL; + LPVOID res = NULL; + if (prot & PROT_READ) { + access |= FILE_MAP_READ; + } + if (prot & PROT_WRITE) { + access |= FILE_MAP_WRITE; + } + if (prot & PROT_EXEC) { + access |= FILE_MAP_EXECUTE; + } + if (flags & MAP_PRIVATE) { + // private mapping + if (prot & PROT_EXEC) { + if (prot & PROT_WRITE) { + if (flags & MAP_ANONYMOUS) { + winprot = PAGE_EXECUTE_READWRITE; + } else { + winprot = PAGE_EXECUTE_WRITECOPY; + } + } else { + winprot = PAGE_EXECUTE_READ; + } + } else if (prot & PROT_WRITE) { + if (flags & MAP_ANONYMOUS) { + winprot = PAGE_READWRITE; + } else { + winprot = PAGE_WRITECOPY; + } + } else { + winprot = PAGE_READONLY; + } + } else { + // shared mapping + if (prot & PROT_EXEC) { + if (prot & PROT_WRITE) { + winprot = PAGE_EXECUTE_READWRITE; + } else { + winprot = PAGE_EXECUTE_READ; + } + } else if (prot & PROT_WRITE) { + winprot = PAGE_READWRITE; + } else { + winprot = PAGE_READONLY; + } + } + if (flags & MAP_ANONYMOUS) { + hFile = INVALID_HANDLE_VALUE; + offset = 0; + } else { + hFile = (HANDLE)_get_osfhandle(fd); + if (hFile == INVALID_HANDLE_VALUE) { + return MAP_FAILED; + } + } + if (flags & MAP_FIXED) { + if (!addr) { + return MAP_FAILED; + } else { + WinUnmap(addr, length); + } + } + hand = CreateFileMapping(hFile, 0, winprot, + (offset + length) >> 32, + (offset + length), 0); + if (!hand) { + return MAP_FAILED; + } + res = MapViewOfFileEx(hand, access, offset >> 32, + offset, length, addr); + if (!res) { + CloseHandle(hand); + return MAP_FAILED; + } + WinLock(); + g_winmap[res] = hand; + WunLock(); + return res; +} + +#else +#include +#include +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS 0x10000000 + +static void *PosixMmap(void *addr, size_t length, int prot, + int flags, int fd, uint64_t offset) { + int tfd; + void *res; + char path[] = "/tmp/llama.dat.XXXXXX"; + if (~flags & MAP_ANONYMOUS) { + res = mmap(addr, length, prot, flags, fd, offset); + } else if ((tfd = mkstemp(path)) != -1) { + unlink(path); + if (!ftruncate(tfd, length)) { + res = mmap(addr, length, prot, flags & ~MAP_ANONYMOUS, tfd, 0); + } else { + res = MAP_FAILED; + } + close(tfd); + } else { + res = MAP_FAILED; + } + return res; +} + +#ifndef mmap +#define mmap PosixMmap +#endif +#endif // MAP_ANONYMOUS +#endif // _MSC_VER