Files
odfstudio/ridljar/com/sun/star/lib/uno/environments/remote/JavaThreadPool.java
T
Stephan Bergmann e0c943d5e4 Java URP: Reliably check whether a JobQueue got disposed
If there are multiple Java URP bridges that get disposed simultaneously, there
was a race in that one JobQueue could receive first its own dispose(), save that
disposeId as _doDispose, then receive an unrelated dispose() and overwrite its
_doDispose with that other disposeId, and only then get to the check of
_doDispose == _disposeId in removeJob(), which would thus never succeed and
cause the thread to hang in that loop forever.

So leverage the fact that the _disposeId, instead of being just an opaque token,
actually is the JavaThreadPool that initiated the disposing, so can be used to
check whether a JobQueue got disposed.  (And rename some entities to make their
meaning more obvious.)

(Which then required reworking parts of the test code that checks the internals
of the Java URP bridge.)

Change-Id: If7f4f494b0f7e7f17e0a5c6a458582ad9bed3054
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/187476
Reviewed-by: Stephan Bergmann <stephan.bergmann@collabora.com>
Tested-by: Jenkins
2025-07-08 13:00:00 +02:00

137 lines
4.6 KiB
Java

/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.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.apache.org/licenses/LICENSE-2.0 .
*/
package com.sun.star.lib.uno.environments.remote;
/**
* This class implements a java thread pool.
*
* @see com.sun.star.uno.UnoRuntime
* @see com.sun.star.lib.uno.environments.remote.NativeThreadPool
* @see com.sun.star.lib.uno.environments.remote.IThreadPool
* @see com.sun.star.lib.uno.environments.remote.Job
* @see com.sun.star.lib.uno.environments.remote.JobQueue
* @since UDK1.0
*/
public class JavaThreadPool implements IThreadPool {
/**
* When set to true, enables various debugging output.
*/
private static final boolean DEBUG = false;
private Throwable _disposeThrowable = null;
JavaThreadPoolFactory _javaThreadPoolFactory;
JavaThreadPool(JavaThreadPoolFactory javaThreadPoolFactory) {
_javaThreadPoolFactory = javaThreadPoolFactory;
}
public ThreadId getThreadId() {
return JavaThreadPoolFactory.getThreadId();
}
public Object attach( ThreadId threadId )
{
if(DEBUG) System.err.println("##### " + getClass().getName() + ".attach - id:" + threadId);
JobQueue jobQueue = _javaThreadPoolFactory.getJobQueue(threadId);
if(jobQueue == null)
jobQueue = new JobQueue(_javaThreadPoolFactory, threadId, false);
// acquiring the jobQueue registers it at the ThreadPoolFactory
jobQueue.acquire();
return jobQueue;
}
public void attach() {
attach( getThreadId() );
}
public void detach( Object handle, ThreadId id )
{
((JobQueue)handle).release();
}
public void detach() {
ThreadId threadId = getThreadId();
detach(_javaThreadPoolFactory.getJobQueue(threadId), threadId );
}
public Object enter( ) throws Throwable {
ThreadId threadId = getThreadId();
return enter( _javaThreadPoolFactory.getJobQueue( threadId ), threadId );
}
public Object enter( Object handle, ThreadId threadId ) throws Throwable {
return ((JobQueue)handle).enter(this);
}
public void putJob(Job job) {
if (!job.isRequest() || job.isSynchronous()) {
JobQueue jobQueue = _javaThreadPoolFactory.getJobQueue(job.getThreadId());
// this has not be synchronized, cause
// sync jobs can only come over one bridge
// (cause the thread blocks on other side)
if(jobQueue == null)
jobQueue = new JobQueue(_javaThreadPoolFactory, job.getThreadId(), true);
// put job acquires the queue and registers it at the ThreadPoolFactory
jobQueue.putJob(job, this);
}
else {
// this has to be synchronized, cause
// async jobs of the same thread can come
// over different bridges
synchronized(_javaThreadPoolFactory) {
JobQueue async_jobQueue = _javaThreadPoolFactory.getAsyncJobQueue(job.getThreadId());
// ensure there is jobQueue
if(async_jobQueue == null) // so, there is really no async queue
async_jobQueue = new JobQueue(_javaThreadPoolFactory, job.getThreadId());
// put job acquires the queue and registers it at the ThreadPoolFactory
async_jobQueue.putJob(job, this);
}
}
}
public void dispose(Throwable throwable) {
assert(throwable != null);
synchronized (this) {
_disposeThrowable = throwable;
}
if(DEBUG) System.err.println("##### " + getClass().getName() + ".dispose:" + throwable);
_javaThreadPoolFactory.notifyAboutSomeDisposedPool();
}
public synchronized Throwable checkDisposed() {
return _disposeThrowable;
}
public void destroy() {
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */