Skip to content

Commit

Permalink
Implement thrd_signal_invoke() for Windows.
Browse files Browse the repository at this point in the history
  • Loading branch information
ned14 committed Feb 13, 2025
1 parent aaf45eb commit 6311956
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 33 deletions.
88 changes: 59 additions & 29 deletions src/wg14_signals/thrd_signal_handle_windows.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,19 +75,67 @@ static int signal_from_win32_exception_code(DWORD c)
}
}

void prepare_rsi(struct WG14_SIGNALS_PREFIX(thrd_raised_signal_info) * rsi,
const int signo, EXCEPTION_POINTERS *ptrs)
{
memset(rsi, 0, sizeof(*rsi));
rsi->signo = signo;
if(ptrs->ExceptionRecord->NumberParameters >= 2 &&
ptrs->ExceptionRecord
->ExceptionInformation[ptrs->ExceptionRecord->NumberParameters - 2] ==
(ULONG_PTR) 0xdeadbeefdeadbeef)
{
rsi->raw_context =
(void *) ptrs->ExceptionRecord
->ExceptionInformation[ptrs->ExceptionRecord->NumberParameters - 1];
}
else
{
rsi->raw_context = (void *) ptrs->ContextRecord;
}
rsi->raw_info = (void *) ptrs->ExceptionRecord;
rsi->error_code = (WG14_SIGNALS_PREFIX(thrd_raised_signal_error_code_t))
ptrs->ExceptionRecord->ExceptionInformation[2]; // NTSTATUS
rsi->addr = (void *) ptrs->ExceptionRecord->ExceptionInformation[1];
}

static long win32_exception_filter(
struct WG14_SIGNALS_PREFIX(thrd_raised_signal_info) * rsi,
const sigset_t *guarded, const int signo,
WG14_SIGNALS_PREFIX(thrd_signal_decide_t) decider,
union WG14_SIGNALS_PREFIX(thrd_raised_signal_info_value) value,
EXCEPTION_POINTERS *ptrs)
{
if(sigismember(guarded, signo))
{
prepare_rsi(rsi, signo, ptrs);
rsi->value = value;
if(decider(rsi))
{
return EXCEPTION_EXECUTE_HANDLER;
}
}
return EXCEPTION_CONTINUE_SEARCH;
}

union WG14_SIGNALS_PREFIX(thrd_raised_signal_info_value)
WG14_SIGNALS_PREFIX(thrd_signal_invoke)(
const sigset_t *signals, WG14_SIGNALS_PREFIX(thrd_signal_func_t) guarded,
WG14_SIGNALS_PREFIX(thrd_signal_recover_t) recovery,
WG14_SIGNALS_PREFIX(thrd_signal_decide_t) decider,
union WG14_SIGNALS_PREFIX(thrd_raised_signal_info_value) value)
{
(void) guarded;
(void) signals;
(void) recovery;
(void) decider;
(void) value;
abort();
struct WG14_SIGNALS_PREFIX(thrd_raised_signal_info) rsi;
__try
{
return guarded(value);
}
__except(win32_exception_filter(
&rsi, signals, signal_from_win32_exception_code(GetExceptionCode()), decider,
value, GetExceptionInformation()))
{
return recovery(&rsi);
}
}

