public class ThreadSequencer extends Object implements SequencerConstants
Internal utility that allows tests to define execution sequences to confirm
specific concurrent execution patterns. Subject code incorporates calls to
the static method sequence(int)
. Each usage in the application code
should follow this pattern:
SequencerConstants
interface, add a static variable with a
name denoting the place in code where sequencing will occur as follows:
final static int SOME_LOCATION = ThreadSequence.allocate("SOME_LOCATION");
sequence(SOME_LOCATION);
The allocate(String)
method simply allocates a unique integer and
stores an associated location name. Currently the maximum number of allocated
locations is 64.
The sequence(int)
method blocks on a Semaphore until a condition for
release is recognized. The condition is determined by a schedule that the
test class must define.
The entire ThreadSequence mechanism must be enabled via
enableSequencer(boolean)
. By default all calls to
sequence(int)
invoke an empty method in the NullSequencer subclass,
which is fast.
In conjunction with enabling the sequencer, a test must also add one or more
sequencing schedules. Each schedule denotes two sets: the "join set" and the
"release set". When a thread calls sequence(x), the thread adds location x to
a list of blocked locations. It then determines whether that set covers any
join set, and if so, it releases all threads in the associated release set.
For example, suppose there are three location A, B and C. Consider two
sections of code executed by two different threads:
and
sequence(A)
// do this before B
sequence(C)
A suitable schedule might include the
pairs (A, B)->(A) and (B, C)->(B, C). In this example one thread blocks until
both sequence(A) and sequence(B) have been called. Then the schedule (A,
B)->(A) releases the call to sequence(A) so that the first thread runs. When
the first thread calls sequence(C), the schedule (B,C)->(B,C) runs, releasing
the second thread's call to sequence(B) and allowing the first thread to
continue without blocking.
sequence(B)
// do this after A
Follow existing usage in SequencerConstants
for defining schedules.
Test classes should invoke the static method addSchedules(int[][])
to add schedules defined in SequencerConstants.
Note: a malformed schedule can cause threads blocked within the sequence method to remain blocked forever.
Modifier and Type | Class and Description |
---|---|
static class |
ThreadSequencer.Condition |
ACCUMULATOR_CHECKPOINT_A, ACCUMULATOR_CHECKPOINT_B, ACCUMULATOR_CHECKPOINT_C, ACCUMULATOR_CHECKPOINT_SCHEDULED, COMMIT_FLUSH_A, COMMIT_FLUSH_B, COMMIT_FLUSH_C, COMMIT_FLUSH_SCHEDULE, DEALLOCATE_CHAIN_A, DEALLOCATE_CHAIN_B, DEALLOCATE_CHAIN_C, DEALLOCATE_CHAIN_SCHEDULED, LONG_RECORD_ALLOCATE_A, LONG_RECORD_ALLOCATE_B, LONG_RECORD_ALLOCATE_SCHEDULED, PAGE_MAP_READ_INVALIDATE_A, PAGE_MAP_READ_INVALIDATE_B, PAGE_MAP_READ_INVALIDATE_C, PAGE_MAP_READ_INVALIDATE_SCHEDULE, RECOVERY_PRUNING_A, RECOVERY_PRUNING_B, RECOVERY_PRUNING_SCHEDULE, WRITE_WRITE_STORE_A, WRITE_WRITE_STORE_B, WRITE_WRITE_STORE_C, WRITE_WRITE_STORE_SCHEDULE
Constructor and Description |
---|
ThreadSequencer() |
Modifier and Type | Method and Description |
---|---|
static void |
addSchedule(int[] awaitLocations,
int[] releaseLocations) |
static void |
addSchedules(int[][] pairs) |
static int |
allocate(String locationName) |
static void |
appendHistoryElement(StringBuilder sb,
int location) |
static int[] |
array(int... args) |
static String |
describeHistory(int[] history) |
static String |
describePartialOrdering(int[]... args) |
static void |
disableSequencer()
Disable sequencer debugging.
|
static void |
enableSequencer(boolean history)
Enable sequencer debugging.
|
static boolean |
historyMeetsPartialOrdering(int[] history,
int[]... partialOrderings)
Compare a particular sequence history to a collection of required
subsets.
|
static int |
out(int location) |
static int[] |
rawSequenceHistoryCopy() |
static void |
sequence(int location)
Possibly block (only when ThreadSequencer is enabled for tests) until a
scheduling condition is met.
|
static String |
sequencerHistory() |
static void |
setCondition(int location,
ThreadSequencer.Condition condition) |
public static int allocate(String locationName)
public static void sequence(int location)
location
- integer uniquely identifying a location in codepublic static void enableSequencer(boolean history)
history
- indicates whether to maintain a schedule historypublic static void disableSequencer()
public static void addSchedule(int[] awaitLocations, int[] releaseLocations)
public static void addSchedules(int[][] pairs)
public static void setCondition(int location, ThreadSequencer.Condition condition)
public static String sequencerHistory()
public static int[] rawSequenceHistoryCopy()
public static void appendHistoryElement(StringBuilder sb, int location)
public static String describeHistory(int[] history)
public static String describePartialOrdering(int[]... args)
public static boolean historyMeetsPartialOrdering(int[] history, int[]... partialOrderings)
For example, a partialOrderings
of:
{ { A_IN, B_IN }, { OUT_B }, { IN_C } }
history
:
{ A_IN, B_IN, OUT_B, IN_C }
{ B_IN, A_IN, OUT_B, IN_C }
Note: Both parameters will be modified by sorting.
history
- An ordered history, e.g. from
rawSequenceHistoryCopy()
.partialOrderings
- Total ordering specification of unordered subsetstrue
if the history fulfilled the required
orderings.public static int[] array(int... args)
public static int out(int location)
Copyright © 2025 Open Identity Platform Community. All rights reserved.