[llvm-commits] [llvm] r116426 - /llvm/trunk/include/llvm/PassSupport.h

Howard Hinnant hhinnant at apple.com
Thu Oct 14 11:20:43 PDT 2010


On Oct 14, 2010, at 1:52 PM, Howard Hinnant wrote:

> On Oct 14, 2010, at 1:34 PM, John McCall wrote:
> 
>> On Oct 14, 2010, at 10:30 AM, Owen Anderson wrote:
>>> On Oct 14, 2010, at 1:25 AM, John McCall wrote:
>>>> While I agree with Sebastian, I wonder if we care.  Is there any good
>>>> reason to not just require the user to ensure that pass initialization
>>>> is thread-safe?  "Don't try to concurrently initialize the standard pass
>>>> registry" does not seem like an unreasonable constraint.
>>> 
>>> The problem is that we're trying to do lazy implicit initialization, hidden in the pass constructors.  It's not unreasonable for users to be instantiating passes on different threads.
>> 
>> Ah, okay.  In that case, we definitely can't portably rely on thread-safe statics.
> 
> I'm butting into a conversation without knowing sufficient background.  So I'm just giving information, and not giving an opinion, on the off chance the information is both unknown and helpful:
> 
> C++0X has thread safe static initialization and my best estimate is that the 'X' is B.  I.e. I expect C++11 to be voted out in 23 weeks and 2 days from today.
> 
> Disclaimer:  predictions of the future are never risk free, and this doesn't mean thread safe static initialization is now portable.  It just means things are likely to trend that way rather quickly.
> 
> Could I interest anyone in pthread_once, or std::call_once? :-)

Oh, I should've added:  Here's the implementation that persuaded the committee:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2382.html#Appendix

It is meant to be portable double-checked locking, but depends on a fast implementation of thread_local data to be effective.

It has another nice characteristic that the Itanium ABI could possibly support:  There is only one global mutex to protect all static initialization.  But that mutex is left unlocked during the actual initialization.  In C++:

// flag == 0 : not initialized
// flag == 1 : initialization in progress
// flag == ~0: initialized
if (__flag != ~0)
{
    pthread_mutex_lock(&__global_mut);
    while (__flag == 1)
        pthread_cond_wait(&__global_cv, &__global_mut);
    if (__flag == 0)
    {
        try
        {
            __flag = 1;
            pthread_mutex_unlock(&__global_mut);
            // Initialize here ...    // __global_mut unlocked here!!!
            pthread_mutex_lock(&__global_mut);
            __flag = ~0ul;
            pthread_mutex_unlock(&__global_mut);
            pthread_cond_broadcast(&__global_cv);
        }
        catch (...)
        {
            pthread_mutex_lock(&__global_mut);
            __flag = 0ul;
            pthread_mutex_unlock(&__global_mut);
            pthread_cond_broadcast(&__global_cv);
            throw;
        }
    }
    else
        pthread_mutex_unlock(&__global_mut);
}

Multiple statics can initialize concurrently since __global_mut is unlocked during the initialization.  Initializations can be arbitrarily long without tying up this global mutex. This is double checked locking, so that first use of __flag probably needs to be an atomic load with acquire memory ordering.  And the bulk of the above code can/should be outlined to a single function.

-Howard





More information about the llvm-commits mailing list