Skip to content

Commit a534627

Browse files
committed
Implement timer for Apple
Add support for timer based on GCD
1 parent 7b31468 commit a534627

File tree

3 files changed

+139
-20
lines changed

3 files changed

+139
-20
lines changed

Release/include/pplx/pplxlinux.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141

4242
#if defined(__APPLE__)
4343
#include "compat/apple_compat.h"
44+
#include <dispatch/dispatch.h>
4445
#else
4546
#include "compat/linux_compat.h"
4647
#include "boost/thread/mutex.hpp"
@@ -97,8 +98,8 @@ namespace platform
9798

9899
void set()
99100
{
100-
std::lock_guard<std::mutex> lock(_lock);
101-
_signaled = true;
101+
std::lock_guard<std::mutex> lock(_lock);
102+
_signaled = true;
102103
_condition.notify_all();
103104
}
104105

@@ -248,14 +249,13 @@ namespace platform
248249
};
249250

250251
class linux_timer;
252+
class apple_timer;
251253

252254
class timer_impl
253255
{
254256
public:
255257
timer_impl()
256-
#if !defined(__APPLE__)
257258
: m_timerImpl(nullptr)
258-
#endif
259259
{
260260
}
261261

@@ -264,8 +264,10 @@ namespace platform
264264
_PPLXIMP void start(unsigned int ms, bool repeat, TaskProc_t userFunc, _In_ void * context);
265265
_PPLXIMP void stop(bool waitForCallbacks);
266266

267-
#if !defined(__APPLE__)
268267
private:
268+
#if defined(__APPLE__)
269+
apple_timer * m_timerImpl;
270+
#else
269271
linux_timer * m_timerImpl;
270272
#endif
271273
};

Release/src/pplx/apple/pplxapple.cpp

