SystemStackError: stack level too deep

Discussion in 'Ruby' started by Oliver Peng, Feb 29, 2008.

  1. Oliver Peng

    Oliver Peng Guest

    Now I am writing a server code to handle each connection by forking a
    new process. Here is the code:

    @tcpServer = TCPServer.new(host, port)

    while true
    if tcp = @tcpServer.accept
    fork do
    // handle all request in this connection
    end
    tcp && tcp.close
    end
    end

    @tcpServer.close_read
    @tcpServer.close_write

    I also set up trap to handle CLD signal:
    trap("CLD") {
    pid_info_array = Process.waitall
    }

    After a period of time, I got the error:

    SystemStackError: stack level too deep

    The position is at the line of Process.waitall.

    I have tried to use Process.wait, but this problem still exist.

    Any ideas. Thanks.
    --
    Posted via http://www.ruby-forum.com/.
     
    Oliver Peng, Feb 29, 2008
    #1
    1. Advertising

  2. On 29.02.2008 22:15, Oliver Peng wrote:
    > Now I am writing a server code to handle each connection by forking a
    > new process. Here is the code:
    >
    > @tcpServer = TCPServer.new(host, port)
    >
    > while true
    > if tcp = @tcpServer.accept
    > fork do
    > // handle all request in this connection
    > end
    > tcp && tcp.close
    > end
    > end
    >
    > @tcpServer.close_read
    > @tcpServer.close_write
    >
    > I also set up trap to handle CLD signal:
    > trap("CLD") {
    > pid_info_array = Process.waitall
    > }
    >
    > After a period of time, I got the error:
    >
    > SystemStackError: stack level too deep
    >
    > The position is at the line of Process.waitall.
    >
    > I have tried to use Process.wait, but this problem still exist.
    >
    > Any ideas. Thanks.


    You are doing an unhealthy mix: Process.waitall and wait block to wait
    for an event but SIGCLD is supposed to be called when that event happens.

    So either, use Process.waitall in main or change the trap code to do
    something like manipulating a child process counter so you can detect
    when the last is gone.

    But at the heart of your problem is a logic error: you cannot have an
    endless loop and wait for all children to exit at the same time. Either
    you decide in the main loop that now no more children are to be created
    OR you just have a main loop that runs forever - but then there is no
    point in waiting for all childs to terminate.

    Kind regards

    robert
     
    Robert Klemme, Mar 1, 2008
    #2
    1. Advertising

  3. Oliver Peng

    Oliver Peng Guest

    Robert Klemme wrote:
    > On 29.02.2008 22:15, Oliver Peng wrote:
    >> tcp && tcp.close
    >>
    >> After a period of time, I got the error:
    >>
    >> SystemStackError: stack level too deep
    >>
    >> The position is at the line of Process.waitall.
    >>
    >> I have tried to use Process.wait, but this problem still exist.
    >>
    >> Any ideas. Thanks.

    >
    > But at the heart of your problem is a logic error: you cannot have an
    > endless loop and wait for all children to exit at the same time. Either
    > you decide in the main loop that now no more children are to be created
    > OR you just have a main loop that runs forever - but then there is no
    > point in waiting for all childs to terminate.
    >
    > Kind regards
    >
    > robert

    Hi Robert:

    Thanks for your replay.

    > You are doing an unhealthy mix: Process.waitall and wait block to wait
    > for an event but SIGCLD is supposed to be called when that event
    > happens.
    >
    > So either, use Process.waitall in main or change the trap code to do
    > something like manipulating a child process counter so you can detect
    > when the last is gone.
    >

    Sorry. I am not sure what do you mean. In my code, it trap the CLD
    signal to run wait method to clean the zombie sub-process, which is same
    as the sample code in book 'Programming ruby'.

    When a child process dies, a signal, SIGCHLD (or SIGCLD) is sent to its
    parent process. So when I run Process.wait, I always should get the
    response at once. And this code can work. The only problem is sometimes
    SystemStackError was raised.

    Can you please use sample code to show me where is the problem?

    Thanks.



    --
    Posted via http://www.ruby-forum.com/.
     
    Oliver Peng, Mar 3, 2008
    #3
  4. 2008/3/3, Oliver Peng <>:
    > Robert Klemme wrote:


    > > You are doing an unhealthy mix: Process.waitall and wait block to wait
    > > for an event but SIGCLD is supposed to be called when that event
    > > happens.
    > >
    > > So either, use Process.waitall in main or change the trap code to do
    > > something like manipulating a child process counter so you can detect
    > > when the last is gone.

    >
    > Sorry. I am not sure what do you mean. In my code, it trap the CLD
    > signal to run wait method to clean the zombie sub-process, which is same
    > as the sample code in book 'Programming ruby'.


    There is no trace of Process.waitall in the signal handler sample code.

    > When a child process dies, a signal, SIGCHLD (or SIGCLD) is sent to its
    > parent process. So when I run Process.wait, I always should get the
    > response at once. And this code can work. The only problem is sometimes
    > SystemStackError was raised.
    >
    > Can you please use sample code to show me where is the problem?


    The problem is in waitall. The sample code otherwise works ok. Try this

    trap "CLD" do
    puts "#{Process.wait} exited"
    # alternative
    p Process.wait2
    end

    5.times do |i|
    pid = fork do
    puts "proc #{i}"
    end and puts "#{pid} created"
    end

    puts "all children created"

    sleep 10

    Here's another approach

    require 'pp'

    5.times do |i|
    pid = fork do
    puts "proc #{i}"
    end and puts "#{pid} created"
    end

    puts "all children created"

    pp Process.waitall


    Kind regards

    robert

    --
    use.inject do |as, often| as.you_can - without end
     
    Robert Klemme, Mar 3, 2008
    #4
  5. Oliver Peng

    Oliver Peng Guest

    Robert Klemme wrote:
    > 2008/3/3, Oliver Peng <>:
    >> Robert Klemme wrote:

    >
    >> as the sample code in book 'Programming ruby'.

    > There is no trace of Process.waitall in the signal handler sample code.
    >
    >> When a child process dies, a signal, SIGCHLD (or SIGCLD) is sent to its
    >> parent process. So when I run Process.wait, I always should get the
    >> response at once. And this code can work. The only problem is sometimes
    >> SystemStackError was raised.
    >>
    >> Can you please use sample code to show me where is the problem?

    >
    > The problem is in waitall. The sample code otherwise works ok. Try
    > this
    >
    > trap "CLD" do
    > puts "#{Process.wait} exited"
    > # alternative
    > p Process.wait2
    > end
    >
    > 5.times do |i|
    > pid = fork do
    > puts "proc #{i}"
    > end and puts "#{pid} created"
    > end
    >
    > puts "all children created"
    >
    > sleep 10
    >
    > Here's another approach
    >
    > require 'pp'
    >
    > 5.times do |i|
    > pid = fork do
    > puts "proc #{i}"
    > end and puts "#{pid} created"
    > end
    >
    > puts "all children created"
    >
    > pp Process.waitall
    >
    >
    > Kind regards
    >
    > robert


    Ok. I see. You mean that waitall shouldn't be used in trap 'CLD' because
    it would wait until all process exit.

    But I use wait at first and get the SystemStackError exception. Then I
    try to use waitall later. So I still don't know why the SystemStackError
    exception is raised.

    I also try to write test code and please have a look:

    ----------------------------------------------------
    Server code:
    require 'socket'

    trap('CLD') do
    pid = Process.wait
    puts "pid #{pid} exited"
    end

    class TestServer

    def initialize
    @tcpServer = TCPServer.new('0.0.0.0', 7777)
    end

    def run
    while tcp = @tcpServer.accept
    fork do
    begin
    while str = tcp.gets()
    tcp.puts("hello")
    end
    ensure
    tcp.close_read
    tcp.close_write
    end
    end
    tcp.close
    end
    end
    end

    server = TestServer.new

    server.run

    ------------------------------------------------
    Client code:

    require 'socket'

    threads = []
    100.times do
    threads << Thread.new() do
    while true
    socket = TCPSocket.new('localhost', 7777)
    socket.puts("hello")
    sleep 1
    socket.gets
    socket.close
    sleep 10
    end
    end
    end

    threads.each {|thr| thr.join}

    From the server output, I can see that CLD signal has been traped and
    server puts the process exit. But from top I can see that zombie process
    are getting more and more. Is there some problem in the code logic?

    Thanks.
    --
    Posted via http://www.ruby-forum.com/.
     
    Oliver Peng, Mar 3, 2008
    #5
  6. On 03.03.2008 21:54, Oliver Peng wrote:
    > Robert Klemme wrote:
    >> 2008/3/3, Oliver Peng <>:
    >>> Robert Klemme wrote:
    >>> as the sample code in book 'Programming ruby'.

    >> There is no trace of Process.waitall in the signal handler sample code.
    >>
    >>> When a child process dies, a signal, SIGCHLD (or SIGCLD) is sent to its
    >>> parent process. So when I run Process.wait, I always should get the
    >>> response at once. And this code can work. The only problem is sometimes
    >>> SystemStackError was raised.
    >>>
    >>> Can you please use sample code to show me where is the problem?

    >> The problem is in waitall. The sample code otherwise works ok. Try
    >> this
    >>
    >> trap "CLD" do
    >> puts "#{Process.wait} exited"
    >> # alternative
    >> p Process.wait2
    >> end
    >>
    >> 5.times do |i|
    >> pid = fork do
    >> puts "proc #{i}"
    >> end and puts "#{pid} created"
    >> end
    >>
    >> puts "all children created"
    >>
    >> sleep 10
    >>
    >> Here's another approach
    >>
    >> require 'pp'
    >>
    >> 5.times do |i|
    >> pid = fork do
    >> puts "proc #{i}"
    >> end and puts "#{pid} created"
    >> end
    >>
    >> puts "all children created"
    >>
    >> pp Process.waitall
    >>
    >>
    >> Kind regards
    >>
    >> robert

    >
    > Ok. I see. You mean that waitall shouldn't be used in trap 'CLD' because
    > it would wait until all process exit.
    >
    > But I use wait at first and get the SystemStackError exception. Then I
    > try to use waitall later. So I still don't know why the SystemStackError
    > exception is raised.
    >
    > I also try to write test code and please have a look:
    >
    > ----------------------------------------------------
    > Server code:
    > require 'socket'
    >
    > trap('CLD') do
    > pid = Process.wait
    > puts "pid #{pid} exited"
    > end
    >
    > class TestServer
    >
    > def initialize
    > @tcpServer = TCPServer.new('0.0.0.0', 7777)
    > end
    >
    > def run
    > while tcp = @tcpServer.accept
    > fork do
    > begin
    > while str = tcp.gets()
    > tcp.puts("hello")
    > end
    > ensure
    > tcp.close_read
    > tcp.close_write
    > end
    > end
    > tcp.close
    > end
    > end
    > end
    >
    > server = TestServer.new
    >
    > server.run
    >
    > ------------------------------------------------
    > Client code:
    >
    > require 'socket'
    >
    > threads = []
    > 100.times do
    > threads << Thread.new() do
    > while true
    > socket = TCPSocket.new('localhost', 7777)
    > socket.puts("hello")
    > sleep 1
    > socket.gets
    > socket.close
    > sleep 10
    > end
    > end
    > end
    >
    > threads.each {|thr| thr.join}
    >
    > From the server output, I can see that CLD signal has been traped and
    > server puts the process exit. But from top I can see that zombie process
    > are getting more and more. Is there some problem in the code logic?


    I can't really see one. Can you post the exception with the stack trace?

    Kind regards

    robert
     
    Robert Klemme, Mar 5, 2008
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Jesper Olsen
    Replies:
    7
    Views:
    596
    Van Jacques
    Jan 16, 2004
  2. Sam Roberts
    Replies:
    1
    Views:
    231
    Yukihiro Matsumoto
    Feb 11, 2005
  3. Bezan Kapadia
    Replies:
    15
    Views:
    334
    Brian Candler
    Feb 16, 2009
  4. Mrmaster Mrmaster
    Replies:
    6
    Views:
    173
    Mrmaster Mrmaster
    Aug 10, 2009
  5. Joshua Muheim
    Replies:
    14
    Views:
    313
    David Masover
    Oct 1, 2009
Loading...

Share This Page