8218975: Bug in macOSX kernel's pthread support
Use freelist of pthread_mutex/condvar pairs on macOSX. Co-authored-by: Patricio Chilano Mateo <patricio.chilano.mateo@oracle.com> Reviewed-by: tschatzl, dholmes, dcubed
This commit is contained in:
parent
646779038f
commit
2946ff5ca5
@ -1671,6 +1671,8 @@ static void pthread_init_common(void) {
|
||||
if ((status = pthread_mutexattr_settype(_mutexAttr, PTHREAD_MUTEX_NORMAL)) != 0) {
|
||||
fatal("pthread_mutexattr_settype: %s", os::strerror(status));
|
||||
}
|
||||
// Solaris has it's own PlatformMonitor, distinct from the one for POSIX.
|
||||
NOT_SOLARIS(os::PlatformMonitor::init();)
|
||||
}
|
||||
|
||||
#ifndef SOLARIS
|
||||
@ -2250,20 +2252,64 @@ void Parker::unpark() {
|
||||
|
||||
// Platform Monitor implementation
|
||||
|
||||
os::PlatformMonitor::PlatformMonitor() {
|
||||
os::PlatformMonitor::Impl::Impl() : _next(NULL) {
|
||||
int status = pthread_cond_init(&_cond, _condAttr);
|
||||
assert_status(status == 0, status, "cond_init");
|
||||
status = pthread_mutex_init(&_mutex, _mutexAttr);
|
||||
assert_status(status == 0, status, "mutex_init");
|
||||
}
|
||||
|
||||
os::PlatformMonitor::~PlatformMonitor() {
|
||||
os::PlatformMonitor::Impl::~Impl() {
|
||||
int status = pthread_cond_destroy(&_cond);
|
||||
assert_status(status == 0, status, "cond_destroy");
|
||||
status = pthread_mutex_destroy(&_mutex);
|
||||
assert_status(status == 0, status, "mutex_destroy");
|
||||
}
|
||||
|
||||
#if PLATFORM_MONITOR_IMPL_INDIRECT
|
||||
|
||||
pthread_mutex_t os::PlatformMonitor::_freelist_lock;
|
||||
os::PlatformMonitor::Impl* os::PlatformMonitor::_freelist = NULL;
|
||||
|
||||
void os::PlatformMonitor::init() {
|
||||
int status = pthread_mutex_init(&_freelist_lock, _mutexAttr);
|
||||
assert_status(status == 0, status, "freelist lock init");
|
||||
}
|
||||
|
||||
struct os::PlatformMonitor::WithFreeListLocked : public StackObj {
|
||||
WithFreeListLocked() {
|
||||
int status = pthread_mutex_lock(&_freelist_lock);
|
||||
assert_status(status == 0, status, "freelist lock");
|
||||
}
|
||||
|
||||
~WithFreeListLocked() {
|
||||
int status = pthread_mutex_unlock(&_freelist_lock);
|
||||
assert_status(status == 0, status, "freelist unlock");
|
||||
}
|
||||
};
|
||||
|
||||
os::PlatformMonitor::PlatformMonitor() {
|
||||
{
|
||||
WithFreeListLocked wfl;
|
||||
_impl = _freelist;
|
||||
if (_impl != NULL) {
|
||||
_freelist = _impl->_next;
|
||||
_impl->_next = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
_impl = new Impl();
|
||||
}
|
||||
|
||||
os::PlatformMonitor::~PlatformMonitor() {
|
||||
WithFreeListLocked wfl;
|
||||
assert(_impl->_next == NULL, "invariant");
|
||||
_impl->_next = _freelist;
|
||||
_freelist = _impl;
|
||||
}
|
||||
|
||||
#endif // PLATFORM_MONITOR_IMPL_INDIRECT
|
||||
|
||||
// Must already be locked
|
||||
int os::PlatformMonitor::wait(jlong millis) {
|
||||
assert(millis >= 0, "negative timeout");
|
||||
@ -2278,7 +2324,7 @@ int os::PlatformMonitor::wait(jlong millis) {
|
||||
to_abstime(&abst, millis * (NANOUNITS / MILLIUNITS), false, false);
|
||||
|
||||
int ret = OS_TIMEOUT;
|
||||
int status = pthread_cond_timedwait(&_cond, &_mutex, &abst);
|
||||
int status = pthread_cond_timedwait(cond(), mutex(), &abst);
|
||||
assert_status(status == 0 || status == ETIMEDOUT,
|
||||
status, "cond_timedwait");
|
||||
if (status == 0) {
|
||||
@ -2286,7 +2332,7 @@ int os::PlatformMonitor::wait(jlong millis) {
|
||||
}
|
||||
return ret;
|
||||
} else {
|
||||
int status = pthread_cond_wait(&_cond, &_mutex);
|
||||
int status = pthread_cond_wait(cond(), mutex());
|
||||
assert_status(status == 0, status, "cond_wait");
|
||||
return OS_OK;
|
||||
}
|
||||
|
@ -232,15 +232,60 @@ class PlatformParker : public CHeapObj<mtSynchronizer> {
|
||||
PlatformParker();
|
||||
};
|
||||
|
||||
// Workaround for a bug in macOSX kernel's pthread support (fixed in Mojave?).
|
||||
// Avoid ever allocating a pthread_mutex_t at the same address as one of our
|
||||
// former pthread_cond_t, by using a freelist of mutex/condvar pairs.
|
||||
// Conditional to avoid extra indirection and padding loss on other platforms.
|
||||
#ifdef __APPLE__
|
||||
#define PLATFORM_MONITOR_IMPL_INDIRECT 1
|
||||
#else
|
||||
#define PLATFORM_MONITOR_IMPL_INDIRECT 0
|
||||
#endif
|
||||
|
||||
// Platform specific implementation that underpins VM Monitor/Mutex class
|
||||
class PlatformMonitor : public CHeapObj<mtSynchronizer> {
|
||||
private:
|
||||
pthread_mutex_t _mutex; // Native mutex for locking
|
||||
pthread_cond_t _cond; // Native condition variable for blocking
|
||||
class Impl : public CHeapObj<mtSynchronizer> {
|
||||
public:
|
||||
pthread_mutex_t _mutex;
|
||||
pthread_cond_t _cond;
|
||||
Impl* _next;
|
||||
|
||||
Impl();
|
||||
~Impl();
|
||||
};
|
||||
|
||||
#if PLATFORM_MONITOR_IMPL_INDIRECT
|
||||
|
||||
Impl* _impl;
|
||||
|
||||
pthread_mutex_t* mutex() { return &(_impl->_mutex); }
|
||||
pthread_cond_t* cond() { return &(_impl->_cond); }
|
||||
|
||||
class WithFreeListLocked;
|
||||
static pthread_mutex_t _freelist_lock;
|
||||
static Impl* _freelist;
|
||||
|
||||
public:
|
||||
PlatformMonitor();
|
||||
PlatformMonitor(); // Use freelist allocation of impl.
|
||||
~PlatformMonitor();
|
||||
|
||||
static void init(); // Initialize the freelist.
|
||||
|
||||
#else
|
||||
|
||||
Impl _impl;
|
||||
|
||||
pthread_mutex_t* mutex() { return &(_impl._mutex); }
|
||||
pthread_cond_t* cond() { return &(_impl._cond); }
|
||||
|
||||
public:
|
||||
static void init() {} // Nothing needed for the non-indirect case.
|
||||
|
||||
// Default constructor and destructor.
|
||||
|
||||
#endif // PLATFORM_MONITOR_IMPL_INDIRECT
|
||||
|
||||
public:
|
||||
void lock();
|
||||
void unlock();
|
||||
bool try_lock();
|
||||
|
@ -50,28 +50,28 @@ inline int os::Posix::clock_getres(clockid_t clock_id, struct timespec *tp) {
|
||||
// Platform Monitor implementation
|
||||
|
||||
inline void os::PlatformMonitor::lock() {
|
||||
int status = pthread_mutex_lock(&_mutex);
|
||||
int status = pthread_mutex_lock(mutex());
|
||||
assert_status(status == 0, status, "mutex_lock");
|
||||
}
|
||||
|
||||
inline void os::PlatformMonitor::unlock() {
|
||||
int status = pthread_mutex_unlock(&_mutex);
|
||||
int status = pthread_mutex_unlock(mutex());
|
||||
assert_status(status == 0, status, "mutex_unlock");
|
||||
}
|
||||
|
||||
inline bool os::PlatformMonitor::try_lock() {
|
||||
int status = pthread_mutex_trylock(&_mutex);
|
||||
int status = pthread_mutex_trylock(mutex());
|
||||
assert_status(status == 0 || status == EBUSY, status, "mutex_trylock");
|
||||
return status == 0;
|
||||
}
|
||||
|
||||
inline void os::PlatformMonitor::notify() {
|
||||
int status = pthread_cond_signal(&_cond);
|
||||
int status = pthread_cond_signal(cond());
|
||||
assert_status(status == 0, status, "cond_signal");
|
||||
}
|
||||
|
||||
inline void os::PlatformMonitor::notify_all() {
|
||||
int status = pthread_cond_broadcast(&_cond);
|
||||
int status = pthread_cond_broadcast(cond());
|
||||
assert_status(status == 0, status, "cond_broadcast");
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user