All Downloads are FREE. Search and download functionalities are using the official Maven repository.

java.lang.Thread Maven / Gradle / Ivy

There is a newer version: 17.alpha.0.57
Show newest version
package java.lang;

import static jdk.internal.sys.linux.Futex.*;
import static jdk.internal.sys.posix.Limits.*;
import static jdk.internal.sys.posix.PThread.*;
import static jdk.internal.sys.posix.Sched.*;

import static jdk.internal.thread.ThreadNative.*;
import static org.qbicc.runtime.CNative.*;
import static org.qbicc.runtime.llvm.LLVM.*;
import static org.qbicc.runtime.stdc.Stdint.*;
import static org.qbicc.runtime.stdc.Stdio.*;
import static org.qbicc.runtime.stdc.Stdlib.*;

import java.lang.module.ModuleDescriptor;
import java.lang.ref.Reference;
import java.security.AccessControlContext;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import jdk.internal.misc.TerminatingThreadLocal;
import jdk.internal.ref.CleanerFactory;
import jdk.internal.thread.ThreadNative;
import org.qbicc.rt.annotation.Tracking;
import org.qbicc.runtime.Build;
import org.qbicc.runtime.Hidden;
import org.qbicc.runtime.Inline;
import org.qbicc.runtime.InlineCondition;
import org.qbicc.runtime.NoReturn;
import org.qbicc.runtime.NoSafePoint;
import org.qbicc.runtime.NoThrow;
import org.qbicc.runtime.stackwalk.JavaStackWalker;
import org.qbicc.runtime.stackwalk.StackWalker;
import sun.nio.ch.Interruptible;

/**
 * The qbicc implementation of the {@code Thread} class.
 */
@Tracking("src/java.base/share/classes/java/lang/Thread.java")
public class Thread implements Runnable {

    final long stackSize;
    private volatile String name;

