Skip to content

Commit 01bd76d

Browse files
authored
Fix timeout handling in SchedulerToExecutorService.awaitTermination (#8301)
Signed-off-by: cuishuang <imcusg@gmail.com>
1 parent 947e681 commit 01bd76d

2 files changed

Lines changed: 49 additions & 5 deletions

File tree

‎src/main/java/io/reactivex/rxjava4/internal/schedulers/SchedulerToExecutorService.java‎

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,29 @@ public boolean isTerminated() {
8484
@Override
8585
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
8686
// FIXME no idea how to passively wait, not really applicable in Rx
87-
long totalTime = unit.convert(timeout, TimeUnit.MILLISECONDS);
87+
long timeoutNanos = unit.toNanos(timeout);
88+
if (isTerminated()) {
89+
return true;
90+
}
91+
if (timeoutNanos <= 0) {
92+
return false;
93+
}
94+
95+
long start = System.nanoTime();
96+
for (;;) {
97+
if (isTerminated()) {
98+
return true;
99+
}
100+
101+
long elapsed = System.nanoTime() - start;
102+
long remaining = timeoutNanos - elapsed;
103+
if (remaining <= 0) {
104+
return isTerminated();
105+
}
88106

89-
while (!isTerminated() && totalTime > 0) {
90-
totalTime--;
91-
Thread.sleep(1);
107+
// There is no termination signal to await, so poll at a short interval.
108+
TimeUnit.NANOSECONDS.sleep(Math.min(remaining, TimeUnit.MILLISECONDS.toNanos(1)));
92109
}
93-
return totalTime > 0;
94110
}
95111

96112
@Override

‎src/test/java/io/reactivex/rxjava4/internal/schedulers/SchedulerToExecutorServiceTest.java‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,4 +216,32 @@ public void invokeAllTimeoutDoesTimeout() throws Throwable {
216216
assertTrue(f.isCancelled(), "Task was not cancelled: " + f);
217217
}
218218
}
219+
220+
@Test
221+
public void awaitTerminationUsesRequestedTimeUnit() throws Exception {
222+
Scheduler scheduler = Schedulers.computation();
223+
Scheduler.Worker worker = scheduler.createWorker();
224+
SchedulerToExecutorService executor = new SchedulerToExecutorService(
225+
scheduler, new AtomicReference<>(worker));
226+
227+
try {
228+
scheduler.scheduleDirect(worker::dispose, 50, TimeUnit.MILLISECONDS);
229+
230+
assertTrue(executor.awaitTermination(1, TimeUnit.SECONDS));
231+
} finally {
232+
worker.dispose();
233+
}
234+
}
235+
236+
@Test
237+
public void awaitTerminationReturnsTrueIfAlreadyTerminated() throws Exception {
238+
SchedulerToExecutorService executor = new SchedulerToExecutorService(
239+
Schedulers.computation(), new AtomicReference<>(null));
240+
241+
assertFalse(executor.awaitTermination(0, TimeUnit.MILLISECONDS));
242+
243+
executor.shutdown();
244+
245+
assertTrue(executor.awaitTermination(0, TimeUnit.MILLISECONDS));
246+
}
219247
}

0 commit comments

Comments
 (0)