Bug 19481 – Aborting from local/libphobos/libdruntime/core/sync/mutex.d(95) Error: pthread_mutex_init failed.
Status
RESOLVED
Resolution
FIXED
Severity
major
Priority
P1
Component
druntime
Product
D
Version
D2
Platform
Other
OS
Solaris
Creation time
2018-12-12T19:00:24Z
Last change time
2019-10-14T03:07:38Z
Keywords
pull
Assigned to
No Owner
Creator
Iain Buclaw
Comments
Comment #0 by ibuclaw — 2018-12-12T19:00:24Z
Thread._locks is not suitably aligned.
---
__gshared align(Mutex.alignof) void[__traits(classInstanceSize, Mutex)][2] _locks;
static void initLocks() @nogc
{
foreach (ref lock; _locks)
{
lock[] = typeid(Mutex).initializer[];
(cast(Mutex)lock.ptr).__ctor();
}
}
---
_locks should be aligned to pthread_mutex_t, not pointer size.
Comment #1 by kinke — 2018-12-12T20:00:22Z
`Mutex.m_hndl.alignof` (as it's a CRITICAL_SECTION for Windows) doesn't work, as it's private.
There's no way to get the class instance alignment, is there? Plus anything > 16 bytes isn't guaranteed by the GC either AFAIK. So class alignments seem a bit problematic in general.
Comment #2 by ibuclaw — 2018-12-12T20:28:24Z
(In reply to kinke from comment #1)
> `Mutex.m_hndl.alignof` (as it's a CRITICAL_SECTION for Windows) doesn't
> work, as it's private.
>
I was thinking of just doing as a quick hack.
---
version (Windows)
{
import core.sys.windows.winbase : CRITICAL_SECTION;
enum Mutex_alignof = CRITICAL_SECTION.alignof;
}
else version (Posix)
{
import core.sys.posix.sys.types : pthread_mutex_t;
enum Mutex_alignof = pthread_mutex_t.alignof;
}
---
Alternatively...
class Mutex
{
enum alignsize = Mutex.m_hndl.alignof;
// ...
}
> There's no way to get the class instance alignment, is there? Plus anything
> > 16 bytes isn't guaranteed by the GC either AFAIK. So class alignments seem
> a bit problematic in general.
No, there isn't a way to do that. I'm currently waiting to hear back if explicitly setting the alignment to 8 fixes the failure on SPARC/Solaris.
Comment #3 by ibuclaw — 2018-12-13T21:29:36Z
According to response, the alignment of _locks[0] is fine, _locks[1] is the problem.
>>>
Unfortunately, this doesn't work: the first time through, _locks[0] was
already 8-byte aligned and everything worked fine. This remained when
using align(8) instead. However, Mutex is 44 bytes on 32-bit
Solaris/x86, so again _locks[1] lands on a non-8 byte boundary and
pthread_mutex_init fails.
I tried rouding up the size of the _locks array members to a multiple of
8, but that let the constructor already fail the first time through
where _d_arraycopy checks that the right amount of data is copied:
_d_arraycopy -> rt.util.array.enforceRawArraysConformable ->
rt.util.array._enforceSameLength
<<<
Comment #4 by kinke — 2018-12-13T22:30:01Z
Argh, it's an array, and class instances aren't padded... - the error stems from the manual initialization in `initLocks()`, right? That should be easily adaptable; the ctor only gets the `this` pointer and shouldn't have any idea about the actual size.
Comment #5 by ibuclaw — 2018-12-13T23:03:35Z
(In reply to kinke from comment #4)
> Argh, it's an array, and class instances aren't padded... - the error stems
> from the manual initialization in `initLocks()`, right? That should be
> easily adaptable; the ctor only gets the `this` pointer and shouldn't have
> any idea about the actual size.
Correct.
This line:
__gshared align(Mutex.alignof) void[__traits(classInstanceSize, Mutex)][2] _locks;
The size should be rounded up to a suitable align boundary, then this line:
lock[] = typeid(Mutex).initializer[];
The slice assignment is adjusted to only initialize up to __traits(classInstanceSize, Mutex).
So we end up with something that looks like:
---
version (Windows)
{
import core.sys.windows.winbase : CRITICAL_SECTION;
enum lockAlign = CRITICAL_SECTION.alignof;
}
else version (Posix)
{
import core.sys.posix.sys.types : pthread_mutex_t;
enum lockAlign = pthread_mutex_t.alignof;
}
enum mutexInstanceSize = __traits(classInstanceSize, Mutex)
enum lockAlignedSize = (mutexInstanceSize + lockAlign - 1) & ~(lockAlign - 1);
__gshared align(lockAlign) void[lockAlignedSize][2] _locks;
static void initLocks() @nogc
{
foreach (ref lock; _locks)
{
lock[0 .. mutexInstanceSize] = typeid(Mutex).initializer[];
(cast(Mutex)lock.ptr).__ctor();
}
}
---
I don't think `align(lockAlign)` is really necessary based on feedback, but it covers us "just incase".
Comment #6 by kinke — 2018-12-13T23:47:04Z
Yep, looks fine, and definitely keep the `align(mutexAlign)`. :) - You could get away with a single `alignedMutexInstanceSize` enum (and no `mutexInstanceSize`) by using `const init = typeid(Mutex).initializer; lock[0 .. init.length] = init[];`.