123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- /*
- +----------------------------------------------------------------------+
- | PHP Version 7 |
- +----------------------------------------------------------------------+
- | Copyright (c) 1997-2013 The PHP Group |
- +----------------------------------------------------------------------+
- | http://www.opensource.org/licenses/mit-license.php MIT License |
- +----------------------------------------------------------------------+
- | Author: Jani Taskinen <[email protected]> |
- | Author: Patrick Reilly <[email protected]> |
- +----------------------------------------------------------------------+
- */
- #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
- */
|