// // Copyright (C) 2014 The Mercury Team // This file may only be copied under the terms of the GNU Library General // Public License - see the file COPYING.LIB in the Mercury distribution. // package jmercury.runtime; import java.util.concurrent.TimeUnit; public class Semaphore extends java.util.concurrent.Semaphore { public Semaphore(int permits, boolean fair) { super(permits, fair); } public Semaphore(int permits) { super(permits); } public void acquire() throws InterruptedException { acquire(1); } public void acquire(int permits) throws InterruptedException { boolean blocked = false; try { if (tryAcquire(permits, 0, TimeUnit.SECONDS)) { return; } else { // This thread will (probably) block. blocked(); blocked = true; super.acquire(permits); } } finally { if (blocked) { running(); // The thread isn't blocked anymore. } } } public void acquireUninterruptibly() { acquireUninterruptibly(1); } public void acquireUninterruptibly(int permits) { boolean interrupted_once = false; boolean keep_trying; boolean success; // Avoid a warning with the loop below success = false; /* * tryAcquire is interruptable so we keep trying until we've * executed it at least once and it was not interrupted. We also * track if we were interrupted so we can raise this condition * again. */ do { keep_trying = true; try { success = tryAcquire(permits, 0, TimeUnit.SECONDS); keep_trying = false; } catch (InterruptedException e) { interrupted_once = true; } } while (keep_trying); if (!success) { // This thread will (probably) block because tryAcquire failed. blocked(); super.acquireUninterruptibly(permits); running(); } if (interrupted_once) { /* ** Because this was supposed to be uninterruptable we need to ** raise the interrupt that we received earlier. */ Thread.currentThread().interrupt(); } } public boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException { return tryAcquire(1, timeout, unit); } public boolean tryAcquire(int permits, long timeout, TimeUnit unit) throws InterruptedException { if (timeout < 1) { return super.tryAcquire(permits, timeout, unit); } else { boolean result; result = tryAcquire(permits, 0, unit); if (result) { // Blocking wasn't necessary return true; } else { // Blocking required, notify thread. blocked(); try { // Block. return tryAcquire(permits, timeout, unit); } finally { running(); } } } } protected void blocked() { MercuryThread mer_thread; mer_thread = MercuryThread.currentThread(); if (mer_thread != null) { mer_thread.blocked(); } } protected void running() { MercuryThread mer_thread; mer_thread = MercuryThread.currentThread(); if (mer_thread != null) { mer_thread.running(); } } }