event-driven server programming tip

event-driven server programming tip

Hi all,

When you write an event-driven server, you may want to be careful about 
accepting new connections vs. handling other events (e.g., read or 
write). My advice is to handle all read/write events first and then 
accept new connections. Mixing accept and I/O events in the main event 
handling loop could lead to a subtle concurrency bug that’s hard to fix. 
Here is an example:

int num_ready;

num_ready = epoll_wait();

for (i = 0; i < num_ready; i++) {
if (accept event) handle_accept();
else if (read event) handle_read();
else if (write event) handle_write();
}

Let’s say you have three events ready after epoll_wait(): read,fd=5, 
accept, write,fd=5.

1. read,fd=5
– suppose you decide to close the connection with fd=5
– you delete the connection context related to fd=5
2. accept
– you call accept(), but the return value happens to be 5!
– you create the connection context related to fd=5
3. write,fd=5
– the right action is to do nothing since fd=5 is already closed at 
step 1
– but you do wrong action with the new connection

Well, this is just one example, but I’ve seen many ugly sequences that 
lead to various server crash. To avoid this complication, I suggest you 
to write the main loop like

int do_accept = 0;
int num_ready;

num_ready = epoll_wait();

for (i = 0; i < num_ready; i++) {
if (accept event) { do_accept=1; }
else if (read event) handle_read();
else if (write event) handle_write();
}

if (do_accept)
handle_accept();

–KyoungSoo

Leave a Reply