Skip to content

Commit 70e05b7

Browse files
peter-hofertkrodriguez
authored andcommitted
[GR-34100] Synchronization improvements.
PullRequest: graal/13301
2 parents f1abe2b + f25c9d0 commit 70e05b7

File tree

3 files changed

+58
-12
lines changed

3 files changed

+58
-12
lines changed

substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/thread/PosixPlatformThreads.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,11 @@ protected void unpark() {
413413
try {
414414
int s;
415415
boolean p;
416-
PosixUtils.checkStatusIs0(Pthread.pthread_mutex_lock(mutex), "PosixParkEvent.unpark(): mutex lock");
416+
int status = Pthread.pthread_mutex_trylock_no_transition(mutex);
417+
if (status == Errno.EBUSY()) { // more expensive transition when potentially blocking:
418+
status = Pthread.pthread_mutex_lock(mutex);
419+
}
420+
PosixUtils.checkStatusIs0(status, "PosixParkEvent.unpark(): mutex lock");
417421
try {
418422
s = event;
419423
event = 1;

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitor.java

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@
2626

2727
package com.oracle.svm.core.monitor;
2828

29+
import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FREQUENT_PROBABILITY;
30+
import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.NOT_FREQUENT_PROBABILITY;
31+
import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
32+
2933
import org.graalvm.nativeimage.CurrentIsolate;
3034
import org.graalvm.nativeimage.IsolateThread;
3135

@@ -145,16 +149,20 @@ protected long getAcquisitions() {
145149
@Override
146150
protected boolean tryAcquire(long acquires) {
147151
assert acquires > 0 && acquires == (int) acquires;
148-
if (getState() == 0 && compareAndSetState(0, getCurrentThreadIdentity())) {
149-
assert acquisitions == 1;
150-
acquisitions = (int) acquires;
151-
return true;
152+
// Do not expect to acquire the lock because this method is typically called after having
153+
// already failed to do so, except after conditional waiting.
154+
if (probability(NOT_FREQUENT_PROBABILITY, getState() == 0)) {
155+
if (probability(FREQUENT_PROBABILITY, compareAndSetState(0, getCurrentThreadIdentity()))) {
156+
assert acquisitions == 1;
157+
acquisitions = (int) acquires;
158+
return true;
159+
}
152160
}
153161
return false;
154162
}
155163

156164
// see ReentrantLock.Sync.tryLock()
157-
boolean tryLock() {
165+
protected boolean tryLock() {
158166
long current = getCurrentThreadIdentity();
159167
long c = getState();
160168
if (c == 0) {

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitorQueuedSynchronizer.java

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,14 @@
6060
* </ul>
6161
*/
6262
abstract class JavaMonitorQueuedSynchronizer {
63+
// Node.status field values
6364
static final int WAITING = 1; // must be 1
6465
static final int CANCELLED = 0x80000000; // must be negative
6566
static final int COND = 2; // in a condition wait
6667

68+
/** Return value of {@link #trySpinAcquire} if successfully acquired. */
69+
protected static final int SPIN_SUCCESS = -1;
70+
6771
// see AbstractQueuedLongSynchronizer.Node
6872
abstract static class Node {
6973
volatile Node prev;
@@ -229,12 +233,36 @@ protected void signalReleaseSuccessor() {
229233
signalNext(head);
230234
}
231235

236+
/**
237+
* Attempt to acquire as part of spinning, returning {@link #SPIN_SUCCESS} if successful, else
238+
* the number of remaining attempts.
239+
*/
240+
protected int trySpinAcquire(int spins, long arg) {
241+
assert spins > 0;
242+
if (tryAcquire(arg)) {
243+
return SPIN_SUCCESS;
244+
}
245+
return spins - 1;
246+
}
247+
248+
/**
249+
* Given the number of previous park operations, returns the number of attempts for
250+
* {@link #trySpinAcquire}, provided that the thread is eligible to acquire the lock (not queued
251+
* yet or first in the queue).
252+
*/
253+
protected int getSpinAttempts(int parks) {
254+
if (parks < 0 || parks > 8) {
255+
return 0xff;
256+
}
257+
return (1 << parks) - 1;
258+
}
259+
232260
// see AbstractQueuedLongSynchronizer.acquire(Node, long, boolean, boolean, boolean, long)
233261
@SuppressWarnings("all")
234262
final int acquire(Node node, long arg) {
235263
Thread current = Thread.currentThread();
236-
byte spins = 0;
237-
byte postSpins = 0;
264+
int parks = 0;
265+
int spins = getSpinAttempts(parks);
238266
boolean first = false;
239267
Node pred = null;
240268

@@ -251,7 +279,13 @@ final int acquire(Node node, long arg) {
251279
if (first || pred == null) {
252280
boolean acquired;
253281
try {
254-
acquired = tryAcquire(arg);
282+
if (spins > 0) {
283+
spins = trySpinAcquire(spins, arg);
284+
acquired = (spins == SPIN_SUCCESS);
285+
assert !acquired || isHeldExclusively();
286+
} else {
287+
acquired = tryAcquire(arg);
288+
}
255289
} catch (Throwable ex) {
256290
cancelAcquire(node);
257291
throw ex;
@@ -279,13 +313,13 @@ final int acquire(Node node, long arg) {
279313
} else {
280314
t.next = node;
281315
}
282-
} else if (first && spins != 0) {
283-
--spins; // reduce unfairness on rewaits
316+
} else if (first && spins > 0) {
284317
Thread.onSpinWait();
285318
} else if (node.status == 0) {
286319
node.status = WAITING; // enable signal and recheck
287320
} else {
288-
spins = postSpins = (byte) ((postSpins << 1) | 1);
321+
parks++;
322+
spins = getSpinAttempts(parks);
289323
LockSupport.park(this);
290324
node.clearStatus();
291325
}

0 commit comments

Comments
 (0)