Showing with 67 additions and 0 deletions.
  1. +67 −0 src/core/thread.d
67 changes: 67 additions & 0 deletions src/core/thread.d
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,7 @@ else version( Posix )
status = sigdelset( &sigres, resumeSignalNumber );
assert( status == 0 );

version (FreeBSD) Thread.sm_suspendagain = false;
status = sem_post( &suspendCount );
assert( status == 0 );

Expand All @@ -413,6 +414,17 @@ else version( Posix )
}
}

// avoid deadlocks on FreeBSD, see Issue 13416
version (FreeBSD)
{
if (THR_IN_CRITICAL(pthread_self()))
{
Thread.sm_suspendagain = true;
if (sem_post(&suspendCount)) assert(0);
return;
}
}

callWithStackShell(&op);
}

Expand All @@ -426,6 +438,27 @@ else version( Posix )
{

}

// HACK libthr internal (thr_private.h) macro, used to
// avoid deadlocks in signal handler, see Issue 13416
version (FreeBSD) bool THR_IN_CRITICAL(pthread_t p) nothrow @nogc
{
import core.sys.posix.sys.types : c_long, lwpid_t;
// If the begin of pthread would be changed in libthr (unlikely)
// we'll run into undefined behavior, compare with thr_private.h.
static struct pthread
{
c_long tid;
static struct umutex { lwpid_t owner; uint flags; uint[2] ceilings; uint[4] spare; }
umutex lock;
uint cycle;
int locklevel;
int critical_count;
// ...
}
auto priv = cast(pthread*)p;
return priv.locklevel > 0 || priv.critical_count > 0;
}
}
}
else
Expand Down Expand Up @@ -1334,6 +1367,12 @@ private:
//
__gshared Thread sm_main;

version (FreeBSD)
{
// set when suspend failed and should be retried, see Issue 13416
static shared bool sm_suspendagain;
}


//
// Standard thread data
Expand Down Expand Up @@ -2450,6 +2489,7 @@ private void suspend( Thread t ) nothrow
{
if( t.m_addr != pthread_self() )
{
Lagain:
if( pthread_kill( t.m_addr, suspendSignalNumber ) != 0 )
{
if( !t.isRunning )
Expand All @@ -2465,6 +2505,11 @@ private void suspend( Thread t ) nothrow
onThreadError( "Unable to wait for semaphore" );
errno = 0;
}
version (FreeBSD)
{
// avoid deadlocks, see Issue 13416
if (Thread.sm_suspendagain) goto Lagain;
}
}
else if( !t.m_lock )
{
Expand Down Expand Up @@ -5138,3 +5183,25 @@ version( D_InlineAsm_X86_64 )
fib.call();
}
}

// regression test for Issue 13416
version (FreeBSD) unittest
{
static void loop()
{
pthread_attr_t attr;
pthread_attr_init(&attr);
auto thr = pthread_self();
foreach (i; 0 .. 50)
pthread_attr_get_np(thr, &attr);
pthread_attr_destroy(&attr);
}

auto thr = new Thread(&loop).start();
foreach (i; 0 .. 50)
{
thread_suspendAll();
thread_resumeAll();
}
thr.join();
}