Skip to content
This repository was archived by the owner on Jul 24, 2024. It is now read-only.

Commit b659f0b

Browse files
committed
Implement timeout for callbacks
1 parent 9bf96cf commit b659f0b

2 files changed

Lines changed: 46 additions & 26 deletions

File tree

src/binding.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,15 @@ Sass_Import_List sass_importer(const char* cur_path, Sass_Importer_Entry cb, str
1818
argv.push_back((void*)prev_path);
1919

2020
TRACEINST(&bridge) << "Importer will be executed";
21-
return bridge(argv);
21+
22+
Sass_Import_List retval = bridge(argv);
23+
if (bridge.timedout) {
24+
TRACEINST(&bridge) << "Importer timeout";
25+
retval = sass_make_import_list(1);
26+
retval[0] = sass_make_import_entry(0, 0, 0);
27+
sass_import_set_error(retval[0], "Importer timed out or blocked (>2000ms)", -1, -1);
28+
}
29+
return retval;
2230
}
2331

2432
union Sass_Value* sass_custom_function(const union Sass_Value* s_args, Sass_Function_Entry cb, struct Sass_Options* opts)
@@ -32,7 +40,13 @@ union Sass_Value* sass_custom_function(const union Sass_Value* s_args, Sass_Func
3240
}
3341

3442
TRACEINST(&bridge) << "Function will be executed";
35-
return bridge(argv);
43+
Sass_Value *retval = bridge(argv);
44+
if (bridge.timedout) {
45+
TRACEINST(&bridge) << "Function timeout";
46+
return sass_make_error("Function timed out or blocked (>2000ms)");
47+
} else
48+
return retval;
49+
}
3650
}
3751

3852
int ExtractOptions(v8::Local<v8::Object> options, void* cptr, sass_context_wrapper* ctx_w, bool is_file, bool is_sync) {

src/callback_bridge.h

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class CallbackBridge {
2020

2121
// Executes the callback
2222
T operator()(std::vector<void*>);
23+
int timedout;
2324

2425
protected:
2526
// We will expose a bridge object to the JS callback that wraps this instance so we don't loose context.
@@ -60,7 +61,7 @@ template <typename T, typename L>
6061
Nan::Persistent<v8::Function> CallbackBridge<T, L>::wrapper_constructor;
6162

6263
template <typename T, typename L>
63-
CallbackBridge<T, L>::CallbackBridge(v8::Local<v8::Function> callback, bool is_sync) : callback(new Nan::Callback(callback)), is_sync(is_sync) {
64+
CallbackBridge<T, L>::CallbackBridge(v8::Local<v8::Function> callback, bool is_sync) : timedout(0), callback(new Nan::Callback(callback)), is_sync(is_sync) {
6465
/*
6566
* This is invoked from the main JavaScript thread.
6667
* V8 context is available.
@@ -70,7 +71,7 @@ CallbackBridge<T, L>::CallbackBridge(v8::Local<v8::Function> callback, bool is_s
7071
}
7172

7273
template <typename T, typename L>
73-
CallbackBridge<T, L>::CallbackBridge(const CallbackBridge<T,L>& other) : callback(new Nan::Callback(other.callback->GetFunction())), is_sync(other.is_sync) {
74+
CallbackBridge<T, L>::CallbackBridge(const CallbackBridge<T,L>& other) : timedout(0), callback(new Nan::Callback(other.callback->GetFunction())), is_sync(other.is_sync) {
7475
/*
7576
* This is invoked from the main JavaScript thread.
7677
* V8 context is available.
@@ -99,6 +100,7 @@ CallbackBridge<T, L>::operator= (const CallbackBridge<T,L>& other)
99100

100101
this->callback = new Nan::Callback(other.callback->GetFunction());
101102
this->is_sync = other.is_sync;
103+
this->timedout = 0;
102104
init_uv();
103105
init_wrapper();
104106
}
@@ -179,12 +181,12 @@ T CallbackBridge<T, L>::operator()(std::vector<void*> argv) {
179181
* async I/O executed from JavaScript callbacks.
180182
*/
181183
this->argv = argv;
182-
184+
this->timedout = 0;
183185
uv_mutex_lock(&this->cv_mutex);
184186
this->has_returned = false;
185187
uv_async_send(this->async);
186-
while (!this->has_returned) {
187-
uv_cond_wait(&this->condition_variable, &this->cv_mutex);
188+
while (!this->has_returned && this->timedout == 0) {
189+
this->timedout = uv_cond_timedwait(&this->condition_variable, &this->cv_mutex, 2 * (uint64_t)1e9);
188190
}
189191
uv_mutex_unlock(&this->cv_mutex);
190192
return this->return_value;
@@ -204,19 +206,21 @@ void CallbackBridge<T, L>::dispatched_async_uv_callback(uv_async_t *req) {
204206
* from types invoked by pre_process_args() and
205207
* post_process_args().
206208
*/
207-
Nan::HandleScope scope;
208-
Nan::TryCatch try_catch;
209+
if (!bridge->timedout) {
210+
Nan::HandleScope scope;
211+
Nan::TryCatch try_catch;
209212

210-
std::vector<v8::Local<v8::Value>> argv_v8 = bridge->pre_process_args(bridge->argv);
211-
if (try_catch.HasCaught()) {
212-
Nan::FatalException(try_catch);
213-
}
214-
argv_v8.push_back(Nan::New(bridge->wrapper));
213+
std::vector<v8::Local<v8::Value>> argv_v8 = bridge->pre_process_args(bridge->argv);
214+
if (try_catch.HasCaught()) {
215+
Nan::FatalException(try_catch);
216+
}
217+
argv_v8.push_back(Nan::New(bridge->wrapper));
215218

216-
bridge->callback->Call(argv_v8.size(), &argv_v8[0]);
219+
bridge->callback->Call(argv_v8.size(), &argv_v8[0]);
217220

218-
if (try_catch.HasCaught()) {
219-
Nan::FatalException(try_catch);
221+
if (try_catch.HasCaught()) {
222+
Nan::FatalException(try_catch);
223+
}
220224
}
221225
}
222226

@@ -233,18 +237,20 @@ NAN_METHOD(CallbackBridge<T COMMA L>::ReturnCallback) {
233237
CallbackBridge<T, L>* bridge = static_cast<CallbackBridge<T, L>*>(Nan::GetInternalFieldPointer(info.This(), 0));
234238
Nan::TryCatch try_catch;
235239

236-
bridge->return_value = bridge->post_process_return_value(info[0]);
240+
if (!bridge->timedout) {
241+
bridge->return_value = bridge->post_process_return_value(info[0]);
237242

238-
{
239-
uv_mutex_lock(&bridge->cv_mutex);
240-
bridge->has_returned = true;
241-
uv_mutex_unlock(&bridge->cv_mutex);
242-
}
243+
{
244+
uv_mutex_lock(&bridge->cv_mutex);
245+
bridge->has_returned = true;
246+
uv_mutex_unlock(&bridge->cv_mutex);
247+
}
243248

244-
uv_cond_broadcast(&bridge->condition_variable);
249+
uv_cond_broadcast(&bridge->condition_variable);
245250

246-
if (try_catch.HasCaught()) {
247-
Nan::FatalException(try_catch);
251+
if (try_catch.HasCaught()) {
252+
Nan::FatalException(try_catch);
253+
}
248254
}
249255
}
250256

0 commit comments

Comments
 (0)