Skip to content

the buffer size ioctls on linux return EINVAL when it's not supported #281

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 17, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 27 additions & 9 deletions src/event/event_epoll.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ typedef struct dispatch_muxnote_s {
int dmn_ident;
uint32_t dmn_events;
int16_t dmn_filter;
bool dmn_socket_listener;
bool dmn_skip_outq_ioctl;
bool dmn_skip_inq_ioctl;
} *dispatch_muxnote_t;

typedef struct dispatch_epoll_timeout_s {
Expand Down Expand Up @@ -143,7 +144,7 @@ _dispatch_muxnote_create(dispatch_unote_t du, uint32_t events)
struct stat sb;
int fd = du._du->du_ident;
int16_t filter = du._du->du_filter;
bool socket_listener = false;
bool skip_outq_ioctl = false, skip_inq_ioctl = false;
sigset_t sigmask;

switch (filter) {
Expand Down Expand Up @@ -173,11 +174,15 @@ _dispatch_muxnote_create(dispatch_unote_t du, uint32_t events)
if (fd < 0) {
return NULL;
}
// Linux doesn't support output queue size ioctls for regular files
skip_outq_ioctl = true;
} else if (S_ISSOCK(sb.st_mode)) {
socklen_t vlen = sizeof(int);
int v;
// Linux doesn't support saying how many clients are ready to be
// accept()ed for sockets
if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &v, &vlen) == 0) {
socket_listener = (bool)v;
skip_inq_ioctl = (bool)v;
}
}
break;
Expand All @@ -193,7 +198,8 @@ _dispatch_muxnote_create(dispatch_unote_t du, uint32_t events)
dmn->dmn_ident = du._du->du_ident;
dmn->dmn_filter = filter;
dmn->dmn_events = events;
dmn->dmn_socket_listener = socket_listener;
dmn->dmn_skip_outq_ioctl = skip_outq_ioctl;
dmn->dmn_skip_inq_ioctl = skip_inq_ioctl;
return dmn;
}

Expand Down Expand Up @@ -480,16 +486,28 @@ _dispatch_event_merge_signal(dispatch_muxnote_t dmn)
static uintptr_t
_dispatch_get_buffer_size(dispatch_muxnote_t dmn, bool writer)
{
unsigned long op = writer ? SIOCOUTQ : SIOCINQ;
int n;

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

if (dispatch_assume_zero(ioctl(dmn->dmn_ident, op, &n))) {
if (ioctl(dmn->dmn_ident, writer ? SIOCOUTQ : SIOCINQ, &n) != 0) {
switch (errno) {
case EINVAL:
case ENOTTY:
// this file descriptor actually doesn't support the buffer
// size ioctl, remember that for next time to avoid the syscall.
break;
default:
dispatch_assume_zero(errno);
break;
}
if (writer) {
dmn->dmn_skip_outq_ioctl = true;
} else {
dmn->dmn_skip_inq_ioctl = true;
}
return 1;
}
return (uintptr_t)n;
Expand Down
3 changes: 2 additions & 1 deletion tests/dispatch_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ test_timer(void)
fprintf(stderr, "%d\n", ++i);
if (i >= stop_at) {
test_long("i", i, stop_at);
dispatch_source_set_timer(s, dispatch_time(DISPATCH_TIME_NOW, 0), 0, 0);
dispatch_source_set_timer(s, dispatch_time(DISPATCH_TIME_NOW, 0),
DISPATCH_TIME_FOREVER, 0);
dispatch_source_cancel(s);
}
});
Expand Down