1d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood/*
2d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood * Copyright (C) 2014 The Android Open Source Project
3d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood *
4d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood * Licensed under the Apache License, Version 2.0 (the "License");
5d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood * you may not use this file except in compliance with the License.
6d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood * You may obtain a copy of the License at
7d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood *
8d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood *      http://www.apache.org/licenses/LICENSE-2.0
9d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood *
10d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood * Unless required by applicable law or agreed to in writing, software
11d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood * distributed under the License is distributed on an "AS IS" BASIS,
12d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood * See the License for the specific language governing permissions and
14d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood * limitations under the License.
15d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood */
16d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood
17d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwoodpackage com.android.internal.midi;
18d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood
19b6f50d357bd3d4d296be6bb047f5ce93a79cbca1Mike Lockwoodimport java.util.Iterator;
20d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwoodimport java.util.SortedMap;
21d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwoodimport java.util.TreeMap;
22d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood
23d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood/**
24d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood * Store arbitrary timestamped events using a Long timestamp.
25d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood * Only one Thread can write into the buffer.
26d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood * And only one Thread can read from the buffer.
27d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood */
28d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwoodpublic class EventScheduler {
29d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood    private static final long NANOS_PER_MILLI = 1000000;
30d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood
312776133be7ac60dc8d6aea5b12e35449ca331836Mike Lockwood    private final Object mLock = new Object();
32b6f50d357bd3d4d296be6bb047f5ce93a79cbca1Mike Lockwood    volatile private SortedMap<Long, FastEventQueue> mEventBuffer;
33d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood    private FastEventQueue mEventPool = null;
34d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood    private int mMaxPoolSize = 200;
352776133be7ac60dc8d6aea5b12e35449ca331836Mike Lockwood    private boolean mClosed;
36d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood
37d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood    public EventScheduler() {
38d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        mEventBuffer = new TreeMap<Long, FastEventQueue>();
39d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood    }
40d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood
41d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood    // If we keep at least one node in the list then it can be atomic
42d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood    // and non-blocking.
43d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood    private class FastEventQueue {
44d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        // One thread takes from the beginning of the list.
45d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        volatile SchedulableEvent mFirst;
46d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        // A second thread returns events to the end of the list.
47d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        volatile SchedulableEvent mLast;
48d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        volatile long mEventsAdded;
49d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        volatile long mEventsRemoved;
50d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood
51d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        FastEventQueue(SchedulableEvent event) {
52d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood            mFirst = event;
53d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood            mLast = mFirst;
54d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood            mEventsAdded = 1;
55d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood            mEventsRemoved = 0;
56d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        }
57d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood
58d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        int size() {
59d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood            return (int)(mEventsAdded - mEventsRemoved);
60d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        }
61d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood
62d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        /**
63d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood         * Do not call this unless there is more than one event
64d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood         * in the list.
65d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood         * @return first event in the list
66d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood         */
67d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        public SchedulableEvent remove() {
68d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood            // Take first event.
69d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood            mEventsRemoved++;
70d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood            SchedulableEvent event = mFirst;
71d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood            mFirst = event.mNext;
72b6f50d357bd3d4d296be6bb047f5ce93a79cbca1Mike Lockwood            event.mNext = null;
73d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood            return event;
74d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        }
75d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood
76d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        /**
77d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood         * @param event
78d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood         */
79d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        public void add(SchedulableEvent event) {
80d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood            event.mNext = null;
81d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood            mLast.mNext = event;
82d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood            mLast = event;
83d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood            mEventsAdded++;
84d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        }
85d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood    }
86d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood
87d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood    /**
88d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood     * Base class for events that can be stored in the EventScheduler.
89d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood     */
90d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood    public static class SchedulableEvent {
91d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        private long mTimestamp;
92b6f50d357bd3d4d296be6bb047f5ce93a79cbca1Mike Lockwood        volatile private SchedulableEvent mNext = null;
93d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood
94d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        /**
95d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood         * @param timestamp
96d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood         */
97d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        public SchedulableEvent(long timestamp) {
98d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood            mTimestamp = timestamp;
99d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        }
100d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood
101d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        /**
102d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood         * @return timestamp
103d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood         */
104d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        public long getTimestamp() {
105d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood            return mTimestamp;
106d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        }
107d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood
108d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        /**
109d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood         * The timestamp should not be modified when the event is in the
110d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood         * scheduling buffer.
111d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood         */
112d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        public void setTimestamp(long timestamp) {
113d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood            mTimestamp = timestamp;
114d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        }
115d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood    }
116d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood
117d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood    /**
118d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood     * Get an event from the pool.
119d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood     * Always leave at least one event in the pool.
120d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood     * @return event or null
121d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood     */
122d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood    public SchedulableEvent removeEventfromPool() {
123d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        SchedulableEvent event = null;
124d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        if (mEventPool != null && (mEventPool.size() > 1)) {
125d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood            event = mEventPool.remove();
126d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        }
127d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        return event;
128d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood    }
129d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood
130d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood    /**
131d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood     * Return events to a pool so they can be reused.
132d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood     *
133d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood     * @param event
134d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood     */
135d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood    public void addEventToPool(SchedulableEvent event) {
136d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        if (mEventPool == null) {
137d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood            mEventPool = new FastEventQueue(event);
138d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        // If we already have enough items in the pool then just
139d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        // drop the event. This prevents unbounded memory leaks.
140d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        } else if (mEventPool.size() < mMaxPoolSize) {
141d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood            mEventPool.add(event);
142d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        }
143d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood    }
144d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood
145d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood    /**
146d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood     * Add an event to the scheduler. Events with the same time will be
147d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood     * processed in order.
148d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood     *
149d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood     * @param event
150d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood     */
151d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood    public void add(SchedulableEvent event) {
1522776133be7ac60dc8d6aea5b12e35449ca331836Mike Lockwood        synchronized (mLock) {
153d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood            FastEventQueue list = mEventBuffer.get(event.getTimestamp());
154d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood            if (list == null) {
155d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                long lowestTime = mEventBuffer.isEmpty() ? Long.MAX_VALUE
156d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                        : mEventBuffer.firstKey();
157d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                list = new FastEventQueue(event);
158d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                mEventBuffer.put(event.getTimestamp(), list);
159d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                // If the event we added is earlier than the previous earliest
160d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                // event then notify any threads waiting for the next event.
161d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                if (event.getTimestamp() < lowestTime) {
1622776133be7ac60dc8d6aea5b12e35449ca331836Mike Lockwood                    mLock.notify();
163d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                }
164d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood            } else {
165d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                list.add(event);
166d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood            }
167d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        }
168d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood    }
169d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood
170d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood    private SchedulableEvent removeNextEventLocked(long lowestTime) {
171d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        SchedulableEvent event;
172d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        FastEventQueue list = mEventBuffer.get(lowestTime);
173d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        // Remove list from tree if this is the last node.
174d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        if ((list.size() == 1)) {
175d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood            mEventBuffer.remove(lowestTime);
176d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        }
177d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        event = list.remove();
178d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        return event;
179d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood    }
180d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood
181d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood    /**
182d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood     * Check to see if any scheduled events are ready to be processed.
183d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood     *
184d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood     * @param timestamp
185d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood     * @return next event or null if none ready
186d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood     */
187d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood    public SchedulableEvent getNextEvent(long time) {
188d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        SchedulableEvent event = null;
1892776133be7ac60dc8d6aea5b12e35449ca331836Mike Lockwood        synchronized (mLock) {
190d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood            if (!mEventBuffer.isEmpty()) {
191d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                long lowestTime = mEventBuffer.firstKey();
192d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                // Is it time for this list to be processed?
193d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                if (lowestTime <= time) {
194d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                    event = removeNextEventLocked(lowestTime);
195d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                }
196d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood            }
197d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        }
198d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        // Log.i(TAG, "getNextEvent: event = " + event);
199d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        return event;
200d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood    }
201d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood
202d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood    /**
203d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood     * Return the next available event or wait until there is an event ready to
204d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood     * be processed. This method assumes that the timestamps are in nanoseconds
205d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood     * and that the current time is System.nanoTime().
206d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood     *
207d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood     * @return event
208d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood     * @throws InterruptedException
209d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood     */
210d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood    public SchedulableEvent waitNextEvent() throws InterruptedException {
211d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        SchedulableEvent event = null;
2122776133be7ac60dc8d6aea5b12e35449ca331836Mike Lockwood        synchronized (mLock) {
2132776133be7ac60dc8d6aea5b12e35449ca331836Mike Lockwood            while (!mClosed) {
2142776133be7ac60dc8d6aea5b12e35449ca331836Mike Lockwood                long millisToWait = Integer.MAX_VALUE;
215d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                if (!mEventBuffer.isEmpty()) {
216d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                    long now = System.nanoTime();
217d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                    long lowestTime = mEventBuffer.firstKey();
218d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                    // Is it time for the earliest list to be processed?
219d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                    if (lowestTime <= now) {
220d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                        event = removeNextEventLocked(lowestTime);
221d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                        break;
222d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                    } else {
223d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                        // Figure out how long to sleep until next event.
224d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                        long nanosToWait = lowestTime - now;
225d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                        // Add 1 millisecond so we don't wake up before it is
226d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                        // ready.
227d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                        millisToWait = 1 + (nanosToWait / NANOS_PER_MILLI);
228d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                        // Clip 64-bit value to 32-bit max.
229d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                        if (millisToWait > Integer.MAX_VALUE) {
230d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                            millisToWait = Integer.MAX_VALUE;
231d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                        }
232d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                    }
233d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood                }
2342776133be7ac60dc8d6aea5b12e35449ca331836Mike Lockwood                mLock.wait((int) millisToWait);
235d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood            }
236d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        }
237d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood        return event;
238d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood    }
2392776133be7ac60dc8d6aea5b12e35449ca331836Mike Lockwood
240b6f50d357bd3d4d296be6bb047f5ce93a79cbca1Mike Lockwood    protected void flush() {
241b6f50d357bd3d4d296be6bb047f5ce93a79cbca1Mike Lockwood        // Replace our event buffer with a fresh empty one
242b6f50d357bd3d4d296be6bb047f5ce93a79cbca1Mike Lockwood        mEventBuffer = new TreeMap<Long, FastEventQueue>();
243b6f50d357bd3d4d296be6bb047f5ce93a79cbca1Mike Lockwood    }
244b6f50d357bd3d4d296be6bb047f5ce93a79cbca1Mike Lockwood
2452776133be7ac60dc8d6aea5b12e35449ca331836Mike Lockwood    public void close() {
2462776133be7ac60dc8d6aea5b12e35449ca331836Mike Lockwood        synchronized (mLock) {
2472776133be7ac60dc8d6aea5b12e35449ca331836Mike Lockwood            mClosed = true;
2482776133be7ac60dc8d6aea5b12e35449ca331836Mike Lockwood            mLock.notify();
2492776133be7ac60dc8d6aea5b12e35449ca331836Mike Lockwood        }
2502776133be7ac60dc8d6aea5b12e35449ca331836Mike Lockwood    }
251d1b16fe2fb7527eee214898263ec4d6dabbfb0b4Mike Lockwood}
252