// You must NOT do anything async signal unsafe in here!
Expand Down Expand Up @@ -143,7 +191,7 @@ EXCEPTION_POINTERS *ptrs)
if(signo == 0)
{
// Not a supported exception code
return 0; // EXCEPTION_CONTINUE_SEARCH
return EXCEPTION_CONTINUE_SEARCH;
}
struct WG14_SIGNALS_PREFIX(thrd_signal_global_state_t) *state =
WG14_SIGNALS_PREFIX(thrd_signal_global_state)();
Expand All @@ -154,28 +202,10 @@ EXCEPTION_POINTERS *ptrs)
{
// We don't have a handler installed for that signal
UNLOCK(state->lock);
return 0; // EXCEPTION_CONTINUE_SEARCH
return EXCEPTION_CONTINUE_SEARCH;
}
struct WG14_SIGNALS_PREFIX(thrd_raised_signal_info) rsi;
memset(&rsi, 0, sizeof(rsi));
rsi.signo = signo;
if(ptrs->ExceptionRecord->NumberParameters >= 2 &&
ptrs->ExceptionRecord
->ExceptionInformation[ptrs->ExceptionRecord->NumberParameters - 2] ==
(ULONG_PTR) 0xdeadbeefdeadbeef)
{
rsi.raw_context =
(void *) ptrs->ExceptionRecord
->ExceptionInformation[ptrs->ExceptionRecord->NumberParameters - 1];
}
else
{
rsi.raw_context = (void *) ptrs->ContextRecord;
}
rsi.raw_info = (void *) ptrs->ExceptionRecord;
rsi.error_code = (WG14_SIGNALS_PREFIX(thrd_raised_signal_error_code_t))
ptrs->ExceptionRecord->ExceptionInformation[2]; // NTSTATUS
rsi.addr = (void *) ptrs->ExceptionRecord->ExceptionInformation[1];
prepare_rsi(&rsi, signo, ptrs);
if(it.data->val->global_handler.front != WG14_SIGNALS_NULLPTR)
{
struct global_signal_decider_t *current =
Expand All @@ -194,15 +224,15 @@ EXCEPTION_POINTERS *ptrs)
longjmp(tss->buf, 1);
}
// This will generally end the process
return -1; // EXCEPTION_CONTINUE_EXECUTION
return EXCEPTION_CONTINUE_EXECUTION;
}
LOCK(state->lock);
current = current->next;
} while(current != WG14_SIGNALS_NULLPTR);
}
// None of our deciders want this, so call previously installed signal handler
UNLOCK(state->lock);
return 0; // EXCEPTION_CONTINUE_SEARCH
return EXCEPTION_CONTINUE_SEARCH;
}

/* The interaction between AddVectoredContinueHandler,
Expand Down
39 changes: 35 additions & 4 deletions test/thrd_signal_handle_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,55 @@

struct shared_t
{
int count;
int count_decider, count_recovery;
};

static union WG14_SIGNALS_PREFIX(thrd_raised_signal_info_value)
sigill_recovery_func(const struct WG14_SIGNALS_PREFIX(thrd_raised_signal_info) *
rsi)
{
struct shared_t *shared = (struct shared_t *) rsi->value.ptr_value;
shared->count_recovery++;
return rsi->value;
}
static bool
sigill_decider_func(struct WG14_SIGNALS_PREFIX(thrd_raised_signal_info) * rsi)
{
struct shared_t *shared = (struct shared_t *) rsi->value.ptr_value;
shared->count++;
shared->count_decider++;
return true; // handled
}
static union WG14_SIGNALS_PREFIX(thrd_raised_signal_info_value)
sigill_func(union WG14_SIGNALS_PREFIX(thrd_raised_signal_info_value) value)
{
WG14_SIGNALS_PREFIX(thrd_signal_raise)(SIGILL, WG14_SIGNALS_NULLPTR,
WG14_SIGNALS_NULLPTR);
return value;
}

int main()
{
int ret = 0;
void *handlers =
WG14_SIGNALS_PREFIX(modern_signals_install)(WG14_SIGNALS_NULLPTR, 0);

// Test thread local handling
{
struct shared_t shared = {.count_decider = 0, .count_recovery = 0};
union WG14_SIGNALS_PREFIX(thrd_raised_signal_info_value)
value = {.ptr_value = &shared};
sigset_t guarded;
sigemptyset(&guarded);
sigaddset(&guarded, SIGILL);
WG14_SIGNALS_PREFIX(thrd_signal_invoke)(
&guarded, sigill_func, sigill_recovery_func, sigill_decider_func, value);
CHECK(shared.count_decider == 1);
CHECK(shared.count_recovery == 1);
}

// Test global handling
{
struct shared_t shared = {.count = 0};
struct shared_t shared = {.count_decider = 0, .count_recovery = 0};
union WG14_SIGNALS_PREFIX(thrd_raised_signal_info_value)
value = {.ptr_value = &shared};
sigset_t guarded;
Expand All @@ -32,7 +62,8 @@ int main()
&guarded, false, sigill_decider_func, value);
CHECK(WG14_SIGNALS_PREFIX(thrd_signal_raise)(SIGILL, WG14_SIGNALS_NULLPTR,
WG14_SIGNALS_NULLPTR));
CHECK(shared.count == 1);
CHECK(shared.count_decider == 1);
CHECK(shared.count_recovery == 0);
WG14_SIGNALS_PREFIX(signal_decider_destroy(sigill_decider));
}

Expand Down

0 comments on commit 6311956

Please sign in to comment.