Skip to content

Instantly share code, notes, and snippets.

@CAFxX
Created February 16, 2012 14:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CAFxX/1845141 to your computer and use it in GitHub Desktop.
Save CAFxX/1845141 to your computer and use it in GitHub Desktop.
filemap
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define CHECK(err, cond) { if (cond) return err; }
#define CHECK_RES(res) { int RES = res; CHECK(RES, RES != FILEMAP_OK); }
#define CHECK_HANDLE(m) { CHECK_RES(__filemap_check_handle(m)); }
#define OK() { return FILEMAP_OK; }
#define __(M, body) { CHECK_HANDLE(M); { body } OK(); }
typedef struct {
void *m;
off_t m_size;
int f;
off_t f_size;
} filemap;
typedef unsigned char byte;
enum filemap_errors {
FILEMAP_OK = 0,
FILEMAP_ERROR_FILE_OPEN,
FILEMAP_ERROR_MMAP,
FILEMAP_ERROR_INVALID_HANDLE,
FILEMAP_ERROR_MUNMAP,
FILEMAP_ERROR_FILE_SEEK,
FILEMAP_ERROR_FILE_RESIZE,
FILEMAP_ERROR_MSYNC
};
static int __filemap_check_handle(filemap *m) {
CHECK(FILEMAP_ERROR_INVALID_HANDLE, m == NULL);
OK();
}
static int __filemap_init(filemap *m) {__(m,
m->m = NULL;
m->m_size = 0;
m->f = -1;
m->f_size = 0;
)}
filemap filemap_handle() {
filemap m;
__filemap_init(&m);
return m;
}
int filemap_sync_ex(filemap *m, off_t offset, off_t length, int async) {__(m,
byte *addr = (byte*)(m->m) + offset;
int flags = async ? MS_ASYNC : MS_SYNC;
CHECK(FILEMAP_ERROR_MSYNC, msync(addr, length, flags) != 0);
)}
int filemap_sync(filemap *m) {__(m,
CHECK(FILEMAP_OK, m->m_size == 0);
return filemap_sync_ex(m, 0, m->m_size, 0);
)}
int filemap_async(filemap *m) {__(m,
CHECK(FILEMAP_OK, m->m_size == 0);
return filemap_sync_ex(m, 0, m->m_size, 1);
)}
static int __filemap_mmap(filemap *m) {__(m,
m->m = mmap(m->m, m->f_size, PROT_READ|PROT_WRITE, MAP_SHARED, m->f, 0);
CHECK(FILEMAP_ERROR_MMAP, m->m == MAP_FAILED && m->f_size > 0);
m->m_size = m->f_size;
)}
static int __filemap_munmap(filemap *m) {__(m,
CHECK(FILEMAP_OK, m->m_size == 0);
CHECK_RES(filemap_async(m));
CHECK(FILEMAP_ERROR_MUNMAP, munmap(m->m, m->m_size));
m->m_size = 0;
)}
int filemap_open(filemap *m, char *filename) {__(m,
CHECK_RES(__filemap_init(m));
CHECK(FILEMAP_ERROR_FILE_OPEN, (m->f = open(filename, O_RDWR|O_CREAT, S_IRWXU)) < 0);
CHECK(FILEMAP_ERROR_FILE_SEEK, (m->f_size = lseek(m->f, 0, SEEK_END)) == (off_t)-1);
CHECK_RES(__filemap_mmap(m));
fprintf(stderr, "%s %5d %p-%p %12ld bytes\n", "M", m->f, m->m, (byte*)(m->m)+m->m_size-1, m->f_size);
)}
int filemap_close(filemap *m) {__(m,
__filemap_munmap(m);
close(m->f);
)}
int filemap_resize(filemap *m, off_t size) {__(m,
CHECK(FILEMAP_OK, size == m->m_size);
CHECK_RES(__filemap_munmap(m));
CHECK(FILEMAP_ERROR_FILE_RESIZE, ftruncate(m->f, size) != 0);
m->f_size = size;
CHECK_RES(__filemap_mmap(m));
fprintf(stderr, "%s %5d %p-%p %12ld bytes\n", "R", m->f, m->m, (byte*)(m->m)+m->m_size-1, m->f_size);
)}
inline void* filemap_access(filemap *m, off_t start, off_t end) {
CHECK(NULL, m == NULL || end > m->m_size || start >= end);
return (byte*)(m->m) + start;
}
int main() {
int i, j=4, k;
filemap _m, *m = &_m;
CHECK_RES(filemap_open(m, "data.dat"));
srand(time(0));
for (i=0; i<50; i++) {
CHECK_RES(filemap_resize(m, j+=1<<(i/2)));
for (k=0; k<j-sizeof(int); k++)
*(byte*)filemap_access(m, k, k+sizeof(int)) = rand();
filemap_sync(m);
}
CHECK_RES(filemap_close(m));
return 0;
}
/*
Filemap m("data.dat");
Filemap m("data.dat", 1<<24);
m.resize(1<<20);
T* p = m.ptr<T>(offset);
m.sync();
m.close();
*/
#ifdef __cplusplus
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment