Based on 574634bcacb01efe15ca2742effd461a5b7afb5f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Tue, 13 May 2014 23:22:13 +0200
Subject: [PATCH] core: close socket fds asynchronously

http://lists.freedesktop.org/archives/systemd-devel/2014-April/018928.html
---
 src/core/async.c   |   24 ++++++++++++++++++++++++
 src/core/service.c |    5 +++--
 2 files changed, 27 insertions(+), 2 deletions(-)

Index: src/core/service.c
===================================================================
--- src/core/service.c.orig
+++ src/core/service.c
@@ -25,6 +25,7 @@
 #include <unistd.h>
 #include <sys/reboot.h>
 
+#include "async.h"
 #include "manager.h"
 #include "unit.h"
 #include "service.h"
@@ -240,7 +241,7 @@ static void service_close_socket_fd(Serv
         if (s->socket_fd < 0)
                 return;
 
-        close_nointr_nofail(s->socket_fd);
+        asynchronous_close(s->socket_fd);
         s->socket_fd = -1;
 }
 
@@ -2767,7 +2768,7 @@ static int service_deserialize_item(Unit
                 else {
 
                         if (s->socket_fd >= 0)
-                                close_nointr_nofail(s->socket_fd);
+                                asynchronous_close(s->socket_fd);
                         s->socket_fd = fdset_remove(fds, fd);
                 }
         } else if (streq(key, "main-exec-status-pid")) {
Index: src/core/async.c
===================================================================
--- src/core/async.c.orig
+++ src/core/async.c
@@ -24,6 +24,7 @@
 
 #include "async.h"
 #include "log.h"
+#include "util.h"
 
 int asynchronous_job(void* (*func)(void *p), void *arg) {
         pthread_attr_t a;
@@ -70,3 +71,26 @@ int asynchronous_sync(void) {
 
         return asynchronous_job(sync_thread, NULL);
 }
+
+static void *close_thread(void *p) {
+        int fd = PTR_TO_INT(p);
+        if (fd >= 0)
+               close_nointr_nofail(fd);
+        return NULL;
+}
+
+int asynchronous_close(int fd) {
+        int r;
+
+        /* This is supposed to behave similar to safe_close(), but
+         * actually invoke close() asynchronously, so that it will
+         * never block. Ideally the kernel would have an API for this,
+         * but it doesn't, so we work around it, and hide this as a
+         * far away as we can. */
+
+        r = asynchronous_job(close_thread, INT_TO_PTR(fd));
+        if (r < 0 && fd >= 0)
+                close_nointr_nofail(fd);
+
+        return -1;
+}
Index: src/core/async.h
===================================================================
--- src/core/async.h.orig
+++ src/core/async.h
@@ -23,3 +23,4 @@
 
 int asynchronous_job(void* (*func)(void *p), void *arg);
 int asynchronous_sync(void);
+int asynchronous_close(int fd);
