/* * Copyright 2016 higherfrequencytrading.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.openhft.lang.locks; import java.util.concurrent.TimeUnit; public final class AcquisitionStrategies { private AcquisitionStrategies() { } public static AcquisitionStrategy<LockingStrategy, RuntimeException> spinLoop( long duration, TimeUnit unit) { return new SpinLoopAcquisitionStrategy<LockingStrategy>(duration, unit); } public static AcquisitionStrategy<LockingStrategy, RuntimeException> spinLoopOrFail( long duration, TimeUnit unit) { return new SpinLoopOrFailAcquisitionStrategy<LockingStrategy>(duration, unit); } public static AcquisitionStrategy<ReadWriteWithWaitsLockingStrategy, RuntimeException> spinLoopRegisteringWaitOrFail(long duration, TimeUnit unit) { return new SpinLoopWriteWithWaitsAcquisitionStrategy(duration, unit); } private static class SpinLoopAcquisitionStrategy<S extends LockingStrategy> implements AcquisitionStrategy<S, RuntimeException> { private final long durationNanos; private SpinLoopAcquisitionStrategy(long duration, TimeUnit unit) { durationNanos = unit.toNanos(duration); } @Override public <T> boolean acquire(TryAcquireOperation<? super S> operation, S strategy, NativeAtomicAccess<T> access, T t, long offset) { if (operation.tryAcquire(strategy, access, t, offset)) return true; long deadLine = System.currentTimeMillis() + durationNanos; beforeLoop(strategy, access, t, offset); do { if (operation.tryAcquire(strategy, access, t, offset)) return true; } while (deadLine - System.currentTimeMillis() >= 0L); // overflow-cautious afterLoop(strategy, access, t, offset); return end(); } <T> void beforeLoop(S strategy, NativeAtomicAccess<T> access, T t, long offset) { } <T> void afterLoop(S strategy, NativeAtomicAccess<T> access, T t, long offset) { } boolean end() { return false; } } private static class SpinLoopOrFailAcquisitionStrategy<S extends LockingStrategy> extends SpinLoopAcquisitionStrategy<S> { private SpinLoopOrFailAcquisitionStrategy(long duration, TimeUnit unit) { super(duration, unit); } @Override boolean end() { throw new RuntimeException("Failed to acquire the lock"); } } private static class SpinLoopWriteWithWaitsAcquisitionStrategy extends SpinLoopOrFailAcquisitionStrategy<ReadWriteWithWaitsLockingStrategy> { private SpinLoopWriteWithWaitsAcquisitionStrategy(long duration, TimeUnit unit) { super(duration, unit); } @Override <T> void beforeLoop(ReadWriteWithWaitsLockingStrategy strategy, NativeAtomicAccess<T> access, T t, long offset) { strategy.registerWait(access, t, offset); } @Override <T> void afterLoop(ReadWriteWithWaitsLockingStrategy strategy, NativeAtomicAccess<T> access, T t, long offset) { strategy.deregisterWait(access, t, offset); } } }