1 package io.jawk.jrt;
2
3 /*-
4 * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
5 * Jawk
6 * ჻჻჻჻჻჻
7 * Copyright (C) 2006 - 2026 MetricsHub
8 * ჻჻჻჻჻჻
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as
11 * published by the Free Software Foundation, either version 3 of the
12 * License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Lesser Public License for more details.
18 *
19 * You should have received a copy of the GNU General Lesser Public
20 * License along with this program. If not, see
21 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
22 * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
23 */
24
25 import java.util.LinkedList;
26 import java.util.List;
27
28 /**
29 * Manages multiple blocking code segments simultaneously such that
30 * unblocking one block condition releases the block of all other
31 * block code segments.
32 *
33 * @see BlockObject
34 * @author Danny Daglas
35 */
36 public class BlockManager {
37
38 private String notifier = null;
39
40 /**
41 * Executes all block segments simultaneously, waiting for
42 * one block release.
43 * <p>
44 * The algorithm is as follows:
45 * <ul>
46 * <li>Collect linked block objects into a List.
47 * <li>Spawn a BlockThread for each block object.
48 * <li>Wait for notification from any of the BlockThreads.
49 * <li>Interrupt remaining block threads.
50 * <li>Wait for each BlockThread to die.
51 * <li>Return the block object notifier which satisfied their block condition.
52 * </ul>
53 * <p>
54 * And, the BlockThread algorithm is as follows:
55 * <ul>
56 * <li>try, catch for InterruptedException ...
57 * <ul>
58 * <li>Execute the BlockObject block segment.
59 * <li>Assign the notifier from this BlockObject
60 * if one isn't already assigned (to mitigate
61 * a race condition).
62 * <li>Notify the BlockManager.
63 * </ul>
64 * <li>If interrupted, do nothing and return.
65 * </ul>
66 *
67 * @param bo BlockObject to employ. Other block objects
68 * may be linked to this block object. In this event,
69 * employ all block objects simultaneously.
70 * @return a {@link java.lang.String} object
71 */
72 public String block(BlockObject bo) {
73 // get all block objects
74 List<BlockObject> bos = bo.getBlockObjects();
75 // each block object contains a wait statement
76 // (either indefinite or timed)
77
78 // for each block object
79 // spawn a thread (preferably using a threadpool)
80 // do the wait
81 // signal a break in the block
82 // interrupt all other threads, resulting in InterruptedExceptions
83
84 List<Thread> threadList = new LinkedList<Thread>();
85 String blockNotifier = null;
86 synchronized (this) {
87 notifier = null;
88 for (BlockObject blockobj : bos) {
89 // spawn a thread
90 Thread t = new BlockThread(blockobj);
91 t.start();
92 threadList.add(t);
93 }
94
95 // now, wait for notification from one of the BlockThreads
96 while (notifier == null) {
97 try {
98 this.wait();
99 } catch (InterruptedException ie) {
100 Thread.currentThread().interrupt();
101 }
102 }
103 blockNotifier = notifier;
104 }
105
106 // block successful, interrupt other blockers
107 // and wait for thread deaths
108 for (Thread t : threadList) {
109 t.interrupt();
110 try {
111 t.join();
112 } catch (InterruptedException ie) {
113 Thread.currentThread().interrupt();
114 }
115 }
116
117 // return who was the notifier
118 return blockNotifier;
119 }
120
121 private final class BlockThread extends Thread {
122
123 private BlockObject bo;
124
125 private BlockThread(BlockObject bo) {
126 setName("BlockThread for " + bo.getNotifierTag());
127 this.bo = bo;
128 }
129
130 @Override
131 public void run() {
132 try {
133 bo.block();
134 synchronized (BlockManager.this) {
135 if (notifier == null) {
136 notifier = bo.getNotifierTag();
137 }
138 BlockManager.this.notifyAll();
139 }
140 } catch (InterruptedException ie) {
141 currentThread().interrupt();
142 } catch (RuntimeException re) {
143 throw re;
144 }
145 }
146 }
147 }