Skip to content

Commit 8947dcf

Browse files
authored
Merge pull request #281 from apple/mad/epoll-fixes-2
the buffer size ioctls on linux return EINVAL when it's not supported
2 parents f8e71eb + 3b5d69b commit 8947dcf

File tree

2 files changed

+29
-10
lines changed

2 files changed

+29
-10
lines changed

src/event/event_epoll.c

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ typedef struct dispatch_muxnote_s {
5151
int dmn_ident;
5252
uint32_t dmn_events;
5353
int16_t dmn_filter;
54-
bool dmn_socket_listener;
54+
bool dmn_skip_outq_ioctl;
55+
bool dmn_skip_inq_ioctl;
5556
} *dispatch_muxnote_t;
5657

5758
typedef struct dispatch_epoll_timeout_s {
@@ -143,7 +144,7 @@ _dispatch_muxnote_create(dispatch_unote_t du, uint32_t events)
143144
struct stat sb;
144145
int fd = du._du->du_ident;
145146
int16_t filter = du._du->du_filter;
146-
bool socket_listener = false;
147+
bool skip_outq_ioctl = false, skip_inq_ioctl = false;
147148
sigset_t sigmask;
148149

149150
switch (filter) {
@@ -173,11 +174,15 @@ _dispatch_muxnote_create(dispatch_unote_t du, uint32_t events)
173174
if (fd < 0) {
174175
return NULL;
175176
}
177+
// Linux doesn't support output queue size ioctls for regular files
178+
skip_outq_ioctl = true;
176179
} else if (S_ISSOCK(sb.st_mode)) {
177180
socklen_t vlen = sizeof(int);
178181
int v;
182+
// Linux doesn't support saying how many clients are ready to be
183+
// accept()ed for sockets
179184
if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &v, &vlen) == 0) {
180-
socket_listener = (bool)v;
185+
skip_inq_ioctl = (bool)v;
181186
}
182187
}
183188
break;
@@ -193,7 +198,8 @@ _dispatch_muxnote_create(dispatch_unote_t du, uint32_t events)
193198
dmn->dmn_ident = du._du->du_ident;
194199
dmn->dmn_filter = filter;
195200
dmn->dmn_events = events;
196-
dmn->dmn_socket_listener = socket_listener;
201+
dmn->dmn_skip_outq_ioctl = skip_outq_ioctl;
202+
dmn->dmn_skip_inq_ioctl = skip_inq_ioctl;
197203
return dmn;
198204
}
199205

@@ -480,16 +486,28 @@ _dispatch_event_merge_signal(dispatch_muxnote_t dmn)
480486
static uintptr_t
481487
_dispatch_get_buffer_size(dispatch_muxnote_t dmn, bool writer)
482488
{
483-
unsigned long op = writer ? SIOCOUTQ : SIOCINQ;
484489
int n;
485490

486-
if (!writer && dmn->dmn_socket_listener) {
487-
// Linux doesn't support saying how many clients are ready to be
488-
// accept()ed
491+
if (writer ? dmn->dmn_skip_outq_ioctl : dmn->dmn_skip_inq_ioctl) {
489492
return 1;
490493
}
491494

492-
if (dispatch_assume_zero(ioctl(dmn->dmn_ident, op, &n))) {
495+
if (ioctl(dmn->dmn_ident, writer ? SIOCOUTQ : SIOCINQ, &n) != 0) {
496+
switch (errno) {
497+
case EINVAL:
498+
case ENOTTY:
499+
// this file descriptor actually doesn't support the buffer
500+
// size ioctl, remember that for next time to avoid the syscall.
501+
break;
502+
default:
503+
dispatch_assume_zero(errno);
504+
break;
505+
}
506+
if (writer) {
507+
dmn->dmn_skip_outq_ioctl = true;
508+
} else {
509+
dmn->dmn_skip_inq_ioctl = true;
510+
}
493511
return 1;
494512
}
495513
return (uintptr_t)n;

tests/dispatch_timer.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ test_timer(void)
8686
fprintf(stderr, "%d\n", ++i);
8787
if (i >= stop_at) {
8888
test_long("i", i, stop_at);
89-
dispatch_source_set_timer(s, dispatch_time(DISPATCH_TIME_NOW, 0), 0, 0);
89+
dispatch_source_set_timer(s, dispatch_time(DISPATCH_TIME_NOW, 0),
90+
DISPATCH_TIME_FOREVER, 0);
9091
dispatch_source_cancel(s);
9192
}
9293
});

0 commit comments

Comments
 (0)