| Index: src/Timeout.cpp |
| =================================================================== |
| new file mode 100644 |
| --- /dev/null |
| +++ b/src/Timeout.cpp |
| @@ -0,0 +1,120 @@ |
| +/* |
| + * This file is part of Adblock Plus <https://adblockplus.org/>, |
| + * Copyright (C) 2006-2017 Eyeo GmbH |
| + * |
| + * Adblock Plus is free software: you can redistribute it and/or modify |
| + * it under the terms of the GNU General Public License version 3 as |
| + * published by the Free Software Foundation. |
| + * |
| + * Adblock Plus is distributed in the hope that it will be useful, |
| + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + * GNU General Public License for more details. |
| + * |
| + * You should have received a copy of the GNU General Public License |
| + * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
| + */ |
| + |
| +#include "JsEngineInternal.h" |
| +#include "JsEngineTransition.h" |
| +#include "Scheduler.h" |
| +#include "Timeout.h" |
| +#include "Utils.h" |
| + |
| +namespace |
| +{ |
| + class TimeoutTask |
| + : public TaskFunctionInterface |
| + { |
| + typedef int64_t delayType; // return type of v8::Value::GetInteger() |
| + /** |
| + * shared_ptr ensures the engine remains in existence |
| + * while we're waiting for the task to complete. |
| + * The scheduler ought to undertake this responsibility, |
| + * but until then we must do it ourselves. |
| + */ |
| + JsEngineInternal* engine; |
| + V8PersistentNG<v8::Function> function; |
| + delayType delay; |
| + PersistentValueArray functionArguments; |
| + DelayedExecutor executor; |
| + |
| + void body() |
| + { |
| + V8ExecutionScope sentry(engine); |
| + auto isolate = engine->GetIsolate(); |
| + engine->ApplyFunction(function.Get(isolate), functionArguments.GetAsLocal(isolate)); |
| + } |
| + |
| + public: |
| + TimeoutTask( |
| + JsEngineInternal *engine, |
| + V8PersistentNG<v8::Function> function, |
| + delayType delay, |
| + PersistentValueArray functionArguments |
| + ) : |
| + engine(engine), |
| + function(function), |
| + delay(delay), |
| + functionArguments(std::move(functionArguments)), |
| + executor([this]() { body(); }) |
| + {} |
| + |
| + void operator()() override |
| + { |
| + executor.RunWithDelay(std::chrono::milliseconds(delay)); |
| + } |
| + |
| + void Interrupt() override |
| + { |
| + executor.ForestallExecution(); |
| + } |
| + }; |
| +} |
| + |
| +/** |
| + * Callback function registered to v8 to implement `SetTimeout` |
| + * |
| + * Note that this implementation does not support the "evaluate code" version |
| + * of `SetTimeout`, only the "apply function" version. |
| + * |
| + * \par Reference |
| + * https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout |
| + */ |
| +v8::Handle<v8::Value> CallbackForSetTimeout(const v8::Arguments& arguments) |
| +{ |
| + auto engine = JsEngineInternal::ExtractEngine(arguments); |
| + try |
| + { |
| + if (arguments.Length() < 2) |
| + { |
| + throw std::runtime_error("setTimeout: must have at least 2 arguments"); |
| + } |
| + if (!arguments[0]->IsFunction()) |
| + { |
| + throw std::runtime_error("setTimeout: argument 1 must be a function"); |
| + } |
| + auto isolate = engine->GetIsolate(); |
| + size_t n = arguments.Length() - 2; |
| + PersistentValueArray functionArguments(n); |
| + for (size_t i = 0; i < n; i++) |
| + { |
| + functionArguments[i] = V8PersistentNG<v8::Value>(isolate, arguments[i + 2]); |
| + } |
| + /* |
| + * Run the task |
| + */ |
| + auto task(std::make_shared<TimeoutTask>(engine, |
| + V8PersistentNG<v8::Function>(isolate, v8::Local<v8::Function>::Cast(arguments[0])), |
| + arguments[1]->IntegerValue(), std::move(functionArguments))); |
| + engine->ScheduleTask(std::move(task), ImmediateSingleUseThread); |
| + // We should actually return the timer ID here, which could be |
| + // used via clearTimeout(). But since we don't seem to need |
| + // clearTimeout(), we can save that for later. |
| + return v8::Undefined(); |
| + } |
| + catch (const std::exception& e) |
| + { |
| + return v8::ThrowException(engine->ToV8String(e.what())); |
| + } |
| +} |