/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Common Public License (CPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/cpl1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.scheduler; import org.jikesrvm.VM; import org.jikesrvm.annotations.NoSubArchCompile; import org.jikesrvm.memorymanagers.mminterface.MM_Constants; import org.jikesrvm.memorymanagers.mminterface.MM_Interface; import org.jikesrvm.runtime.VM_Magic; import org.vmmagic.pragma.Inline; import org.vmmagic.pragma.Uninterruptible; import org.vmmagic.unboxed.Address; import org.vmmagic.unboxed.Offset; /** * Class to provide synchronization methods where java language * synchronization is insufficient and VM_Magic.prepare and VM_Magic.attempt * are at too low a level */ @Uninterruptible public class VM_Synchronization { /** * Atomically swap test value to new value in the specified object and the specified field * @param base object containing field * @param offset position of field * @param testValue expected value of field * @param newValue new value of field * @return true => successful swap, false => field not equal to testValue */ @Inline public static boolean tryCompareAndSwap(Object base, Offset offset, int testValue, int newValue) { int oldValue; do { oldValue = VM_Magic.prepareInt(base, offset); if (oldValue != testValue) return false; } while (!VM_Magic.attemptInt(base, offset, oldValue, newValue)); return true; } /** * Atomically swap test value to new value in the specified object and the specified field * @param base object containing field * @param offset position of field * @param testValue expected value of field * @param newValue new value of field * @return true => successful swap, false => field not equal to testValue */ @Inline public static boolean tryCompareAndSwap(Object base, Offset offset, long testValue, long newValue) { long oldValue; do { oldValue = VM_Magic.prepareLong(base, offset); if (oldValue != testValue) return false; } while (!VM_Magic.attemptLong(base, offset, oldValue, newValue)); return true; } /** * Atomically swap test value to new value in the specified object and the specified field * @param base object containing field * @param offset position of field * @param testValue expected value of field * @param newValue new value of field * @return true => successful swap, false => field not equal to testValue */ @Inline public static boolean tryCompareAndSwap(Object base, Offset offset, Object testValue, Object newValue) { if (MM_Constants.NEEDS_WRITE_BARRIER) { return MM_Interface.tryCompareAndSwapWriteBarrier(base, offset, testValue, newValue); } else { Object oldValue; do { oldValue = VM_Magic.prepareObject(base, offset); if (oldValue != testValue) return false; } while (!VM_Magic.attemptObject(base, offset, oldValue, newValue)); return true; } } @Inline public static boolean testAndSet(Object base, Offset offset, int newValue) { int oldValue; do { oldValue = VM_Magic.prepareInt(base, offset); if (oldValue != 0) return false; } while (!VM_Magic.attemptInt(base, offset, oldValue, newValue)); return true; } @Inline public static int fetchAndStore(Object base, Offset offset, int newValue) { int oldValue; do { oldValue = VM_Magic.prepareInt(base, offset); } while (!VM_Magic.attemptInt(base, offset, oldValue, newValue)); return oldValue; } @Inline public static Address fetchAndStoreAddress(Object base, Offset offset, Address newValue) { Address oldValue; do { oldValue = VM_Magic.prepareAddress(base, offset); } while (!VM_Magic.attemptAddress(base, offset, oldValue, newValue)); return oldValue; } @Inline public static int fetchAndAdd(Object base, Offset offset, int increment) { int oldValue; do { oldValue = VM_Magic.prepareInt(base, offset); } while (!VM_Magic.attemptInt(base, offset, oldValue, oldValue + increment)); return oldValue; } @Inline public static int fetchAndDecrement(Object base, Offset offset, int decrement) { int oldValue; do { oldValue = VM_Magic.prepareInt(base, offset); } while (!VM_Magic.attemptInt(base, offset, oldValue, oldValue - decrement)); return oldValue; } @Inline public static Address fetchAndAddAddress(Address addr, int increment) { Address oldValue; do { oldValue = VM_Magic.prepareAddress(VM_Magic.addressAsObject(addr), Offset.zero()); } while (!VM_Magic.attemptAddress(VM_Magic.addressAsObject(addr), Offset.zero(), oldValue, oldValue.plus(increment))); return oldValue; } @Inline @NoSubArchCompile public static Address fetchAndAddAddressWithBound(Address addr, int increment, Address bound) { Address oldValue, newValue; if (VM.VerifyAssertions) VM._assert(increment > 0); do { oldValue = VM_Magic.prepareAddress(VM_Magic.addressAsObject(addr), Offset.zero()); newValue = oldValue.plus(increment); if (newValue.GT(bound)) return Address.max(); } while (!VM_Magic.attemptAddress(VM_Magic.addressAsObject(addr), Offset.zero(), oldValue, newValue)); return oldValue; } @Inline @NoSubArchCompile public static Address fetchAndSubAddressWithBound(Address addr, int decrement, Address bound) { Address oldValue, newValue; if (VM.VerifyAssertions) VM._assert(decrement > 0); do { oldValue = VM_Magic.prepareAddress(VM_Magic.addressAsObject(addr), Offset.zero()); newValue = oldValue.minus(decrement); if (newValue.LT(bound)) return Address.max(); } while (!VM_Magic.attemptAddress(VM_Magic.addressAsObject(addr), Offset.zero(), oldValue, newValue)); return oldValue; } @Inline @NoSubArchCompile public static Address fetchAndAddAddressWithBound(Object base, Offset offset, int increment, Address bound) { Address oldValue, newValue; if (VM.VerifyAssertions) VM._assert(increment > 0); do { oldValue = VM_Magic.prepareAddress(base, offset); newValue = oldValue.plus(increment); if (newValue.GT(bound)) return Address.max(); } while (!VM_Magic.attemptAddress(base, offset, oldValue, newValue)); return oldValue; } @Inline @NoSubArchCompile public static Address fetchAndSubAddressWithBound(Object base, Offset offset, int decrement, Address bound) { Address oldValue, newValue; if (VM.VerifyAssertions) VM._assert(decrement > 0); do { oldValue = VM_Magic.prepareAddress(base, offset); newValue = oldValue.minus(decrement); if (newValue.LT(bound)) return Address.max(); } while (!VM_Magic.attemptAddress(base, offset, oldValue, newValue)); return oldValue; } }