<div dir="ltr"><div><div><div>Hi,<br></div><div><br></div>at first glance I didn't like returning fd from wl_connection_destroy, but at the other, I did!<br>If you think about the connection as a buffer for the fd (and that is really the case),<br>then it make sense to do something like:<br><br></div><div>      create conn      ------------------     destroy conn <br></div>fd ----------------------> | connection | ------------------------> fd<br>                             ------------------<br><br></div><div>The race in threaded environment is real (one thread closes fd, say 6, other thread opens new fd<br>- it will get the first free value which is 6 - and the first thread close the 6 again and we're in trouble..)<br></div><div>So it's important to close every fd only once.<br></div><div><br></div><div>For me it's OK and:<br><br></div>Reviewed-by: Marek Chalupa <<a href="mailto:mchqwerty@gmail.com">mchqwerty@gmail.com</a>><br></div><div class="gmail_extra"><br><div class="gmail_quote">On 30 September 2014 14:43, Benjamin Herr <span dir="ltr"><<a href="mailto:ben@0x539.de" target="_blank">ben@0x539.de</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Calling close() on the same file descriptor that a previous call to<br>
close() already closed is wrong, and racy if another thread received<br>
that same file descriptor as a eg. new socket or actual file.<br>
<br>
There are two situations where wl_connection_destroy() would close its<br>
file descriptor and then another function up in the call chain would<br>
close the same file descriptor:<br>
<br>
  * When wl_client_create() fails after calling wl_connection_create(),<br>
    it will call wl_connection_destroy() before returning. However, its<br>
    caller will always close the file descriptor if wl_client_create()<br>
    fails.<br>
<br>
  * wl_display_disconnect() unconditionally closes the display file<br>
    descriptor and also calls wl_connection_destroy().<br>
<br>
So these two seem to expect wl_connection_destroy() to leave the file<br>
descriptor open. The other caller of wl_connection_destroy(),<br>
wl_client_destroy(), does however expect wl_connection_destroy() to<br>
close its file descriptor, alas.<br>
<br>
This patch changes wl_connection_destroy() to indulge this majority of<br>
two callers by simply not closing the file descriptor. For the benefit<br>
of wl_client_destroy(), wl_connection_destroy() then returns the<br>
unclosed file descriptor so that wl_client_destroy() can close it<br>
itself.<br>
<br>
Since wl_connection_destroy() is a private function called from few<br>
places, changing its semantics seemed like the more expedient way to<br>
address the double-close() problem than shuffling around the logic in<br>
wl_client_create() to somehow enable it to always avoid calling<br>
wl_connection_destroy().<br>
<br>
Signed-off-by: Benjamin Herr <<a href="mailto:ben@0x539.de">ben@0x539.de</a>><br>
---<br>
 src/connection.c        | 7 +++++--<br>
 src/wayland-private.h   | 2 +-<br>
 src/wayland-server.c    | 2 +-<br>
 tests/connection-test.c | 8 ++++++--<br>
 4 files changed, 13 insertions(+), 6 deletions(-)<br>
<br>
diff --git a/src/connection.c b/src/connection.c<br>
index f292853..c5daca6 100644<br>
--- a/src/connection.c<br>
+++ b/src/connection.c<br>
@@ -189,13 +189,16 @@ close_fds(struct wl_buffer *buffer, int max)<br>
        buffer->tail += size;<br>
 }<br>
<br>
-void<br>
+int<br>
 wl_connection_destroy(struct wl_connection *connection)<br>
 {<br>
+       int fd = connection->fd;<br>
+<br>
        close_fds(&connection->fds_out, -1);<br>
        close_fds(&connection->fds_in, -1);<br>
-       close(connection->fd);<br>
        free(connection);<br>
+<br>
+       return fd;<br>
 }<br>
<br>
 void<br>
diff --git a/src/wayland-private.h b/src/wayland-private.h<br>
index 67e8783..db76081 100644<br>
--- a/src/wayland-private.h<br>
+++ b/src/wayland-private.h<br>
@@ -86,7 +86,7 @@ int wl_interface_equal(const struct wl_interface *iface1,<br>
                       const struct wl_interface *iface2);<br>
<br>
 struct wl_connection *wl_connection_create(int fd);<br>
-void wl_connection_destroy(struct wl_connection *connection);<br>
+int wl_connection_destroy(struct wl_connection *connection);<br>
 void wl_connection_copy(struct wl_connection *connection, void *data, size_t size);<br>
 void wl_connection_consume(struct wl_connection *connection, size_t size);<br>
<br>
diff --git a/src/wayland-server.c b/src/wayland-server.c<br>
index 674aeca..7caeb30 100644<br>
--- a/src/wayland-server.c<br>
+++ b/src/wayland-server.c<br>
@@ -670,7 +670,7 @@ wl_client_destroy(struct wl_client *client)<br>
        wl_map_for_each(&client->objects, destroy_resource, &serial);<br>
        wl_map_release(&client->objects);<br>
        wl_event_source_remove(client->source);<br>
-       wl_connection_destroy(client->connection);<br>
+       close(wl_connection_destroy(client->connection));<br>
        wl_list_remove(&client->link);<br>
        free(client);<br>
 }<br>
diff --git a/tests/connection-test.c b/tests/connection-test.c<br>
index 659bf68..4497128 100644<br>
--- a/tests/connection-test.c<br>
+++ b/tests/connection-test.c<br>
@@ -57,6 +57,7 @@ TEST(connection_create)<br>
<br>
        connection = setup(s);<br>
        wl_connection_destroy(connection);<br>
+       close(s[0]);<br>
        close(s[1]);<br>
 }<br>
<br>
@@ -74,6 +75,7 @@ TEST(connection_write)<br>
        assert(memcmp(message, buffer, sizeof message) == 0);<br>
<br>
        wl_connection_destroy(connection);<br>
+       close(s[0]);<br>
        close(s[1]);<br>
 }<br>
<br>
@@ -92,6 +94,7 @@ TEST(connection_data)<br>
        wl_connection_consume(connection, sizeof message);<br>
<br>
        wl_connection_destroy(connection);<br>
+       close(s[0]);<br>
        close(s[1]);<br>
 }<br>
<br>
@@ -117,6 +120,7 @@ TEST(connection_queue)<br>
        assert(memcmp(message, buffer + sizeof message, sizeof message) == 0);<br>
<br>
        wl_connection_destroy(connection);<br>
+       close(s[0]);<br>
        close(s[1]);<br>
 }<br>
<br>
@@ -147,8 +151,8 @@ setup_marshal_data(struct marshal_data *data)<br>
 static void<br>
 release_marshal_data(struct marshal_data *data)<br>
 {<br>
-       wl_connection_destroy(data->read_connection);<br>
-       wl_connection_destroy(data->write_connection);<br>
+       close(wl_connection_destroy(data->read_connection));<br>
+       close(wl_connection_destroy(data->write_connection));<br>
 }<br>
<br>
 static void<br>
<span class="HOEnZb"><font color="#888888">--<br>
2.1.1<br>
<br>
_______________________________________________<br>
wayland-devel mailing list<br>
<a href="mailto:wayland-devel@lists.freedesktop.org">wayland-devel@lists.freedesktop.org</a><br>
<a href="http://lists.freedesktop.org/mailman/listinfo/wayland-devel" target="_blank">http://lists.freedesktop.org/mailman/listinfo/wayland-devel</a><br>
</font></span></blockquote></div><br></div>