{"action":"created","issue":{"url":"https://api.github.com/repos/manastech/crystal/issues/600","labels_url":"https://api.github.com/repos/manastech/crystal/issues/600/labels{/name}","comments_url":"https://api.github.com/repos/manastech/crystal/issues/600/comments","events_url":"https://api.github.com/repos/manastech/crystal/issues/600/events","html_url":"https://github.com/manastech/crystal/issues/600","id":72308613,"number":600,"title":"HTTP::Server#listen_fork","user":{"login":"will","id":1973,"avatar_url":"https://avatars.githubusercontent.com/u/1973?v=3","gravatar_id":"","url":"https://api.github.com/users/will","html_url":"https://github.com/will","followers_url":"https://api.github.com/users/will/followers","following_url":"https://api.github.com/users/will/following{/other_user}","gists_url":"https://api.github.com/users/will/gists{/gist_id}","starred_url":"https://api.github.com/users/will/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/will/subscriptions","organizations_url":"https://api.github.com/users/will/orgs","repos_url":"https://api.github.com/users/will/repos","events_url":"https://api.github.com/users/will/events{/privacy}","received_events_url":"https://api.github.com/users/will/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":10,"created_at":"2015-04-30T23:24:50Z","updated_at":"2015-08-13T01:36:42Z","closed_at":null,"body":"On Crystal 0.7, given \r\n\r\n```\r\ndef fib(n)\r\n  if n == 0\r\n    return 0\r\n  elsif n == 1\r\n    return 1\r\n  else\r\n    return fib(n-1) + fib(n-2)\r\n  end\r\nend\r\n\r\nserver = HTTP::Server.new 8080, do |request|\r\n  i = request.path[1..-1].to_i\r\n  HTTP::Response.ok \"text/plain\", fib(i).to_s\r\nend\r\n\r\nputs \"Listening on http://0.0.0.0:8080\"\r\nserver.listen_fork\r\n```\r\n\r\nwe get \r\n```\r\nListening on http://0.0.0.0:8080\r\n[warn] kevent: Bad file descriptor\r\n[PCL] Stale coroutine called: curr=0x10834a000  exitto=0x7f9e92801200  caller=0x7f9e92801200\r\n[warn] kevent: Bad file descriptor\r\n[PCL] Stale coroutine called: curr=0x10834a000  exitto=0x7f9e92801200  caller=0x7f9e92801200\r\n[warn] kevent: Bad file descriptor\r\n[PCL] Stale coroutine called: curr=0x10834a000  exitto=0x7f9e92801200  caller=0x7f9e92801200\r\n[warn] kevent: Bad file descriptor\r\n[PCL] Stale coroutine called: curr=0x10834a000  exitto=0x7f9e92801200  caller=0x7f9e92801200\r\n[warn] kevent: Bad file descriptor\r\n[PCL] Stale coroutine called: curr=0x10834a000  exitto=0x7f9e92801200  caller=0x7f9e92801200\r\n[warn] kevent: Bad file descriptor\r\n[PCL] Stale coroutine called: curr=0x10834a000  exitto=0x7f9e92801200  caller=0x7f9e92801200\r\nReady\r\n[warn] kevent: Bad file descriptor\r\n[PCL] Stale coroutine called: curr=0x10834a000  exitto=0x7f9e92801200  caller=0x7f9e92801200\r\n[warn] kevent: Bad file descriptor\r\n[PCL] Stale coroutine called: curr=0x10834a000  exitto=0x7f9e92801200  caller=0x7f9e92801200\r\n```\r\nand it does not serve requests.\r\n\r\nEven setting the number of workers to 1 `server.listen_fork(1)` is no help\r\n```\r\nListening on http://0.0.0.0:8080\r\nReady\r\n[warn] kevent: Bad file descriptor\r\n[PCL] Stale coroutine called: curr=0x10f0f3000  exitto=0x7ff333801200  caller=0x7ff333801200\r\n```\r\n\r\nInstead of fork, we also tried to use threads in a similar way to the listen_fork:\r\n```\r\nclass HTTP::Server\r\n  def listen_thread(workers = 8)\r\n    server = TCPServer.new(@port)\r\n    workers.times do\r\n      t = Thread.new do\r\n        puts \"starting worker\"\r\n          loop {\r\n            puts \"before handle_client\"\r\n            spawn handle_client(server.accept)\r\n            puts \"after handle_client\"\r\n          }\r\n      end\r\n    end\r\n\r\n    puts \"Ready\"\r\n    gets\r\n  end\r\nend \r\n```\r\nwhich gives\r\n```\r\nListening on http://0.0.0.0:8080\r\nstarting worker\r\nbefore handle_client\r\nstarting worker\r\nbefore handle_client\r\nstarting worker\r\nbefore handle_client\r\nstarting worker\r\nbefore handle_client\r\nstarting worker\r\nbefore handle_client\r\nstarting worker\r\nbefore handle_client\r\nstarting worker\r\nbefore handle_client\r\nstarting worker\r\nbefore handle_client\r\nReady\r\n```\r\n\r\nBy adding a call to t.join we can see a stacktrace \r\n```\r\nListening on http://0.0.0.0:8080\r\nstarting worker\r\nbefore handle_client\r\nCould not get the current fiber (Exception)\r\n*Exception#initialize<Exception, String, Nil>:Array(String) +21 [4352266693]\r\n*Exception::new<String>:Exception +111 [4352266639]\r\n*raise<String>:NoReturn +6 [4352237734]\r\n*Fiber::current:Fiber +59 [4352269371]\r\n*TCPServer#accept<TCPServer>:TCPSocket +145 [4352290065]\r\n~fun_literal_12 +125 [4352240557]\r\n~fun_literal_11 +49 [4352240417]\r\n*Thread(Nil, NoReturn)@Thread(T, R)#start<Thread(Nil, NoReturn)>:Exception+ +100 [4352292084]\r\n~fun_literal_9 +6 [4352240294]\r\nGC_inner_start_routine +117 [4352690741]\r\nGC_call_with_stack_base +59 [4352671835]\r\nGC_start_routine +31 [4352697887]\r\n_pthread_body +138 [140735574333593]\r\n_pthread_struct_init +0 [140735574333226]\r\nProgram terminated abnormally with error code: 256\r\n```\r\n\r\nWe also poked around by adding a fiber manually in the thread, but that did not help.\r\n\r\ncc @fdr who looked into this with me earlier today"},"comment":{"url":"https://api.github.com/repos/manastech/crystal/issues/comments/130499867","html_url":"https://github.com/manastech/crystal/issues/600#issuecomment-130499867","issue_url":"https://api.github.com/repos/manastech/crystal/issues/600","id":130499867,"user":{"login":"strcmp","id":8934693,"avatar_url":"https://avatars.githubusercontent.com/u/8934693?v=3","gravatar_id":"","url":"https://api.github.com/users/strcmp","html_url":"https://github.com/strcmp","followers_url":"https://api.github.com/users/strcmp/followers","following_url":"https://api.github.com/users/strcmp/following{/other_user}","gists_url":"https://api.github.com/users/strcmp/gists{/gist_id}","starred_url":"https://api.github.com/users/strcmp/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/strcmp/subscriptions","organizations_url":"https://api.github.com/users/strcmp/orgs","repos_url":"https://api.github.com/users/strcmp/repos","events_url":"https://api.github.com/users/strcmp/events{/privacy}","received_events_url":"https://api.github.com/users/strcmp/received_events","type":"User","site_admin":false},"created_at":"2015-08-13T01:36:42Z","updated_at":"2015-08-13T01:36:42Z","body":"in Java/Go/Objective-C runtime I don't think their implementations allow for fork, definitely true for JVM/ObjC runtime. why not remove when it's a problem? :)"}}