1
/* Copyright 2016 Software Freedom Conservancy Inc.
3
* This software is licensed under the GNU Lesser General Public License
4
* (version 2.1 or later). See the COPYING file in this distribution.
7
namespace Geary.Synchronization {
10
* A synchronization primitive that spins waiting for a completion state to be reached.
12
* SpinWaiter allows for the caller to specify work to be performed periodically in a callback
13
* while waiting for another thread to notify completion.
16
public class SpinWaiter : BaseObject {
17
public delegate bool PollService();
19
private int poll_msec;
20
private PollService cb;
21
private Mutex mutex = Mutex();
22
private Cond cond = Cond();
23
private bool notified = false;
26
* Create a {@link SpinWaiter}.
28
* poll_msec indicates how long to delay while spinning before interrupting and allowing
29
* the {@link PollService} to execute. If poll_msec is zero or less, PollService will be
32
public SpinWaiter(int poll_msec, owned PollService cb) {
33
this.poll_msec = poll_msec;
38
* Spins waiting for a completion state to be reached.
40
* There's two ways the completion state can be reached: (1) PollService returns false,
41
* indicating an abort state, (2) {@link notify} is called, indicating a success state, or
42
* (3) the Cancellable was cancelled, causing an IOError.CANCELLED exception to be thrown.
44
* {@link PollService} will be called from within the calling thread context.
46
* Although this is thread-safe, it's not designed to be invoked by multiple callers. That
47
* could cause the PollService callback to be called more often than specified in the
50
public bool wait(Cancellable? cancellable = null) throws Error {
51
// normalize poll_msec; negative values are zeroed
52
int64 actual_poll_msec = Numeric.int64_floor(0, poll_msec);
59
if (cancellable != null && cancellable.is_cancelled())
62
int64 end_time = get_monotonic_time() + (actual_poll_msec * TimeSpan.MILLISECOND);
63
if (!cond.wait_until(mutex, end_time)) {
64
// timeout passed, allow the callback to run
67
// PollService returned false, abort
80
if (cancellable.is_cancelled())
81
throw new IOError.CANCELLED("SpinWaiter.wait cancelled");
87
* Signals a completion state to a thread calling {@link wait}.
89
* This call is thread-safe. However, once a {@link SpinWaiter} has been signalled to stop,
90
* it cannot be restarted.
92
public new void notify() {
102
* Indicates if the {@link SpinWaiter} has been notified.
104
* Other completion states (PollService returning false, Cancellable being cancelled in
105
* {@link wait}) are not recorded here.
107
* This method is thread-safe.
111
public bool is_notified() {