Lines changed: 129 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -66,25 +66,142 @@ namespace details {
6666
{
6767
}
6868

69-
timer_impl::~timer_impl()
69+
class apple_timer
7070
{
71-
}
71+
struct callback_finisher
72+
{
73+
apple_timer * m_timer;
74+
callback_finisher(apple_timer *timer) : m_timer(timer)
75+
{
76+
m_timer->_in_callback = true;
77+
}
78+
~callback_finisher()
79+
{
80+
m_timer->_in_callback = false;
81+
}
82+
};
7283

73-
void timer_impl::start(unsigned int ms, bool repeating, TaskProc_t proc, void * context)
74-
{
75-
if (repeating)
84+
private:
85+
bool _repeat;
86+
dispatch_time_t _nextPopTime;
87+
TaskProc_t _proc;
88+
void * _context;
89+
std::atomic_int _callbacks_pending;
90+
std::atomic_bool _orphan;
91+
pplx::extensibility::event_t _completed;
92+
std::atomic_bool _stop_requested;
93+
std::atomic_bool _in_callback; // support reentrancy
94+
95+
static void timer_callback(void * context)
7696
{
77-
throw std::logic_error("PPLX repeating timer is not supported on the Apple platform.");
97+
apple_timer * ptimer = (apple_timer*)context;
98+
callback_finisher _(ptimer);
99+
ptimer->_callbacks_pending--;
100+
if(ptimer->_repeat)
101+
{
102+
if(ptimer->_stop_requested && ptimer->_callbacks_pending == 0) {
103+
ptimer->finalize_callback();
104+
}
105+
else{
106+
ptimer->_proc(ptimer->_context);
107+
ptimer->dispatch_repeated_worker();
108+
}
109+
}
110+
else
111+
{
112+
ptimer->_proc(ptimer->_context);
113+
ptimer->finalize_callback();
114+
}
115+
}
116+
117+
void finalize_callback()
118+
{
119+
if(_orphan)
120+
{
121+
delete this;
122+
}
123+
else
124+
{
125+
_completed.set();
126+
}
78127
}
79-
80-
int64_t deltaNanoseconds = ms * NSEC_PER_MSEC;
81-
dispatch_time_t dispatchTime = dispatch_time(DISPATCH_TIME_NOW, deltaNanoseconds);
82128

83-
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
84-
dispatch_after_f(dispatchTime, queue, context, proc);
129+
void dispatch_repeated_worker()
130+
{
131+
_callbacks_pending++;
132+
dispatch_after_f(_nextPopTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), this, timer_callback);
133+
}
134+
135+
void dispatch_repeated(int64_t intervalInNanoSeconds)
136+
{
137+
dispatch_time_t firstPopTime = dispatch_time(DISPATCH_TIME_NOW, intervalInNanoSeconds);
138+
139+
_nextPopTime = dispatch_time(firstPopTime, intervalInNanoSeconds);
140+
141+
dispatch_repeated_worker();
142+
}
143+
144+
public:
145+
apple_timer(unsigned int ms, bool repeating, TaskProc_t proc, void * context) :
146+
_repeat(repeating)
147+
, _proc(proc)
148+
, _context(context)
149+
,_callbacks_pending(0)
150+
,_orphan(false)
151+
,_stop_requested(false)
152+
,_in_callback(false)
153+
{
154+
int64_t deltaNanoseconds = ms * NSEC_PER_MSEC;
155+
_completed.reset();
156+
157+
if (repeating)
158+
{
159+
dispatch_repeated(deltaNanoseconds);
160+
}
161+
else
162+
{
163+
dispatch_time_t dispatchTime = dispatch_time(DISPATCH_TIME_NOW, deltaNanoseconds);
164+
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
165+
_callbacks_pending++;
166+
dispatch_after_f(dispatchTime, queue, this, timer_callback);
167+
}
168+
}
169+
170+
void stop(bool wait)
171+
{
172+
_stop_requested = true;
173+
if(_in_callback)
174+
{
175+
// this timer will clean up itself when it's done executing the callback
176+
_orphan = true;
177+
}
178+
else
179+
{
180+
if (wait || !_repeat)
181+
{
182+
_completed.wait();
183+
}
184+
delete this;
185+
}
186+
}
187+
};
188+
189+
_PPLXIMP void timer_impl::start(unsigned int ms, bool repeating, TaskProc_t proc, void * context)
190+
{
191+
_ASSERTE(m_timerImpl == nullptr);
192+
m_timerImpl = new apple_timer(ms, repeating, proc, context);
193+
}
194+
195+
_PPLXIMP void timer_impl::stop(bool waitForCallbacks)
196+
{
197+
if( m_timerImpl != nullptr )
198+
{
199+
m_timerImpl->stop(waitForCallbacks);
200+
m_timerImpl = nullptr;
201+
}
85202
}
86203

87-
void timer_impl::stop(bool /* waitForCallbacks */)
204+
timer_impl::~timer_impl()
88205
{
89206
}
90207

Release/tests/Functional/pplx/pplx_test/pplx_op_test.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ struct TimerCallbackContext
362362
}
363363
};
364364

365-
TEST(timer_oneshot, "Ignore:Apple", "Not yet implemented")
365+
TEST(timer_oneshot)
366366
{
367367
TimerCallbackContext context;
368368
context.count = 1234;
@@ -374,7 +374,7 @@ TEST(timer_oneshot, "Ignore:Apple", "Not yet implemented")
374374
context.simpleTimer.stop(true);
375375
}
376376

377-
TEST(timer_start_stop, "Ignore:Apple", "Not yet implemented")
377+
TEST(timer_start_stop)
378378
{
379379
TimerCallbackContext context;
380380
context.count = 1234;
@@ -391,7 +391,7 @@ TEST(timer_start_stop, "Ignore:Apple", "Not yet implemented")
391391
context.simpleTimer.stop(false);
392392
}
393393

394-
TEST(timer_repeat, "Ignore:Apple", "Not yet implemented")
394+
TEST(timer_repeat)
395395
{
396396
TimerCallbackContext context;
397397
context.count = 10;

0 commit comments

Comments
 (0)