/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.max.vm.runtime;
import com.sun.max.annotate.*;
import com.sun.max.memory.*;
import com.sun.max.unsafe.*;
/**
* Direct access to OS (native) monitors for low-level use.
*/
public class OSMonitor {
static {
new CriticalNativeMethod(OSMonitor.class, "nativeMutexSize");
new CriticalNativeMethod(OSMonitor.class, "nativeMutexInitialize");
new CriticalNativeMethod(OSMonitor.class, "nativeConditionSize");
new CriticalNativeMethod(OSMonitor.class, "nativeConditionInitialize");
new CriticalNativeMethod(OSMonitor.class, "nativeMutexUnlock");
new CriticalNativeMethod(OSMonitor.class, "nativeMutexLock");
new CriticalNativeMethod(OSMonitor.class, "nativeMutexTryLock");
new CriticalNativeMethod(OSMonitor.class, "nativeConditionNotify");
new CriticalNativeMethod(OSMonitor.class, "nativeConditionWait");
new CriticalNativeMethod(OSMonitor.class, "nativeTakeLockAndNotify");
new CriticalNativeMethod(OSMonitor.class, "nativeTakeLockAndWait");
}
static int mutexSize;
static int conditionSize;
static int getMutexSize() {
if (mutexSize == 0) {
mutexSize = nativeMutexSize();
}
return mutexSize;
}
static int getConditionSize() {
if (conditionSize == 0) {
conditionSize = nativeConditionSize();
}
return conditionSize;
}
public static Word newMutex() {
return newMutex(true);
}
public static Word newMutex(boolean mustAllocate) {
Size size = Size.fromInt(getMutexSize());
Word mutex;
if (mustAllocate) {
mutex = Memory.mustAllocate(size);
} else {
mutex = Memory.allocate(size);
}
if (!mutex.isZero()) {
nativeMutexInitialize(mutex);
}
return mutex;
}
public static Word newCondition() {
return newCondition(true);
}
public static Word newCondition(boolean mustAllocate) {
Size size = Size.fromInt(getConditionSize());
Word condition;
if (mustAllocate) {
condition = Memory.mustAllocate(size);
} else {
condition = Memory.allocate(size);
}
if (!condition.isZero()) {
nativeConditionInitialize(condition);
}
return condition;
}
/**
* A per-thread monitor used for suspend and resume.
*/
public static final class SuspendMonitor {
private Word condition;
private Word mutex;
public void init() {
if (mutex.isZero()) {
mutex = OSMonitor.newMutex();
condition = OSMonitor.newCondition();
}
}
public void destroy() {
if (!mutex.isZero()) {
Memory.deallocate(mutex.asAddress());
}
if (!condition.isZero()) {
Memory.deallocate(condition.asAddress());
}
}
@INLINE
public void suspend() {
nativeTakeLockAndWait(mutex, condition, 0);
}
@INLINE
/**
* Resume the suspended thread.
* If the lock associated with the monitor cannot be acquired return false.
*/
public boolean resume() {
return nativeTakeLockAndNotify(mutex, condition, false);
}
}
@C_FUNCTION
public static native int nativeMutexSize();
@C_FUNCTION
public static native void nativeMutexInitialize(Word mutex);
@C_FUNCTION
public static native int nativeConditionSize();
@C_FUNCTION
public static native void nativeConditionInitialize(Word condition);
@C_FUNCTION
public static native boolean nativeMutexUnlock(Word mutex);
@C_FUNCTION
public static native boolean nativeMutexTryLock(Word mutex);
// May block so JNI
public static native boolean nativeMutexLock(Word mutex);
@C_FUNCTION
public static native boolean nativeConditionNotify(Word condition, boolean all);
// May block so JNI
public static native boolean nativeConditionWait(Word mutex, Word condition, long timeoutMilliSeconds);
// These methods combine lock/wait lock/notify for thread suspend
// Only the owning thread ever calls nativeTakeLockAndWait.
// Only the VmOperation thread ever calls nativeTakeLockAndNotify
@C_FUNCTION
/**
* Check mutex, if locked return false, else take it and notify condition.
* I.e., this function does not block.
*/
public static native boolean nativeTakeLockAndNotify(Word mutex, Word condition, boolean all);
/**
* Take the mutex and wait on the condition.
* This is JNI so that a suspended thread is THREAD_IN_NATIVE for VmOperation.
*/
public static native boolean nativeTakeLockAndWait(Word mutex, Word condition, long millis);
}