org.jruby.internal.runtime.ThreadService Maven / Gradle / Ivy
/***** BEGIN LICENSE BLOCK *****
* Version: CPL 1.0/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Common Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.eclipse.org/legal/cpl-v10.html
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* Copyright (C) 2002-2004 Anders Bengtsson
* Copyright (C) 2004 Charles O Nutter
* Copyright (C) 2004 Stefan Matthias Aust
* Copyright (C) 2006 Miguel Covarrubias
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the CPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the CPL, the GPL or the LGPL.
***** END LICENSE BLOCK *****/
package org.jruby.internal.runtime;
import java.lang.ref.SoftReference;
import java.util.concurrent.locks.ReentrantLock;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.Future;
import org.jruby.Ruby;
import org.jruby.RubyThread;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.ThreadContext;
/**
* ThreadService maintains lists ofall the JRuby-specific thread data structures
* needed for Ruby's threading API and for JRuby's execution. The main
* structures are:
*
*
* - ThreadContext, which contains frames, scopes, etc needed for Ruby execution
* - RubyThread, the Ruby object representation of a thread's state
* - RubyThreadGroup, which represents a group of Ruby threads
* - NativeThread, used to wrap native Java threads
* - FutureThread, used to wrap java.util.concurrent.Future
*
*
* In order to ensure these structures do not linger after the thread has terminated,
* most of them are either weakly or softly referenced. The references associated
* with these structures are:
*
*
* - ThreadService has a hard reference to a ThreadLocal, which holds a soft reference
* to a ThreadContext. So the thread's locals softly reference ThreadContext.
* We use a soft reference to keep ThreadContext instances from going away too
* quickly when a Java thread leaves Ruby space completely, which would otherwise
* result in a lot of ThreadContext object churn.
* - ThreadService maintains a weak map from the actual java.lang.Thread (or
* java.util.concurrent.Future) instance to the associated RubyThread. The map
* is weak-keyyed, so it will not prevent the collection of the associated
* Thread or Future. The associated RubyThread will remain alive as long as the
* Thread/Future and this ThreadService instance are both alive, maintaining
* the external thread's identity in Ruby-land.
* - RubyThread has a weak reference to its to ThreadContext.
* - ThreadContext has a hard reference to its associated RubyThread. Ignoring other
* references, this will usually mean RubyThread is softly reachable via the
* soft threadlocal reference to ThreadContext in ThreadService.
* - RubyThreadGroup has hard references to threads it owns. The thread removes
* itself on termination (if it's a Ruby thread) or when the ThreadContext is
* collected (as in the case of "adopted" Java threads.
*
*
* These data structures can come to life in one of two ways:
*
*
* - A Ruby thread is started. This constructs a new RubyThread object, which
* calls to ThreadService to initialize a ThreadContext and appropriate mappings
* in all ThreadService's structures. The body of the thread is wrapped with a
* finally block that will forcibly unregister the thread and all related
* structures from ThreadService.
* - A Java thread enters Ruby by doing a call. The thread is "adopted", and
* gains a RubyThread instance, a ThreadContext instance, and all associated
* mappings in ThreadService. Since we don't know when the thread has "left"
* Ruby permanently, no forcible unregistration is attempted for the various
* structures and maps. However, they should not be hard-rooted; the
* ThreadContext is only softly reachable at best if no calls are in-flight,
* so it will collect. Its collection will release the reference to RubyThread,
* and its finalizer will unregister that RubyThread from its RubyThreadGroup.
* With the RubyThread gone, the Thread-to-RubyThread map will eventually clear,
* releasing the hard reference to the Thread itself.
*
*/
public class ThreadService {
private Ruby runtime;
/**
* A hard reference to the "main" context, so we always have one waiting for
* "main" thread execution.
*/
private ThreadContext mainContext;
/**
* A thread-local soft reference to the current thread's ThreadContext. We
* use a soft reference so that the ThreadContext is still collectible but
* will not immediately disappear once dereferenced, to avoid churning
* through ThreadContext instances every time a Java thread enters and exits
* Ruby space.
*/
private ThreadLocal> localContext;
/**
* The Java thread group into which we register all Ruby threads. This is
* distinct from the RubyThreadGroup, which is simply a mutable collection
* of threads.
*/
private ThreadGroup rubyThreadGroup;
/**
* A map from a Java Thread or Future to its RubyThread instance. This is
* a synchronized WeakHashMap, so it weakly references its keys; this means
* that when the Thread/Future goes away, eventually its entry in this map
* will follow.
*/
private final Map
© 2015 - 2025 Weber Informatics LLC | Privacy Policy