Permalink
Browse files

Implement read/2 and position/2 for mmap

  • Loading branch information...
1 parent 11a9570 commit 079544e05aa9fed96be16703565584ea17a18117 @krestenkrab committed Jan 14, 2012
Showing with 120 additions and 1 deletion.
  1. +99 −0 c_src/emmap.cpp
  2. +21 −1 src/emmap.erl
View
@@ -11,6 +11,7 @@ static ErlNifResourceType* MMAP_RESOURCE;
typedef struct
{
+ size_t position;
int direct;
int prot;
bool closed;
@@ -59,10 +60,16 @@ static ERL_NIF_TERM ATOM_FILE;
static ERL_NIF_TERM ATOM_FIXED;
static ERL_NIF_TERM ATOM_NOCACHE;
+static ERL_NIF_TERM ATOM_BOF;
+static ERL_NIF_TERM ATOM_CUR;
+static ERL_NIF_TERM ATOM_EOF;
+
static ERL_NIF_TERM emmap_open(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM emmap_read(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM emmap_close(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM emmap_pread(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM emmap_pwrite(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM emmap_position(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
extern "C" {
@@ -72,6 +79,8 @@ extern "C" {
{"close_nif", 1, emmap_close},
{"pread_nif", 3, emmap_pread},
{"pwrite_nif", 3, emmap_pwrite},
+ {"position_nif", 3, emmap_position},
+ {"read_nif", 2, emmap_read},
};
ERL_NIF_INIT(emmap, nif_funcs, &on_load, NULL, NULL, NULL);
@@ -98,6 +107,10 @@ static int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
ATOM_FIXED = enif_make_atom(env, "fixed");
ATOM_NOCACHE = enif_make_atom(env, "nocache");
+ ATOM_BOF = enif_make_atom(env, "bof");
+ ATOM_CUR = enif_make_atom(env, "cur");
+ ATOM_EOF = enif_make_atom(env, "eof");
+
return 0;
}
@@ -232,6 +245,7 @@ static ERL_NIF_TERM emmap_open(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
handle->len = len;
handle->closed = false;
handle->direct = direct;
+ handle->position = 0;
ERL_NIF_TERM resource = enif_make_resource(env, handle);
enif_release_resource_compat(env, handle);
@@ -353,3 +367,88 @@ static ERL_NIF_TERM emmap_pwrite(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
return enif_make_badarg(env);
}
}
+
+static ERL_NIF_TERM emmap_read(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ mhandle *handle;
+ unsigned long bytes;
+
+ if (enif_get_resource(env, argv[0], MMAP_RESOURCE, (void**)&handle)
+ && enif_get_ulong(env, argv[1], &bytes)) {
+
+
+ enif_rwlock_rwlock(handle->rwlock);
+
+ if (handle->position == handle->len) {
+ enif_rwlock_rwunlock(handle->rwlock);
+ return ATOM_EOF;
+ }
+
+ unsigned long new_pos = handle->position + bytes;
+ if (new_pos > handle->len) { new_pos = handle->len; }
+ long size = new_pos - handle->position;
+ long start = handle->position;
+ handle->position = new_pos;
+ enif_rwlock_rwunlock(handle->rwlock);
+
+ if (handle->direct) {
+
+ ERL_NIF_TERM res = enif_make_resource_binary
+ (env, handle, (void*) (((char*)handle->mem) + start), size);
+
+ return enif_make_tuple2(env, ATOM_OK, res);
+
+ } else {
+
+ ErlNifBinary bin;
+ // When it is non-direct, we have to allocate the binary
+ if (!enif_alloc_binary((size_t) size, &bin)) {
+ return make_error_tuple(env, ENOMEM);
+ }
+
+ memcpy(bin.data, (void*) (((char*)handle->mem) + start), size);
+
+ ERL_NIF_TERM res = enif_make_binary(env, &bin);
+ return enif_make_tuple2(env, ATOM_OK, res);
+ }
+
+ } else {
+ return enif_make_badarg(env);
+ }
+}
+
+static ERL_NIF_TERM emmap_position(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ mhandle *handle;
+ long position;
+ long relpos;
+ if (argc==3
+ && enif_get_resource(env, argv[0], MMAP_RESOURCE, (void**)&handle)
+ && enif_get_long(env, argv[2], &relpos)
+ && (argv[1] == ATOM_CUR || argv[1] == ATOM_BOF || argv[1] == ATOM_EOF))
+ {
+ enif_rwlock_rwlock(handle->rwlock);
+
+ if (argv[1] == ATOM_BOF) {
+ position = 0L + relpos;
+ } else if (argv[1] == ATOM_CUR) {
+ position = handle->position + relpos;
+ } else if (argv[1] == ATOM_EOF) {
+ position = handle->len - relpos;
+ }
+
+ if (position < 0L || ((unsigned long)position) > handle->len) {
+ enif_rwlock_rwunlock(handle->rwlock);
+ return enif_make_badarg(env);
+ }
+
+ handle->position = position;
+ enif_rwlock_rwunlock(handle->rwlock);
+
+ return enif_make_tuple2(env, ATOM_OK, enif_make_ulong(env, position));
+ }
+ else
+ {
+ return enif_make_badarg(env);
+ }
+}
View
@@ -1,6 +1,6 @@
-module(emmap).
--export([open/4, close/1, pread/3, pwrite/3]).
+-export([open/4, close/1, pread/3, pwrite/3, read/2, position/2]).
-on_load(init/0).
-ifdef(TEST).
@@ -50,12 +50,28 @@ pread(#file_descriptor{ module=?MODULE, data=Mem }, Off, Len) ->
pread_nif(_,_,_) ->
{ok, <<>>}.
+read(#file_descriptor{ module=?MODULE, data=Mem }, Len) ->
+ read_nif(Mem, Len).
+
+read_nif(_,_) ->
+ {ok, <<>>}.
+
+
pwrite(#file_descriptor{ module=?MODULE, data=Mem }, Off, Data) ->
pwrite_nif(Mem, Off, Data).
pwrite_nif(_,_,_) ->
ok.
+position(#file_descriptor{ module=?MODULE, data=Mem}, At)
+ when is_integer(At) ->
+ position_nif(Mem, bof, At);
+position(#file_descriptor{ module=?MODULE, data=Mem}, {From, Off})
+ when From == 'bof'; From == 'cur'; From == 'eof' ->
+ position_nif(Mem, From, Off).
+
+position_nif(_,_From,_Off) ->
+ ok.
-ifdef(TEST).
@@ -78,6 +94,10 @@ simple_test() ->
%% Woot!
<<"xx">> = Mem,
+ {ok, 0} = file:position(MFile, {cur, 0}),
+ {ok, <<"ab">>} = file:read(MFile, 2),
+ {ok, <<"xx">>} = file:read(MFile, 2),
+
file:close(MFile),
file:close(MFile2) .

0 comments on commit 079544e

Please sign in to comment.