CriticalSectionManager.java
/*
** Module : CriticalSectionManager.java
** Abstract : provides a protection mechanism for critical sections which are
** sensitive to thread interruption.
**
** Copyright (c) 2009-2017, Golden Code Development Corporation.
**
** -#- -I- --Date-- --JPRM-- -------------------Description-------------------
** 001 CA 20091106 @44322 Initial version. Provides a protection mechanism
** for critical sections sensitive to thread
** interruption.
** 002 CA 20091203 @44475 Fixed a bug in beginSection - we must ensure the
** thread interrupted flag is cleared, regardless of
** the value of wa.threadInterrupted field; else,
** problems may appear if nested crticial sections
** are used.
*/
/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
**
** Additional terms under GNU Affero GPL version 3 section 7:
**
** Under Section 7 of the GNU Affero GPL version 3, the following additional
** terms apply to the works covered under the License. These additional terms
** are non-permissive additional terms allowed under Section 7 of the GNU
** Affero GPL version 3 and may not be removed by you.
**
** 0. Attribution Requirement.
**
** You must preserve all legal notices or author attributions in the covered
** work or Appropriate Legal Notices displayed by works containing the covered
** work. You may not remove from the covered work any author or developer
** credit already included within the covered work.
**
** 1. No License To Use Trademarks.
**
** This license does not grant any license or rights to use the trademarks
** Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
** of Golden Code Development Corporation. You are not authorized to use the
** name Golden Code, FWD, or the names of any author or contributor, for
** publicity purposes without written authorization.
**
** 2. No Misrepresentation of Affiliation.
**
** You may not represent yourself as Golden Code Development Corporation or FWD.
**
** You may not represent yourself for publicity purposes as associated with
** Golden Code Development Corporation, FWD, or any author or contributor to
** the covered work, without written authorization.
**
** 3. No Misrepresentation of Source or Origin.
**
** You may not represent the covered work as solely your work. All modified
** versions of the covered work must be marked in a reasonable way to make it
** clear that the modified work is not originating from Golden Code Development
** Corporation or FWD. All modified versions must contain the notices of
** attribution required in this license.
*/
package com.goldencode.p2j.net;
import com.goldencode.p2j.security.ContextLocal;
/**
* This class provides a mechanism to protect critical sections against thread
* interruption. By critical sections we mean any portion of code which is
* sensitive to thread interruption (i.e. would fail if it sees the thread
* marked as interrupted), but that portion of code must complete regardless
* of the thread interrupt state.
* <p>
* The class provides these methods:
* <ol>
* <li> {@link #beginSection()} and {@link #endSection()} must bracket any
* portion of code which is determined to be sensitive to thread
* interruption. Also, the {@link #endSection()} method ensures that,
* when the critical section ends, it will force the interrupt flag
* of the thread to be set if it was set when the critical section
* started OR if an interruption occurred during the critical section
* (which was deferred).
* </li>
* <li> {@link #interrupt} is used to deliver an interruption to the
* Conversation thread. This ensures that the interrupt will never bes
* executed while a critical section is in process (in such a case the
* interrupt is remembered but its application is deferred until the
* {@link #endSection} finds that all nested critical sections have
* been exited). If no critical section is in process, the interrupt
* is immediately applied to the given thread.
* </li>
* </ol>
*/
public final class CriticalSectionManager
{
/** Store context-local state variables. */
private static final ContextLocal<WorkArea> instance =
new ContextLocal<WorkArea>()
{
protected WorkArea initialValue()
{
return (new WorkArea());
}
};
/**
* Private constructor. Doesn't allow instances of this class.
*/
private CriticalSectionManager()
{
// do not allow instantiation of this class
}
/**
* Method called before the start of a critical section. The method waits
* for any lock to be released, to not interfere with thread interruption.
* <p>
* When the lock was released, it will mark the start of a new critical
* section and also save the the interrupted state of the current thread.
*/
public static void beginSection()
{
WorkArea wa = instance.get();
synchronized (wa)
{
// start the critical section
wa.criticalSection++;
// clear and save the interrupted state
boolean interrupt = Thread.interrupted();
wa.threadInterrupted = wa.threadInterrupted || interrupt;
}
}
/**
* Method called right after the end of a critical section; must be
* executed in a <code>finally</code> block.
* <p>
* This will decrement the critical section count and it will force the
* interrupt flag of the thread to be set if it was set when the critical
* section started OR if an interruption occurred during the critical
* section (if there is a deferred interrupt needing to be delivered).
*/
public static void endSection()
{
WorkArea wa = instance.get();
synchronized (wa)
{
wa.criticalSection--;
if (wa.criticalSection == 0)
{
if (wa.threadInterrupted)
{
// if required and last critical section ended, interrupt
// the thread
Thread.currentThread().interrupt();
}
// all critical sections finished, reset the flag
wa.threadInterrupted = false;
}
}
}
/**
* Notify the target thread about an interruption. If a critical section is
* in progress, postpone the interrupt until it is finished.
*
* @param thread
* The target thread which should be interrupted.
*/
public static void interrupt(Thread thread)
{
WorkArea wa = instance.get();
synchronized (wa)
{
if (wa.criticalSection == 0)
{
thread.interrupt();
}
else
{
wa.threadInterrupted = true;
}
}
}
/**
* Container for context-local variables.
*/
private static final class WorkArea
{
/** Count of critical section being executed. */
private int criticalSection = 0;
/** Thread interruption state flag. */
private boolean threadInterrupted = false;
}
}