Signals in Julia

Here’s the translation of the Go code to Julia, with explanations adapted for Julia:

Our program demonstrates how to handle signals in Julia. For example, we might want a server to gracefully shutdown when it receives a SIGTERM, or a command-line tool to stop processing input if it receives a SIGINT. Here’s how to handle signals in Julia.

using Base.Threads

# Julia signal notification works by sending signal values to a channel.
# We'll create a channel to receive these notifications.
sigs = Channel{Int32}(1)

# We use `Base.sigatomic_begin()` and `Base.sigatomic_end()` to ensure
# signal handling is atomic.
Base.sigatomic_begin()
signal_handler = (sig) -> put!(sigs, sig)
Base.sigatomic_end()

# Register the signal handler for SIGINT and SIGTERM
for sig in [SIGINT, SIGTERM]
    ccall(:signal, Ptr{Cvoid}, (Cint, Ptr{Cvoid}), sig, @cfunction(signal_handler, Cvoid, (Cint,)))
end

# We could receive from `sigs` here in the main function, but let's see
# how this could also be done in a separate task, to demonstrate a more
# realistic scenario of graceful shutdown.
done = Channel{Bool}(1)

# This task executes a blocking receive for signals. When it gets one
# it'll print it out and then notify the program that it can finish.
@async begin
    sig = take!(sigs)
    println()
    println("Received signal: $sig")
    put!(done, true)
end

# The program will wait here until it gets the expected signal
# (as indicated by the task above sending a value on `done`) and then exit.
println("awaiting signal")
take!(done)
println("exiting")

When we run this program it will block waiting for a signal. By typing ctrl-C (which the terminal shows as ^C) we can send a SIGINT signal, causing the program to print the signal number and then exit.

$ julia signals.jl
awaiting signal
^C
Received signal: 2
exiting

In this Julia version:

  1. We use a Channel instead of a Go channel to receive signals.
  2. We create a signal handler function and register it using ccall and @cfunction.
  3. Instead of a goroutine, we use Julia’s @async macro to create a task for signal handling.
  4. We use take! and put! for channel operations instead of <-.

The overall structure and functionality remain similar to the Go version, adapted to Julia’s syntax and conventions.