ThreadManager.java

  1. /*
  2.  * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This
  3.  * code is released under a tri EPL/GPL/LGPL license. You can use it,
  4.  * redistribute it and/or modify it under the terms of the:
  5.  *
  6.  * Eclipse Public License version 1.0
  7.  * GNU General Public License version 2
  8.  * GNU Lesser General Public License version 2.1
  9.  */
  10. package org.jruby.truffle.runtime.subsystems;

  11. import com.oracle.truffle.api.CompilerDirectives;
  12. import org.jruby.truffle.runtime.RubyContext;
  13. import org.jruby.truffle.runtime.core.RubyThread;

  14. import java.util.Collections;
  15. import java.util.Set;
  16. import java.util.concurrent.ConcurrentHashMap;
  17. import java.util.concurrent.locks.ReentrantLock;

  18. /**
  19.  * Manages Ruby {@code Thread} objects.
  20.  */
  21. public class ThreadManager {

  22.     private final ReentrantLock globalLock = new ReentrantLock();

  23.     private final RubyThread rootThread;
  24.     private RubyThread currentThread;

  25.     private final Set<RubyThread> runningThreads = Collections.newSetFromMap(new ConcurrentHashMap<RubyThread, Boolean>());

  26.     public ThreadManager(RubyContext context) {
  27.         rootThread = new RubyThread(context.getCoreLibrary().getThreadClass(), this);
  28.         runningThreads.add(rootThread);
  29.         enterGlobalLock(rootThread);
  30.     }

  31.     /**
  32.      * Enters the global lock. Reentrant, but be aware that Ruby threads are not one-to-one with
  33.      * Java threads. Needs to be told which Ruby thread is becoming active as it can't work this out
  34.      * from the current Java thread. Remember to call {@link #leaveGlobalLock} again before
  35.      * blocking.
  36.      */
  37.     @CompilerDirectives.TruffleBoundary
  38.     public void enterGlobalLock(RubyThread thread) {
  39.         globalLock.lock();
  40.         currentThread = thread;
  41.     }

  42.     /**
  43.      * Leaves the global lock, returning the Ruby thread which has just stopped being the current
  44.      * thread. Remember to call {@link #enterGlobalLock} again with that returned thread before
  45.      * executing any Ruby code. You probably want to use this with a {@code finally} statement to
  46.      * make sure that happens
  47.      */
  48.     @CompilerDirectives.TruffleBoundary
  49.     public RubyThread leaveGlobalLock() {
  50.         if (!globalLock.isHeldByCurrentThread()) {
  51.             throw new RuntimeException("You don't own this lock!");
  52.         }

  53.         final RubyThread result = currentThread;
  54.         globalLock.unlock();
  55.         return result;
  56.     }

  57.     public RubyThread getCurrentThread() {
  58.         return currentThread;
  59.     }

  60.     public void registerThread(RubyThread thread) {
  61.         synchronized (this) {
  62.             runningThreads.add(thread);
  63.         }
  64.     }

  65.     public void unregisterThread(RubyThread thread) {
  66.         synchronized (this) {
  67.             runningThreads.remove(thread);
  68.         }
  69.     }

  70.     public void shutdown() {
  71.         for (RubyThread thread : runningThreads) {
  72.             thread.shutdown();
  73.         }
  74.     }

  75. }