2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 | Copyright (c) 1997-2010 The PHP Group |
7 +----------------------------------------------------------------------+
8 | This source file is subject to version 3.01 of the PHP license, |
9 | that is bundled with this package in the file LICENSE, and is |
10 | available through the world-wide-web at the following url: |
11 | http://www.php.net/license/3_01.txt |
12 | If you did not receive a copy of the PHP license and are unable to |
13 | obtain it through the world-wide-web, please send a note to |
14 | license@php.net so we can mail you a copy immediately. |
15 +----------------------------------------------------------------------+
17 #include "hphp/runtime/ext/intervaltimer/ext_intervaltimer.h"
19 #include "hphp/runtime/base/array-init.h"
20 #include "hphp/runtime/base/builtin-functions.h"
21 #include "hphp/runtime/base/req-optional.h"
22 #include "hphp/runtime/base/surprise-flags.h"
23 #include "hphp/runtime/base/request-info.h"
24 #include "hphp/runtime/ext/asio/ext_waitable-wait-handle.h"
25 #include "hphp/runtime/vm/native-data.h"
26 #include "hphp/util/rds-local.h"
29 ///////////////////////////////////////////////////////////////////////////////
31 struct TimerPool final
: RequestEventHandler
{
32 using TimerSet
= req::fast_set
<IntervalTimer
*>;
33 TimerSet
& timers() { return *m_timers
; }
35 void requestInit() override
{
39 void requestShutdown() override
{
41 for (auto it
= m_timers
->begin(); it
!= m_timers
->end(); ) {
43 it
= m_timers
->erase(it
);
44 timer
->~IntervalTimer();
46 } while (!m_timers
->empty());
51 req::Optional
<TimerSet
> m_timers
;
54 IMPLEMENT_STATIC_REQUEST_LOCAL(TimerPool
, s_timer_pool
);
56 ///////////////////////////////////////////////////////////////////////////////
62 s_ResumeAwait("ResumeAwait"),
66 static StaticString
sample_type_string(IntervalTimer::SampleType type
) {
68 case IntervalTimer::IOWaitSample
: return s_IOWait
;
69 case IntervalTimer::ResumeAwaitSample
: return s_ResumeAwait
;
70 case IntervalTimer::EnterSample
: return s_Enter
;
71 case IntervalTimer::ExitSample
: return s_Exit
;
78 void IntervalTimer::RunCallbacks(
79 IntervalTimer::SampleType type
,
80 c_WaitableWaitHandle
* wh
82 clearSurpriseFlag(IntervalTimerFlag
);
84 auto const timers
= s_timer_pool
->timers(); // makes a copy!
85 for (auto timer
: timers
) {
86 if (!s_timer_pool
->timers().count(timer
)) {
87 // This timer has been removed from the pool by one of the callbacks.
92 std::lock_guard
<std::mutex
> lock(timer
->m_signalMutex
);
93 count
= timer
->m_count
;
100 auto args
= make_vec_array(sample_type_string(type
), count
, Object
{wh
});
101 vm_call_user_func(timer
->m_callback
, args
);
102 } catch (Object
& ex
) {
103 raise_error("Uncaught exception escaping IntervalTimer: %s",
104 throwable_to_string(ex
.get()).data());
109 IntervalTimer::~IntervalTimer() {
113 void IntervalTimer::init(double interval
,
115 const Variant
& callback
,
116 RequestInjectionData
* data
) {
117 m_interval
= interval
;
119 m_callback
= callback
;
123 void IntervalTimer::start() {
125 if (m_thread
.joinable()) return;
127 m_thread
= std::thread([](IntervalTimer
* t
) { t
->run(); }, this);
128 s_timer_pool
->timers().insert(this);
131 void IntervalTimer::stop() {
133 if (!m_thread
.joinable()) return;
135 std::lock_guard
<std::mutex
> lock(m_mutex
);
140 s_timer_pool
->timers().erase(this);
143 void IntervalTimer::run() {
144 auto waitTime
= m_initial
;
146 std::unique_lock
<std::mutex
> lock(m_mutex
);
147 auto status
= m_cv
.wait_for(lock
,
148 #ifdef MSVC_NO_STD_CHRONO_DURATION_DOUBLE_ADD
149 std::chrono::duration
<__int64
>((__int64
)waitTime
),
151 std::chrono::duration
<double>(waitTime
),
153 [this]{ return m_done
; });
156 std::lock_guard
<std::mutex
> l(m_signalMutex
);
157 m_data
->setFlag(IntervalTimerFlag
);
160 waitTime
= m_interval
;
161 } while (waitTime
!= 0.0);
164 ///////////////////////////////////////////////////////////////////////////////
166 Class
* IntervalTimer::c_Class
= nullptr;
167 const StaticString
IntervalTimer::c_ClassName("IntervalTimer");
169 void HHVM_METHOD(IntervalTimer
, __construct
,
172 const Variant
& callback
) {
173 auto data
= Native::data
<IntervalTimer
>(this_
);
174 data
->init(interval
, initial
, callback
,
175 &RequestInfo::s_requestInfo
->m_reqInjectionData
);
178 void HHVM_METHOD(IntervalTimer
, start
) {
179 auto data
= Native::data
<IntervalTimer
>(this_
);
183 void HHVM_METHOD(IntervalTimer
, stop
) {
184 auto data
= Native::data
<IntervalTimer
>(this_
);
188 ///////////////////////////////////////////////////////////////////////////////
190 static struct IntervalTimerExtension final
: Extension
{
191 IntervalTimerExtension() : Extension("intervaltimer") {}
193 void moduleInit() override
{
194 HHVM_ME(IntervalTimer
, __construct
);
195 HHVM_ME(IntervalTimer
, start
);
196 HHVM_ME(IntervalTimer
, stop
);
197 Native::registerNativeDataInfo
<IntervalTimer
>(
198 IntervalTimer::c_ClassName
.get(),
199 Native::NDIFlags::NO_SWEEP
);
201 loadSystemlib("intervaltimer");
203 } s_intervaltimer_extension
;
205 ///////////////////////////////////////////////////////////////////////////////