0
0
mirror of https://github.com/phpv8/v8js.git synced 2024-11-08 10:18:41 +00:00
phpv8/v8js_timer.cc
2017-03-11 17:57:33 +01:00

159 lines
4.5 KiB
C++

/*
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2013 The PHP Group |
+----------------------------------------------------------------------+
| http://www.opensource.org/licenses/mit-license.php MIT License |
+----------------------------------------------------------------------+
| Author: Jani Taskinen <jani.taskinen@iki.fi> |
| Author: Patrick Reilly <preilly@php.net> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef _WIN32
#include <concrt.h>
#endif
#include "php_v8js_macros.h"
#include "v8js_v8.h"
#include "v8js_exceptions.h"
#include "v8js_timer.h"
extern "C" {
#include "ext/date/php_date.h"
#include "ext/standard/php_string.h"
#include "zend_interfaces.h"
#include "zend_closures.h"
#include "ext/spl/spl_exceptions.h"
#include "zend_exceptions.h"
}
static void v8js_timer_interrupt_handler(v8::Isolate *isolate, void *data) { /* {{{ */
zend_v8js_globals *globals = static_cast<zend_v8js_globals *>(data);
if (!globals->timer_stack.size()) {
return;
}
v8::Locker locker(isolate);
v8::HeapStatistics hs;
bool send_notification = false;
bool has_sent_notification = false;
do {
if (send_notification) {
isolate->LowMemoryNotification();
has_sent_notification = true;
}
isolate->GetHeapStatistics(&hs);
globals->timer_mutex.lock();
for (std::deque< v8js_timer_ctx* >::iterator it = globals->timer_stack.begin();
it != globals->timer_stack.end(); it ++) {
v8js_timer_ctx *timer_ctx = *it;
v8js_ctx *c = timer_ctx->ctx;
if(c->isolate != isolate || timer_ctx->killed) {
continue;
}
if (timer_ctx->memory_limit > 0 && hs.used_heap_size() > timer_ctx->memory_limit) {
if (has_sent_notification) {
timer_ctx->killed = true;
v8::V8::TerminateExecution(c->isolate);
c->memory_limit_hit = true;
} else {
// force garbage collection, then check again
send_notification = true;
break;
}
}
}
globals->timer_mutex.unlock();
} while(send_notification != has_sent_notification);
}
/* }}} */
void v8js_timer_thread(zend_v8js_globals *globals) /* {{{ */
{
while (!globals->timer_stop) {
globals->timer_mutex.lock();
if (globals->timer_stack.size()) {
v8js_timer_ctx *timer_ctx = globals->timer_stack.front();
v8js_ctx *c = timer_ctx->ctx;
std::chrono::time_point<std::chrono::high_resolution_clock> now = std::chrono::high_resolution_clock::now();
if(timer_ctx->killed) {
/* execution already terminated, nothing to check anymore,
* but wait for caller to pop this timer context. */
}
else if(timer_ctx->time_limit > 0 && now > timer_ctx->time_point) {
timer_ctx->killed = true;
v8::V8::TerminateExecution(c->isolate);
c->time_limit_hit = true;
}
else if (timer_ctx->memory_limit > 0) {
/* If a memory_limit is set, we need to interrupt execution
* and check heap size within the callback. We must *not*
* directly call GetHeapStatistics here, since we don't have
* a v8::Locker on the isolate, but are expected to hold one,
* and cannot aquire it as v8 is executing the script ... */
c->isolate->RequestInterrupt(v8js_timer_interrupt_handler, static_cast<void *>(globals));
}
}
globals->timer_mutex.unlock();
// Sleep for 10ms
#ifdef _WIN32
concurrency::wait(10);
#else
std::chrono::milliseconds duration(10);
std::this_thread::sleep_for(duration);
#endif
}
}
/* }}} */
void v8js_timer_push(long time_limit, size_t memory_limit, v8js_ctx *c) /* {{{ */
{
V8JSG(timer_mutex).lock();
// Create context for this timer
v8js_timer_ctx *timer_ctx = (v8js_timer_ctx *)emalloc(sizeof(v8js_timer_ctx));
// Calculate the time point when the time limit is exceeded
std::chrono::milliseconds duration(time_limit);
std::chrono::time_point<std::chrono::high_resolution_clock> from = std::chrono::high_resolution_clock::now();
// Push the timer context
timer_ctx->time_limit = time_limit;
timer_ctx->memory_limit = memory_limit;
timer_ctx->time_point = from + duration;
timer_ctx->ctx = c;
timer_ctx->killed = false;
V8JSG(timer_stack).push_front(timer_ctx);
V8JSG(timer_mutex).unlock();
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* indent-tabs-mode: t
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/