Issue with threads and socket accept

Hi,

I’m writing a multi-threaded server, and would like to stop it on a
signal (SIGINT on Ctrl-C in this case).
The problem is that after the first connection is accepted, and then
Ctrl-C is hit, the “while accept” loop doesn’t break. If you hit Ctrl-
C before any connections, it just works fine. And the single-threaded
version, of course, works
as well.

Could somebody explain what am I doing wrong?

Below is a simple application that reproduces the problem. Change the
last line to “server.serve_seq” to run a single-threaded version.

Thanks in advance!

#!/usr/local/bin/ruby -w

require ‘socket’

class MyServer
def initialize
@servsock = TCPServer.new(“127.0.0.1”, 1111)
end

def work(sock)
begin
lines = 0
lines += 1 while sock.gets
puts “Got #{lines} lines.”
rescue Exception => e
print "exception: "; p e
ensure
sock.close
end
end

def serve_mt
while clisock = @servsock.accept
Thread.new(clisock) { |sock| work(sock) }
end
end

def serve_seq
while sock = @servsock.accept
work(sock)
end
end

def shutdown
return nil if @servsock.nil? or @servsock.closed?
puts “Shutting down…”
@servsock.close
end
end

server = MyServer.new
Signal.trap(“INT”) { server.shutdown }
server.serve_mt

On Dec 11, 2007 11:18 AM, Vasyl S. [email protected] wrote:

Could somebody explain what am I doing wrong?

Without addressing your specific question, let me suggest that you
investigate the Ruby/Eventmachine library. It should make your
application
easier to develop.

On Dec 11, 7:53 pm, “Francis C.” [email protected]
wrote:

Without addressing your specific question, let me suggest that you
investigate the Ruby/Eventmachine library. It should make your application
easier to develop.

Thanks, Francis, I’m just reading the docs for your library!

On 2007-12-12 01:18 +0900 (Wed), Vasyl S. wrote:

I’m writing a multi-threaded server, and would like to stop it on a
signal (SIGINT on Ctrl-C in this case).
The problem is that after the first connection is accepted, and then
Ctrl-C is hit, the “while accept” loop doesn’t break…
Could somebody explain what am I doing wrong?

Errr…“not investigating deep and strange mysteries of the Ruby
interpreter
signal handling that are not comprehensible even after reading the
source?”

I hope I get a point for that answer.

But anyway, much as I’d like to know why the signal handling is set up
to ignore signals when waiting in accept(), a situation on which the
source code that does this is particularly silent, I just live with the
solution, which is:

Do a select() before your accept(), and wait until the socket in
question becomes readable.

You and I are not the only ones caught by this, as it happens. The
native
Ruby FastCGI code has the same issue.

cjs

On Dec 11, 7:43 pm, Curt S. [email protected] wrote:

Errr…“not investigating deep and strange mysteries of the Ruby interpreter
signal handling that are not comprehensible even after reading the source?”

I hope I get a point for that answer.

You probably do :slight_smile:

But anyway, much as I’d like to know why the signal handling is set up
to ignore signals when waiting in accept(), a situation on which the
source code that does this is particularly silent, I just live with the
solution, which is:

Well, actually the signal handler gets called, it calls shutdown,
outputs a message
to the stdout and closes the server socket. And the main thread is
still inside accept.

Do a select() before your accept(), and wait until the socket in
question becomes readable.

I’ve tried this, with the same success:

def serve_mt2
until @servsock.closed?
IO.select([@servsock])
clisock = @servsock.accept
Thread.new(clisock) { |sock| work(sock) }
end
end