Yukihiro Matsumoto wrote:
Hello.
Can you show us the source of your extension? Preferably with error
producing script, please?
After investigating the matter I’m not sure if it’s a bug in my C
extension, it’s most major part is a port of a multi-threaded server
class in ruby, but the sugfault can occour almost anywhere in the code,
especially where IO is invloved.
In fact I was able to produce the segfaulting on regular basis by
reverting back to the pure ruby version:
== START MTServer.rb ==
MultiThreaded(using thread pool) TCPServer, derived from
GServer.rb(which was
require “socket”
require “thread”
module Radical
module Server
# A worker thread class, binds to server and accepts connections
class MTWorker
def initialize(employer,clientnum=-1)
@employer=employer
@clientnum=clientnum
@run=true
@thread=Thread.new &method('run').to_proc
end
def stop()
@run=false
Thread.kill @thread
end
def run()
while @run
begin
@employer.avail+=1
s=@employer.accept
@employer.avail-=1
begin
@employer.serve(s)
rescue Exception => detail
LogManager.log(“sever_error”,detail.message)
ensure
begin
@clientnum-=1
@run=false if @clientnum==0
s.close
rescue
end
end
rescue Exception => x
LogManager.log(“sever_error”,detail.message)
end
end
@employer.workers.delete(self)
end
end
class MTServer
DEFAULT_HOST = "0.0.0.0"
# To be overriden
def serve(io)
end
def stop
Thread.kill @tcpServerMonitor
@workers.each do |w|
w.stop
end
end
def stopped?
@tcpServerThread == nil
end
def shutdown
@shutdown = true
end
def join
@tcpServerThread.join if @tcpServerThread
end
attr_reader :port, :host, :maxConnections,:workers
attr_accessor :avail
def initialize(port, host, minWorkers,maxWorkers,tempWorkers)
@autoclose=true
@avail=0
@m=Mutex.new
@tcpServerThread = nil
@port = port
@host = host
@workers=[]
@minWorkers = minWorkers.to_i
@maxWorkers = maxWorkers.to_i
@tempWorkers = tempWorkers.to_i
end
# Thread safe wrapper to TCPServer#accept
def accept()
@m.synchronize do
s=@tcpServer.accept
if not @ssl.nil?
s=Radical::SSL::SSLSocket.new(client,@ssl[1],@ssl[0])
s.accept
end
return s
end
end
def start(ssl=nil)
raise "running" if !stopped?
@ssl=ssl
@shutdown = false
@tcpServer = TCPServer.new(@host,@port)
@port = @tcpServer.addr[1]
1.upto(@minWorkers) { @workers << MTWorker.new(self) }
if @maxWorkers!=-1
@tcpServerMonitor = Thread.new {
while 1
if @avail<1
if @workers.length<@maxWorkers
@workers << MTWorker.new(self,-1)
next
elsif @workers.length>@maxWorkers and
@workers.length-@maxWorkers<@tempWorkers then
@workers << MTWorker.new(self,500)
end
end
sleep(1)
end
}
else
@tcpServerThread = Thread.new {
begin
while 1
s=@tcpServer.accept
if not @ssl.nil?
s=Radical::SSL::SSLSocket.new(client,@ssl[1],@ssl[0])
s.accept
end
serve s
end
end
}
end
self
end
end
end
end
== END MTServer.rb ==
There is an HTTP server class running on top that feeds a Handler which
does the rest of the dirty job. What I was doing to reproduce the
problem is to benchmark the server with 70 concurrent users, after 10-15
the process is RIP.
I will try to code tomorrow a simple echo server and a benchmarker so
the problem can be isolated.
Idan.