LMMS
Loading...
Searching...
No Matches
juce_Timer.cpp
Go to the documentation of this file.
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23namespace juce
24{
25
26class Timer::TimerThread : private Thread,
27 private DeletedAtShutdown,
28 private AsyncUpdater
29{
30public:
31 using LockType = CriticalSection; // (mysteriously, using a SpinLock here causes problems on some XP machines..)
32
33 TimerThread() : Thread ("JUCE Timer")
34 {
35 timers.reserve (32);
37 }
38
39 ~TimerThread() override
40 {
43 callbackArrived.signal();
44 stopThread (4000);
45 jassert (instance == this || instance == nullptr);
46
47 if (instance == this)
48 instance = nullptr;
49 }
50
51 void run() override
52 {
53 auto lastTime = Time::getMillisecondCounter();
55
56 while (! threadShouldExit())
57 {
58 auto now = Time::getMillisecondCounter();
59 auto elapsed = (int) (now >= lastTime ? (now - lastTime)
60 : (std::numeric_limits<uint32>::max() - (lastTime - now)));
61 lastTime = now;
62
63 auto timeUntilFirstTimer = getTimeUntilFirstTimer (elapsed);
64
65 if (timeUntilFirstTimer <= 0)
66 {
67 if (callbackArrived.wait (0))
68 {
69 // already a message in flight - do nothing..
70 }
71 else
72 {
73 messageToSend->post();
74
75 if (! callbackArrived.wait (300))
76 {
77 // Sometimes our message can get discarded by the OS (e.g. when running as an RTAS
78 // when the app has a modal loop), so this is how long to wait before assuming the
79 // message has been lost and trying again.
80 messageToSend->post();
81 }
82
83 continue;
84 }
85 }
86
87 // don't wait for too long because running this loop also helps keep the
88 // Time::getApproximateMillisecondTimer value stay up-to-date
89 wait (jlimit (1, 100, timeUntilFirstTimer));
90 }
91 }
92
94 {
96
98
99 while (! timers.empty())
100 {
101 auto& first = timers.front();
102
103 if (first.countdownMs > 0)
104 break;
105
106 auto* timer = first.timer;
107 first.countdownMs = timer->timerPeriodMs;
109 notify();
110
112
114 {
115 timer->timerCallback();
116 }
118
119 // avoid getting stuck in a loop if a timer callback repeatedly takes too long
121 break;
122 }
123
124 callbackArrived.signal();
125 }
126
128 {
129 if (! isThreadRunning())
130 {
131 // (This is relied on by some plugins in cases where the MM has
132 // had to restart and the async callback never started)
135 }
136
137 callTimers();
138 }
139
140 static void add (Timer* tim) noexcept
141 {
142 if (instance == nullptr)
143 instance = new TimerThread();
144
145 instance->addTimer (tim);
146 }
147
148 static void remove (Timer* tim) noexcept
149 {
150 if (instance != nullptr)
151 instance->removeTimer (tim);
152 }
153
154 static void resetCounter (Timer* tim) noexcept
155 {
156 if (instance != nullptr)
157 instance->resetTimerCounter (tim);
158 }
159
162
163private:
165 {
168 };
169
170 std::vector<TimerCountdown> timers;
171
173
175 {
177
178 void messageCallback() override
179 {
180 if (instance != nullptr)
181 instance->callTimers();
182 }
183 };
184
185 //==============================================================================
187 {
188 // Trying to add a timer that's already here - shouldn't get to this point,
189 // so if you get this assertion, let me know!
190 jassert (std::none_of (timers.begin(), timers.end(),
191 [t] (TimerCountdown i) { return i.timer == t; }));
192
193 auto pos = timers.size();
194
195 timers.push_back ({ t, t->timerPeriodMs });
196 t->positionInQueue = pos;
198 notify();
199 }
200
202 {
203 auto pos = t->positionInQueue;
204 auto lastIndex = timers.size() - 1;
205
206 jassert (pos <= lastIndex);
207 jassert (timers[pos].timer == t);
208
209 for (auto i = pos; i < lastIndex; ++i)
210 {
211 timers[i] = timers[i + 1];
212 timers[i].timer->positionInQueue = i;
213 }
214
215 timers.pop_back();
216 }
217
218 void resetTimerCounter (Timer* t) noexcept
219 {
220 auto pos = t->positionInQueue;
221
222 jassert (pos < timers.size());
223 jassert (timers[pos].timer == t);
224
225 auto lastCountdown = timers[pos].countdownMs;
226 auto newCountdown = t->timerPeriodMs;
227
228 if (newCountdown != lastCountdown)
229 {
230 timers[pos].countdownMs = newCountdown;
231
232 if (newCountdown > lastCountdown)
234 else
236
237 notify();
238 }
239 }
240
241 void shuffleTimerBackInQueue (size_t pos)
242 {
243 auto numTimers = timers.size();
244
245 if (pos < numTimers - 1)
246 {
247 auto t = timers[pos];
248
249 for (;;)
250 {
251 auto next = pos + 1;
252
253 if (next == numTimers || timers[next].countdownMs >= t.countdownMs)
254 break;
255
256 timers[pos] = timers[next];
257 timers[pos].timer->positionInQueue = pos;
258
259 ++pos;
260 }
261
262 timers[pos] = t;
263 t.timer->positionInQueue = pos;
264 }
265 }
266
268 {
269 if (pos > 0)
270 {
271 auto t = timers[pos];
272
273 while (pos > 0)
274 {
275 auto& prev = timers[(size_t) pos - 1];
276
277 if (prev.countdownMs <= t.countdownMs)
278 break;
279
280 timers[pos] = prev;
281 timers[pos].timer->positionInQueue = pos;
282
283 --pos;
284 }
285
286 timers[pos] = t;
287 t.timer->positionInQueue = pos;
288 }
289 }
290
291 int getTimeUntilFirstTimer (int numMillisecsElapsed)
292 {
294
295 if (timers.empty())
296 return 1000;
297
298 for (auto& t : timers)
299 t.countdownMs -= numMillisecsElapsed;
300
301 return timers.front().countdownMs;
302 }
303
304 void handleAsyncUpdate() override
305 {
306 startThread (7);
307 }
308
310};
311
314
315//==============================================================================
317Timer::Timer (const Timer&) noexcept {}
318
320{
321 // If you're destroying a timer on a background thread, make sure the timer has
322 // been stopped before execution reaches this point. A simple way to achieve this
323 // is to add a call to `stopTimer()` to the destructor of your class which inherits
324 // from Timer.
327 || MessageManager::getInstanceWithoutCreating()->currentThreadHasLockedMessageManager());
328
329 stopTimer();
330}
331
332void Timer::startTimer (int interval) noexcept
333{
334 // If you're calling this before (or after) the MessageManager is
335 // running, then you're not going to get any timer callbacks!
337
339
340 bool wasStopped = (timerPeriodMs == 0);
341 timerPeriodMs = jmax (1, interval);
342
343 if (wasStopped)
344 TimerThread::add (this);
345 else
347}
348
349void Timer::startTimerHz (int timerFrequencyHz) noexcept
350{
351 if (timerFrequencyHz > 0)
352 startTimer (1000 / timerFrequencyHz);
353 else
354 stopTimer();
355}
356
358{
360
361 if (timerPeriodMs > 0)
362 {
363 TimerThread::remove (this);
364 timerPeriodMs = 0;
365 }
366}
367
369{
370 if (TimerThread::instance != nullptr)
371 TimerThread::instance->callTimersSynchronously();
372}
373
374struct LambdaInvoker : private Timer
375{
376 LambdaInvoker (int milliseconds, std::function<void()> f) : function (f)
377 {
378 startTimer (milliseconds);
379 }
380
381 void timerCallback() override
382 {
383 auto f = function;
384 delete this;
385 f();
386 }
387
388 std::function<void()> function;
389
391};
392
393void JUCE_CALLTYPE Timer::callAfterDelay (int milliseconds, std::function<void()> f)
394{
395 new LambdaInvoker (milliseconds, f);
396}
397
398} // namespace juce
Type jmax(const Type a, const Type b)
Definition MathsFunctions.h:48
#define noexcept
Definition DistrhoDefines.h:72
void triggerAsyncUpdate()
Definition juce_AsyncUpdater.cpp:62
void cancelPendingUpdate() noexcept
Definition juce_AsyncUpdater.cpp:74
AsyncUpdater()
Definition juce_AsyncUpdater.cpp:44
Definition juce_CriticalSection.h:43
GenericScopedLock< CriticalSection > ScopedLockType
Definition juce_CriticalSection.h:93
GenericScopedUnlock< CriticalSection > ScopedUnlockType
Definition juce_CriticalSection.h:96
DeletedAtShutdown()
Definition juce_DeletedAtShutdown.cpp:34
Definition juce_MessageManager.h:182
static MessageManager * getInstanceWithoutCreating() noexcept
Definition juce_MessageManager.cpp:58
Definition juce_ReferenceCountedObject.h:247
void startThread()
Definition juce_Thread.cpp:122
bool wait(int timeOutMilliseconds) const
Definition juce_Thread.cpp:299
Thread(const String &threadName, size_t threadStackSize=0)
Definition juce_Thread.cpp:26
bool threadShouldExit() const
Definition juce_Thread.cpp:177
bool stopThread(int timeOutMilliseconds)
Definition juce_Thread.cpp:208
void notify() const
Definition juce_Thread.cpp:304
void signalThreadShouldExit()
Definition juce_Thread.cpp:171
bool isThreadRunning() const
Definition juce_Thread.cpp:155
static uint32 getMillisecondCounter() noexcept
Definition juce_Time.cpp:241
Definition juce_Timer.cpp:29
void removeTimer(Timer *t)
Definition juce_Timer.cpp:201
void callTimersSynchronously()
Definition juce_Timer.cpp:127
static TimerThread * instance
Definition juce_Timer.cpp:160
std::vector< TimerCountdown > timers
Definition juce_Timer.cpp:170
void run() override
Definition juce_Timer.cpp:51
int getTimeUntilFirstTimer(int numMillisecsElapsed)
Definition juce_Timer.cpp:291
~TimerThread() override
Definition juce_Timer.cpp:39
static void resetCounter(Timer *tim) noexcept
Definition juce_Timer.cpp:154
WaitableEvent callbackArrived
Definition juce_Timer.cpp:172
static void add(Timer *tim) noexcept
Definition juce_Timer.cpp:140
TimerThread()
Definition juce_Timer.cpp:33
void shuffleTimerBackInQueue(size_t pos)
Definition juce_Timer.cpp:241
CriticalSection LockType
Definition juce_Timer.cpp:31
static void remove(Timer *tim) noexcept
Definition juce_Timer.cpp:148
void resetTimerCounter(Timer *t) noexcept
Definition juce_Timer.cpp:218
void shuffleTimerForwardInQueue(size_t pos)
Definition juce_Timer.cpp:267
static LockType lock
Definition juce_Timer.cpp:161
void addTimer(Timer *t)
Definition juce_Timer.cpp:186
void callTimers()
Definition juce_Timer.cpp:93
void handleAsyncUpdate() override
Definition juce_Timer.cpp:304
virtual ~Timer()
Definition juce_Timer.cpp:319
void stopTimer() noexcept
Definition juce_Timer.cpp:357
Timer() noexcept
Definition juce_Timer.cpp:316
void startTimerHz(int timerFrequencyHz) noexcept
Definition juce_Timer.cpp:349
bool isTimerRunning() const noexcept
Definition juce_Timer.h:111
int timerPeriodMs
Definition juce_Timer.h:132
static void JUCE_CALLTYPE callPendingTimersSynchronously()
Definition juce_Timer.cpp:368
static void JUCE_CALLTYPE callAfterDelay(int milliseconds, std::function< void()> functionToCall)
Definition juce_Timer.cpp:393
void startTimer(int intervalInMilliseconds) noexcept
Definition juce_Timer.cpp:332
Definition juce_WaitableEvent.h:36
struct huft * t
Definition inflate.c:943
register unsigned i
Definition inflate.c:1575
unsigned f
Definition inflate.c:1572
static double timeout
Definition pugl.h:1799
#define JUCE_TRY
Definition juce_ApplicationBase.h:329
#define JUCE_CATCH_EXCEPTION
Definition juce_ApplicationBase.h:330
#define JUCE_ASSERT_MESSAGE_MANAGER_EXISTS
Definition juce_MessageManager.h:479
#define jassert(expression)
#define JUCE_DECLARE_NON_COPYABLE(className)
#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className)
#define JUCE_CALLTYPE
Definition carla_juce.cpp:31
Type jlimit(Type lowerLimit, Type upperLimit, Type valueToConstrain) noexcept
Definition juce_MathsFunctions.h:262
Definition juce_Timer.cpp:375
void timerCallback() override
Definition juce_Timer.cpp:381
std::function< void()> function
Definition juce_Timer.cpp:388
LambdaInvoker(int milliseconds, std::function< void()> f)
Definition juce_Timer.cpp:376
Definition juce_Timer.cpp:175
CallTimersMessage()
Definition juce_Timer.cpp:176
void messageCallback() override
Definition juce_Timer.cpp:178
Definition juce_Timer.cpp:165
int countdownMs
Definition juce_Timer.cpp:167
Timer * timer
Definition juce_Timer.cpp:166
typedef int(UZ_EXP MsgFn)()
#define void
Definition unzip.h:396