|
|
@ -135,55 +135,28 @@ static ERL_NIF_TERM enabled_garbage_collection(ErlNifEnv *env, int argc, const E |
|
|
|
|
|
|
|
// trace(TraceTag, TracerState, Tracee, TraceTerm, Opts) |
|
|
|
static ERL_NIF_TERM trace(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { |
|
|
|
enif_fprintf(stdout, "IMY************trace:"); |
|
|
|
for (int i = 0; i <= argc - 1; i++) { |
|
|
|
if (i != 1) { |
|
|
|
enif_fprintf(stdout, " %d %T", i, argv[i]); |
|
|
|
} |
|
|
|
} |
|
|
|
enif_fprintf(stdout, "\n"); |
|
|
|
|
|
|
|
ERL_NIF_TERM tracers, head, ts, extra, mspec, msg; |
|
|
|
ErlNifPid tracer; |
|
|
|
unsigned int nth; |
|
|
|
size_t len; |
|
|
|
int has_extra, has_mspec; |
|
|
|
|
|
|
|
if (!enif_get_map_value(env, argv[1], atom_tracers, &tracers)) |
|
|
|
return atom_ok; |
|
|
|
|
|
|
|
// We know for a fact that the argument is a map. And if not, |
|
|
|
// no problem because we will return when trying to get a value from it. |
|
|
|
enif_get_map_size(env, tracers, &len); |
|
|
|
|
|
|
|
#if (ERL_NIF_MAJOR_VERSION >= 2) && (ERL_NIF_MINOR_VERSION >= 12) |
|
|
|
nth = enif_hash(ERL_NIF_INTERNAL_HASH, argv[2], 0) % len; |
|
|
|
#else |
|
|
|
// Select the correct tracer for this process. |
|
|
|
// |
|
|
|
// The pid value is detailed in: |
|
|
|
// 5b6dd0e84cf0f1dc19ddd05f86cf04b2695d8a9e/erts/emulator/beam/erl_term.h#L498 |
|
|
|
// |
|
|
|
// As can be seen there, the first four bits of the pid value |
|
|
|
// are always the same. We therefore shift them out. |
|
|
|
|
|
|
|
ErlNifPid tracee; |
|
|
|
|
|
|
|
if (!enif_get_local_pid(env, argv[2], &tracee)) |
|
|
|
return atom_ok; |
|
|
|
|
|
|
|
nth = (tracee.pid >> 4) % len; |
|
|
|
#endif |
|
|
|
// IMY-todo 参数打印 |
|
|
|
// enif_fprintf(stdout, "IMY************trace:"); |
|
|
|
// for (int i = 0; i <= argc - 1; i++) { |
|
|
|
// if (i != 1) { |
|
|
|
// enif_fprintf(stdout, " %d %T", i, argv[i]); |
|
|
|
// } |
|
|
|
// } |
|
|
|
// enif_fprintf(stdout, "\n"); |
|
|
|
|
|
|
|
int arity, has_extra, has_mspec; |
|
|
|
const ERL_NIF_TERM *tuple; |
|
|
|
ErlNifPid tracer_pid; |
|
|
|
|
|
|
|
if (!enif_get_map_value(env, tracers, enif_make_int(env, nth), &head)) |
|
|
|
if (!enif_get_tuple(env, argv[1], &arity, &tuple)) { |
|
|
|
return atom_ok; |
|
|
|
} |
|
|
|
|
|
|
|
if (!enif_get_local_pid(env, head, &tracer)) |
|
|
|
// Disable the trace when one of the tracers is not a local process. |
|
|
|
if (!enif_get_local_pid(env, tuple[0], &tracer_pid)) |
|
|
|
return atom_ok; |
|
|
|
|
|
|
|
// Everything good. Generate a timestamp to include in the message. |
|
|
|
|
|
|
|
ts = enif_make_int64(env, enif_monotonic_time(ERL_NIF_USEC)); |
|
|
|
ERL_NIF_TERM ts, extra, mspec, msg; |
|
|
|
|
|
|
|
// Build the message. There can be two different messages |
|
|
|
// depending on whether the extra option was set: |
|
|
@ -201,6 +174,10 @@ static ERL_NIF_TERM trace(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { |
|
|
|
has_extra = enif_get_map_value(env, argv[4], atom_extra, &extra); |
|
|
|
has_mspec = enif_get_map_value(env, argv[4], atom_match_spec_result, &mspec); |
|
|
|
|
|
|
|
ErlNifTime mon = enif_monotonic_time(ERL_NIF_NSEC); |
|
|
|
ts = enif_make_int64(env, mon); |
|
|
|
//ts = enif_cpu_time(env); |
|
|
|
|
|
|
|
if (has_extra && has_mspec) |
|
|
|
msg = enif_make_tuple6(env, argv[0], argv[2], ts, argv[3], extra, mspec); |
|
|
|
else if (has_extra) |
|
|
@ -210,9 +187,8 @@ static ERL_NIF_TERM trace(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { |
|
|
|
else |
|
|
|
msg = enif_make_tuple4(env, argv[0], argv[2], ts, argv[3]); |
|
|
|
|
|
|
|
// Send the message to the selected tracer. |
|
|
|
|
|
|
|
enif_send(env, &tracer, NULL, msg); |
|
|
|
// Send the message to the tracer_pid. |
|
|
|
enif_send(env, &tracer_pid, NULL, msg); |
|
|
|
|
|
|
|
return atom_ok; |
|
|
|
} |
|
|
@ -228,5 +204,4 @@ static ErlNifFunc nifFuns[] = { |
|
|
|
{"trace", 5, trace}, |
|
|
|
}; |
|
|
|
|
|
|
|
ERL_NIF_INIT(tpTracerNif, nifFuns, load, NULL, upgrade, unload |
|
|
|
) |
|
|
|
ERL_NIF_INIT(tpTracerNif, nifFuns, load, NULL, upgrade, unload) |