Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 13 Aug 2001 12:04:55 -0400
From:      Jonathan Chen <jon@freebsd.org>
To:        hackers@freebsd.org
Subject:   pthreads and poll()
Message-ID:  <20010813120455.A63309@enterprise.spock.org>

next in thread | raw e-mail | index | archive | help

Yesterday marked my first attempt at mixing poll() with pthreads.  
Needless to say, things did not work out the way I wanted them to.  So, I
began the task of finding out the behaviors of various OSes to see if my
code would run fine on them.  For your reference and amusement, my results
and test code is included below.

I think that waking only one thread up is the correct behavior, or is there
something that toggles which behavior I want?  Perhaps someone with access
to the POSIX standard would care to confirm what the Right Thing is?  
Perhaps that someone would then proceed to fix all the incorrect
implementations... or am I asking too much? :)

Looks like I'm going to have to swear off mixing poll() with pthreads for
at least two years if I want my code to be portable...

Aside: I thought that linuxthreads == Linux's implementation of pthreads?  
Now why do they behave differently?

-Jon



		 FreeBSD4/5   OpenBSD  Linux  IRIX  AIX  Solaris8
		  sys  lth      2.8    2.4.1  6.5   4.3    5.8
poll/tcpaccept	   N    Y        N       N     Y     N      Y
poll/udp	   N    Y        N       Y     *     N      Y
poll/file	   N    Y        N       Y     *     N      Y

Legend:

FreeBSD tested with system pthread (sys), linuxthreads (lth) and GNU pth (pth).
poll/tcpaccept	- poll() before accept() of a tcp socket
poll/udp	- poll() before recv() of a udp socket
poll/file	- poll() before read() of a named fifo socket
Y: only 1 thread wakes up.
N: all threads wake up.
*: IRIX's behavior seems to be nondeterministic.  Perhaps IRIX has some AI 
   to detect the best behavior...  Nah...


#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <poll.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <errno.h>

#ifdef _THREAD_SAFE
# include <pthread.h>
#endif

struct pollfd pfd;

void* testcode(void* arg) {
  int ret;
  struct sockaddr_in addr;
  int len;
  char buf[1024];

  fprintf(stderr,"thread %d: polling...\n", (int)arg);
  ret = poll(&pfd, 1, -1);
  if (ret != 1)
    fprintf(stderr,"thread %d: bad poll return %d\n", (int)arg, ret);
  fprintf(stderr,"thread %d: reading...\n", (int)arg);
#if defined(TEST_TCP)
  len = sizeof(struct sockaddr_in);
  ret = accept(pfd.fd, (struct sockaddr*)&addr, &len);
#elif defined(TEST_UDP)
  ret = recv(pfd.fd, buf, 1024, 0);
#elif defined(TEST_READ)
  ret = read(pfd.fd, buf, 1024);
#endif

  if (ret <= 0)
    fprintf(stderr,"thread %d: broken return %d %d %s\n", (int)arg, ret,
	    errno, strerror(errno));
  
  fprintf(stderr,"thread %d: exit\n", (int)arg);
  return 0;
}

int main(int argc, char* argv[]) {
  int tmp;
#ifdef _THREAD_SAFE
  pthread_t threads[3];
#endif
  struct sockaddr_in addr;
  int len;

  srandom(time(NULL));
  bzero(&addr, sizeof(struct sockaddr_in));
  addr.sin_family=AF_INET;
  len=sizeof(struct sockaddr_in);
  addr.sin_port=htons(random()%10000+1024);
  pfd.events = POLLIN;

#if defined(TEST_TCP)
  pfd.fd = socket(PF_INET, SOCK_STREAM, 0);
  bind(pfd.fd, (struct sockaddr*)&addr, len);
  listen(pfd.fd, 1);
  fprintf(stderr,"TCP listening on port %d\n", ntohs(addr.sin_port));
#elif defined(TEST_UDP)
  pfd.fd = socket(PF_INET, SOCK_DGRAM, 0);
  bind(pfd.fd, (struct sockaddr*)&addr, len);
  fprintf(stderr,"UDP listening on port %d\n", ntohs(addr.sin_port));
#elif defined(TEST_READ)
  pfd.fd = open("/tmp/testfile", O_RDONLY);
  fprintf(stderr,"File polling on /tmp/testfile\n", 94);
#else
  assert(0);
#endif
  
  tmp = fcntl(pfd.fd, F_SETFL, O_NONBLOCK);
  if (tmp != 0)
    fprintf(stderr, "fcntl returns %d %d %s\n", tmp, errno, strerror(errno));

#ifdef _THREAD_SAFE
  for (tmp = 0; tmp < 2; tmp++) {
    pthread_create(&(threads[tmp]), NULL, testcode, (void*)tmp);
  }
#endif
  testcode((void*)-1);
#ifdef _THREAD_SAFE
  for (tmp = 0; tmp < 2; tmp++) {
    pthread_join(threads[tmp], NULL);
  }
#endif
  exit(0);
}



To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20010813120455.A63309>