-module(shmem). -on_load(load_nif/0). -export([open/2, close/1, pread/3, pwrite/3]). load_nif() -> Path = case code:lib_dir(corelib) of P when is_list(P) -> filename:join(P, priv); _ -> "./priv" end, % check if there is a file on disk NifName = Path ++ "/shmem", case file:read_file_info(NifName ++ ".so") of {ok, _} -> case erlang:load_nif(NifName, LoadInfo) of ok -> ok; {error, {load_failed, NifLoadError}} -> case re:run(NifLoadError, "'([^']+)'",[{capture,all_but_first,list}]) of {match, [RealNifMsg]} -> {error, {load_failed, RealNifMsg}}; _ -> {error, {load_failed, NifLoadError}} end; {error, NifLoadError} -> {error, NifLoadError} end; {error, enoent} -> ok end. -type shmem() :: any(). -type shmem_opts() :: #{ len := pos_integer(), write => true, create => true }. -type shm_error() :: out_of_range | readonly | mmap_failed | shm_open_failed | closed. -spec open(ShmName, Opts) -> {ok, shmem()} | {error, shm_error()} when ShmName :: binary(), Opts :: shmem_opts(). open(ShmName, #{len := Length} = Opts) -> Write = maps:get(write, Opts, false), Create = maps:get(create, Opts, false), open0(ShmName, Length, Write, Create). open0(ShmName, Len, Write, Create) -> erlang:nif_error(not_loaded, [ShmName, Len, Write, Create]). -spec pread(Shm, Offset, Len) -> {ok, binary()} | {error, shm_error()} when Shm::shmem(), Offset::non_neg_integer(), Len::pos_integer(). pread(Shm, Offset, Len) -> erlang:nif_error(not_loaded, [Shm, Offset, Len]). -spec pwrite(Shm, Offset, Binary) -> ok | {error, shm_error()} when Shm::shmem(), Offset::non_neg_integer(), Binary::binary(). pwrite(Shm, Offset, Binary) -> erlang:nif_error(not_loaded, [Shm, Offset, size(Binary)]). -spec close(Shm) -> ok when Shm::shmem(). close(_Shm) -> ok.