lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
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

Powered by Openwall GNU/*/Linux Powered by OpenVZ