| ryah ( @ 2008-03-09 22:03:00 |
| Entry tags: | ebb |
ev loop - ruby interface
I've made several attempts at rewriting the core interface between libev event loop and Ruby. The current implementation is the fastest:
trap('INT') { @running = false }
FFI::server_listen_on_port(port)
puts "Ebb listening at http://0.0.0.0:#{port}/"
@running = true
while FFI::server_process_connections() and @running
if client = FFI::waiting_clients.shift
process_client(app, client)
end
endThe key here is FFI::server_process_connections() which accesses the libev event loop, checks to see if there are any pending events, if so processes them - after all pending requests are finished it returns. If there are not any pending events the call blocks. The blocking is good because it prevents that while loop from running unrestrained. I have a timeout on libev which executes an event after 0.1 seconds just to get the function to return from it's blocked state occasionally.Ruby's thread scheduler will not act while a C FFI function is being called. This setup is a bit precarious for multithreaded applications - they only get processing time when that loop runs.
It would be better if I could separate libev's loop from Ruby a bit more. I tried that today by putting
ev_loop() in it's own pthread separated from the Ruby VM. The question then is, how does the Ruby side sit and wait for new connections? libev callbacks into the RubyVM cannot be executed from the outside like this. The solution I settled on was using a pipe with a nonblocking write side and a blocking read side. Thus the Ruby loop can gracefully block until new connections come in, but still free up the scheduler to handle other threads. This is how it looks notify_fd = FFI::server_listen_on_port(port)
notifier = IO.new(notify_fd)
puts "Ebb listening at http://0.0.0.0:#{port}/"
while notifier.read(1)
if client = FFI::server_next_client()
process_client(app, client)
end
endI like this a lot because it offers a clear interface. Unfortunately it just isn't very fast! Here it is compared to Ebb 0.0.4 and Thin:

Revert back or profile and hope for an obvious fix? Any suggestions?