1 package org.daisy.pipeline.tts;
2
3 import java.util.concurrent.atomic.AtomicBoolean;
4
5
6
7
8
9
10
11
12
13
14
15 public class TTSTimeout extends Thread {
16
17 public interface ThreadFreeInterrupter {
18 void threadFreeInterrupt();
19 }
20
21 private Thread mJob;
22 private int mSeconds;
23 private AtomicBoolean mClosed;
24 private boolean mEnable;
25 private ThreadFreeInterrupter mInterrupter;
26
27 public TTSTimeout() {
28 mClosed = new AtomicBoolean(false);
29 mEnable = false;
30 mInterrupter = null;
31 start();
32 }
33
34
35
36
37
38 public void close() {
39 mClosed.set(true);
40 this.interrupt();
41 }
42
43 public void enable(Thread job, ThreadFreeInterrupter interruptable, int seconds) {
44 if (seconds < 0)
45 throw new IllegalArgumentException("Expecting a positive number of seconds");
46 mInterrupter = interruptable;
47 mJob = job;
48 mEnable = true;
49 mSeconds = seconds;
50 synchronized (mClosed) {
51 mClosed.notify();
52 }
53 }
54
55 public void enable(Thread job, int seconds) {
56 enable(job, null, seconds);
57 }
58
59 public void enableForCurrentThread(ThreadFreeInterrupter interruptable, int seconds) {
60 enable(Thread.currentThread(), interruptable, seconds);
61 }
62
63 public void enableForCurrentThread(int seconds) {
64 enableForCurrentThread(null, seconds);
65 }
66
67
68
69
70 public void disable() {
71 this.interrupt();
72
73
74 synchronized (mClosed) {
75 while (mEnable) {
76 try {
77 mClosed.wait();
78 } catch (InterruptedException e) {
79
80 }
81 }
82 }
83 }
84
85 @Override
86 public void run() {
87 while (!mClosed.get()) {
88 synchronized (mClosed) {
89 while (!mEnable) {
90 try {
91 mClosed.wait();
92 } catch (InterruptedException e) {
93
94 return;
95 }
96 }
97 }
98 try {
99 sleep(Math.multiplyExact(mSeconds, 1000));
100 } catch (InterruptedException e) {
101
102 notifyFinished();
103 continue;
104 }
105
106 mJob.interrupt();
107
108
109 try {
110 sleep(1000);
111 } catch (InterruptedException e) {
112
113 notifyFinished();
114 continue;
115 }
116 if (interrupted()) {
117
118 notifyFinished();
119 continue;
120 }
121
122
123 if (mInterrupter != null)
124 mInterrupter.threadFreeInterrupt();
125
126
127 try {
128 sleep(Long.MAX_VALUE);
129 } catch (InterruptedException e) {
130
131 notifyFinished();
132 continue;
133 }
134 }
135 }
136
137 private void notifyFinished() {
138 mEnable = false;
139 synchronized (mClosed) {
140 mClosed.notify();
141 }
142 }
143
144 }