23

I'm trying to implement a function that would call an interrupt signal in Go. I know how to intercept interrupt signals from the console, by using signal.Notify(interruptChannel, os.Interrupt), however, I can't find a way to actually send the interrupt signals around. I've found that you can send a signal to a process, but I'm not sure if this can be used to send a top-level interrupt signal.

Is there a way to send an interrupt signal from within a Go function that could be captured by anything that is listening for system interrupt signals, or is that something that's not supported in Go?

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
ThePiachu
  • 8,695
  • 17
  • 65
  • 94
  • 1
    What do you mean by a "top-level interrupt signal"? SIGINT is just like any other signal. – JimB Nov 09 '16 at 02:24

3 Answers3

70

Assuming you are using something like this for capturing interrupt signal

var stopChan = make(chan os.Signal, 2)
signal.Notify(stopChan, os.Interrupt, syscall.SIGTERM, syscall.SIGINT)

<-stopChan // wait for SIGINT

Use below from anywhere in your code to send interrupt signal to above wait part.

syscall.Kill(syscall.Getpid(), syscall.SIGINT)

Or if you are in the same package where where stopChan variable is defined. Thus making it accessible. You can do this.

stopChan <- syscall.SIGINT

Or you can define stopChan as a global variable (making the first letter in Capital letter will achieve the same), then you can send interrupt signal from a different package too.

Stopchan <- syscall.SIGINT
Debasish Mitra
  • 1,394
  • 1
  • 14
  • 17
  • 9
    Why the buffer is 2? – Berkant İpek Mar 19 '19 at 09:12
  • 2
    Note that syscall.Kill() is not available on Windows. – rfay Jun 21 '19 at 21:47
  • @BerkantIpek The documentation states, "Package signal will not block sending to c: the caller must ensure that c has sufficient buffer space to keep up with the expected signal rate." Because there are multiple signals being handled in this example, one may expect to handle a higher throughput, too. At least that's my guess. – Tyler Kropp Jan 12 '21 at 02:51
20

Get the process using FindProcess, StartProcess or some other means. Call Signal to send the interrupt:

 err := p.Signal(os.Interrupt)

This will send the signal to the target process (assuming the calling process has permission to do so) and invoke whatever signal handlers the target process may have for SIGINT.

Charlie Tumahai
  • 113,709
  • 12
  • 249
  • 242
1

For the windows case you may use the following method:

func SendInterrupt() error {
    d, e := syscall.LoadDLL("kernel32.dll")
    if e != nil {
        return fmt.Errorf("LoadDLL: %v", e)
    }
    p, e := d.FindProc("GenerateConsoleCtrlEvent")
    if e != nil {
        return fmt.Errorf("FindProc: %v", e)
    }
    r, _, e := p.Call(syscall.CTRL_BREAK_EVENT, uintptr(syscall.Getpid()))
    if r == 0 {
        return fmt.Errorf("GenerateConsoleCtrlEvent: %v", e)
    }
    return nil
}