Skip to content

Commit 6633f1e

Browse files
authored
Merge pull request #207 from tobiasdiez/win-support
Fix compilation on Windows
2 parents fa6d45d + 224b24c commit 6633f1e

File tree

6 files changed

+106
-58
lines changed

6 files changed

+106
-58
lines changed

.github/workflows/ci.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Run Sage CI for Linux/Cygwin/macOS
1+
name: CI
22

33
## This GitHub Actions workflow provides:
44
##
@@ -51,7 +51,7 @@ concurrency:
5151
cancel-in-progress: true
5252

5353
jobs:
54-
cygwin-without-sage:
54+
cygwin:
5555
runs-on: windows-latest
5656
strategy:
5757
fail-fast: false
@@ -88,7 +88,7 @@ jobs:
8888
strategy:
8989
fail-fast: false
9090
matrix:
91-
os: ['macos-13', 'macos-latest', 'ubuntu-latest']
91+
os: ['macos-13', 'macos-latest', 'ubuntu-latest', 'windows-latest']
9292
python-version: ['3.10', '3.11', '3.12', '3.13-dev']
9393
steps:
9494
- name: Set up the repository

meson.build

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ cxx = meson.get_compiler('cpp')
1414
is_windows = host_machine.system() == 'windows'
1515
is_cygwin = host_machine.system() == 'cygwin'
1616
is_msvc = cc.get_id() == 'msvc'
17+
is_mingw = cc.get_id()=='gcc' and host_machine.system()=='windows'
1718

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

48-
config.set('HAVE_FORK', cc.has_function('fork') ? 1 : 0)
49+
config.set('HAVE_FORK', (cc.has_function('fork') and not is_mingw) ? 1 : 0)
4950
config.set('HAVE_KILL', cc.has_function('kill') ? 1 : 0)
5051
config.set('HAVE_SIGPROCMASK', cc.has_function('sigprocmask') ? 1 : 0)
5152
config.set('HAVE_SIGALTSTACK', cc.has_function('sigaltstack') ? 1 : 0)

src/conftest.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
11
import pathlib
2+
import platform
23

34
from _pytest.nodes import Collector
45
from _pytest.doctest import DoctestModule
56

7+
if platform.system() == "Windows":
8+
collect_ignore = [
9+
"cysignals/alarm.pyx",
10+
"cysignals/pselect.pyx",
11+
"cysignals/pysignals.pyx",
12+
"cysignals/tests.pyx",
13+
]
14+
615

