+/**
+ * Internal callback for evloop management.
+ * The effect of this function is hidden: it exits
+ * the waiting poll if any. Then it wakes up a thread
+ * awaiting the evloop using signal.
+ */
+static int on_evloop_efd(sd_event_source *s, int fd, uint32_t revents, void *userdata)
+{
+ uint64_t x;
+ struct evloop *evloop = userdata;
+ read(evloop->efd, &x, sizeof x);
+ pthread_mutex_lock(&mutex);
+ pthread_cond_broadcast(&evloop->cond);
+ pthread_mutex_unlock(&mutex);
+ return 1;
+}
+
+/* temporary hack */
+#if !defined(REMOVE_SYSTEMD_EVENT)
+__attribute__((unused))
+#endif
+static void evloop_callback(void *arg, uint32_t event, struct fdev *fdev)
+{
+ sig_monitor(0, evloop_run, arg);
+}
+
+/**
+ * Gets a sd_event item for the current thread.
+ * @return a sd_event or NULL in case of error
+ */
+static struct sd_event *get_sd_event_locked()
+{
+ struct evloop *el;
+ uint64_t x;
+ int rc;
+
+ /* creates the evloop on need */
+ el = &evloop[0];
+ if (!el->sdev) {
+ /* start the creation */
+ el->state = 0;
+ /* creates the eventfd for waking up polls */
+ el->efd = eventfd(0, EFD_CLOEXEC);
+ if (el->efd < 0) {
+ ERROR("can't make eventfd for events");
+ goto error1;
+ }
+ /* create the systemd event loop */
+ rc = sd_event_new(&el->sdev);
+ if (rc < 0) {
+ ERROR("can't make new event loop");
+ goto error2;
+ }
+ /* put the eventfd in the event loop */
+ rc = sd_event_add_io(el->sdev, NULL, el->efd, EPOLLIN, on_evloop_efd, el);
+ if (rc < 0) {
+ ERROR("can't register eventfd");
+#if !defined(REMOVE_SYSTEMD_EVENT)
+ sd_event_unref(el->sdev);
+ el->sdev = NULL;
+error2:
+ close(el->efd);
+error1:
+ return NULL;
+ }
+#else
+ goto error3;
+ }
+ /* handle the event loop */
+ el->fdev = fdev_epoll_add(get_fdevepoll(), sd_event_get_fd(el->sdev));
+ if (!el->fdev) {
+ ERROR("can't create fdev");
+error3:
+ sd_event_unref(el->sdev);
+error2:
+ close(el->efd);
+error1:
+ memset(el, 0, sizeof *el);
+ return NULL;
+ }
+ fdev_set_autoclose(el->fdev, 0);
+ fdev_set_events(el->fdev, EPOLLIN);
+ fdev_set_callback(el->fdev, evloop_callback, el);
+#endif
+ }
+
+ /* attach the event loop to the current thread */
+ if (current_evloop != el) {
+ if (current_evloop)
+ __atomic_and_fetch(¤t_evloop->state, ~EVLOOP_STATE_LOCK, __ATOMIC_RELAXED);
+ current_evloop = el;
+ __atomic_or_fetch(&el->state, EVLOOP_STATE_LOCK, __ATOMIC_RELAXED);
+ }
+
+ /* wait for a modifiable event loop */
+ while (__atomic_load_n(&el->state, __ATOMIC_RELAXED) & EVLOOP_STATE_WAIT) {
+ x = 1;
+ write(el->efd, &x, sizeof x);
+ pthread_cond_wait(&el->cond, &mutex);
+ }
+
+ return el->sdev;
+}
+
+/**
+ * Gets a sd_event item for the current thread.
+ * @return a sd_event or NULL in case of error
+ */
+struct sd_event *jobs_get_sd_event()