Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix compilation on Windows #207

Merged
merged 10 commits into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Run Sage CI for Linux/Cygwin/macOS
name: CI

## This GitHub Actions workflow provides:
##
Expand Down Expand Up @@ -51,7 +51,7 @@ concurrency:
cancel-in-progress: true

jobs:
cygwin-without-sage:
cygwin:
runs-on: windows-latest
strategy:
fail-fast: false
Expand Down Expand Up @@ -88,7 +88,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: ['macos-13', 'macos-latest', 'ubuntu-latest']
os: ['macos-13', 'macos-latest', 'ubuntu-latest', 'windows-latest']
python-version: ['3.10', '3.11', '3.12', '3.13-dev']
steps:
- name: Set up the repository
Expand Down
3 changes: 2 additions & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ cxx = meson.get_compiler('cpp')
is_windows = host_machine.system() == 'windows'
is_cygwin = host_machine.system() == 'cygwin'
is_msvc = cc.get_id() == 'msvc'
is_mingw = cc.get_id()=='gcc' and host_machine.system()=='windows'

# Set preprocessor macros
# Disable .c line numbers in exception tracebacks
Expand Down Expand Up @@ -45,7 +46,7 @@ config.set('HAVE_TIME_H', cc.has_header('time.h') ? 1 : 0)
config.set('HAVE_SYS_WAIT_H', cc.has_header('sys/wait.h') ? 1 : 0)
config.set('HAVE_WINDOWS_H', cc.has_header('windows.h') ? 1 : 0)

config.set('HAVE_FORK', cc.has_function('fork') ? 1 : 0)
config.set('HAVE_FORK', (cc.has_function('fork') and not is_mingw) ? 1 : 0)
config.set('HAVE_KILL', cc.has_function('kill') ? 1 : 0)
config.set('HAVE_SIGPROCMASK', cc.has_function('sigprocmask') ? 1 : 0)
config.set('HAVE_SIGALTSTACK', cc.has_function('sigaltstack') ? 1 : 0)
Expand Down
9 changes: 9 additions & 0 deletions src/conftest.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
import pathlib
import platform

from _pytest.nodes import Collector
from _pytest.doctest import DoctestModule

if platform.system() == "Windows":
collect_ignore = [
"cysignals/alarm.pyx",
"cysignals/pselect.pyx",
"cysignals/pysignals.pyx",
"cysignals/tests.pyx",
]