716
def pytest_collect_file(
817
file_path: pathlib.Path,

src/cysignals/cysignals_config.h.in

Lines changed: 0 additions & 43 deletions
This file was deleted.

src/cysignals/implementation.c

Lines changed: 69 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ Interrupt and signal handling for Cython
3434
#include <stdlib.h>
3535
#include <limits.h>
3636
#include <errno.h>
37-
#include <pthread.h>
3837
#if HAVE_SYS_TYPES_H
3938
#include <sys/types.h>
4039
#endif
@@ -88,6 +87,9 @@ void custom_set_pending_signal(int sig){
8887
#if HAVE_WINDOWS_H
8988
#include <windows.h>
9089
#endif
90+
#if !_WIN32
91+
#include <pthread.h>
92+
#endif
9193
#include "struct_signals.h"
9294

9395

@@ -108,9 +110,11 @@ static sigset_t default_sigmask;
108110
static sigset_t sigmask_with_sigint;
109111
#endif
110112

113+
#if !_WIN32
111114
/* A trampoline to jump to after handling a signal. */
112115
static cyjmp_buf trampoline_setup;
113116
static sigjmp_buf trampoline;
117+
#endif
114118

115119
static void setup_cysignals_handlers(void);
116120
static void cysigs_interrupt_handler(int sig);
@@ -194,15 +198,23 @@ static inline void print_stderr_ptr(void *ptr)
194198

195199
/* Reset all signal handlers and the signal mask to their defaults. */
196200
static inline void sig_reset_defaults(void) {
201+
#ifdef SIGHUP
197202
signal(SIGHUP, SIG_DFL);
203+
#endif
198204
signal(SIGINT, SIG_DFL);
205+
#ifdef SIGQUIT
199206
signal(SIGQUIT, SIG_DFL);
207+
#endif
200208
signal(SIGILL, SIG_DFL);
201209
signal(SIGABRT, SIG_DFL);
202210
signal(SIGFPE, SIG_DFL);
211+
#ifdef SIGBUS
203212
signal(SIGBUS, SIG_DFL);
213+
#endif
204214
signal(SIGSEGV, SIG_DFL);
215+
#ifdef SIGALRM
205216
signal(SIGALRM, SIG_DFL);
217+
#endif
206218
signal(SIGTERM, SIG_DFL);
207219
#if HAVE_SIGPROCMASK
208220
sigprocmask(SIG_SETMASK, &default_sigmask, NULL);
@@ -228,10 +240,14 @@ static inline void sigdie_for_sig(int sig, int inside)
228240
sigdie(sig, "Unhandled SIGFPE during signal handling.");
229241
else if (sig == SIGSEGV)
230242
sigdie(sig, "Unhandled SIGSEGV during signal handling.");
243+
#ifdef SIGBUS
231244
else if (sig == SIGBUS)
232245
sigdie(sig, "Unhandled SIGBUS during signal handling.");
246+
#endif
247+
#ifdef SIGQUIT
233248
else if (sig == SIGQUIT)
234249
sigdie(sig, NULL);
250+
#endif
235251
else
236252
sigdie(sig, "Unknown signal during signal handling.");
237253
}
@@ -244,10 +260,14 @@ static inline void sigdie_for_sig(int sig, int inside)
244260
sigdie(sig, "Unhandled SIGFPE: An unhandled floating point exception occurred.");
245261
else if (sig == SIGSEGV)
246262
sigdie(sig, "Unhandled SIGSEGV: A segmentation fault occurred.");
263+
#ifdef SIGBUS
247264
else if (sig == SIGBUS)
248265
sigdie(sig, "Unhandled SIGBUS: A bus error occurred.");
266+
#endif
267+
#ifdef SIGQUIT
249268
else if (sig == SIGQUIT)
250269
sigdie(sig, NULL);
270+
#endif
251271
else
252272
sigdie(sig, "Unknown signal received.");
253273
}
@@ -330,8 +350,22 @@ static void cygwin_setup_alt_stack() {
330350

331351
#endif /* CYGWIN && __x86_64__ */
332352

353+
void get_monotonic_time(struct timespec *ts) {
354+
#ifdef _WIN32
355+
LARGE_INTEGER frequency;
356+
LARGE_INTEGER counter;
357+
358+
QueryPerformanceFrequency(&frequency);
359+
QueryPerformanceCounter(&counter);
360+
361+
ts->tv_sec = counter.QuadPart / frequency.QuadPart;
362+
ts->tv_nsec = (counter.QuadPart % frequency.QuadPart) * 1e9 / frequency.QuadPart;
363+
#else
364+
clock_gettime(CLOCK_MONOTONIC, ts);
365+
#endif
366+
}
333367

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

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

398+
#if !_WIN32
364399
/* Jump back to sig_on() (the first one if there is a stack) */
365400
siglongjmp(trampoline, sig);
401+
#endif
366402
}
367403
}
368404
else
@@ -376,7 +412,11 @@ static void cysigs_interrupt_handler(int sig)
376412
/* If we are here, we cannot handle the interrupt immediately, so
377413
* we store the signal number for later use. But make sure we
378414
* don't overwrite a SIGHUP or SIGTERM which we already received. */
379-
if (cysigs.interrupt_received != SIGHUP && cysigs.interrupt_received != SIGTERM)
415+
if (
416+
#ifdef SIGHUP
417+
cysigs.interrupt_received != SIGHUP &&
418+
#endif
419+
cysigs.interrupt_received != SIGTERM)
380420
{
381421
cysigs.interrupt_received = sig;
382422
custom_set_pending_signal(sig);
@@ -393,24 +433,28 @@ static void cysigs_signal_handler(int sig)
393433
int inside = cysigs.inside_signal_handler;
394434
cysigs.inside_signal_handler = 1;
395435

396-
if (inside == 0 && cysigs.sig_on_count > 0 && sig != SIGQUIT)
397-
{
436+
if (inside == 0 && cysigs.sig_on_count > 0
437+
#ifdef SIGQUIT
438+
&& sig != SIGQUIT
439+
#endif
440+
) {
398441
/* We are inside sig_on(), so we can handle the signal! */
399442
#if ENABLE_DEBUG_CYSIGNALS
400443
if (cysigs.debug_level >= 1) {
401444
print_stderr("\n*** SIG ");
402445
print_stderr_long(sig);
403446
print_stderr(" *** inside sig_on\n");
404447
if (cysigs.debug_level >= 3) print_backtrace();
405-
clock_gettime(CLOCK_MONOTONIC, &sigtime);
448+
get_monotonic_time(&sigtime);
406449
}
407450
#endif
408451

409452
/* Raise an exception so Python can see it */
410453
do_raise_exception(sig);
411-
454+
#if !_WIN32
412455
/* Jump back to sig_on() (the first one if there is a stack) */
413456
siglongjmp(trampoline, sig);
457+
#endif
414458
}
415459
else
416460
{
@@ -422,7 +466,7 @@ static void cysigs_signal_handler(int sig)
422466
}
423467
}
424468

425-
469+
#if !_WIN32
426470
/* A trampoline to jump to after handling a signal.
427471
*
428472
* The jump to sig_on() uses cylongjmp(), which does not restore the
@@ -506,6 +550,7 @@ static void setup_trampoline(void)
506550
cylongjmp(trampoline_setup, 1);
507551
}
508552
}
553+
#endif
509554

510555

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

609654
static void setup_cysignals_handlers(void)
610655
{
656+
#ifdef _WIN32
657+
signal(SIGINT, cysigs_interrupt_handler);
658+
signal(SIGTERM, cysigs_interrupt_handler);
659+
signal(SIGABRT, cysigs_signal_handler);
660+
#else
611661
struct sigaction sa;
612662
memset(&sa, 0, sizeof(sa));
613663

@@ -635,21 +685,30 @@ static void setup_cysignals_handlers(void)
635685
/* Handlers for interrupt-like signals */
636686
sa.sa_handler = cysigs_interrupt_handler;
637687
sa.sa_flags = 0;
688+
#ifdef SIGHUP
638689
if (sigaction(SIGHUP, &sa, NULL)) {perror("cysignals sigaction"); exit(1);}
690+
#endif
639691
if (sigaction(SIGINT, &sa, NULL)) {perror("cysignals sigaction"); exit(1);}
692+
#ifdef SIGALRM
640693
if (sigaction(SIGALRM, &sa, NULL)) {perror("cysignals sigaction"); exit(1);}
694+
#endif
641695

642696
/* Handlers for critical signals */
643697
sa.sa_handler = cysigs_signal_handler;
644698
/* Allow signals during signal handling, we have code to deal with
645699
* this case. */
646700
sa.sa_flags = SA_NODEFER | SA_ONSTACK;
701+
#ifdef SIGQUIT
647702
if (sigaction(SIGQUIT, &sa, NULL)) {perror("cysignals sigaction"); exit(1);}
703+
#endif
648704
if (sigaction(SIGILL, &sa, NULL)) {perror("cysignals sigaction"); exit(1);}
649705
if (sigaction(SIGABRT, &sa, NULL)) {perror("cysignals sigaction"); exit(1);}
650706
if (sigaction(SIGFPE, &sa, NULL)) {perror("cysignals sigaction"); exit(1);}
707+
#ifdef SIGBUS
651708
if (sigaction(SIGBUS, &sa, NULL)) {perror("cysignals sigaction"); exit(1);}
709+
#endif
652710
if (sigaction(SIGSEGV, &sa, NULL)) {perror("cysignals sigaction"); exit(1);}
711+
#endif
653712
}
654713

655714

0 commit comments

Comments
 (0)