Skip to content

Consider "RMI Runtime" thread group as a user group and not a system group #971

Description

@trancexpress

While debugging LSP code that is triggered by LSP4J, I've noticed that the threads which service LSP requests are considered system threads.

They are under the "RMI Runtime" thread group, defined here: https://github.com/openjdk/jdk/blob/10af769eb06427e37ae943a21964ae51de4526c6/src/java.rmi/share/classes/sun/rmi/runtime/RuntimeUtil.java#L76

    /**
     * Special child of the system thread group for running tasks that
     * may execute user code. The need for a separate thread group may
     * be a vestige of it having had a different security policy from
     * the system thread group, so this might no longer be necessary.
     */
    private static final ThreadGroup userThreadGroup =
        new ThreadGroup(systemThreadGroup, "RMI Runtime");

Threads created with this group are called user threads by the JDK: https://github.com/openjdk/jdk/blob/10af769eb06427e37ae943a21964ae51de4526c6/src/java.rmi/share/classes/sun/rmi/runtime/RuntimeUtil.java#L182

    public static Thread newUserThread(Runnable runnable, String name, boolean daemon) {
        return newThread(userThreadGroup, runnable, name, daemon);
    }

Such threads seem to be created to service TCP socket communication: https://github.com/openjdk/jdk/blob/10af769eb06427e37ae943a21964ae51de4526c6/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPTransport.java#L101

    private static final ExecutorService connectionThreadPool =
        new ThreadPoolExecutor(0, maxConnectionThreads,
            threadKeepAliveTime, TimeUnit.MILLISECONDS,
            new SynchronousQueue<Runnable>(),
            new ThreadFactory() {
                public Thread newThread(Runnable runnable) {
                    return RuntimeUtil.newUserThread(runnable, "TCP Connection(idle)", true);
                }
            });

See: https://github.com/openjdk/jdk/blob/10af769eb06427e37ae943a21964ae51de4526c6/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPTransport.java#L356-L385

        /**
         * Accepts connections from the server socket and executes
         * handlers for them in the thread pool.
         **/
        private void executeAcceptLoop() {
            if (tcpLog.isLoggable(Log.BRIEF)) {
                tcpLog.log(Log.BRIEF, "listening on port " +
                           getEndpoint().getPort());
            }

            while (true) {
                Socket socket = null;
                try {
                    socket = serverSocket.accept();

                    /*
                     * Find client host name (or "0.0.0.0" if unknown)
                     */
                    InetAddress clientAddr = socket.getInetAddress();
                    String clientHost = (clientAddr != null
                                         ? clientAddr.getHostAddress()
                                         : "0.0.0.0");

                    /*
                     * Execute connection handler in the thread pool,
                     * which uses non-system threads.
                     */
                    try {
                        connectionThreadPool.execute(
                            new ConnectionHandler(socket, clientHost));

In this context I have 2 issues with JDT debug:

  1. To debug LSP code, I had to enable system threads. System threads are not shown per default so I was wondering what is going on until I thought to enable "show system threads" in the Debug view.
  2. We still have this bug, which is probably (very) difficult to fix: "System Thread" is buggy #846

So my question is, should we consider threads in the group "RMI Runtime" to not be system threads? Considering JDK code calls them user threads?

Currently we have this in JDIThread:

protected void determineIfSystemThread() throws DebugException {

	protected void determineIfSystemThread() throws DebugException {
		fIsSystemThread = false;
		ThreadGroupReference tgr = getUnderlyingThreadGroup();
		fIsSystemThread = tgr != null;
		while (tgr != null) {
			String tgn = null;
			try {
				tgn = tgr.name();
				tgr = tgr.parent();
			} catch (UnsupportedOperationException e) {
				fIsSystemThread = false;
				break;
			} catch (RuntimeException e) {
				targetRequestFailed(
						MessageFormat.format(
								JDIDebugModelMessages.JDIThread_exception_determining_if_system_thread,
								e.toString()), e);
				// execution will not reach this line, as
				// #targetRequestFailed will throw an exception
				return;
			}
			if (tgn != null && tgn.equals(MAIN_THREAD_GROUP)) {
				fIsSystemThread = false;
				break;
			}
		}
	}

The main thread group being:

private static final String MAIN_THREAD_GROUP = "main"; //$NON-NLS-1$

	/**
	 * Constant for the name of the main thread group.
	 */
	private static final String MAIN_THREAD_GROUP = "main"; //$NON-NLS-1$

Should we add a 2nd constant for "RMI Runtime" and use that as well, to determine if a thread is a system thread?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions