summaryrefslogtreecommitdiff
path: root/src/vm/autotrace.cpp
blob: 75afe908457c9316e218d6c7d792b8829bfb51e9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

/**
 *
 * AutoTrace: This infrastructure is used to run automated testing of Diagnostic Server based tracing via
 * EventPipe.  The feature itself is enabled via the feature flag FEATURE_AUTO_TRACE.
 * 
 * Two environment variables dictate behavior:
 * - COMPlus_AutoTrace_N_Tracers: a number in [0,64] where 0 will disable the feature
 * - COMPlus_AutoTrace_Command: The path to an executable to be invoked.  Typically this will be a "run.sh|cmd".
 *  > (NB: you should `cd` into the directory you intend to execute `COMPlus_AutoTrace_Command` from as the first line of the script.)
 * 
 * Once turned on, AutoTrace will run the specified command `COMPlus_AutoTrace_N_Tracers` times.  There is an event that will pause execution
 * of the runtime until all the tracers have attached.  Once all the tracers are attached, execution will continue normally.
 * 
 * This logic is easily modified to accommodate testing other mechanisms related to the Diagnostic Server.
 * 
 */

#include "common.h" // Required for pre-compiled header

#ifdef FEATURE_AUTO_TRACE
#ifdef FEATURE_PAL
#include "pal.h"
#endif // FEATURE_PAL

HANDLE auto_trace_event;
static size_t g_n_tracers = 1;
static const WCHAR* command_format = W("%hs -p %d");
static WCHAR* command = nullptr;

void auto_trace_init()
{
    char *nAutoTracersValue = getenv("COMPlus_AutoTrace_N_Tracers");
    if (nAutoTracersValue != NULL)
    {
        g_n_tracers = strtoul(nAutoTracersValue, NULL, 10);
    }

    // Get the command to run auto-trace.  Note that the `-p <pid>` option
    // will be automatically added for you
    char *commandTextValue = getenv("COMPlus_AutoTrace_Command");
    if (commandTextValue != NULL)
    {
        DWORD currentProcessId = GetCurrentProcessId();
        command = new WCHAR[8192];
        _snwprintf_s(command, 8192, _TRUNCATE, command_format, commandTextValue, currentProcessId);
    }
    else
    {
        // we don't have anything to run, just set
        // n tracers to 0...
        g_n_tracers = 0;
    }

    auto_trace_event = CreateEventW(
        /* lpEventAttributes = */ NULL,
        /* bManualReset      = */ FALSE,
        /* bInitialState     = */ FALSE,
        /* lpName            = */ nullptr
    );
}

void auto_trace_launch_internal()
{
    DWORD currentProcessId = GetCurrentProcessId();
    STARTUPINFO si;
    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(STARTUPINFO);
#ifndef FEATURE_PAL
    si.dwFlags = STARTF_USESHOWWINDOW;
    si.wShowWindow = SW_HIDE;
#endif
    
    PROCESS_INFORMATION result;

    BOOL code = CreateProcessW(
        /* lpApplicationName    = */ nullptr,
        /* lpCommandLine        = */ command,
        /* lpCommandLine        = */ nullptr,
        /* lpThreadAttributes   = */ nullptr,
        /* bInheritHandles      = */ false,
        /* dwCreationFlags      = */ CREATE_NEW_CONSOLE,
        /* lpEnvironment        = */ nullptr,
        /* lpCurrentDirectory   = */ nullptr,
        /* lpStartupInfo        = */ &si,
        /* lpProcessInformation = */ &result
    );
}

void auto_trace_launch()
{
    for (int i = 0; i < g_n_tracers; ++i)
    {
        auto_trace_launch_internal();
    }
    delete[] command;
}

void auto_trace_wait()
{
    if (g_n_tracers > 0)
        WaitForSingleObject(auto_trace_event, INFINITE);
}

void auto_trace_signal()
{
    #ifdef SetEvent
    #undef SetEvent
    #endif
    static size_t nCalls = 0;
    if (++nCalls == g_n_tracers)
        SetEvent(auto_trace_event);
}

#endif // FEATURE_AUTO_TRACE