Signals in D Programming Language

Here’s the translation of the Go code example to D, formatted in Markdown suitable for Hugo:

Our program demonstrates how to handle Unix signals in D. 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 D with channels.

import std.stdio;
import core.sys.posix.signal;
import core.thread;
import core.sync.semaphore;

void main()
{
    // D signal handling works by registering signal handlers.
    // We'll create a semaphore to synchronize between the main thread
    // and the signal handler.
    auto semaphore = new Semaphore(0);

    // Register the signal handler for SIGINT and SIGTERM
    signal(SIGINT, &signalHandler);
    signal(SIGTERM, &signalHandler);

    // This is our signal handler function
    extern (C) void signalHandler(int sig) nothrow @nogc @system
    {
        semaphore.notify();
    }

    // We could wait for the semaphore here in the main
    // function, but let's see how this could also be
    // done in a separate thread, to demonstrate
    // a more realistic scenario of graceful shutdown.
    auto done = new Semaphore(0);

    // This thread waits for a signal. When it gets one it'll print it out
    // and then notify the program that it can finish.
    new Thread({
        semaphore.wait();
        writeln();
        writeln("Received signal");
        done.notify();
    }).start();

    // The program will wait here until it gets the
    // expected signal (as indicated by the thread
    // above notifying the 'done' semaphore) and then exit.
    writeln("awaiting signal");
    done.wait();
    writeln("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 Received signal and then exit.

$ dmd -run signals.d
awaiting signal
^C
Received signal
exiting

In this D version:

  1. We use the core.sys.posix.signal module for signal handling.
  2. Instead of channels, we use semaphores from core.sync.semaphore for synchronization.
  3. We define a signal handler function that notifies a semaphore when a signal is received.
  4. We create a separate thread to wait for the signal, mimicking the goroutine in the original example.
  5. The main thread waits on a semaphore, similar to the channel receive in the original.

This approach provides similar functionality to the original Go code, adapted to D’s idioms and libraries.