diff --git a/c_src/quicer_nif.c b/c_src/quicer_nif.c index de6ff29e..4cbd8b93 100644 --- a/c_src/quicer_nif.c +++ b/c_src/quicer_nif.c @@ -1142,6 +1142,10 @@ on_load(ErlNifEnv *env, init_atoms(env); +#if defined(QUICER_USE_SNK) + enif_set_pid_undefined(&GLOBAL_SNAB_KC_PID); +#endif + // TP must run after init_atoms as atoms are used in TP TP_NIF_3(start, &MsQuic, 0); if (!enif_get_uint(env, loadinfo, &load_vsn)) @@ -1738,7 +1742,11 @@ static ErlNifFunc nif_funcs[] = { { "get_stream_owner", 1, get_stream_owner1, 0}, { "get_listener_owner", 1, get_listener_owner1, 0}, /* for testing */ - { "mock_buffer_sig", 3, mock_buffer_sig, 0} + { "mock_buffer_sig", 3, mock_buffer_sig, 0}, + #ifdef QUICER_USE_SNK + { "set_snab_kc_pid", 1, set_snab_kc_pid, 0}, + { "get_snab_kc_pid", 0, get_snab_kc_pid, 0}, + #endif // clang-format on }; diff --git a/c_src/quicer_tp.c b/c_src/quicer_tp.c index b2874e55..e92eda5a 100644 --- a/c_src/quicer_tp.c +++ b/c_src/quicer_tp.c @@ -1,12 +1,42 @@ #define TRACEPOINT_CREATE_PROBES #define TRACEPOINT_DEFINE #include "quicer_tp.h" +#include "assert.h" extern uint64_t CxPlatTimeUs64(void); +// Compiler attributes +#define __unused_parm__ __attribute__((unused)) + +// Global pid for snabbkaffe collector +ErlNifPid GLOBAL_SNAB_KC_PID; // help macro to copy atom to env for debug emulator assertions #define ATOM_IN_ENV(X) enif_make_copy(env, ATOM_##X) +// This is a helper function to set the pid of the snabbkaffe collector +// because enif_whereis_pid in resource dtor violates beam lock orderings. +ERL_NIF_TERM +set_snab_kc_pid(ErlNifEnv *env, + __unused_parm__ int argc, + const ERL_NIF_TERM argv[]) +{ + assert(argc == 1); + if (!enif_get_local_pid(env, argv[0], &GLOBAL_SNAB_KC_PID)) + { + return ERROR_TUPLE_2(ATOM_BADARG); + } + return ATOM_OK; +} + +ERL_NIF_TERM +get_snab_kc_pid(ErlNifEnv *env, + __unused_parm__ int argc, + __unused_parm__ const ERL_NIF_TERM argv[]) +{ + assert(argc == 0); + return enif_make_pid(env, &GLOBAL_SNAB_KC_PID); +} + void tp_snk(ErlNifEnv *env, const char *ctx, @@ -15,45 +45,40 @@ tp_snk(ErlNifEnv *env, uint64_t rid, uint64_t mark) { - ErlNifPid pid; - if (enif_whereis_pid(env, ATOM_SNABBKAFFE_COLLECTOR, &pid)) - { - ERL_NIF_TERM snk_event; - ERL_NIF_TERM snk_event_key_array[7] - = { ATOM_IN_ENV(SNK_KIND), ATOM_IN_ENV(CONTEXT), - ATOM_IN_ENV(FUNCTION), ATOM_IN_ENV(TAG), - ATOM_IN_ENV(RESOURCE_ID), ATOM_IN_ENV(MARK), - ATOM_IN_ENV(SNK_META) }; - - ERL_NIF_TERM snk_evt_meta; - ERL_NIF_TERM snk_evt_meta_key_array[1] = { ATOM_IN_ENV(TIME) }; - ERL_NIF_TERM snk_evt_meta_val_array[1] - = { enif_make_uint64(env, CxPlatTimeUs64()) }; - - // shall never fail - enif_make_map_from_arrays(env, - snk_evt_meta_key_array, - snk_evt_meta_val_array, - 1, - &snk_evt_meta); - - ERL_NIF_TERM snk_event_val_array[7] = { - ATOM_IN_ENV(DEBUG), // snk_kind - enif_make_string(env, ctx, ERL_NIF_LATIN1), // context - enif_make_string(env, fun, ERL_NIF_LATIN1), // fun - enif_make_string(env, tag, ERL_NIF_LATIN1), // tag - enif_make_uint64(env, rid), // rid - enif_make_uint64(env, mark), // mark - snk_evt_meta // snk_meta - }; - - enif_make_map_from_arrays( - env, snk_event_key_array, snk_event_val_array, 7, &snk_event); - - ERL_NIF_TERM report = enif_make_tuple2( - env, - ATOM_IN_ENV(GEN_CAST), - enif_make_tuple2(env, ATOM_IN_ENV(TRACE), snk_event)); - enif_send(NULL, &pid, NULL, report); - } + ErlNifPid *pid = &GLOBAL_SNAB_KC_PID; + + ERL_NIF_TERM snk_event; + ERL_NIF_TERM snk_event_key_array[7] + = { ATOM_IN_ENV(SNK_KIND), ATOM_IN_ENV(CONTEXT), + ATOM_IN_ENV(FUNCTION), ATOM_IN_ENV(TAG), + ATOM_IN_ENV(RESOURCE_ID), ATOM_IN_ENV(MARK), + ATOM_IN_ENV(SNK_META) }; + + ERL_NIF_TERM snk_evt_meta; + ERL_NIF_TERM snk_evt_meta_key_array[1] = { ATOM_IN_ENV(TIME) }; + ERL_NIF_TERM snk_evt_meta_val_array[1] + = { enif_make_uint64(env, CxPlatTimeUs64()) }; + + // shall never fail + enif_make_map_from_arrays( + env, snk_evt_meta_key_array, snk_evt_meta_val_array, 1, &snk_evt_meta); + + ERL_NIF_TERM snk_event_val_array[7] = { + ATOM_IN_ENV(DEBUG), // snk_kind + enif_make_string(env, ctx, ERL_NIF_LATIN1), // context + enif_make_string(env, fun, ERL_NIF_LATIN1), // fun + enif_make_string(env, tag, ERL_NIF_LATIN1), // tag + enif_make_uint64(env, rid), // rid + enif_make_uint64(env, mark), // mark + snk_evt_meta // snk_meta + }; + + enif_make_map_from_arrays( + env, snk_event_key_array, snk_event_val_array, 7, &snk_event); + + ERL_NIF_TERM report + = enif_make_tuple2(env, + ATOM_IN_ENV(GEN_CAST), + enif_make_tuple2(env, ATOM_IN_ENV(TRACE), snk_event)); + enif_send(NULL, pid, NULL, report); } diff --git a/c_src/quicer_tp.h b/c_src/quicer_tp.h index e9873034..49eb95c3 100644 --- a/c_src/quicer_tp.h +++ b/c_src/quicer_tp.h @@ -54,6 +54,7 @@ TRACEPOINT_EVENT( /* END of ifdef QUICER_USE_LTTNG */ #elif defined(QUICER_USE_SNK) +extern ErlNifPid GLOBAL_SNAB_KC_PID; #define TP_NIF_3(TAG, RID, ARG) \ tp_snk(env, "nif", __func__, #TAG, (uint64_t)RID, ARG) @@ -66,6 +67,11 @@ void tp_snk(ErlNifEnv *env, const char *tag, uint64_t rid, uint64_t mark); + +ERL_NIF_TERM +set_snab_kc_pid(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); +ERL_NIF_TERM +get_snab_kc_pid(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); /* END of ifdef QUICER_USE_SNK */ #else /* NO TP is defined */ diff --git a/src/quicer_nif.erl b/src/quicer_nif.erl index 04d74928..16fa7934 100644 --- a/src/quicer_nif.erl +++ b/src/quicer_nif.erl @@ -65,7 +65,9 @@ get_conn_owner/1, get_stream_owner/1, get_listener_owner/1, - mock_buffer_sig/3 + mock_buffer_sig/3, + set_snab_kc_pid/1, + get_snab_kc_pid/0 ]). -export([abi_version/0]). @@ -405,6 +407,14 @@ flush_stream_buffered_sigs(_H) -> mock_buffer_sig(_StreamHandle, _OrigOwner, _Msg) -> erlang:nif_error(nif_library_not_loaded). +-spec set_snab_kc_pid(pid()) -> ok | {error, badarg}. +set_snab_kc_pid(_Pid) -> + erlang:nif_error(nif_library_not_loaded). + +-spec get_snab_kc_pid() -> pid(). +get_snab_kc_pid() -> + erlang:nif_error(nif_library_not_loaded). + %% Internals -spec locate_lib(file:name(), file:name()) -> {ok, file:filename()} | {error, not_found}. diff --git a/test/quicer_snb_SUITE.erl b/test/quicer_snb_SUITE.erl index cd6ec4b4..81e9812e 100644 --- a/test/quicer_snb_SUITE.erl +++ b/test/quicer_snb_SUITE.erl @@ -66,6 +66,17 @@ -include_lib("snabbkaffe/include/snabbkaffe.hrl"). -include("quicer.hrl"). +-define(my_check_trace(BUCKET, RUN, CHECK), + ?check_trace( + BUCKET, + begin + quicer_nif:set_snab_kc_pid(whereis(snabbkaffe_collector)), + RUN + end, + CHECK + ) +). + %%-------------------------------------------------------------------- %% @spec suite() -> Info %% Info = [tuple()] @@ -247,7 +258,7 @@ tc_app_echo_server(Config) -> {ok, _QuicApp} = quicer_start_listener(mqtt, Port, Options), {ok, Conn} = quicer:connect("localhost", Port, default_conn_opts(), 5000), {ok, Stm} = quicer:start_stream(Conn, [{active, false}]), - ?check_trace( + ?my_check_trace( #{timetrap => 5000}, begin {ok, 4} = quicer:async_send(Stm, <<"ping">>), @@ -312,7 +323,7 @@ tc_slow_conn(Config) -> ], Options = {ListenerOpts, ConnectionOpts, StreamOpts}, ct:pal("Listener Options: ~p", [Options]), - ?check_trace( + ?my_check_trace( #{timetrap => 1000}, begin {ok, _QuicApp} = quicer_start_listener(mqtt, Port, Options), @@ -367,7 +378,7 @@ tc_stream_owner_down(Config) -> ], Options = {ListenerOpts, ConnectionOpts, StreamOpts}, ct:pal("Listener Options: ~p", [Options]), - ?check_trace( + ?my_check_trace( #{timetrap => 10000}, begin {ok, _QuicApp} = quicer_start_listener(mqtt, Port, Options), @@ -501,7 +512,7 @@ tc_stream_acceptor_down(Config) -> ], Options = {ListenerOpts, ConnectionOpts, StreamOpts}, ct:pal("Listener Options: ~p", [Options]), - ?check_trace( + ?my_check_trace( #{timetrap => 10000}, begin {ok, _QuicApp} = quicer:spawn_listener(mqtt, Port, Options), @@ -601,7 +612,7 @@ tc_conn_owner_down(Config) -> ], Options = {ListenerOpts, ConnectionOpts, StreamOpts}, ct:pal("Listener Options: ~p", [Options]), - ?check_trace( + ?my_check_trace( #{timetrap => 10000}, begin {ok, _QuicApp} = quicer_start_listener(mqtt, Port, Options), @@ -795,7 +806,7 @@ tc_conn_close_flag_1(Config) -> ], Options = {ListenerOpts, ConnectionOpts, StreamOpts}, ct:pal("Listener Options: ~p", [Options]), - ?check_trace( + ?my_check_trace( #{timetrap => 1000}, begin {ok, _QuicApp} = quicer_start_listener(mqtt, Port, Options), @@ -878,7 +889,7 @@ tc_conn_close_flag_2(Config) -> ], Options = {ListenerOpts, ConnectionOpts, StreamOpts}, ct:pal("Listener Options: ~p", [Options]), - ?check_trace( + ?my_check_trace( #{timetrap => 10000}, begin {ok, _QuicApp} = quicer_start_listener(mqtt, Port, Options), @@ -927,7 +938,7 @@ tc_stream_close_errno(Config) -> ], Options = {ListenerOpts, ConnectionOpts, StreamOpts}, ct:pal("Listener Options: ~p", [Options]), - ?check_trace( + ?my_check_trace( #{timetrap => 10000}, begin {ok, _QuicApp} = quicer_start_listener(mqtt, Port, Options), @@ -1046,7 +1057,7 @@ tc_stream_shutdown_abort(Config) -> ], Options = {ListenerOpts, ConnectionOpts, StreamOpts}, ct:pal("Listener Options: ~p", [Options]), - ?check_trace( + ?my_check_trace( #{timetrap => 10000}, begin {ok, _QuicApp} = quicer_start_listener(mqtt, Port, Options), @@ -1203,7 +1214,7 @@ tc_conn_idle_close(Config) -> ], Options = {ListenerOpts, ConnectionOpts, StreamOpts}, ct:pal("Listener Options: ~p", [Options]), - ?check_trace( + ?my_check_trace( #{timetrap => 10000}, begin {ok, _QuicApp} = quicer_start_listener(mqtt, Port, Options), @@ -1318,7 +1329,7 @@ tc_conn_gc(Config) -> ], Options = {ListenerOpts, ConnectionOpts, StreamOpts}, ct:pal("Listener Options: ~p", [Options]), - ?check_trace( + ?my_check_trace( #{timetrap => 100000}, begin %% Spawn a process that will die without handle cleanups @@ -1490,7 +1501,7 @@ tc_conn_no_gc(Config) -> ], Options = {ListenerOpts, ConnectionOpts, StreamOpts}, ct:pal("Listener Options: ~p", [Options]), - ?check_trace( + ?my_check_trace( #{timetrap => 10000}, begin %% Spawn a client process that will close the connection explicitly before die. @@ -1622,7 +1633,7 @@ tc_conn_no_gc_2(Config) -> ], Options = {ListenerOpts, ConnectionOpts, StreamOpts}, ct:pal("Listener Options: ~p", [Options]), - ?check_trace( + ?my_check_trace( #{timetrap => 20000}, begin %% Spawn a client process that will close the connection explicitly before die. @@ -1773,7 +1784,7 @@ tc_conn_resume_nst(Config) -> ], Options = {ListenerOpts, ConnectionOpts, StreamOpts}, ct:pal("Listener Options: ~p", [Options]), - ?check_trace( + ?my_check_trace( #{timetrap => 10000}, begin {ok, _QuicApp} = quicer_start_listener(mqtt, Port, Options), @@ -1878,7 +1889,7 @@ tc_conn_resume_nst_with_stream(Config) -> ], Options = {ListenerOpts, ConnectionOpts, StreamOpts}, ct:pal("Listener Options: ~p", [Options]), - ?check_trace( + ?my_check_trace( #{timetrap => 10000}, begin {ok, _QuicApp} = quicer_start_listener(mqtt, Port, Options), @@ -1979,7 +1990,7 @@ tc_conn_resume_nst_async(Config) -> ], Options = {ListenerOpts, ConnectionOpts, StreamOpts}, ct:pal("Listener Options: ~p", [Options]), - ?check_trace( + ?my_check_trace( #{timetrap => 10000}, begin {ok, _QuicApp} = quicer_start_listener(mqtt, Port, Options), @@ -2078,7 +2089,7 @@ tc_conn_resume_nst_async_2(Config) -> ], Options = {ListenerOpts, ConnectionOpts, StreamOpts}, ct:pal("Listener Options: ~p", [Options]), - ?check_trace( + ?my_check_trace( #{timetrap => 10000}, begin {ok, _QuicApp} = quicer_start_listener(mqtt, Port, Options), @@ -2177,7 +2188,7 @@ tc_conn_resume_nst_with_data(Config) -> ], Options = {ListenerOpts, ConnectionOpts, StreamOpts}, ct:pal("Listener Options: ~p", [Options]), - ?check_trace( + ?my_check_trace( #{timetrap => 10000}, begin {ok, _QuicApp} = quicer_start_listener(mqtt, Port, Options), @@ -2316,7 +2327,7 @@ tc_listener_no_acceptor(Config) -> ], Options = {ListenerOpts, ConnectionOpts, StreamOpts}, ct:pal("Listener Options: ~p", [Options]), - ?check_trace( + ?my_check_trace( #{timetrap => 10000}, begin {ok, _QuicApp} = quicer_start_listener(mqtt, Port, Options), @@ -2351,7 +2362,7 @@ tc_listener_no_acceptor(Config) -> %% @doc this triggers listener start fail tc_listener_inval_local_addr(Config) -> BadListenOn = "8.8.8.8:443", - ?check_trace( + ?my_check_trace( #{timetrap => 10000}, begin Res = quicer:listen(BadListenOn, default_listen_opts(Config)), @@ -2391,7 +2402,7 @@ tc_listener_inval_local_addr(Config) -> tc_conn_start_inval_port(_Config) -> application:ensure_all_started(quicer), BadPort = 65536, - ?check_trace( + ?my_check_trace( #{timetrap => 10000}, begin Res = quicer:connect("localhost", BadPort, default_conn_opts(), infinity), @@ -2449,7 +2460,7 @@ tc_conn_stop_notify_acceptor(Config) -> ], Options = {ListenerOpts, ConnectionOpts, StreamOpts}, ct:pal("Listener Options: ~p", [Options]), - ?check_trace( + ?my_check_trace( #{timetrap => 10000}, begin Parent = self(), @@ -2521,7 +2532,7 @@ tc_accept_stream_active_once(Config) -> ], Options = {ListenerOpts, ConnectionOpts, StreamOpts}, ct:pal("Listener Options: ~p", [Options]), - ?check_trace( + ?my_check_trace( #{timetrap => 10000}, begin {ok, _QuicApp} = quicer:spawn_listener(mqtt, Port, Options), @@ -2610,7 +2621,7 @@ tc_accept_stream_active_N(Config) -> ], Options = {ListenerOpts, ConnectionOpts, StreamOpts}, ct:pal("Listener Options: ~p", [Options]), - ?check_trace( + ?my_check_trace( #{timetrap => 10000}, begin {ok, _QuicApp} = quicer:spawn_listener(mqtt, Port, Options), @@ -2721,7 +2732,7 @@ tc_multi_streams(Config) -> ], Options = {ListenerOpts, ConnectionOpts, StreamOpts}, ct:pal("Listener Options: ~p", [Options]), - ?check_trace( + ?my_check_trace( #{timetrap => 10000}, begin {ok, _QuicApp} = quicer:spawn_listener(mqtt, Port, Options), @@ -2793,7 +2804,7 @@ tc_multi_streams_example_server_1(Config) -> ], Options = {ListenerOpts, ConnectionOpts, StreamOpts}, ct:pal("Listener Options: ~p", [Options]), - ?check_trace( + ?my_check_trace( #{timetrap => 10000}, begin {ok, _QuicApp} = quicer:spawn_listener(mqtt, Port, Options), @@ -2914,7 +2925,7 @@ tc_multi_streams_example_server_2(Config) -> ], Options = {ListenerOpts, ConnectionOpts, StreamOpts}, ct:pal("Listener Options: ~p", [Options]), - ?check_trace( + ?my_check_trace( #{timetrap => 10000}, begin {ok, _QuicApp} = quicer:spawn_listener(mqtt, Port, Options), @@ -2996,7 +3007,7 @@ tc_multi_streams_example_server_3(Config) -> ], Options = {ListenerOpts, ConnectionOpts, StreamOpts}, ct:pal("Listener Options: ~p", [Options]), - ?check_trace( + ?my_check_trace( #{timetrap => 10000}, begin {ok, _QuicApp} = quicer:spawn_listener(mqtt, Port, Options), @@ -3241,7 +3252,7 @@ tc_passive_recv_1(Config) -> ], Options = {ListenerOpts, ConnectionOpts, StreamOpts}, ct:pal("Listener Options: ~p", [Options]), - ?check_trace( + ?my_check_trace( #{timetrap => 10000}, begin {ok, _QuicApp} = quicer:spawn_listener(mqtt, Port, Options),