Changeset 15496


Ignore:
Timestamp:
12/21/20 21:28:29 (2 years ago)
Author:
Mark Evenson
Message:

Support use of Project Loom virtual threads

Thanks to no-defun-allowed for clueing me into that this would be
somewhat easily done.

When the underlying JVM supports virtual threads, :VIRTUAL-THREADS
will be present in CL:*FEATURES*.

The special variable THREADS:*THREADING-MODEL* contains the type of
threads being spawned by the implementation: it will be :NATIVE for
the default, which is usually a one-to-one mapping from each Java
thread to a native thread, and will be :VIRTUAL if using the
lightweight threads present in Project Loom JVMs.

Tested on "OpenJDK_64-Bit_Server_VM-Oracle_Corporation-16-loom+9-316".

Netbeans 12.2 has problems running the debugger with this change due
to some sort of bad interaction with the JDWP protocol.

Project Loom documentation of java.lang.Thread
<https://download.java.net/java/early_access/loom/docs/api/java.base/java/lang/Thread.html>

Overview of Project Loom
<https://cr.openjdk.java.net/~rpressler/loom/loom/sol1_part1.html#migration-from-threads-to-virtual-threads>

Early Access binaries for openjdk16-loom
<https://jdk.java.net/loom/>

Location:
trunk/abcl/src/org/armedbear/lisp
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/abcl/src/org/armedbear/lisp/Lisp.java

    r15406 r15496  
    4040import java.io.Reader;
    4141import java.io.StringReader;
     42import java.lang.reflect.Method;
    4243import java.math.BigInteger;
    4344import java.net.URL;
     
    24862487      }
    24872488    }
     2489
     2490    // Available Threading models
     2491
     2492    if (LispThread.virtualThreadingAvailable()) {
     2493      featureList = featureList.push(internKeyword("VIRTUAL-THREADS"));
     2494    }
     2495   
    24882496    Symbol.FEATURES.initializeSpecial(featureList);
    24892497  }
  • trunk/abcl/src/org/armedbear/lisp/LispThread.java

    r15436 r15496  
    3535
    3636import java.lang.ref.WeakReference;
     37import java.lang.reflect.Method;
     38import java.lang.reflect.InvocationTargetException;
    3739import static org.armedbear.lisp.Lisp.*;
    3840
     
    8587        name = new SimpleString(javaThread.getName());
    8688    }
     89
     90  public static boolean virtualThreadingAvailable() {
     91    try {
     92      Class clazz = Class.forName("java.lang.Thread");
     93      Class[] parameters = { java.lang.Runnable.class };
     94      Method method = clazz.getDeclaredMethod("startVirtualThread", parameters);
     95      return true;
     96    } catch (ClassNotFoundException e1) {
     97      Debug.trace("Failed to get java.lang.Thread by name");
     98    } catch (NoSuchMethodException e2) {
     99      // This is the case in non-Loom JVMs
     100    } catch (SecurityException e3) {
     101      Debug.trace("SecurityException caught introspecting threading interface: " + e3.toString());
     102    }
     103    return false;
     104  }
     105
     106  public static Symbol NATIVE_THREADS = internKeyword("NATIVE");
     107  public static Symbol VIRTUAL_THREADS = internKeyword("VIRTUAL");
     108
     109  static {
     110    if (virtualThreadingAvailable()) {
     111      Symbol._THREADING_MODEL.initializeSpecial(VIRTUAL_THREADS);
     112    } else {
     113      Symbol._THREADING_MODEL.initializeSpecial(NATIVE_THREADS);
     114    }
     115  }
     116
     117  static Method threadBuilder = null;
     118  static Method builderName = null;
     119  static Method builderDaemon = null;
     120  static Method builderVirtual = null;
     121  static Method builderTask = null;
     122  static Method builderBuild = null;
     123
     124  static {
     125    try {
     126      Class clazz = Class.forName("java.lang.Thread");
     127      threadBuilder = clazz.getDeclaredMethod("builder");
     128      clazz = Class.forName("java.lang.Thread$Builder");
     129      builderDaemon = clazz.getDeclaredMethod("daemon", boolean.class);
     130      builderName = clazz.getDeclaredMethod("name", String.class);
     131      builderVirtual = clazz.getDeclaredMethod("virtual");
     132      builderTask = clazz.getDeclaredMethod("task", java.lang.Runnable.class);
     133      builderBuild = clazz.getDeclaredMethod("build");
     134    } catch (Exception e) {
     135      if (virtualThreadingAvailable()) {
     136  Debug.trace("Failed to introspect virtual threading methods: " + e);
     137      }
     138    }
     139  }
    87140
    88141    LispThread(final Function fun, LispObject name)
     
    117170            }
    118171        };
    119         javaThread = new Thread(r);
    120         this.name = name;
    121         map.put(javaThread, this);
    122         if (name != NIL)
    123             javaThread.setName(name.getStringValue());
    124         javaThread.setDaemon(true);
    125         javaThread.start();
     172  this.name = name;
     173
     174  Thread thread = null;
     175 
     176  if (Symbol._THREADING_MODEL.getSymbolValue().equals(NATIVE_THREADS)) {
     177    thread = new Thread(r);
     178    if (name != NIL) {
     179            thread.setName(name.getStringValue());
     180    }
     181    thread.setDaemon(true);
     182  } else {
     183    synchronized (threadBuilder) { // Thread.Builder isn't thread safe
     184      Object o = null;
     185      try {
     186        o = threadBuilder.invoke(null);
     187        if (name != NIL) {
     188    o = builderName.invoke(o, name.getStringValue());
     189        }
     190        o = builderDaemon.invoke(o, true);
     191        o = builderVirtual.invoke(o);
     192        o = builderTask.invoke(o, r);
     193        thread = (java.lang.Thread)builderBuild.invoke(o);
     194      } catch (IllegalAccessException e1) {
     195        Debug.trace("Use of reflection to start virtual thread failed: " + e1.toString());
     196      } catch (InvocationTargetException e2) {
     197        Debug.trace("Failed to invoke method to start virtual thread: " + e2.toString());
     198      }
     199    }
     200  }
     201  if (thread == null) {
     202    Debug.trace("Failed to create java.lang.Thread");
     203    javaThread = null;
     204  } else {
     205    javaThread = thread;
     206    map.put(javaThread, this);
     207    javaThread.start();
     208  }
    126209    }
    127210
  • trunk/abcl/src/org/armedbear/lisp/Symbol.java

    r15396 r15496  
    32683268  public static final Symbol THREAD =
    32693269    PACKAGE_THREADS.addExternalSymbol("THREAD");
     3270  public static final Symbol _THREADING_MODEL =
     3271    PACKAGE_THREADS.addExternalSymbol("*THREADING-MODEL*");
     3272   
    32703273
    32713274  // JVM
Note: See TracChangeset for help on using the changeset viewer.