Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ The open options is a list containing zero or more of these:
- `private`, `shared`: The file is opened with copy-on-write semantics, or sharing memory with the underlying file.
- `direct`: read/pread operations do not copy memory, but rather use "resource binaries" that can change content if the underlying data is changed. This is the most performant, but also has other implications.
- `lock`, `nolock` do (or do not) use a semaphore to control state changes internally in the NIF library.
- `auto_unlink` automatically deletes the mapped file after the mapped data was garbage collected. This can be used when the mapped file is a file-based shared-memory area (e.g. `/run/shm/...`) and is mapped in `direct` mode to free the memory after the data was gc'd.

From this point, `Mem` can be used with the `file` operations

Expand Down
28 changes: 19 additions & 9 deletions c_src/emmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ typedef struct
ErlNifRWLock* rwlock;
void* mem;
size_t len;
bool auto_unlink;
char path[1024];
} mhandle;

static int on_load(ErlNifEnv*, void**, ERL_NIF_TERM);
Expand Down Expand Up @@ -71,6 +73,7 @@ static ERL_NIF_TERM ATOM_ANON;
static ERL_NIF_TERM ATOM_FILE;
static ERL_NIF_TERM ATOM_FIXED;
static ERL_NIF_TERM ATOM_NOCACHE;
static ERL_NIF_TERM ATOM_AUTO_UNLINK;

static ERL_NIF_TERM ATOM_BOF;
static ERL_NIF_TERM ATOM_CUR;
Expand Down Expand Up @@ -120,6 +123,7 @@ static int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
ATOM_FILE = enif_make_atom(env, "file");
ATOM_FIXED = enif_make_atom(env, "fixed");
ATOM_NOCACHE = enif_make_atom(env, "nocache");
ATOM_AUTO_UNLINK = enif_make_atom(env, "auto_unlink");

ATOM_BOF = enif_make_atom(env, "bof");
ATOM_CUR = enif_make_atom(env, "cur");
Expand Down Expand Up @@ -164,12 +168,14 @@ static ERL_NIF_TERM make_error_tuple(ErlNifEnv* env, int err) {
}


int decode_flags(ErlNifEnv* env, ERL_NIF_TERM list, int *prot, int *flags, bool *direct, bool *lock)
int decode_flags(ErlNifEnv* env, ERL_NIF_TERM list, int *prot, int *flags, bool *direct, bool *lock,
bool *auto_unlink)
{
bool l = true;
bool d = false;
int f = MAP_FILE;
int p = 0;
*auto_unlink = false;
ERL_NIF_TERM head;
while (enif_get_list_cell(env, list, &head, &list)) {

Expand Down Expand Up @@ -198,7 +204,8 @@ int decode_flags(ErlNifEnv* env, ERL_NIF_TERM list, int *prot, int *flags, bool
// f |= MAP_FIXED;
} else if (enif_is_identical(head, ATOM_NOCACHE)) {
f |= MAP_NOCACHE;

} else if(enif_is_identical(head, ATOM_AUTO_UNLINK)) {
*auto_unlink = true;
} else {
return 0;
}
Expand Down Expand Up @@ -228,26 +235,27 @@ static ERL_NIF_TERM emmap_open(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
{
int flags;
int prot;
bool direct, lock;
bool direct, lock, auto_unlink;
unsigned long int len;
unsigned long int offset;
char buf[1024];

#ifndef NDEBUG
if ( sizeof(long int) != sizeof(size_t) ) {
abort();
}
#endif
mhandle* handle = (mhandle*)enif_alloc_resource_compat(env, MMAP_RESOURCE,
sizeof(mhandle));

if (argc == 4
&& enif_get_string(env, argv[0], buf, 1024, ERL_NIF_LATIN1)
&& enif_get_string(env, argv[0], handle->path, 1024, ERL_NIF_LATIN1)
&& enif_get_ulong(env, argv[1], &offset)
&& enif_get_ulong(env, argv[2], &len)
&& decode_flags(env, argv[3], &prot, &flags, &direct, &lock)) {
&& decode_flags(env, argv[3], &prot, &flags, &direct, &lock, &auto_unlink)) {

int mode = (((prot & PROT_WRITE)==PROT_WRITE) ? O_RDWR : O_RDONLY);

int fd = open(buf, mode);
int fd = open(handle->path, mode);
if (fd < 0) {
return make_error_tuple(env, errno);
}
Expand All @@ -259,8 +267,6 @@ static ERL_NIF_TERM emmap_open(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv

close(fd);

mhandle* handle = (mhandle*)enif_alloc_resource_compat(env, MMAP_RESOURCE,
sizeof(mhandle));

if (lock)
handle->rwlock = enif_rwlock_create((char*)"mmap");
Expand All @@ -273,6 +279,7 @@ static ERL_NIF_TERM emmap_open(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
handle->closed = false;
handle->direct = direct;
handle->position = 0;
handle->auto_unlink = auto_unlink;

ERL_NIF_TERM resource = enif_make_resource(env, handle);
enif_release_resource_compat(env, handle);
Expand All @@ -296,6 +303,9 @@ static ERL_NIF_TERM emmap_close(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
res = emmap_unmap(handle, false);
RW_UNLOCK;

if(handle->auto_unlink && unlink(handle->path) != 0)
return make_error_tuple(env, errno);

if (res == 0) {
return ATOM_OK;
}
Expand Down
2 changes: 1 addition & 1 deletion src/emmap.erl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
| direct
| lock | nolock
| private | shared
| nocache
| nocache | auto_unlink
.

-type mmap_file() :: #file_descriptor{}.
Expand Down