Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

Re: Mysterious bad file descriptor after fork

by sgt (Deacon)
on Jul 11, 2007 at 08:24 UTC ( [id://625968]=note: print w/replies, xml ) Need Help??


in reply to Mysterious bad file descriptor after fork

Well you did not tell us the OS. First I would look at the conditions to get EBADF error conditions with select. Probably you got some error condition that invalidate read or write on the "latest selected desc".

Then you seem to be using a mixed scheme with an accept-fork loop and a select loop. usually I tend to use one or the other i.e

  • accept+fork server and deal with the request in each child, need to take care of communication back to the father (pre-forked schemes are useful too especially in conjunction with DBI).
  • polling server (select loop) you add a correct "accept"ed desc to your set of valid desc and let the OS poll for you. if you don't trust your clients it's probably better to go non-blocking which means you need to handle partial reads. To do that correctly you need something like Lincoln Stein's IO::SessionData (part of SOAP::Lite), IO::Multiplex is useful too. If the OS is linux some even loop based on epoll could be a nice way to handle things. There is a module based on libevent.
  • there are threading models too, but I don't use that in production (yet)
  • So I don't understand your grand scheme of things...can you explain a bit more. In any case the "sharing" of data between father and child you seem to imply seems suspicious to me: it can only be a "one-go" thing anyway, why not do the necessary init in the child anyway?

    One basic rule is also that given a desc opened (with the close-on-exec flag not set) in the father, only the child or the father must use it at any time, meaning better to close it in the father if meant for the child. Are you sure your code comply with that? Can you post a representative snippet we could try? If you use a file instead of a db, does it work?

    You could also have a look to Net::Server.

    cheers --stephan
    • Comment on Re: Mysterious bad file descriptor after fork

    Replies are listed 'Best First'.
    Re^2: Mysterious bad file descriptor after fork
    by gnork (Scribe) on Jul 11, 2007 at 12:15 UTC
      Yippie, after one week, and loud thinking while writing on perl monks I finally found the problem.

      In the event_loop a select() iterates over two arrays/IO::Select objects ($rd_handles, $wt_handles).

      After server start $rd_handles contains only the "$main_socket" and the parent selects only for that socket. After forking, the sockets are closed (child socket in parent, main_socket in child) BUT the $main_socket remained in $rd_handles of the child process. This caused the EBADF, since there was a closed fdesc in that array. It was always there, I dont understand why one variant worked when the other didn't. Strangely enough, the first step to correct that, $rd_handles->remove($main_socket) didn't work. The $main_socket was still in the array along with valid sockets and I still got EBADF from select().

      So I decided to undef $rd_handles/$wt_handles, recreate the two objects and add the child socket there.
      That fixed it. Thanks for your input, sometimes I have to think loud and none of my coworkers is suitable for that.

      As for the architecture... it is a combination of accept once / select over a set of sockets added to rd_/wt_handles after accept and callback procedures registered for each of these sockets. Now when a message arrives over a socket, the associated procedure is called and the result is send back to the client.

      It took me a while to understand the inner workings of Msg.pm (props to Mr. Sriram Srinivasan). The module wasn't designed with a forking solution in mind and in it's original form is not intended for production use (as stated by the author). For a long time I avoided messing with it, but now I had to. Learned a lot while doing so.

      Best regards
      gnork

      cat /dev/world | perl -e "(/(^.*? \?) 42\!/) && (print $1))"
      errors->(c)

    Log In?
    Username:
    Password:

    What's my password?
    Create A New User
    Domain Nodelet?
    Node Status?
    node history
    Node Type: note [id://625968]
    help
    Chatterbox?
    and the web crawler heard nothing...

    How do I use this?Last hourOther CB clients
    Other Users?
    Others taking refuge in the Monastery: (6)
    As of 2024-04-24 13:18 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?

      No recent polls found