[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Bug#628493: perl: FTBFS on kfreebsd-i386: t/op/threads failed



perl -Mthreads -e 'threads->create(sub {})->detach; fork'

which crashes non-deterministically about half the time for me.

Thanks for reduced testcase.

The problem might be in usage of "pthread_atfork(lock, unlock, unlock)".
It is perfectly valid to unlock() in parent.
But in child it might be problematic.
There might be congestion of the lock, i.e. some other thread is waiting for it. After fork(), there is no such thread in child, which could be waken up.

The POSIX is not clear about it:
http://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html
http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_atfork.html

It would be better in child to just reinit the mutex.
The attached code crashes non-deterministically for me with unlock(),
but works at 100% with reinit().

It should suffice to add into util.c

*************
void
Perl_atfork_reinit(void)
{
    dVAR;
#if defined(USE_ITHREADS)
    /* locks must be released in same order as in atfork_lock() */
#  ifdef MYMALLOC
    MUTEX_INIT(&PL_malloc_mutex);
#  endif
    OP_REFCNT_INIT;
#endif
}
************

and

--- miniperlmain.c
+++ miniperlmain.c
@@ -101,7 +101,7 @@
      * --GSAR 2001-07-20 */
     PTHREAD_ATFORK(Perl_atfork_lock,
                    Perl_atfork_unlock,
-                   Perl_atfork_unlock);
+                   Perl_atfork_reinit);
 #endif

     if (!PL_do_undump) {


Untested, though.

Petr
#include <pthread.h>
pthread_t pt;
pthread_mutex_t m;

void bw(int x)
{
 while (x--);
}

void lo()
{
int e = pthread_mutex_lock(&m);
  printf("lo %d\n", e);

}

void unlo()
{
int e = pthread_mutex_unlock(&m);
//if (e)
  printf("unlo %d\n", e);
}


void reinit()
{
  pthread_mutex_init(&m, NULL);
}

void doit()
{
  
  bw(40000);
  lo();
  bw(40000);
  unlo();

  bw(40000);
  lo();
  bw(40000);
  unlo();

  bw(40000);
  lo();
  bw(40000);
  unlo();

  bw(40000);
  lo();
  bw(40000);
  unlo();
}


int main()
{
  int i;
  pthread_mutex_init(&m, NULL);

#if 1
  pthread_atfork(lo, unlo, reinit);
#else  
  pthread_atfork(lo, unlo, unlo);
#endif
  
  pthread_create(&pt, NULL, doit, NULL);
  pthread_detach(pt);
  if (0 == fork())
  {
     doit();
     lo();
  }   
  else
  {
     doit();
     lo();
  }   
  return 0;  
}

Reply to: