Skip to content
Open
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
13 changes: 13 additions & 0 deletions process/interrupt_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//go:build !windows

package process

import "os"

// SendInterrupt sends an interrupt signal to the current process.
// On Unix systems, this sends os.Interrupt (SIGINT).
func SendInterrupt() {
if p, err := os.FindProcess(os.Getpid()); err == nil {
_ = p.Signal(os.Interrupt)
}
}
27 changes: 27 additions & 0 deletions process/interrupt_unix_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//go:build !windows

package process

import (
"os"
"os/signal"
"testing"
"time"

"github.com/stretchr/testify/require"
)

func TestSendInterrupt(t *testing.T) {
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, os.Interrupt)
defer signal.Stop(sigChan)

SendInterrupt()

select {
case sig := <-sigChan:
require.Equal(t, os.Interrupt, sig)
case <-time.After(2 * time.Second):
t.Fatal("timeout waiting for interrupt signal")
}
}
24 changes: 24 additions & 0 deletions process/interrupt_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//go:build windows

package process

import (
"os"
"syscall"
)

var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
procGenerateConsoleCtrlEvent = kernel32.NewProc("GenerateConsoleCtrlEvent")
)

// SendInterrupt sends an interrupt signal to the current process.
// On Windows, this uses GenerateConsoleCtrlEvent with CTRL_BREAK_EVENT
// because Go's p.Signal(os.Interrupt) is not implemented on Windows.
func SendInterrupt() {
// Send CTRL_BREAK_EVENT to current process's process group
// Using os.Getpid() targets only processes in our group (typically just us in production)
// This avoids sending to all console processes (group 0) which would kill parent processes
pid := os.Getpid()
procGenerateConsoleCtrlEvent.Call(syscall.CTRL_BREAK_EVENT, uintptr(pid))
}
20 changes: 20 additions & 0 deletions process/interrupt_windows_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//go:build windows

package process

import "testing"

func TestSendInterrupt(t *testing.T) {
// On Windows CI (GitHub Actions), GenerateConsoleCtrlEvent may not work
// as expected without a proper console attached.
// This test verifies the function doesn't panic and the syscall loads correctly.
defer func() {
if r := recover(); r != nil {
t.Fatalf("SendInterrupt panicked: %v", r)
}
}()

// Just verify it doesn't crash - the actual signal delivery
// depends on console configuration which varies in CI
SendInterrupt()
}
Loading