diff --git a/c_src/sema_nif.cpp b/c_src/sema_nif.cpp index ae1f651..1e1318a 100644 --- a/c_src/sema_nif.cpp +++ b/c_src/sema_nif.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #ifdef TRACE #include @@ -99,6 +100,9 @@ struct sema { return map_ret; } + unsigned capacity() const { return max; } + unsigned capacity(unsigned n) { auto old=max; max=n; return old; } + ERL_NIF_TERM try_to_take(ErlNifEnv *env, const ErlNifPid& pid, unsigned n) { unsigned x = cnt.load(std::memory_order_relaxed); while (x + n <= max) { @@ -272,8 +276,7 @@ create(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { static ERL_NIF_TERM info(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { - if (argc != 1) - return enif_make_badarg(env); + assert(argc == 1); sema *res = nullptr; if (!enif_get_resource(env, argv[0], SEMA, (void **)&res)) @@ -285,6 +288,21 @@ info(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { return res->info(env); } +static ERL_NIF_TERM +capacity(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { + assert(argc >= 1 && argc <= 2); + + sema *res = nullptr; + if (!enif_get_resource(env, argv[0], SEMA, (void **)&res) || !res) + return enif_make_badarg(env); + + unsigned max = 0; + if (argc == 2 && !enif_get_uint(env, argv[1], &max)) + return enif_make_badarg(env); + + return enif_make_uint(env, argc == 2 ? res->capacity(max) : res->capacity()); +} + static ERL_NIF_TERM acquire(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { if (argc < 1 || argc > 2) @@ -357,13 +375,15 @@ release(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { } static ErlNifFunc nif_funcs[] = { - {"create", 1, create}, - {"info", 1, info}, - {"acquire", 1, acquire}, - {"acquire", 2, acquire}, - {"release", 1, release}, - {"release", 2, release}, - {"release", 3, release} + {"create", 1, create}, + {"info", 1, info}, + {"capacity", 1, capacity}, + {"capacity", 2, capacity}, + {"acquire", 1, acquire}, + {"acquire", 2, acquire}, + {"release", 1, release}, + {"release", 2, release}, + {"release", 3, release} }; ERL_NIF_INIT(sema_nif, nif_funcs, &load, nullptr, nullptr, nullptr); diff --git a/src/sema_nif.erl b/src/sema_nif.erl index 805cecd..3d6f67e 100644 --- a/src/sema_nif.erl +++ b/src/sema_nif.erl @@ -3,6 +3,8 @@ -export([ create/1, info/1, + capacity/1, + capacity/2, acquire/1, acquire/2, release/1, @@ -13,6 +15,8 @@ -nifs([ create/1, info/1, + capacity/1, + capacity/2, acquire/1, acquire/2, release/1, @@ -41,10 +45,11 @@ -export_type([sema_ref/0, acquire_ret/0, release_ret/0]). +% @doc Create a new semaphore with the given capacity -spec create(Max :: pos_integer()) -> sema_ref(). create(_) -> not_loaded(?LINE). -% get internal properties of the semaphore resource +% @doc Get internal properties of the semaphore resource -spec info(Semaphore :: sema_ref()) -> #{ % number of units acquired @@ -56,23 +61,32 @@ create(_) -> not_loaded(?LINE). }. info(_) -> not_loaded(?LINE). -% acquire resource unit for calling process, monitor process +% @doc Get semaphore maximum capacity +-spec capacity(Semaphore :: sema_ref()) -> pos_integer(). +capacity(_) -> not_loaded(?LINE). + +% @doc Set semaphore maximum capacity. +% Return old capacity. +-spec capacity(Semaphore :: sema_ref(), Max :: integer()) -> pos_integer(). +capacity(_, _Max) -> not_loaded(?LINE). + +% @doc Acquire resource unit for calling process, monitor process -spec acquire(Semaphore :: sema_ref()) -> Ret :: acquire_ret(). acquire(_) -> not_loaded(?LINE). -% acquire resource Cnt units for calling process, monitor process +% @doc Acquire resource Cnt units for calling process, monitor process -spec acquire(Semaphore :: sema_ref(), Cnt :: pos_integer()) -> Ret :: acquire_ret(). acquire(_, _) -> not_loaded(?LINE). -% release resource unit acquired by calling process +% @doc Release resource unit acquired by calling process -spec release(Semaphore :: sema_ref()) -> Ret :: release_ret(). release(_) -> not_loaded(?LINE). -% release resource unit(s) acquired by calling/another process +% @doc Release resource unit(s) acquired by calling/another process -spec release(Semaphore :: sema_ref(), Arg :: pos_integer() | pid()) -> Ret :: release_ret(). release(_, _) -> not_loaded(?LINE). -% release resource units acquired by another process +% @doc Release resource units acquired by another process -spec release(Semaphore :: sema_ref(), Cnt :: pos_integer(), Pid :: pid()) -> Ret :: release_ret(). release(_, _, _) -> not_loaded(?LINE). diff --git a/test/sema_tests.erl b/test/sema_tests.erl index a1e1fc6..4a75706 100644 --- a/test/sema_tests.erl +++ b/test/sema_tests.erl @@ -6,6 +6,7 @@ basic_api_test() -> ?assertError(badarg, sema_nif:create(-1)), S = sema_nif:create(3), + ?assertEqual(3, sema_nif:capacity(S)), ?assertEqual(#{cnt => 0, dead => 0, max => 3}, sema_nif:info(S)), ?assertEqual({ok, 1}, sema_nif:acquire(S)), @@ -65,6 +66,8 @@ basic_api_test() -> ?assertEqual({ok, 0}, sema_nif:release(S, 2)), ?assertEqual(#{cnt => 0, dead => 0, max => 3}, sema_nif:info(S)), + ?assertEqual(3, sema_nif:capacity(S, 5)), + ?assertEqual(5, sema_nif:capacity(S)), ok. gc_test() ->