[cfe-commits] patch: libcxxabi cxa_*_virtual and cxa_guard_* methods

Howard Hinnant hhinnant at apple.com
Sun May 22 13:55:42 PDT 2011


On May 22, 2011, at 4:45 PM, Nick Lewycky wrote:

> I translated your code into using pthread_mutex_t and pthread_cond_t, and came up with the following.  I tried to keep your notation so as to make the two implementations more easily comparable:
> 
> #include <pthread.h>
> #include <stdint.h>
> #include <stdio.h>
> #include <stdlib.h>
> 
> namespace __cxxabiv1
> {
> 
> namespace __libcxxabi
> {
> 
> void abort(const char* s) {printf("%s\n", s); ::abort();}
> 
> }  // __libcxxabi
> 
> static pthread_mutex_t guard_mut = PTHREAD_MUTEX_INITIALIZER;
> static pthread_cond_t  guard_cv  = PTHREAD_COND_INITIALIZER;
> 
> extern "C"
> {
> 
> int __cxa_guard_acquire(int64_t* guard_object)
> {
>    uint8_t* initialized = (uint8_t*)guard_object;
>    uint8_t* lock = (uint8_t*)guard_object + 1;
>    int r = pthread_mutex_lock(&guard_mut);
>    if (r != 0)
>        __libcxxabi::abort("__cxa_guard_acquire failed to acquire mutex");
>    if (*initialized == 1)
>    {
>        r = pthread_mutex_unlock(&guard_mut);
>        if (r != 0)
>            __libcxxabi::abort("__cxa_guard_acquire failed to release mutex");
>        return 0;
>    }
>    while (*lock == 1)
>        pthread_cond_wait(&guard_cv, &guard_mut);
>    int result = *initialized;
>    if (result == 0)
>        *lock = 1;
>    r = pthread_mutex_unlock(&guard_mut);
>    if (r != 0)
>        __libcxxabi::abort("__cxa_guard_acquire failed to release mutex");
>    return result == 0;
> }
> 
> void __cxa_guard_release(int64_t* guard_object)
> {
>    uint8_t* initialized = (uint8_t*)guard_object;
>    uint8_t* lock = (uint8_t*)guard_object + 1;
>    int r = pthread_mutex_lock(&guard_mut);
>    if (r != 0)
>        __libcxxabi::abort("__cxa_guard_release failed to acquire mutex");
>    *initialized = 1;
>    *lock = 0;
>    r = pthread_mutex_unlock(&guard_mut);
>    if (r != 0)
>        __libcxxabi::abort("__cxa_guard_release failed to release mutex");
>    r = pthread_cond_broadcast(&guard_cv);
>    if (r != 0)
>        __libcxxabi::abort("__cxa_guard_release failed to broadcast condition variable");
> }
> 
> void __cxa_guard_abort(int64_t* guard_object)
> {
>    uint8_t* lock = (uint8_t*)guard_object + 1;
>    int r = pthread_mutex_lock(&guard_mut);
>    if (r != 0)
>        __libcxxabi::abort("__cxa_guard_abort failed to acquire mutex");
>    *lock = 0;
>    r = pthread_mutex_unlock(&guard_mut);
>    if (r != 0)
>        __libcxxabi::abort("__cxa_guard_abort failed to release mutex");
>    r = pthread_cond_broadcast(&guard_cv);
>    if (r != 0)
>        __libcxxabi::abort("__cxa_guard_abort failed to broadcast condition variable");
> }
> 
> }  // extern "C"
> 
> }  // __cxxabiv1
> 
> The structure of our implementations is nearly identical.
> 
> If I understand correctly, yours does detect recursive initializers. pthread_mutex_lock will return EDEADLK, and your code will abort.

Unfortunately no.  I'm not holding the pthread_mutex_t during initialization, only while setting/inspecting guard_object.  I get a hang caused by deadlock.

Fwiw, there's some harmless but worthless code in my __cxa_guard_acquire.  Here it is again with it removed:

int __cxa_guard_acquire(int64_t* guard_object)
{
    uint8_t* initialized = (uint8_t*)guard_object;
    uint8_t* lock = (uint8_t*)guard_object + 1;
    int r = pthread_mutex_lock(&guard_mut);
    if (r != 0)
        __libcxxabi::abort("__cxa_guard_acquire failed to acquire mutex");
    while (*lock == 1)
        pthread_cond_wait(&guard_cv, &guard_mut);
    int result = *initialized;
    if (result == 0)
        *lock = 1;
    r = pthread_mutex_unlock(&guard_mut);
    if (r != 0)
        __libcxxabi::abort("__cxa_guard_acquire failed to release mutex");
    return result == 0;
}

Howard





More information about the cfe-commits mailing list