tzset() locks in Linux after fork()

Discussion in 'C++' started by mike@fonolo.com, Aug 10, 2010.

  1. Guest

    I've got an issue with an application I've developed that uses a
    combination of threads (pthreads) and fork()'d processes.

    In short, my parent process has a handful of threads that run to
    perform various tasks; when a new request comes into the parent
    process, it forks off a new child to handle the request; one of the
    first things the child does is initiate a library that has a date
    class that calls tzset().

    My parent process also logs the requests from a thread, which writes
    the date to the log using localtime_r(), which also calls tzset().

    The problem, is that one of out every x child processes fork()'d
    simply hangs at a lock in tzset() when the library is initialized.

    I've reproduced this by creating a very simple test program, that
    simply calls tzset() over and over from a thread, while it forks, and
    then calls tzset() in the child process- I can get it to hang almost
    immediately.

    and this only seems to happen on my Linux machines (CentO/S 5.5)- my
    FreeBSD (8.0) runs my test program file, without any locks.

    So my question is: if I fork() while tzset() is holding a lock in the
    parent process, will the lock get copied to the child process locked?
    Is this a known result? is there a way around this?

    Test program, which is just a super simple version of what I see in my
    real app, and gdb output below, which is when I attached to a child
    process that had hung.

    Mike

    #include <stdlib.h>
    #include <stdio.h>
    #include <time.h>
    #include <unistd.h>
    #include <signal.h>
    #include <pthread.h>

    static void* setter(void*)
    {
    while(1)
    {
    tzset();
    }

    return NULL;
    }

    int main(void)
    {
    pthread_t thread;
    pthread_create(&thread, NULL, &setter, NULL);

    signal(SIGCHLD, SIG_IGN);

    while(1)
    {
    switch(fork())
    {
    case 0:
    {
    fprintf(stderr, "CHILD >> tzset()\n");
    tzset();
    exit(1);
    }
    break;
    case -1:
    {
    fprintf(stderr, ">> failed to fork()
    \n");
    }
    break;
    default:
    {
    ;
    }
    }

    usleep(1000);
    }

    return 0;
    }

    Reading symbols from /home/mike/thr/test...done.
    Attaching to program: /home/mike/thr/test, process 8397
    Reading symbols from /lib64/libpthread.so.0...(no debugging symbols
    found)...done.
    [Thread debugging using libthread_db enabled]
    Loaded symbols for /lib64/libpthread.so.0
    Reading symbols from /usr/lib64/libstdc++.so.6...(no debugging symbols
    found)...done.
    Loaded symbols for /usr/lib64/libstdc++.so.6
    Reading symbols from /lib64/libm.so.6...(no debugging symbols
    found)...done.
    Loaded symbols for /lib64/libm.so.6
    Reading symbols from /lib64/libgcc_s.so.1...(no debugging symbols
    found)...done.
    Loaded symbols for /lib64/libgcc_s.so.1
    Reading symbols from /lib64/libc.so.6...(no debugging symbols
    found)...done.
    Loaded symbols for /lib64/libc.so.6
    Reading symbols from /lib64/ld-linux-x86-64.so.2...(no debugging
    symbols found)...done.
    Loaded symbols for /lib64/ld-linux-x86-64.so.2
    0x0000003512cdfade in __lll_lock_wait_private () from /lib64/libc.so.6
    (gdb) bt
    #0 0x0000003512cdfade in __lll_lock_wait_private () from /lib64/
    libc.so.6
    #1 0x0000003512c8d20b in _L_lock_1920 () from /lib64/libc.so.6
    #2 0x0000003512c8d0f1 in tzset () from /lib64/libc.so.6
    #3 0x0000000000400811 in main () at test.cpp:32
    (gdb) info threads
    * 1 Thread 0x2ab3c2e9dbb0 (LWP 8397) 0x0000003512cdfade in
    __lll_lock_wait_private () from /lib64/libc.so.6
     
    , Aug 10, 2010
    #1
    1. Advertising

  2. Jorgen Grahn Guest

    On Mon, 2010-08-09, wrote:
    > I've got an issue with an application I've developed that uses a
    > combination of threads (pthreads) and fork()'d processes.

    [...]

    Others have replied with advice, but in general you're much better off
    posting to ... whatever Unix or Linux programming group has the best
    audience.

    This is comp.lang.c++, your program seems to be a traditional C
    program, and the question would be offtopic even in comp.lang.c.

    (Your question was interesting and well formulated though.)

    /Jorgen

    --
    // Jorgen Grahn <grahn@ Oo o. . .
    \X/ snipabacken.se> O o .
     
    Jorgen Grahn, Aug 10, 2010
    #2
    1. Advertising

  3. Mike Pultz Guest

    On Aug 10, 1:47 am, Paavo Helde <> wrote:
    > "" <> wrote in news:a9aaf2e4-d0b9-46b0-
    > :
    >
    > > I've got an issue with an application I've developed that uses a
    > > combination of threads (pthreads) and fork()'d processes.

    >
    > > In short, my parent process has a handful of threads that run to
    > > perform various tasks; when a new request comes into the parent
    > > process, it forks off a new child to handle the request; one of the
    > > first things the child does is initiate a library that has a date
    > > class that calls tzset().

    >
    > > My parent process also logs the requests from a thread, which writes
    > > the date to the log using localtime_r(), which also calls tzset().

    >
    > > The problem, is that one of out every x child processes fork()'d
    > > simply hangs at a lock in tzset() when the library is initialized.

    >
    > Sam has already answered your immediate question. Just a few more notes.
    >
    > In Linux, the threads are implemented as processes sharing the same
    > memory space. When you call fork() in a multithreaded program, you will
    > get a copy of the current thread and a copy of the whole memory space.
    > This means that the memory space has lots of inaccessible stuff inside
    > it, like dynamic allocations from other threads, stacks of the other
    > threads etc. Carrying this garbage along is just not clean even if the
    > program could be otherwise put to work. And yes, this inaccessible memory  
    > can contain things like acquired user-space locks.
    >
    > So yes, if you want to clone your multithreaded process, then it would be
    > wise to exec() yourself immediately after fork(), possibly with some
    > special command-line arguments showing that you are starting an internal
    > child, and passing over any needed information.


    Thanks everyone- unfortunately, that's what I thought-

    I would just use threads for everything, and no fork(), but the stupid
    library I'm using uses lots of global static variables, and even has
    some cases where it exit()'s from inside methods!!

    I considered using execv() as well, but I'm using a socketpair() for
    IPC, so it would make that pretty tough.

    I guess I was just hoping for some magical "un-lock-everything()"
    function I could call after I fork()'d ;)

    Jorgen- you are right- this is Linux specific, though I had a tough
    time finding a good (competent) Linux C group- figured I'd ask here.

    Cheers,

    Mike
     
    Mike Pultz, Aug 10, 2010
    #3
    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. Gilles Ganault

    [2.4.2/Linux] Getting Python to fork?

    Gilles Ganault, Feb 4, 2008, in forum: Python
    Replies:
    12
    Views:
    655
    Gilles Ganault
    Feb 13, 2008
  2. Eric Snow

    os.fork and pty.fork

    Eric Snow, Jan 8, 2009, in forum: Python
    Replies:
    0
    Views:
    575
    Eric Snow
    Jan 8, 2009
  3. Chris Withers
    Replies:
    3
    Views:
    811
    Nobody
    Jun 19, 2010
  4. Ray

    os.fork on linux defunct

    Ray, Jul 30, 2010, in forum: Python
    Replies:
    3
    Views:
    1,669
    Lawrence D'Oliveiro
    Jul 31, 2010
  5. Elmar
    Replies:
    14
    Views:
    1,236
    Elmar
    Jan 11, 2012
Loading...

Share This Page