Skip to content

Instantly share code, notes, and snippets.

@drsnyder
Created February 8, 2013 01:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save drsnyder/4735889 to your computer and use it in GitHub Desktop.
Save drsnyder/4735889 to your computer and use it in GitHub Desktop.
Exercise the poll() on a shared pipe() context switching issue on Linux.
/*
* Exercise the poll() on a shared pipe() context switching issue on Linux using threads. Original code taken from
* http://lkml.indiana.edu/hypermail/linux/kernel/1012.1/03515.html and modified to use threads.
*
* On older 2.6 Linux kernels running this program will drive context switches per second up near 1M/s.
* On 3.x kernels you will see the csw/s pushed up to ~12k depending on the current process load.
*
* gcc -o t-poller t-poller.c -lpthread
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <poll.h>
#include <pthread.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/resource.h>
#define THREADS 400
#define ITERATIONS 5000
void ignore_sigpipe(void)
{
struct sigaction act;
int r;
memset(&act, 0, sizeof(act));
act.sa_handler = SIG_IGN;
act.sa_flags = SA_RESTART;
r = sigaction(SIGPIPE, &act, NULL);
}
void * child(void * ptr)
{
struct pollfd pfd;
struct rusage ru1, ru2;
int diff, msglen;
int fd = *(int*)ptr;
char * msg = "ping\n";
int * total;
total = malloc(sizeof(int));
*total = 0;
memset(&pfd, 0, sizeof(pfd));
msglen = strlen(msg);
pfd.fd = fd;
pfd.events = 0;
while (write(fd, msg, msglen) == msglen) {
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) {
*total = *total + diff;
}
}
pthread_exit((void*)total);
return (void *)NULL;
}
int main(int argc, char ** argv)
{
struct pollfd pfds[2];
int ret, i, iterations, fd[2];
char buf[1024];
void * thread_data;
pthread_t threads[THREADS];
memset(pfds, 0, sizeof(pfds));
ignore_sigpipe();
iterations = 0;
pipe(fd);
for (i = 0; i < THREADS; i++) {
pthread_create( &threads[i], NULL, child, (void *)&fd[1]);
}
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 (iterations >= ITERATIONS)
break;
if (pfds[1].revents != 0)
read(fd[0], buf, sizeof(buf));
iterations++;
}
close(fd[0]);
close(fd[1]);
for (i = 0; i < THREADS; i++) {
ret = pthread_join( threads[i], &thread_data);
if (ret == 0) {
ret = *(int*)thread_data;
fprintf(stderr, "%d\n", ret);
} else {
fprintf(stderr, "pthread_join: error %d\n", ret);
}
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment