diff --git a/c_src/quicer_ctx.c b/c_src/quicer_ctx.c index 43f85280..45e7adf6 100644 --- a/c_src/quicer_ctx.c +++ b/c_src/quicer_ctx.c @@ -437,3 +437,18 @@ cleanup_owner_signals(QuicerStreamCTX *s_ctx) OwnerSignalQueueDestroy(s_ctx->sig_queue); s_ctx->sig_queue = NULL; } + +ERL_NIF_TERM +copy_stream_handle(ErlNifEnv *env, + __unused_parm__ int argc, + const ERL_NIF_TERM argv[]) +{ + QuicerStreamCTX *ctx = NULL; + if (!enif_get_resource(env, argv[0], ctx_stream_t, (void **)&ctx)) + { + return enif_make_badarg(env); + } + assert(ctx != NULL); + enif_make_copy(ctx->env, ctx->eHandle); + return ATOM_OK; +} diff --git a/c_src/quicer_ctx.h b/c_src/quicer_ctx.h index 9482ed93..9068566d 100644 --- a/c_src/quicer_ctx.h +++ b/c_src/quicer_ctx.h @@ -202,4 +202,7 @@ void cache_stream_id(QuicerStreamCTX *s_ctx); void cleanup_owner_signals(QuicerStreamCTX *s_ctx); +ERL_NIF_TERM +copy_stream_handle(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); + #endif // __QUICER_CTX_H_ diff --git a/c_src/quicer_nif.c b/c_src/quicer_nif.c index 4cbd8b93..45309b21 100644 --- a/c_src/quicer_nif.c +++ b/c_src/quicer_nif.c @@ -21,6 +21,10 @@ limitations under the License. #include "quicer_listener.h" #include "quicer_vsn.h" +#if defined(__linux__) +#include +#endif + #include #include @@ -1692,6 +1696,28 @@ make_event(ErlNifEnv *env, prop); // 4th element, event props :: any()) // } +#if defined(__linux__) +ERL_NIF_TERM +do_malloc_trim(__unused_parm__ ErlNifEnv *env, + __unused_parm__ int argc, + __unused_parm__ const ERL_NIF_TERM argv[]) +{ + CXPLAT_FRE_ASSERT(argc == 0); + malloc_trim(0); + return ATOM_OK; +} + +ERL_NIF_TERM +do_malloc_stats(__unused_parm__ ErlNifEnv *env, + __unused_parm__ int argc, + __unused_parm__ const ERL_NIF_TERM argv[]) +{ + CXPLAT_FRE_ASSERT(argc == 0); + malloc_stats(); + return ATOM_OK; +} +#endif + static ErlNifFunc nif_funcs[] = { /* | name | arity| funptr | flags| * @@ -1741,8 +1767,13 @@ static ErlNifFunc nif_funcs[] = { { "get_conn_owner", 1, get_conn_owner1, 0}, { "get_stream_owner", 1, get_stream_owner1, 0}, { "get_listener_owner", 1, get_listener_owner1, 0}, + { "copy_stream_handle", 1, copy_stream_handle, 0}, /* for testing */ { "mock_buffer_sig", 3, mock_buffer_sig, 0}, +#if defined(__linux__) + { "malloc_trim", 0, do_malloc_trim, 0}, + { "malloc_stats", 0, do_malloc_stats, 0}, +#endif #ifdef QUICER_USE_SNK { "set_snab_kc_pid", 1, set_snab_kc_pid, 0}, { "get_snab_kc_pid", 0, get_snab_kc_pid, 0}, diff --git a/src/quicer_nif.erl b/src/quicer_nif.erl index 16fa7934..3d260a0a 100644 --- a/src/quicer_nif.erl +++ b/src/quicer_nif.erl @@ -54,6 +54,12 @@ get_stream_rid/1 ]). +%% tools +-export([ + malloc_trim/0, + malloc_stats/0 +]). + %% For tests only -export([ open_connection/0, @@ -65,6 +71,7 @@ get_conn_owner/1, get_stream_owner/1, get_listener_owner/1, + copy_stream_handle/1, mock_buffer_sig/3, set_snab_kc_pid/1, get_snab_kc_pid/0 @@ -346,6 +353,14 @@ get_conn_rid(_Handle) -> get_stream_rid(_Handle) -> erlang:nif_error(nif_library_not_loaded). +-spec malloc_trim() -> ok. +malloc_trim() -> + erlang:nif_error(nif_library_not_loaded). + +-spec malloc_stats() -> ok. +malloc_stats() -> + erlang:nif_error(nif_library_not_loaded). + -spec controlling_process(connection_handle() | stream_handle(), pid()) -> ok | {error, closed | badarg | owner_dead | not_owner}. @@ -385,6 +400,10 @@ get_connections() -> get_connections(_RegHandle) -> erlang:nif_error(nif_library_not_loaded). +-spec copy_stream_handle(stream_handle()) -> {ok, stream_handle()} | {error, badarg}. +copy_stream_handle(_H) -> + erlang:nif_error(nif_library_not_loaded). + %% @doc enable signal buffering, used in stream handoff. %% * not exposed API. -spec enable_sig_buffer(stream_handle()) -> ok. diff --git a/test/quicer_SUITE.erl b/test/quicer_SUITE.erl index 14c65954..0c6a4928 100644 --- a/test/quicer_SUITE.erl +++ b/test/quicer_SUITE.erl @@ -155,6 +155,10 @@ tc_peercert_server/1, tc_peercert_server_nocert/1, + %% Toolings + tc_malloc_trim/1, + tc_malloc_stats/1, + %% Versions test tc_abi_version/1 %% testcase to verify env works @@ -226,6 +230,14 @@ end_per_group(_Groupname, _Config) -> %%%=================================================================== %%% Testcase specific setup/teardown %%%=================================================================== +init_per_testcase(TC, Config) when + TC =:= tc_malloc_trim orelse + TC =:= tc_malloc_stats +-> + case os:type() of + {unix, darwin} -> {skip, "Not runnable on MacOS"}; + _ -> Config + end; init_per_testcase(_TestCase, Config) -> quicer_test_lib:cleanup_msquic(), [{timetrap, 5000} | Config]. @@ -838,10 +850,10 @@ tc_stream_controlling_process_demon(Config) -> end ), receive - {'DOWN', MonRef, process, NewOwner, {Res, Stm}} -> + {'DOWN', MonRef, process, OldOwner, {Res, Stm}} -> ct:pal("Set controlling_process res: ~p", [Res]) end, - ?assertEqual({error, owner_dead}, quicer:controlling_process(Stm, NewOwner)), + ?assertEqual({error, owner_dead}, quicer:controlling_process(Stm, OldOwner)), ok = quicer:setopt(Stm, active, true), {ok, _Len} = quicer:send(Stm, <<"owner_changed">>), receive @@ -3193,6 +3205,12 @@ tc_setopt_congestion_control_algorithm(Config) -> SPid ! done, ok. +tc_malloc_trim(_) -> + quicer_nif:malloc_trim(). + +tc_malloc_stats(_) -> + quicer_nif:malloc_stats(). + %%% ==================== %%% Internal helpers %%% ====================