Home > Uncategorized > Curious difference between epoll, poll, kqueue and select

Curious difference between epoll, poll, kqueue and select

Suppose you have a brand new nonblocking socket and you want to do something with it (i have a connect in mind – but it’s irrelevant anyway). So what is your obvious choice for that since the socket is non-blocking ? Use select or poll or whatever ofcourse. Right? NO.

Sadly they don’t work the same with unconnected sockets – i wonder why.

select (win32):

>>> import select, socket
>>> s = socket.socket()
>>> select.select([s], [s], [s], 1)
([], [], [])

select (linux):

>>> import select, socket
>>> s = socket.socket()
>>> select.select([s], [s], [s], 1)
([<socket._socketobject>], [<socket._socketobject>], [])

select (freebsd):

>>> import select, socket
>>> s = socket.socket()
>>> select.select([s], [s], [s], 1)
([], [], [])

Pretty inconsistent eh?poll (linux):

>>> import select, socket
>>> poll = select.poll()
>>> s = socket.socket()
>>> poll.register(s.fileno(), select.POLLIN | select.POLLOUT)
>>> (fd, ev), = poll.poll(1000)
>>> ev & select.POLLIN
0
>>> ev & select.POLLOUT
4
>>> ev & select.POLLERR
0
>>> ev & select.POLLHUP
16

poll (freebsd):

>>> import select, socket
>>> poll = select.poll()
>>> s = socket.socket()
>>> poll.register(s.fileno(), select.POLLIN | select.POLLOUT)
>>> (fd, ev), = poll.poll(1000)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueErr1r: need more than 0 values to unpack

Oh NOES!!!!1 It’s not portable.epoll:

>>> import epoll, socket
>>> efd = epoll.epoll_create(16)
>>> s = socket.socket()
>>> epoll.epoll_ctl(efd, epoll.EPOLL_CTL_ADD, s.fileno(), epoll.EPOLLIN | epoll.EPOLLOUT)
0
>>> (ev, fd), = epoll.epoll_wait(efd, 16, 1000)
>>> ev & epoll.EPOLLHUP
16
>>> ev & epoll.EPOLLOUT
4

kqueue:

>>> import kqueue, socket
>>> kq = kqueue.kqueue()
>>> s = socket.socket()
>>> kq.kevent(kqueue.EV_SET(s.fileno(), kqueue.EVFILT_READ | kqueue.EVFILT_WRITE, kqueue.EV_ADD | kqueue.EV_ENABLE))
>>> kq.kevent(None, 16, 1000000000)
[]

I wonder why are these so inconsistent. One would expect come consistent results for multiplexing a simple thing such a unconnected brand new socket, no?If you think that is horrible – well, i do – check out the tricks to check for connection success on non-blocking sockets – and they don’t cover win32:

However, win32 has a much nicer api in the so called overlapped io wich is very different: you don’t need to check the sockets before making a operation – you just make the socket call with a overlapped and check for for completed calls (via io completion ports – gqcs). Still, you can use some selects variants (WSAAsyncSelect, WSAEventSelect, select) wich are just as bad.

Unfortunately python has a incomplete binding, pywin32 (not that bad – only ConnectEx and TransmitFile missing) for that and it’s actually fairly easy to crash your python interpreter with this.

About these ads
Tags: ,
  1. anonymous
    July 18, 2009 at 10:49 pm | #1

    If you tell us what the point of callinh select or epoll on an unconnected stream socket is (which is what you seem to be trying to d), we might be concerned.

    While there are some differences between all those interfaces, they work pretty consistent if you actually do useful stuff, such as non-blocking connects, accepts or i/o.

    Otherwise, it’s just garbage in garbage out.

    (overlapped I/O is a lot less consistent btw., and requires you to tie down a lot of resources. It is hardly an improvement over select)

    • Ionel Maries
      July 19, 2009 at 12:37 am | #2

      Checking unconnected sockets for readiness is useful when you want to accept/connect with that (non-blocking) socket.

  2. Zapp
    October 18, 2009 at 5:29 pm | #3

    It’s incosistent because the different calls appeared on different platforms in different time. I can see how you sit today with windows, linux AND bsd and go “why so many different calls”, but those operating systems appeared at different times, not to mention the myriad of various unix “flavors” and two major differences between them (bsd/system V).

    Also, event loop calls like epoll/kqueue are pretty recent additions which address the now classic question of “how do you write server that handles 10.000 simultaneous connections”. Back in the days, that wasn’t the issue, because everything was smaller and less used. People never could imagine running out of space in IPv4 address space, or running out of port numbers (16-bit).

    However, today, with internet around and new applications like telecom, I found myself recently writing code thats trying to establish one million tcp connections, on a single machine, on linux.

    There was a lot of kernel hacking required to make it possible, and all the old cruft like select() and poll() are pretty much useless there, because they just simply don’t scale.

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 170 other followers