    /**
     * The thread configuration.
     * 
    *
  • bits 0-3: thread priority; valid values are 1 through 10 (note that thread priority is configurable after thread start)
  • *
  • bit 4: 1 = daemon thread; 0 = non-daemon thread
  • *
  • bits 5-30: unused
  • *
  • bit 31: 1 = configuration locked (thread start requested); 0 = configuration mutable
  • *
*/ @SuppressWarnings("FieldMayBeFinal") private volatile int config; private static final int CONFIG_PRIORITY = 0xF << 0; private static final int CONFIG_DAEMON = 1 << 4; private static final int CONFIG_LOCKED = 1 << 31; private Runnable target; private ThreadGroup group; private volatile ClassLoader contextClassLoader; /** * This is a pointer to the native structure of the thread. */ // note: OpenJDK has a similar field called `eetop`; some tools might look for that field? ptr threadNativePtr; /** * @see InheritableThreadLocal */ ThreadLocal.ThreadLocalMap threadLocals = null; /** * @see InheritableThreadLocal */ ThreadLocal.ThreadLocalMap inheritableThreadLocals = null; /** * Thread ID. */ // must be named "tid" due to reference from Unsafe final long tid; // must be named "parkBlocker" due to reference from Unsafe @SuppressWarnings("unused") volatile Object parkBlocker; /* The object in which this thread is blocked in an interruptible I/O * operation, if any. The blocker's interrupt method should be invoked * after setting this thread's interrupt status. */ private volatile Interruptible blocker; private final Object blockerLock = new Object(); /* Referenced by ThreadLocalRandom for usage by ForkJoinPool */ @SuppressWarnings("unused") private AccessControlContext inheritedAccessControlContext; // null unless explicitly set private volatile UncaughtExceptionHandler uncaughtExceptionHandler; // null unless explicitly set private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler; // todo: these three TLR fields need to be isolated from the possibility of false sharing // @see java.util.concurrent.ThreadLocalRandom long threadLocalRandomSeed; int threadLocalRandomProbe; int threadLocalRandomSecondarySeed; public static final int MIN_PRIORITY = 1; public static final int NORM_PRIORITY = 5; public static final int MAX_PRIORITY = 10; private static final StackTraceElement[] EMPTY_STACK_TRACE = new StackTraceElement[0]; // ================================== // Public API // ================================== public static native Thread currentThread(); public static void yield() { if (Build.Target.isPosix()) { final ptr threadNativePtr = currentThread().threadNativePtr; // safepoint for the duration of the yield, but thread is still runnable enterSafePoint(threadNativePtr, 0, 0); sched_yield(); exitSafePoint(threadNativePtr, 0, 0); } // else no operation } // Sleep implementation public static void sleep(long millis) throws InterruptedException { sleep(millis, 0); } public static void sleep(long millis, int nanos) throws InterruptedException { if (millis == 0 && nanos == 0) { return; } park(millis, nanos, STATE_WAITING | STATE_SLEEPING, STATE_RUNNABLE, STATE_INTERRUPTED, 0); if (Thread.interrupted()) { throw new InterruptedException(); } } @NoThrow @NoSafePoint @Inline(InlineCondition.ALWAYS) public static void onSpinWait() { if (Build.isHost()) { return; } else if (Build.Target.isAmd64()) { asm(c_void.class, "pause", "", ASM_FLAG_SIDE_EFFECT); } else if (Build.Target.isAarch64()) { asm(c_void.class, "yield", "", ASM_FLAG_SIDE_EFFECT); } else { // no operation return; } } @Override protected Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } // these ctors are all provided in the JDK public Thread() { this(null, null, "Thread-" + nextThreadNum(), 0); } public Thread(Runnable target) { this(null, target, "Thread-" + nextThreadNum(), 0); } Thread(Runnable target, AccessControlContext ignored) { this(null, target, "Thread-" + nextThreadNum(), 0, false); } public Thread(ThreadGroup group, Runnable target) { this(group, target, "Thread-" + nextThreadNum(), 0); } public Thread(String name) { this(null, null, name, 0); } public Thread(ThreadGroup group, String name) { this(group, null, name, 0); } public Thread(Runnable target, String name) { this(null, target, name, 0); } public Thread(ThreadGroup group, Runnable target, String name) { this(group, target, name, 0); } public Thread(ThreadGroup group, Runnable target, String name, long stackSize) { this(group, target, name, stackSize, true); } public Thread(ThreadGroup g, Runnable target, String name, long stackSize, boolean inheritThreadLocals) { this.name = Objects.requireNonNull(name); Thread parent = currentThread(); if (g == null) { g = parent.getThreadGroup(); } g.addUnstarted(); this.group = g; int parentPriority = parent.getPriority(); int groupMaxPriority = g.getMaxPriority(); if (parentPriority > groupMaxPriority) { parentPriority = groupMaxPriority; } this.config = (parent.isDaemon() ? CONFIG_DAEMON : 0) | parentPriority; this.contextClassLoader = parent.getContextClassLoader(); this.target = target; if (inheritThreadLocals) { final ThreadLocal.ThreadLocalMap parentThreadLocals = parent.inheritableThreadLocals; if (parentThreadLocals != null) { this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parentThreadLocals); } } this.stackSize = stackSize; /* Set thread ID */ this.tid = nextThreadID(); // fields that contain pointers to OS/native resources are initialized in start0() // This allows Thread instances to be created (but not started) at build time. // One typical use case is methods that register shutdown hooks. } public synchronized void start() { if (Build.isHost()) { // this must be replaced on the host throw new IllegalStateException("Host"); } ptr threadNativePtr = addr_of(deref(refToPtr(this)).threadNativePtr).loadSingleAcquire(); if (threadNativePtr != null) { throw new IllegalThreadStateException(); } threadNativePtr = malloc(sizeof(thread_native.class)); if (threadNativePtr.isNull()) { throw new OutOfMemoryError(); } // zero-init the whole structure threadNativePtr.storeUnshared(zero()); if (Build.Target.isPosix()) { if (! Build.Target.isLinux() && ! Build.Target.isWasm()) { if (pthread_mutex_init(addr_of(deref(threadNativePtr).mutex), zero()).isNonZero()) abort(); if (pthread_cond_init(addr_of(deref(threadNativePtr).inbound_cond), zero()).isNonZero()) abort(); if (pthread_cond_init(addr_of(deref(threadNativePtr).outbound_cond), zero()).isNonZero()) abort(); } } deref(threadNativePtr).ref = reference.of(this); // register it on to this thread *before* the safepoint if (addr_of(deref(refToPtr(this)).threadNativePtr).compareAndSwap(zero(), threadNativePtr).isNonNull()) { // lost the race :( // release the mutex and conditions if (Build.Target.isPosix()) { if (! Build.Target.isLinux() && ! Build.Target.isWasm()) { if (pthread_cond_destroy(addr_of(deref(threadNativePtr).outbound_cond)).isNonZero()) abort(); if (pthread_cond_destroy(addr_of(deref(threadNativePtr).inbound_cond)).isNonZero()) abort(); if (pthread_mutex_destroy(addr_of(deref(threadNativePtr).mutex)).isNonZero()) abort(); } } free(threadNativePtr); throw new IllegalThreadStateException(); } // now, the tricky part: we have to add this thread to the big linked list final ptr currentThreadNativePtr = Thread.currentThread().threadNativePtr; // enter safepoint in case lock acquire blocks enterSafePoint(currentThreadNativePtr, 0, 0); // acquire lock if (Build.Target.isPosix()) { if (pthread_mutex_lock(addr_of(thread_list_mutex)).isNonZero()) abort(); } else { // ??? abort(); } // we hold the big list lock; do ye olde linked list insertion deref(thread_list_terminus.prev).next = threadNativePtr; deref(threadNativePtr).prev = thread_list_terminus.prev; thread_list_terminus.prev = threadNativePtr; deref(threadNativePtr).next = addr_of(thread_list_terminus); // release lock if (Build.Target.isPosix()) { if (pthread_mutex_unlock(addr_of(thread_list_mutex)).isNonZero()) abort(); } else { // ??? abort(); } // exit safepoint exitSafePoint(currentThreadNativePtr, 0, 0); // now the thread is registered, so we can try to start it up int oldVal; int newVal; int witness; // lock in the config final ptr configPtr = addr_of(deref(refToPtr(this)).config); oldVal = configPtr.loadSingleAcquire().intValue(); final boolean daemon; for (;;) { if ((oldVal & CONFIG_LOCKED) != 0) { // should not be possible, but it's a valid state daemon = (oldVal & CONFIG_DAEMON) != 0; break; } newVal = oldVal | CONFIG_LOCKED; witness = configPtr.compareAndSwapRelease(word(oldVal), word(newVal)).intValue(); if (witness == oldVal) { daemon = (oldVal & CONFIG_DAEMON) != 0; break; } oldVal = witness; } // update the thread status final ptr statePtr = addr_of(deref(threadNativePtr).state); oldVal = statePtr.loadSingleAcquire().intValue(); for (;;) { if ((oldVal & (STATE_ALIVE | STATE_TERMINATED)) != 0) { // shouldn't be possible, but it's a valid state throw new IllegalThreadStateException(); } newVal = oldVal | STATE_ALIVE | STATE_RUNNABLE; witness = statePtr.compareAndSwapRelease(word(oldVal), word(newVal)).intValue(); if (witness == oldVal) { break; } oldVal = witness; } if (! daemon) { addr_of(nonDaemonThreadCount).getAndAdd(word(1)); } try { // provisionally successful! now, check with the group; if this fails, unset the "alive" state group.add(this); // actually start the thread if (Build.Target.isPosix()) { if (! startPosix()) { throw new OutOfMemoryError(); } } else if (Build.Target.isWasi()) { // status result = wasi_thread_spawn(nativePtr); ... throw new UnsupportedOperationException(); } else { throw new UnsupportedOperationException(); } } catch (Throwable t) { // terminated - clear ALIVE and set TERMINATED+EXITED in one swap statePtr.getAndBitwiseXor(word(STATE_ALIVE | STATE_TERMINATED | STATE_EXITED)); // we also must notify any waiters (waiting on GC etc.) // done; now we must signal the thread so it can exit the safepoint notifySafePointOutbound(threadNativePtr); // notify joiners notifyAll(); try { group.threadStartFailed(this); } catch (Throwable ignored) {} if (! daemon) { exitNonDaemonThread(); } throw t; } // started! } @NoSafePoint @Hidden @NoThrow private boolean startPosix() { // assert Build.Target.isPosix(); final pthread_attr_t thread_attr = auto(); int result = pthread_attr_init(addr_of(thread_attr)).intValue(); if (result != 0) { return false; } final long stackSize = this.stackSize; if (stackSize != 0) { long configStackSize; // todo: configure our minimum stack size; just going with 64KB for now if (defined(PTHREAD_STACK_MIN)) { configStackSize = Math.max(65536, Math.max(PTHREAD_STACK_MIN.longValue(), this.stackSize)); } else { configStackSize = Math.max(65536, this.stackSize); } result = pthread_attr_setstacksize(addr_of(thread_attr), word(configStackSize)).intValue(); if (result != 0) { pthread_attr_destroy(addr_of(thread_attr)); return false; } } final ptr threadNativePtr = this.threadNativePtr; final ptr pthreadPtr = addr_of(deref(threadNativePtr).thread); final ptr> run_fn = addr_of(function.of(ThreadNative::runThreadBody)); // todo: safepoint while thread is created? result = pthread_create(pthreadPtr, addr_of(thread_attr), run_fn, threadNativePtr.cast()).intValue(); pthread_attr_destroy(addr_of(thread_attr)); return result == 0; } @Override public void run() { if (target != null) { target.run(); } } @Deprecated(since="1.2") public final void stop() { throw new UnsupportedOperationException(); } public void interrupt() { final ptr threadNativePtr = this.threadNativePtr; if (threadNativePtr.isNull()) { // nothing we can do return; } ptr statusPtr = addr_of(deref(threadNativePtr).state); int oldVal = statusPtr.loadSingleAcquire().intValue(); int newVal, witness; for (;;) { if ((oldVal & (STATE_INTERRUPTED | STATE_EXITED)) != 0) { return; } newVal = oldVal | STATE_INTERRUPTED; witness = statusPtr.compareAndSwap(word(oldVal), word(newVal)).intValue(); if (witness == oldVal) { // success if (this != Thread.currentThread()) { synchronized (blockerLock) { Interruptible b = blocker; if (b != null) { b.interrupt(this); } } notifySafePointOutbound(threadNativePtr); } return; } oldVal = witness; } } @NoSafePoint public static boolean interrupted() { final ptr threadNativePtr = Thread.currentThread().threadNativePtr; // assert threadNativePtr.isNonNull(); final ptr statusPtr = addr_of(deref(threadNativePtr).state); final int oldVal = statusPtr.getAndBitwiseAnd(word(~ STATE_INTERRUPTED)).intValue(); return (oldVal & STATE_INTERRUPTED) != 0; } @NoSafePoint public boolean isInterrupted() { return (getStatus() & STATE_INTERRUPTED) != 0; } @NoSafePoint public final boolean isAlive() { return (getStatus() & STATE_ALIVE) != 0; } @Deprecated(since="1.2", forRemoval=true) public final void suspend() { throw new UnsupportedOperationException(); } @Deprecated(since="1.2", forRemoval=true) public final void resume() { throw new UnsupportedOperationException(); } public final void setPriority(int newPriority) { if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) { throw new IllegalArgumentException(); } ThreadGroup group = getThreadGroup(); if(group != null) { if (newPriority > group.getMaxPriority()) { newPriority = group.getMaxPriority(); } int oldVal = config; int witness; for (;;) { if ((oldVal & CONFIG_PRIORITY) == newPriority) { return; } witness = compareAndSwapConfig(oldVal, oldVal & ~CONFIG_PRIORITY | newPriority); if (witness == oldVal) { return; } oldVal = witness; } } // else do not change priority if there is no group } public final int getPriority() { return config & CONFIG_PRIORITY; } public final void setName(String name) { if (name == null) { throw new NullPointerException("name cannot be null"); } this.name = name; // todo: set native name } public final String getName() { return name; } public final ThreadGroup getThreadGroup() { return group; } public static int activeCount() { return currentThread().getThreadGroup().activeCount(); } public static int enumerate(Thread[] array) { return currentThread().getThreadGroup().enumerate(array); } @Deprecated(since="1.2", forRemoval=true) public int countStackFrames() { throw new UnsupportedOperationException(); } public final synchronized void join(final long millis) throws InterruptedException { if (millis > 0) { if (isAlive()) { final long startTime = System.nanoTime(); long delay = millis; do { wait(delay); } while (isAlive() && (delay = millis - TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)) > 0); } } else if (millis == 0) { while (isAlive()) { wait(); } } else { throw new IllegalArgumentException("timeout value is negative"); } } public final void join(long millis, int nanos) throws InterruptedException { if (millis < 0) { throw new IllegalArgumentException("timeout value is negative"); } if (nanos < 0 || nanos > 999999) { throw new IllegalArgumentException("nanosecond timeout value out of range"); } if (nanos > 0 && millis < Long.MAX_VALUE) { millis++; } join(millis); } public final void join() throws InterruptedException { join(0); } public static void dumpStack() { new Exception("Stack trace").printStackTrace(); } public final void setDaemon(boolean on) { int oldVal = config; int newVal; int witness; for (;;) { if ((oldVal & CONFIG_DAEMON) != 0) { // done already return; } if ((oldVal & CONFIG_LOCKED) != 0) { throw new IllegalThreadStateException(); } newVal = oldVal | CONFIG_DAEMON; witness = compareAndSwapConfig(oldVal, newVal); if (witness == oldVal) { // success return; } oldVal = witness; } } public final boolean isDaemon() { return (config & CONFIG_DAEMON) != 0; } @Deprecated(since="17", forRemoval=true) public final void checkAccess() { // no operation } public String toString() { ThreadGroup group = getThreadGroup(); if (group != null) { return "Thread[" + getName() + "," + getPriority() + "," + group.getName() + "]"; } else { return "Thread[" + getName() + "," + getPriority() + ",]"; } } public ClassLoader getContextClassLoader() { return contextClassLoader; } public void setContextClassLoader(ClassLoader cl) { contextClassLoader = cl; } public static boolean holdsLock(Object obj) { Object$_aliases oa = cast(obj); return oa.holdsLock(); } public StackTraceElement[] getStackTrace() { if (this != Thread.currentThread()) { // optimization so we do not call into the vm for threads that // have not yet started or have terminated if (!isAlive()) { return EMPTY_STACK_TRACE; } ArrayList stackTrace = new ArrayList<>(); // use the Thread.class global monitor to ensure that only one thread does this at a time final ptr threadNativePtr = this.threadNativePtr; synchronized (Thread.class) { requestSafePoint(threadNativePtr, STATE_SAFEPOINT_REQUEST_STACK); awaitSafePoint(threadNativePtr); StackWalker sw = new StackWalker(addr_of(deref(threadNativePtr).saved_context)); JavaStackWalker jsw = new JavaStackWalker(true); while (jsw.next(sw)) { final Class clazz = jsw.getFrameClass(); final ClassLoader cl = clazz.getClassLoader0(); final Module module = clazz.getModule(); stackTrace.add(new StackTraceElement( cl == null ? "boot" : cl.getName(), module.isNamed() ? module.getName() : null, module.getDescriptor().version().map(ModuleDescriptor.Version::toString).orElse(null), clazz.getName(), jsw.getFrameMethodName(), jsw.getFrameSourceFileName(), jsw.getFrameLineNumber() )); } releaseSafePoint(threadNativePtr, STATE_SAFEPOINT_REQUEST_STACK); } return stackTrace.toArray(StackTraceElement[]::new); } else { return (new Exception()).getStackTrace(); } } public static Map getAllStackTraces() { // Get a snapshot of the list of all threads Thread[] threads = getThreads(); StackTraceElement[][] traces = dumpThreads(threads); Map m = new HashMap<>(threads.length); for (int i = 0; i < threads.length; i++) { StackTraceElement[] stackTrace = traces[i]; if (stackTrace != null) { m.put(threads[i], stackTrace); } // else terminated so we don't put it in the map } return m; } public long getId() { return tid; } public enum State { NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED, ; } public State getState() { // get current thread state return jdk.internal.misc.VM.toThreadState(getStatus() & JVMTI_STATE_BITS); } @FunctionalInterface public interface UncaughtExceptionHandler { void uncaughtException(Thread t, Throwable e); } public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) { defaultUncaughtExceptionHandler = eh; } public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(){ return defaultUncaughtExceptionHandler; } public UncaughtExceptionHandler getUncaughtExceptionHandler() { return uncaughtExceptionHandler != null ? uncaughtExceptionHandler : group; } public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) { uncaughtExceptionHandler = eh; } // ================================== // Private // ================================== @NoReturn void end() { Thread self = this; final ptr threadNativePtr = this.threadNativePtr; // allocate this early CleanupAction action = new CleanupAction(threadNativePtr); // terminated - clear ALIVE and RUNNABLE and set TERMINATED in one swap // remove this thread from the thread list (and set termination flag) enterSafePoint(threadNativePtr, STATE_TERMINATED, STATE_ALIVE | STATE_RUNNABLE); pthread_mutex_lock(addr_of(thread_list_mutex)); deref(deref(threadNativePtr).prev).next = deref(threadNativePtr).next; deref(deref(threadNativePtr).next).prev = deref(threadNativePtr).prev; deref(threadNativePtr).next = zero(); deref(threadNativePtr).prev = zero(); pthread_mutex_unlock(addr_of(thread_list_mutex)); exitSafePoint(threadNativePtr, 0, 0); // clean out fields for better GC behavior if (threadLocals != null && TerminatingThreadLocal.REGISTRY.isPresent()) { TerminatingThreadLocal.threadTerminated(); } group.threadTerminated(this); // notify any threads that have called Thread.join() on me synchronized (this) { this.notifyAll(); } // free native structure once it is unreachable CleanerFactory.cleaner().register(this, action); if (! self.isDaemon()) { exitNonDaemonThread(); } group = null; target = null; threadLocals = null; inheritableThreadLocals = null; blocker = null; uncaughtExceptionHandler = null; addr_of(deref(threadNativePtr).state).getAndBitwiseOr(word(STATE_EXITED)); // prevent free before bits update Reference.reachabilityFence(this); if (Build.Target.isPosix()) { // exit the thread so it does not kill the whole process pthread_exit(zero()); } } @SuppressWarnings("unused") // called by `bind` @Hidden @NoThrow @NoReturn static void run0() { Thread thread = Thread.currentThread(); try { //noinspection CallToThreadRun thread.run(); } catch (Throwable t) { Thread.UncaughtExceptionHandler handler = thread.getUncaughtExceptionHandler(); if (handler != null) { try { handler.uncaughtException(thread, t); } catch (Throwable t2) { // exception handler threw an exception... just bail out then fprintf(stderr, utf8z("The uncaught exception handler threw an exception or error\n")); fflush(stderr); } } } thread.end(); } private static StackTraceElement[][] dumpThreads(Thread[] threads) { StackTraceElement[][] res = new StackTraceElement[threads.length][]; for (int i=0; i threads = new ArrayList<>(); ptr current = thread_list_terminus.next; while (current != addr_of(thread_list_terminus)) { threads.add(deref(current).ref.toObject()); current = deref(current).next; } if (Build.Target.isPosix()) { // acquire lock if (pthread_mutex_unlock(addr_of(thread_list_mutex)).isNonZero()) abort(); } return threads.toArray(Thread[]::new); } private static Thread[] getThreads(ptr next, int index) { if (next == addr_of(thread_list_terminus)) { return new Thread[index]; } else { Thread[] array = getThreads(deref(next).next, index + 1); array[index] = deref(next).ref.toObject(); return array; } } /** * Attempt to interrupt a {@link ThreadNative#park(long, int, int, int, int, int)} operation. * * @param wakeBits the wakeup bits to set on the target thread */ void unpark(int wakeBits) { final ptr threadNativePtr = this.threadNativePtr; if (threadNativePtr.isNull()) { return; } final ptr statePtr = addr_of(deref(threadNativePtr).state); int oldVal, newVal, witness; oldVal = statePtr.loadSingleAcquire().intValue(); for (;;) { if ((oldVal & (wakeBits | STATE_EXITED)) != 0) { // no op necessary; unpark already pending or the thread is gone return; } newVal = oldVal | wakeBits; witness = statePtr.compareAndSwap(word(oldVal), word(newVal)).intValue(); if (witness == oldVal) { // done; now we just have to signal waiters break; } // retry oldVal = witness; } // signal the waiter if (Build.Target.isPosix()) { // wake if (pthread_cond_broadcast(addr_of(deref(threadNativePtr).inbound_cond)).isNonZero()) abort(); } else { throw new UnsupportedOperationException(); } return; } @NoSafePoint private int getStatus() { final ptr threadNativePtr = this.threadNativePtr; return threadNativePtr.isNull() ? 0 : addr_of(deref(threadNativePtr).state).loadSingleAcquire().intValue(); } @NoSafePoint private int compareAndSwapConfig(int expect, int update) { return addr_of(deref(refToPtr(this)).config).compareAndSwap(word(expect), word(update)).intValue(); } /** * Set the blocker field; invoked via jdk.internal.access.SharedSecrets from java.nio code */ static void blockedOn(Interruptible b) { Thread.currentThread().blocker = b; } static final class CleanupAction implements Runnable { private final ptr nativePtr; CleanupAction(final ptr nativePtr) { this.nativePtr = nativePtr; } public void run() { freeThreadNative(nativePtr); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy