Files
systemd/man
Beniamino Galvani 9af2d7e4c8 man: update the sample glib/sd-event integration
The normal order of operations when iterating the GLib main loop is:

 - prepare()  -> sd_event_prepare()
 - poll the file descriptors
 - check()    -> sd_event_wait()
 - dispatch() -> sd_event_dispatch()

GLib does not guarantee that check() is always called between two
consecutive prepare() invocations. When another thread attaches or
removes a source with poll fds while the main thread is inside
poll(), g_main_context_check_unlocked() returns immediately without
calling any source's check() callback.

Since the sd_event GSource adapter maps prepare/check/dispatch to
sd_event_prepare/sd_event_wait/sd_event_dispatch, a skipped check()
leaves sd_event in ARMED state. The next prepare() then hits
assertion "e->state == SD_EVENT_INITIAL".

The following program reproduces the faulty scenario by creating a
thread that attaches a new fd during the poll phase:

  #include <stdio.h>
  #include <stdlib.h>
  #include <sys/socket.h>
  #include <glib.h>
  #include <systemd/sd-event.h>
  #include <unistd.h>

  /* from glib-event-glue.c */
  extern GSource *g_sd_event_create_source(sd_event *event);

  static gpointer thread_func(gpointer user_data) {
    GSource *source;
    GPollFD pollfd;
    int fd;

    g_usleep(G_USEC_PER_SEC / 10);

    fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
    if (fd < 0)
      abort();

    source = g_source_new(&(GSourceFuncs){0}, sizeof(GSource));
    pollfd.fd = fd;
    pollfd.events = G_IO_IN;
    pollfd.revents = 0;
    g_source_add_poll(source, &pollfd);
    g_source_attach(source, NULL);
    g_source_destroy(source);
    g_source_unref(source);

    close(fd);

    return NULL;
  }

  int main(int argc, char *argv[]) {
    sd_event *event = NULL;
    GSource *source;
    GThread *thread;
    int i, r;

    r = sd_event_default(&event);
    if (r < 0)
      return 1;

    source = g_sd_event_create_source(event);
    if (!source)
      return 1;

    g_source_attach(source, NULL);

    for (i = 0; i < 50; i++) {
      thread = g_thread_new("check-skip", thread_func, NULL);
      g_main_context_iteration(NULL, TRUE);
      g_thread_join(thread);
      g_main_context_iteration(NULL, FALSE);
    }

    g_source_destroy(source);
    g_source_unref(source);
    sd_event_unref(event);

    return 0;
  }

When the program uses the current glue code, it crashes with:

  Assertion 'e->state == SD_EVENT_INITIAL' failed at src/libsystemd/sd-event/sd-event.c:4560, function sd_event_prepare(). Aborting.

Fix the problem by skipping sd_event_prepare() if the event is
already ARMED: it was already prepared in a previous iteration and
it can be polled immediately.
2026-07-21 14:50:02 +01:00
..
2024-12-25 17:00:31 +01:00
2023-12-25 09:15:53 +01:00
2025-09-18 10:57:38 +01:00
2025-08-10 13:40:32 +02:00
2025-08-11 10:30:26 +02:00
2025-10-04 18:13:27 +02:00
2026-05-18 21:42:56 +02:00
2025-08-11 10:30:26 +02:00
2025-08-11 10:30:26 +02:00
2024-12-25 17:00:31 +01:00
2026-05-15 13:46:08 +01:00
2024-12-25 17:00:31 +01:00
2025-08-10 13:40:32 +02:00
2024-12-25 17:00:31 +01:00
2023-12-26 08:59:53 +01:00
2023-12-26 08:59:53 +01:00
2023-12-26 13:10:36 +01:00
2026-02-20 01:18:54 +09:00
2025-07-16 05:47:38 +09:00
2023-12-24 09:32:26 +01:00
2024-11-06 19:06:40 +09:00
2025-09-18 10:57:38 +01:00