mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-14 05:12:33 +00:00
If threads are blocked while there is work in the queue extra threads may be
spawned to keep the processors busy.
Beginning now, tasks created with thread.spawn are use the thread pool.
(thread.spawn_native does not use the thread pool.)
java/runtime/Semaphore.java:
Wrap Java's Semaphore class which call the current thread's blocked()
and running() methods when a thread blocks and then runs after being
blocked.
library/thread.semaphore.m:
Use our own Semaphore class.
java/runtime/MercuryThread.java:
java/runtime/MercuryWorkerThread.java:
Define blocked() and running() on our threads.
java/runtime/NativeThread.java:
This class is used by spawn_native/4 and is required to define blocked()
and running(), however it implements them as no-ops as it isn't included
in the thread pool.
java/runtime/ThreadStatus.java:
Define the BLOCKED status.
java/runtime/MercuryThreadPool.java:
Count blocked threads seperatly and allow the creation of new threads
when existing threads become blocked.
Add some tracing code to help debug the thread management code. This is
disabled by default.
library/thread.m:
Implement spawn for Java using the thread pool. This was not enabled
earlier because without using java/runtime/Semaphore.java it was
possible to deadlock the system.
java/runtime/Task.java:
Add some tracing code to debug thread state changes, this is disabled by
default.
151 lines
3.7 KiB
Java
151 lines
3.7 KiB
Java
//
|
|
// 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();
|
|
}
|
|
}
|
|
}
|
|
|