[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