[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[Libevent-users] evconnlistener blocks "other stuff"



I recently looked into the problem that spamming my server with
connections would even prevent it from responding to the CTRL-C signal.
First thing I did was to add priorities to my events, with signals getting
the highest and sockets getting the lowest prio. Much to my surprise, that
didn't change anything at all.

After some headscratching, and since I'm using EVLOOP_ONCE anyway to
implement a delayed disposal of objects, I threw some
event_base_loopbreak() calls into the code to see if that would help.
Again, it still didn't get my Ctrl-C until I stopped spamming connections
at the server.

More reading got me to the "complicated event base", and the
event_config_set_max_dispatch_interval() option. Needless to say, it
didn't improve things.

I was already concerned that the evconnlistener didn't support priorities,
but even at default priority it should be lower than the signal priority
as I have 4 priority levels. So, I started to dig into the libevent code
itself.

Turns out, the evconnlistener (listener.c) accepts connections until it
gets an error, apparently (I can't say I went through all the libevent
code)
without checking for things like event_config_set_max_dispatch_interval.
My build now applies a patch to the libevent build that just breaks the
loop after 10 accepts, and that finally got my signals noticed.

I've attached the patch for purely informal reasons; a real change should
not break the loop after 10 tries but use the parameters that libevent
already has. For now, I just needed something that works, and doesn't
require me to spend days researching how libevent is supposed to work
internally.
*** listener.c	2015-01-05 14:54:34.000000000 +0100
--- listener.c	2016-01-15 10:03:38.103375674 +0100
***************
*** 390,399 ****
--- 390,400 ----
  	struct evconnlistener *lev = p;
  	int err;
  	evconnlistener_cb cb;
  	evconnlistener_errorcb errorcb;
  	void *user_data;
+ 	int count=0;
  	LOCK(lev);
  	while (1) {
  		struct sockaddr_storage ss;
  		ev_socklen_t socklen = sizeof(ss);
  		evutil_socket_t new_fd = evutil_accept4_(fd, (struct sockaddr*)&ss, &socklen, lev->accept4_flags);
***************
*** 422,431 ****
--- 423,437 ----
  			int freed = listener_decref_and_unlock(lev);
  			EVUTIL_ASSERT(freed);
  			return;
  		}
  		--lev->refcnt;
+ 		if (++count==10)
+ 		{
+ 			UNLOCK(lev);
+ 			return;
+ 		}
  	}
  	err = evutil_socket_geterror(fd);
  	if (EVUTIL_ERR_ACCEPT_RETRIABLE(err)) {
  		UNLOCK(lev);
  		return;