Repository: JuliaLang/julia
File: src/signals-win.c (C)

Code before:
    ctx->ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
    if (!GetThreadContext(hThread, ctx)) {
        if ((DWORD)-1 == ResumeThread(hThread))
            abort();
        return 0;
    }
    return 1;
}

void jl_thread_resume(int tid)
{
    jl_ptls_t ptls2 = jl_atomic_load_relaxed(&jl_all_tls_states)[tid];
    HANDLE hThread = ptls2->system_id;
    if ((DWORD)-1 == ResumeThread(hThread)) {
        jl_safe_fprintf(ios_safe_stderr, "failed to resume main thread! aborting.\n");
        abort();
    }
}

int jl_thread_suspend(int16_t tid, bt_context_t *ctx)
{
    jl_lock_profile(); // prevent concurrent mutation
    uv_mutex_lock(&jl_in_stackwalk); // prevent multi-threaded dbghelp calls
    jl_profile_process_dll_events(); // process any deferred dll events delayed due to lock contention
    int success = jl_thread_suspend_and_get_state(tid, 0, ctx);
    uv_mutex_unlock(&jl_in_stackwalk);
    jl_unlock_profile();
    return success;
}

static DWORD WINAPI profile_bt( LPVOID lparam )
{
    // Note: illegal to use jl_* functions from this thread except for profiling-specific functions
    HANDLE hTimerQueue = CreateTimerQueue();
    if (hTimerQueue == NULL) {
        jl_safe_fprintf(ios_safe_stderr, "failed to create profile watchdog timer queue.\n");
        abort();
    }
    while (1) {
        DWORD timeout_ms = nsecprof / (GIGA / 1000);
        Sleep(timeout_ms > 0 ? timeout_ms : 1);
        if (jl_profile_is_buffer_full())
            jl_profile_stop_timer(); // does not change the thread state
        if (!profile_running) {
            uv_mutex_lock(&bt_data_prof_lock);
            while (!profile_running)
                uv_cond_wait(&bt_data_prof_cond, &bt_data_prof_lock);
            uv_mutex_unlock(&bt_data_prof_lock);
        }
        else if (profile_all_tasks) {
            // Don't take the stackwalk lock here since it's already taken in `jl_rec_backtrace`

Review comment (suggestion):
```suggestion
    int success = jl_thread_suspend_and_get_state(tid, 0, ctx);
    if (jl_atomic_load_relaxed(&dll_notify_queue)) {
        // if the dll_notify_queue is set, we lost the race against new code being added and cannot safely examine ctx
        // resume the thread and let the outer loop retry (better yet, we could loop in this function instead)
        jl_thread_resume(tid);
        success = 0;
    }
```

Code after:
    ctx->ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
    if (!GetThreadContext(hThread, ctx)) {
        if ((DWORD)-1 == ResumeThread(hThread))
            abort();
        return 0;
    }
    return 1;
}

void jl_thread_resume(int tid)
{
    jl_ptls_t ptls2 = jl_atomic_load_relaxed(&jl_all_tls_states)[tid];
    HANDLE hThread = ptls2->system_id;
    if ((DWORD)-1 == ResumeThread(hThread)) {
        jl_safe_fprintf(ios_safe_stderr, "failed to resume main thread! aborting.\n");
        abort();
    }
}

int jl_thread_suspend(int16_t tid, bt_context_t *ctx)
{
    jl_lock_profile(); // prevent concurrent mutation
    uv_mutex_lock(&jl_in_stackwalk); // prevent multi-threaded dbghelp calls
    uv_mutex_lock(&jl_dll_notify_lock);
    jl_profile_process_dll_events();
    int success = jl_thread_suspend_and_get_state(tid, 0, ctx);
    uv_mutex_unlock(&jl_dll_notify_lock);
    uv_mutex_unlock(&jl_in_stackwalk);
    jl_unlock_profile();
    return success;
}

static DWORD WINAPI profile_bt( LPVOID lparam )
{
    // Note: illegal to use jl_* functions from this thread except for profiling-specific functions
    HANDLE hTimerQueue = CreateTimerQueue();
    if (hTimerQueue == NULL) {
        jl_safe_fprintf(ios_safe_stderr, "failed to create profile watchdog timer queue.\n");
        abort();
    }
    while (1) {
        DWORD timeout_ms = nsecprof / (GIGA / 1000);
        Sleep(timeout_ms > 0 ? timeout_ms : 1);
        if (jl_profile_is_buffer_full())
            jl_profile_stop_timer(); // does not change the thread state
        if (!profile_running) {
            uv_mutex_lock(&bt_data_prof_lock);
            while (!profile_running)
                uv_cond_wait(&bt_data_prof_cond, &bt_data_prof_lock);
            uv_mutex_unlock(&bt_data_prof_lock);
        }