[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <1292433864.5569.105.camel@kurkku.sapo.corppt.com>
Date: Wed, 15 Dec 2010 17:24:24 +0000
From: Timo Sirainen <tss@....fi>
To: linux-kernel@...r.kernel.org
Subject: poll()ing a shared pipe triggers unnecessary context switches
I have one master process reading status updates from a pipe shared by
multiple child processes. The child processes also poll() the pipe's
write fd to see when the master process dies. This works fine, except
each time a child process writes to the pipe, all the child processes
wake up in poll()/epoll_wait() and go back to sleep without returning
anything, triggering unnecessary context switches.
I worked around this by creating yet another pipe just for listening the
master's death, but this still seems like a Linux bug to me. Solaris and
BSDs don't behave like this.
Test program:
/*
gcc poller.c -o poller -Wall
Usage: ./poller
Wait for a while if it prints any "volcs for poll() = .." messages.
It shouldn't.
Program stops by hitting enter.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <poll.h>
#include <sys/time.h>
#include <sys/resource.h>
void child(int fd)
{
struct pollfd pfd;
struct rusage ru1, ru2;
int diff;
memset(&pfd, 0, sizeof(pfd));
pfd.fd = fd;
pfd.events = 0;
while (write(fd, "foo\n", 4) == 4) {
getrusage(RUSAGE_SELF, &ru1);
if (poll(&pfd, 1, 100) != 0)
break;
getrusage(RUSAGE_SELF, &ru2);
diff = ru2.ru_nvcsw - ru1.ru_nvcsw;
if (diff > 2)
printf("volcs for poll() = %d\n", diff);
}
printf("%d exited\n", (int)getpid());
exit(0);
}
int main(void)
{
struct pollfd pfds[2];
int i, fd[2];
char buf[1024];
pipe(fd);
for (i = 0; i < 10; i++) {
if (fork() == 0) {
close(fd[0]);
child(fd[1]);
}
}
memset(pfds, 0, sizeof(pfds));
pfds[0].fd = 0;
pfds[0].events = POLLIN;
pfds[1].fd = fd[0];
pfds[1].events = POLLIN;
while (poll(pfds, 2, -1) > 0) {
if (pfds[0].revents != 0)
break;
if (pfds[1].revents != 0)
read(fd[0], buf, sizeof(buf));
}
close(fd[0]);
close(fd[1]);
printf("done\n");
return 1;
}
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists