Skip to content

Commit 2e3d5c0

Browse files
Merge pull request #478 from gottesmm/sr-9033
Combined PR: SR-9033 handle EPOLLHUP
2 parents a3bff44 + 33c5d81 commit 2e3d5c0

File tree

3 files changed

+102
-0
lines changed

3 files changed

+102
-0
lines changed

src/event/event_epoll.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,20 @@ _dispatch_get_buffer_size(dispatch_muxnote_t dmn, bool writer)
549549
return (uintptr_t)n;
550550
}
551551

552+
static void
553+
_dispatch_event_merge_hangup(dispatch_unote_t du)
554+
{
555+
// consumed by dux_merge_evt()
556+
_dispatch_retain_unote_owner(du);
557+
dispatch_unote_state_t du_state = _dispatch_unote_state(du);
558+
du_state |= DU_STATE_NEEDS_DELETE;
559+
du_state &= ~DU_STATE_ARMED;
560+
_dispatch_unote_state_set(du, du_state);
561+
uintptr_t data = 0; // EOF
562+
os_atomic_store2o(du._dr, ds_pending_data, ~data, relaxed);
563+
dux_merge_evt(du._du, EV_DELETE|EV_DISPATCH, data, 0);
564+
}
565+
552566
static void
553567
_dispatch_event_merge_fd(dispatch_muxnote_t dmn, uint32_t events)
554568
{
@@ -583,6 +597,20 @@ _dispatch_event_merge_fd(dispatch_muxnote_t dmn, uint32_t events)
583597
}
584598
}
585599

600+
// SR-9033: EPOLLHUP is an unmaskable event which we must respond to
601+
if (events & EPOLLHUP) {
602+
LIST_FOREACH_SAFE(dul, &dmn->dmn_readers_head, du_link, dul_next) {
603+
dispatch_unote_t du = _dispatch_unote_linkage_get_unote(dul);
604+
_dispatch_event_merge_hangup(du);
605+
}
606+
LIST_FOREACH_SAFE(dul, &dmn->dmn_writers_head, du_link, dul_next) {
607+
dispatch_unote_t du = _dispatch_unote_linkage_get_unote(dul);
608+
_dispatch_event_merge_hangup(du);
609+
}
610+
epoll_ctl(_dispatch_epfd, EPOLL_CTL_DEL, dmn->dmn_fd, NULL);
611+
return;
612+
}
613+
586614
events = _dispatch_muxnote_armed_events(dmn);
587615
if (events) _dispatch_epoll_update(dmn, events, EPOLL_CTL_MOD);
588616
}

tests/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ set(DISPATCH_C_TESTS
155155
starfish
156156
data
157157
io_net
158+
io_pipe_close
158159
select)
159160

160161
# Tests that usually pass, but occasionally fail.
@@ -194,6 +195,8 @@ foreach(test ${DISPATCH_C_TESTS})
194195
dispatch_${test}.c)
195196
endforeach()
196197

198+
set_tests_properties(dispatch_io_pipe_close PROPERTIES TIMEOUT 5)
199+
197200
# test dispatch API for various C/CXX language variants
198201
add_unit_test(dispatch_c99 NO_BSD_OVERLAY SOURCES dispatch_c99.c)
199202
add_unit_test(dispatch_plusplus SOURCES dispatch_plusplus.cpp)

tests/dispatch_io_pipe_close.c

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright (c) 2019 Apple Inc. All rights reserved.
3+
*
4+
* @APPLE_APACHE_LICENSE_HEADER_START@
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*
18+
* @APPLE_APACHE_LICENSE_HEADER_END@
19+
*/
20+
21+
#include <stdio.h>
22+
#include <unistd.h>
23+
#include <stdlib.h>
24+
#include <limits.h>
25+
#include <errno.h>
26+
27+
#include <bsdtests.h>
28+
#include "dispatch_test.h"
29+
#include <dispatch/dispatch.h>
30+
31+
int
32+
main() {
33+
int pipe_fds[2] = { -1, -1 };
34+
int pipe_err = pipe(pipe_fds);
35+
int readFD = pipe_fds[0];
36+
int writeFD = pipe_fds[1];
37+
38+
dispatch_test_start(NULL);
39+
if (pipe_err) {
40+
test_errno("pipe", errno, 0);
41+
test_stop();
42+
_Exit(EXIT_FAILURE);
43+
}
44+
45+
printf("readFD=%d, writeFD=%d\n", readFD, writeFD);
46+
dispatch_queue_t q = dispatch_queue_create("q", NULL);
47+
dispatch_io_t io = dispatch_io_create(DISPATCH_IO_STREAM, readFD, q, ^(int err) {
48+
printf("cleanup, err=%d\n", err);
49+
close(readFD);
50+
printf("all done\n");
51+
test_stop();
52+
_Exit(EXIT_SUCCESS);
53+
});
54+
dispatch_io_set_low_water(io, 0);
55+
dispatch_io_read(io, 0, UINT_MAX, q, ^(bool done, dispatch_data_t data, int err) {
56+
printf("read: \%d, %zu, %d\n", done, data == NULL ? 0 : dispatch_data_get_size(data), err);
57+
if (data != NULL && dispatch_data_get_size(data) > 0) {
58+
// will only happen once
59+
printf("closing writeFD\n");
60+
close(writeFD);
61+
dispatch_after(DISPATCH_TIME_NOW + 1, q, ^{
62+
dispatch_io_close(io, 0);
63+
});
64+
}
65+
});
66+
dispatch_resume(io);
67+
printf("writing\n");
68+
write(writeFD, "x", 1);
69+
printf("wrtten\n");
70+
dispatch_main();
71+
}

0 commit comments

Comments
 (0)