|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
#include <macros.h>
|
|
|
|
#include <map.h>
|
|
|
|
|
|
|
|
// Set all bytes to 0xff (ints i.e. fd will be -1)
|
|
|
|
static inline void _map_init(map_t *pOUT map)
|
|
|
|
{
|
|
|
|
memset(map, 0xff, sizeof(map_t));
|
|
|
|
TRACE("blanked %p->%lu to 0xff", map, sizeof(map_t));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool _map_is_file(const map_t* map)
|
|
|
|
{
|
|
|
|
TRACE("fd element of union is %x (%d)", map->file.fd, map->file.fd);
|
|
|
|
return map->file.fd > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
map_result_t map_fd(int fd, bool write, usize size, off_t offset, map_t *pOUT map)
|
|
|
|
{
|
|
|
|
TRACE("mapping %lu bytes of fd %d (%s) from offset %lu to %p", size, fd, write ? "rw" : "ro", offset, map);
|
|
|
|
void* ptr = mmap(NULL, size, PROT_READ | (write ? PROT_WRITE : 0), MAP_SHARED, fd, offset);
|
|
|
|
if(ptr == MAP_FAILED) return MAP_ERR_MMAP;
|
|
|
|
TRACE("mapped %p->%lu", ptr, size);
|
|
|
|
map->file = (struct mm_file){
|
|
|
|
.origin = ptr,
|
|
|
|
.len = size,
|
|
|
|
.fd = fd,
|
|
|
|
.fd_offset = offset,
|
|
|
|
};
|
|
|
|
return MAP_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
map_result_t map_file(const char* file, bool write, usize size, off_t offset, map_t *pOUT map)
|
|
|
|
{
|
|
|
|
TRACE("mapping %lu bytes of file `%s' (%s) from %lu to %p", size, file, write ? "rw" : "ro", offset, map);
|
|
|
|
|
|
|
|
int fd = open(file, write ? O_RDWR : O_RDONLY);
|
|
|
|
if(fd < 0) return MAP_ERR_OPEN;
|
|
|
|
TRACE("opened file %d", fd);
|
|
|
|
|
|
|
|
if(!size) {
|
|
|
|
TRACE("user asked for max-size map (size: 0), stating %d to find size...", fd);
|
|
|
|
struct stat st;
|
|
|
|
// Find size of file
|
|
|
|
if(fstat(fd, &st) != 0) return (close(fd), MAP_ERR_STAT);
|
|
|
|
TRACE("fstat() reports size is %lu", st.st_size);
|
|
|
|
size = st.st_size;
|
|
|
|
}
|
|
|
|
TRACE("passing fd %d, size %lu to `map_fd()`", fd, size);
|
|
|
|
return map_fd(fd, write, size, offset, map);
|
|
|
|
}
|
|
|
|
|
|
|
|
map_result_t map_anon(void* ptr, usize len, map_t *pOUT map)
|
|
|
|
{
|
|
|
|
TRACE("mapping anon at %p (%s) of size %lu (map %p)", ptr, ptr ? "fixed" : "dynamic", len, map);
|
|
|
|
ptr = mmap(ptr, len, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | (ptr ? MAP_FIXED : 0), -1, 0);
|
|
|
|
if(ptr==MAP_FAILED) return MAP_ERR_MMAP;
|
|
|
|
|
|
|
|
TRACE("mapped ptr %p->%lu", ptr, len);
|
|
|
|
// Make sure .file.fd is -1, so we can tell this is anon in `map_free()`.
|
|
|
|
_map_init(map);
|
|
|
|
map->anon = (struct mm_anon) {
|
|
|
|
.origin = ptr,
|
|
|
|
.len = len,
|
|
|
|
};
|
|
|
|
return MAP_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
map_result_t map_free(map_t map)
|
|
|
|
{
|
|
|
|
TRACE("unmapping %p->%lu", map.origin, map.len);
|
|
|
|
if( munmap(map.anon.origin, map.anon.len) != 0) return MAP_ERR_UNMAP;
|
|
|
|
if( _map_is_file(&map) ) {
|
|
|
|
TRACE("map is file, closing fd %d", map.file.fd);
|
|
|
|
if( close(map.file.fd) != 0 ) return MAP_ERR_CLOSE;
|
|
|
|
}
|
|
|
|
return MAP_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
map_result_t map_preload(map_t *pINOUT map, bool random)
|
|
|
|
{
|
|
|
|
TRACE("preloading map %p (%p->%lu) for immediate %s access", map, map->origin, map->len, random ? "random" : "sequential");
|
|
|
|
return madvise(map->origin, map->len, MADV_WILLNEED | (random ? MADV_RANDOM : MADV_SEQUENTIAL)) != 0
|
|
|
|
? MAP_ERR_ADVISE
|
|
|
|
: MAP_SUCCESS;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* map_error_str(map_result_t res)
|
|
|
|
{
|
|
|
|
switch(res)
|
|
|
|
{
|
|
|
|
#define CASE(err, str) case err: return str
|
|
|
|
CASE(MAP_ERR_MMAP, "mmap() failed (creating a map)");
|
|
|
|
CASE(MAP_ERR_UNMAP, "munmap() failed (freeing a map)");
|
|
|
|
CASE(MAP_ERR_OPEN, "open() failed (mapping a filepath)");
|
|
|
|
CASE(MAP_ERR_CLOSE, "close() failed (freeing a file-map)");
|
|
|
|
CASE(MAP_ERR_STAT, "fstat() failed: (mapping a full filepath)");
|
|
|
|
CASE(MAP_ERR_ADVISE, "madvise() failed: (preloading mapped file)");
|
|
|
|
|
|
|
|
CASE(MAP_SUCCESS, "success");
|
|
|
|
#undef CASE
|
|
|
|
default:
|
|
|
|
ERROR("unkown or invalid error code %d", (int)res);
|
|
|
|
return "unknown error";
|
|
|
|
}
|
|
|
|
}
|