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

Re: [Libevent-users] Design struggle



On Fri, Aug 29, 2014 at 05:53:50PM +0200, B.R. wrote:
> I am trying to implement a modular filter plug-in system on top of libevent.
> 
> The main concept principles are:
> 1°) Filters are created cointaining information of connections they should
> be bound to (protocol, port), events that should trigger them and a

I guess only one of this: protocol || port

> callback pointer to link with the event
> 2°) Based on those filters, the necessary sockets are created and each
> socket is linked to a list of filters matching them
> 3°) For each filter, an event is created liking the callback to the socket
> file descriptor
> 4°) Each filter is then able to read information from the socket and
> possibly stack information to write that socket, registering a WRITE event
> on it
> 
> My concern here are concurrency (not really race condition since the app is
> single-threaded) :
> I) If multiple filters ask to be triggered on READ event on the same
> socket, what will they see? Will they all be able to read the same message
> which triggered the event and not another one (ie another message received
> while processing the filter list)?

It depends from how you use this.

Kernel will just return array of bytes when you call read() on some
fd/socket, and once you read it, the second read() will never return the
same portion of data.

You could use evbuffer, to save data, and then feed it to every filter
that assigned to this fd/socket, and drain it when you finished.

> 
> II) If multiple filters wanna write data to the socket, is it safe to have
> each filter having its separate buffer and triggering its own WRITE event
> on it?

This is not safe, because write(2) not always will write all you portion
of data, it could write less then @count, and return this value to
libevent, and then event loop will schedule the second WRITE event for
the same fd/socket:

write(10, foobar[4096]foobaz[4096], 8192) = 4096 # event1
write(10, barfoo[4096]bazfoo[4096], 8192) = 4096 # event2
write(10, foobaz[4096], 4096) = 4096 # event1
write(10, bazfoo[4096], 4096) = 4096 # event2
...
read(10, buf, 8192*2) = 8192*2

Actual:
buf = foobar[4096]barfoo[4096]foobaz[4096]bazfoo[4096]
Expected:
buf = foobar[4096]foobaz[4096]barfoo[4096]bazfoo[4096]

Cheers,
Azat.

> 
> Here is a use case summing up both previous inquiries:
> Say a filter wrote data to a socket after parsing the content it read on
> it, and that the peer reacted to that answer, what will subsequent filters,
> for which the READ event has been triggered by the initial message, read?
> a) Initial message?
> b) Either initial message or answer (race, undecided)?
> c) Nothing since the event has been canceled (not pending anymore), the
> subsequent filters will only receive a new event for READ on reception of
> the answer
> 
> I am thinking of using a dispatcher which would sequentially (and manually)
> trigger the event of each of the filters. However that implies not linking

Why you want to do it manually?

> the filters event with the socket, thus forcing me to maintain a separate
> buffer for each of the filter (with memory and processing overhead that
> implies). Moreover, the problem reappears if another message is received on
> the socket while the dispatching loop is at work... and the sequential work
> makes the benefit of the event-based system disappear!

Which problem?
You mean that you filter-handling stuff works significantly slower than
read/write?

> 
> I do not know if the bufferevents would be useful to my case. Anyway, those
> are not an option, since part of the traffic I am handling is UDP datagrams.
> 
> I am new to the library. Please enlighten me if I have missed some key
> points in its design/handling.
> ---
> *B. R.*

***********************************************************************
To unsubscribe, send an e-mail to majordomo@xxxxxxxxxxxxx with
unsubscribe libevent-users    in the body.