def pytest_collect_file(
file_path: pathlib.Path,
Expand Down
43 changes: 0 additions & 43 deletions src/cysignals/cysignals_config.h.in

This file was deleted.

79 changes: 69 additions & 10 deletions src/cysignals/implementation.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ Interrupt and signal handling for Cython
#include <stdlib.h>
#include <limits.h>
#include <errno.h>
#include <pthread.h>
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
Expand Down Expand Up @@ -88,6 +87,9 @@ void custom_set_pending_signal(int sig){
#if HAVE_WINDOWS_H
#include <windows.h>
#endif
#if !_WIN32
#include <pthread.h>
#endif
#include "struct_signals.h"


Expand All @@ -108,9 +110,11 @@ static sigset_t default_sigmask;
static sigset_t sigmask_with_sigint;
#endif

#if !_WIN32
/* A trampoline to jump to after handling a signal. */
static cyjmp_buf trampoline_setup;
static sigjmp_buf trampoline;
#endif

static void setup_cysignals_handlers(void);
static void cysigs_interrupt_handler(int sig);
Expand Down Expand Up @@ -194,15 +198,23 @@ static inline void print_stderr_ptr(void *ptr)

/* Reset all signal handlers and the signal mask to their defaults. */
static inline void sig_reset_defaults(void) {
#ifdef SIGHUP
signal(SIGHUP, SIG_DFL);
#endif
signal(SIGINT, SIG_DFL);
#ifdef SIGQUIT
signal(SIGQUIT, SIG_DFL);
#endif
signal(SIGILL, SIG_DFL);
signal(SIGABRT, SIG_DFL);
signal(SIGFPE, SIG_DFL);
#ifdef SIGBUS
signal(SIGBUS, SIG_DFL);
#endif
signal(SIGSEGV, SIG_DFL);
#ifdef SIGALRM
signal(SIGALRM, SIG_DFL);
#endif
signal(SIGTERM, SIG_DFL);
#if HAVE_SIGPROCMASK
sigprocmask(SIG_SETMASK, &default_sigmask, NULL);
Expand All @@ -228,10 +240,14 @@ static inline void sigdie_for_sig(int sig, int inside)
sigdie(sig, "Unhandled SIGFPE during signal handling.");
else if (sig == SIGSEGV)
sigdie(sig, "Unhandled SIGSEGV during signal handling.");
#ifdef SIGBUS
else if (sig == SIGBUS)
sigdie(sig, "Unhandled SIGBUS during signal handling.");
#endif
#ifdef SIGQUIT
else if (sig == SIGQUIT)
sigdie(sig, NULL);
#endif
else
sigdie(sig, "Unknown signal during signal handling.");
}
Expand All @@ -244,10 +260,14 @@ static inline void sigdie_for_sig(int sig, int inside)
sigdie(sig, "Unhandled SIGFPE: An unhandled floating point exception occurred.");
else if (sig == SIGSEGV)
sigdie(sig, "Unhandled SIGSEGV: A segmentation fault occurred.");
#ifdef SIGBUS
else if (sig == SIGBUS)
sigdie(sig, "Unhandled SIGBUS: A bus error occurred.");
#endif
#ifdef SIGQUIT
else if (sig == SIGQUIT)
sigdie(sig, NULL);
#endif
else
sigdie(sig, "Unknown signal received.");
}
Expand Down Expand Up @@ -330,8 +350,22 @@ static void cygwin_setup_alt_stack() {

#endif /* CYGWIN && __x86_64__ */

void get_monotonic_time(struct timespec *ts) {
#ifdef _WIN32
LARGE_INTEGER frequency;
LARGE_INTEGER counter;

QueryPerformanceFrequency(&frequency);
QueryPerformanceCounter(&counter);

ts->tv_sec = counter.QuadPart / frequency.QuadPart;
ts->tv_nsec = (counter.QuadPart % frequency.QuadPart) * 1e9 / frequency.QuadPart;
#else
clock_gettime(CLOCK_MONOTONIC, ts);
#endif
}

/* Handler for SIGHUP, SIGINT, SIGALRM
/* Handler for SIGHUP, SIGINT, SIGALRM, SIGTERM
*
* Inside sig_on() (i.e. when cysigs.sig_on_count is positive), this
* raises an exception and jumps back to sig_on().
Expand All @@ -350,7 +384,7 @@ static void cysigs_interrupt_handler(int sig)
if (cysigs.debug_level >= 3) print_backtrace();
/* Store time of this signal, unless there is already a
* pending signal. */
if (!cysigs.interrupt_received) clock_gettime(CLOCK_MONOTONIC, &sigtime);
if (!cysigs.interrupt_received) get_monotonic_time(&sigtime);
}
#endif

Expand All @@ -361,8 +395,10 @@ static void cysigs_interrupt_handler(int sig)
/* Raise an exception so Python can see it */
do_raise_exception(sig);

#if !_WIN32
/* Jump back to sig_on() (the first one if there is a stack) */
siglongjmp(trampoline, sig);
#endif
}
}
else
Expand All @@ -376,7 +412,11 @@ static void cysigs_interrupt_handler(int sig)
/* If we are here, we cannot handle the interrupt immediately, so
* we store the signal number for later use. But make sure we
* don't overwrite a SIGHUP or SIGTERM which we already received. */
if (cysigs.interrupt_received != SIGHUP && cysigs.interrupt_received != SIGTERM)
if (
#ifdef SIGHUP
cysigs.interrupt_received != SIGHUP &&
#endif
cysigs.interrupt_received != SIGTERM)
{
cysigs.interrupt_received = sig;
custom_set_pending_signal(sig);
Expand All @@ -393,24 +433,28 @@ static void cysigs_signal_handler(int sig)
int inside = cysigs.inside_signal_handler;
cysigs.inside_signal_handler = 1;

if (inside == 0 && cysigs.sig_on_count > 0 && sig != SIGQUIT)
{
if (inside == 0 && cysigs.sig_on_count > 0
#ifdef SIGQUIT
&& sig != SIGQUIT
#endif
) {
/* We are inside sig_on(), so we can handle the signal! */
#if ENABLE_DEBUG_CYSIGNALS
if (cysigs.debug_level >= 1) {
print_stderr("\n*** SIG ");
print_stderr_long(sig);
print_stderr(" *** inside sig_on\n");
if (cysigs.debug_level >= 3) print_backtrace();
clock_gettime(CLOCK_MONOTONIC, &sigtime);
get_monotonic_time(&sigtime);
}
#endif

/* Raise an exception so Python can see it */
do_raise_exception(sig);

#if !_WIN32
/* Jump back to sig_on() (the first one if there is a stack) */
siglongjmp(trampoline, sig);
#endif
}
else
{
Expand All @@ -422,7 +466,7 @@ static void cysigs_signal_handler(int sig)
}
}


#if !_WIN32
/* A trampoline to jump to after handling a signal.
*
* The jump to sig_on() uses cylongjmp(), which does not restore the
Expand Down Expand Up @@ -506,6 +550,7 @@ static void setup_trampoline(void)
cylongjmp(trampoline_setup, 1);
}
}
#endif


/* This calls sig_raise_exception() to actually raise the exception. */
Expand All @@ -514,7 +559,7 @@ static void do_raise_exception(int sig)
#if ENABLE_DEBUG_CYSIGNALS
struct timespec raisetime;
if (cysigs.debug_level >= 2) {
clock_gettime(CLOCK_MONOTONIC, &raisetime);
get_monotonic_time(&raisetime);
long delta_ms = (raisetime.tv_sec - sigtime.tv_sec)*1000L + (raisetime.tv_nsec - sigtime.tv_nsec)/1000000L;
PyGILState_STATE gilstate = PyGILState_Ensure();
print_stderr("do_raise_exception(sig=");
Expand Down Expand Up @@ -608,6 +653,11 @@ static void setup_alt_stack(void)

static void setup_cysignals_handlers(void)
{
#ifdef _WIN32
signal(SIGINT, cysigs_interrupt_handler);
signal(SIGTERM, cysigs_interrupt_handler);
signal(SIGABRT, cysigs_signal_handler);
#else
struct sigaction sa;
memset(&sa, 0, sizeof(sa));

Expand Down Expand Up @@ -635,21 +685,30 @@ static void setup_cysignals_handlers(void)
/* Handlers for interrupt-like signals */
sa.sa_handler = cysigs_interrupt_handler;
sa.sa_flags = 0;
#ifdef SIGHUP
if (sigaction(SIGHUP, &sa, NULL)) {perror("cysignals sigaction"); exit(1);}
#endif
if (sigaction(SIGINT, &sa, NULL)) {perror("cysignals sigaction"); exit(1);}
#ifdef SIGALRM
if (sigaction(SIGALRM, &sa, NULL)) {perror("cysignals sigaction"); exit(1);}
#endif

/* Handlers for critical signals */
sa.sa_handler = cysigs_signal_handler;
/* Allow signals during signal handling, we have code to deal with
* this case. */
sa.sa_flags = SA_NODEFER | SA_ONSTACK;
#ifdef SIGQUIT
if (sigaction(SIGQUIT, &sa, NULL)) {perror("cysignals sigaction"); exit(1);}
#endif
if (sigaction(SIGILL, &sa, NULL)) {perror("cysignals sigaction"); exit(1);}
if (sigaction(SIGABRT, &sa, NULL)) {perror("cysignals sigaction"); exit(1);}
if (sigaction(SIGFPE, &sa, NULL)) {perror("cysignals sigaction"); exit(1);}
#ifdef SIGBUS
if (sigaction(SIGBUS, &sa, NULL)) {perror("cysignals sigaction"); exit(1);}
#endif
if (sigaction(SIGSEGV, &sa, NULL)) {perror("cysignals sigaction"); exit(1);}
#endif
}


Expand Down
Loading
Loading