From 00057b70a5a2f2c23ca3d150216490425659c955 Mon Sep 17 00:00:00 2001 From: Adeel Date: Tue, 18 Nov 2014 17:29:46 +0200 Subject: [PATCH 01/17] Importer: Uses libsass importers. --- src/binding.cpp | 57 ++++++++++++++++++++++++++++++++++-- src/sass_context_wrapper.cpp | 3 +- src/sass_context_wrapper.h | 3 +- 3 files changed, 58 insertions(+), 5 deletions(-) diff --git a/src/binding.cpp b/src/binding.cpp index 89e3469e8..7dd76c724 100644 --- a/src/binding.cpp +++ b/src/binding.cpp @@ -12,13 +12,62 @@ char* CreateString(Local value) { return str; } +struct Sass_Import** sass_importer(const char* file, void* cookie) +{ + NanScope(); + + Handle argv[] = { + NanNew(file) + }; + + Local returned_value = NanNew(((NanCallback*)cookie)->Call(2, argv)); + + if(returned_value->IsArray()) { + Handle array = Handle::Cast(returned_value); + + struct Sass_Import** incs = sass_make_import_list(array->Length()); + + for(size_t i = 0; i < array->Length(); ++i) { + Local value = array->Get(i); + + if(!value->IsObject()) + continue; + + Local object = Local::Cast(value); + char* path = CreateString(object->Get(String::New("path"))); + char* contents = CreateString(object->Get(String::New("contents"))); + + incs[i] = sass_make_import_entry(path, (!contents || contents[0] == '\0') ? 0 : strdup(contents), 0); + } + + return incs; + } else if(returned_value->IsObject()) { + struct Sass_Import** incs = sass_make_import_list(1); + Local object = Local::Cast(returned_value); + char* path = CreateString(object->Get(String::New("path"))); + char* contents = CreateString(object->Get(String::New("contents"))); + + incs[0] = sass_make_import_entry(path, (!contents || contents[0] == '\0') ? 0 : strdup(contents), 0); + + return incs; + } + + struct Sass_Import** incs = sass_make_import_list(1); + + incs[0] = sass_make_import_entry(file, 0, 0); + + return incs; +} + void ExtractOptions(Local options, void* cptr, sass_context_wrapper* ctx_w, bool isFile) { if (ctx_w) { NanAssignPersistent(ctx_w->stats, options->Get(NanNew("stats"))->ToObject()); // async (callback) style Local callback = Local::Cast(options->Get(NanNew("success"))); - Local errorCallback = Local::Cast(options->Get(NanNew("error"))); + Local error_callback = Local::Cast(options->Get(NanNew("error"))); + Local importer_callback = Local::Cast(options->Get(NanNew("importer"))); + if (isFile) { ctx_w->fctx = (struct Sass_File_Context*) cptr; } else { @@ -26,7 +75,8 @@ void ExtractOptions(Local options, void* cptr, sass_context_wrapper* ctx } ctx_w->request.data = ctx_w; ctx_w->callback = new NanCallback(callback); - ctx_w->errorCallback = new NanCallback(errorCallback); + ctx_w->error_callback = new NanCallback(error_callback); + ctx_w->importer_callback = new NanCallback(importer_callback); } struct Sass_Context* ctx; @@ -50,6 +100,7 @@ void ExtractOptions(Local options, void* cptr, sass_context_wrapper* ctx sass_option_set_source_map_file(sass_options, CreateString(options->Get(NanNew("sourceMap")))); sass_option_set_include_path(sass_options, CreateString(options->Get(NanNew("paths")))); sass_option_set_precision(sass_options, options->Get(NanNew("precision"))->Int32Value()); + sass_option_set_importer(sass_options, sass_make_importer(sass_importer, ctx_w->importer_callback)); } void FillStatsObj(Handle stats, Sass_Context* ctx) { @@ -112,7 +163,7 @@ void MakeCallback(uv_work_t* req) { NanNew(err), NanNew(error_status) }; - ctx_w->errorCallback->Call(2, argv); + ctx_w->error_callback->Call(2, argv); } if (try_catch.HasCaught()) { node::FatalException(try_catch); diff --git a/src/sass_context_wrapper.cpp b/src/sass_context_wrapper.cpp index 5f29b0d1c..4a6acefa5 100644 --- a/src/sass_context_wrapper.cpp +++ b/src/sass_context_wrapper.cpp @@ -34,7 +34,8 @@ extern "C" { NanDisposePersistent(ctx_w->stats); delete ctx_w->callback; - delete ctx_w->errorCallback; + delete ctx_w->error_callback; + delete ctx_w->importer_callback; free(ctx_w); } diff --git a/src/sass_context_wrapper.h b/src/sass_context_wrapper.h index a4c106a6b..5612dcec8 100644 --- a/src/sass_context_wrapper.h +++ b/src/sass_context_wrapper.h @@ -17,7 +17,8 @@ struct sass_context_wrapper { Persistent stats; uv_work_t request; NanCallback* callback; - NanCallback* errorCallback; + NanCallback* error_callback; + NanCallback* importer_callback; }; struct sass_context_wrapper* sass_make_context_wrapper(void); From 3a9c84bcefca1a9ed4f8bb30a4d39d9567ae9c29 Mon Sep 17 00:00:00 2001 From: Adeel Date: Tue, 18 Nov 2014 22:23:48 +0200 Subject: [PATCH 02/17] Importer: Moves the setter inside condition. --- src/binding.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/binding.cpp b/src/binding.cpp index 7dd76c724..227c99cda 100644 --- a/src/binding.cpp +++ b/src/binding.cpp @@ -60,6 +60,16 @@ struct Sass_Import** sass_importer(const char* file, void* cookie) } void ExtractOptions(Local options, void* cptr, sass_context_wrapper* ctx_w, bool isFile) { + struct Sass_Context* ctx; + + if (isFile) { + ctx = sass_file_context_get_context((struct Sass_File_Context*) cptr); + } else { + ctx = sass_data_context_get_context((struct Sass_Data_Context*) cptr); + } + + struct Sass_Options* sass_options = sass_context_get_options(ctx); + if (ctx_w) { NanAssignPersistent(ctx_w->stats, options->Get(NanNew("stats"))->ToObject()); @@ -77,18 +87,11 @@ void ExtractOptions(Local options, void* cptr, sass_context_wrapper* ctx ctx_w->callback = new NanCallback(callback); ctx_w->error_callback = new NanCallback(error_callback); ctx_w->importer_callback = new NanCallback(importer_callback); - } - - struct Sass_Context* ctx; - if (isFile) { - ctx = sass_file_context_get_context((struct Sass_File_Context*) cptr); - } else { - ctx = sass_data_context_get_context((struct Sass_Data_Context*) cptr); + if(!importer_callback->IsUndefined()) + sass_option_set_importer(sass_options, sass_make_importer(sass_importer, ctx_w->importer_callback)); } - struct Sass_Options* sass_options = sass_context_get_options(ctx); - sass_option_set_output_path(sass_options, CreateString(options->Get(NanNew("outFile")))); sass_option_set_image_path(sass_options, CreateString(options->Get(NanNew("imagePath")))); sass_option_set_output_style(sass_options, (Sass_Output_Style)options->Get(NanNew("style"))->Int32Value()); @@ -100,7 +103,6 @@ void ExtractOptions(Local options, void* cptr, sass_context_wrapper* ctx sass_option_set_source_map_file(sass_options, CreateString(options->Get(NanNew("sourceMap")))); sass_option_set_include_path(sass_options, CreateString(options->Get(NanNew("paths")))); sass_option_set_precision(sass_options, options->Get(NanNew("precision"))->Int32Value()); - sass_option_set_importer(sass_options, sass_make_importer(sass_importer, ctx_w->importer_callback)); } void FillStatsObj(Handle stats, Sass_Context* ctx) { From fa595ff89e98078d09d64034bb50007580ee4819 Mon Sep 17 00:00:00 2001 From: Adeel Date: Tue, 18 Nov 2014 23:17:01 +0200 Subject: [PATCH 03/17] Code: Renames callback <-> success_callback. --- src/binding.cpp | 6 +++--- src/sass_context_wrapper.cpp | 2 +- src/sass_context_wrapper.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/binding.cpp b/src/binding.cpp index 227c99cda..5a3aee602 100644 --- a/src/binding.cpp +++ b/src/binding.cpp @@ -74,7 +74,7 @@ void ExtractOptions(Local options, void* cptr, sass_context_wrapper* ctx NanAssignPersistent(ctx_w->stats, options->Get(NanNew("stats"))->ToObject()); // async (callback) style - Local callback = Local::Cast(options->Get(NanNew("success"))); + Local success_callback = Local::Cast(options->Get(NanNew("success"))); Local error_callback = Local::Cast(options->Get(NanNew("error"))); Local importer_callback = Local::Cast(options->Get(NanNew("importer"))); @@ -84,7 +84,7 @@ void ExtractOptions(Local options, void* cptr, sass_context_wrapper* ctx ctx_w->dctx = (struct Sass_Data_Context*) cptr; } ctx_w->request.data = ctx_w; - ctx_w->callback = new NanCallback(callback); + ctx_w->success_callback = new NanCallback(success_callback); ctx_w->error_callback = new NanCallback(error_callback); ctx_w->importer_callback = new NanCallback(importer_callback); @@ -157,7 +157,7 @@ void MakeCallback(uv_work_t* req) { NanNew(val), NanNew(ctx_w->stats)->Get(NanNew("sourceMap")) }; - ctx_w->callback->Call(2, argv); + ctx_w->success_callback->Call(2, argv); } else { // if error, do callback(error) const char* err = sass_context_get_error_json(ctx); diff --git a/src/sass_context_wrapper.cpp b/src/sass_context_wrapper.cpp index 4a6acefa5..d4b969bcf 100644 --- a/src/sass_context_wrapper.cpp +++ b/src/sass_context_wrapper.cpp @@ -33,7 +33,7 @@ extern "C" { } NanDisposePersistent(ctx_w->stats); - delete ctx_w->callback; + delete ctx_w->success_callback; delete ctx_w->error_callback; delete ctx_w->importer_callback; diff --git a/src/sass_context_wrapper.h b/src/sass_context_wrapper.h index 5612dcec8..6fdeded5c 100644 --- a/src/sass_context_wrapper.h +++ b/src/sass_context_wrapper.h @@ -16,7 +16,7 @@ struct sass_context_wrapper { Sass_File_Context* fctx; Persistent stats; uv_work_t request; - NanCallback* callback; + NanCallback* success_callback; NanCallback* error_callback; NanCallback* importer_callback; }; From cbcacc24bf52546173082af1d718992372103a4a Mon Sep 17 00:00:00 2001 From: Adeel Date: Fri, 21 Nov 2014 14:51:59 +0200 Subject: [PATCH 04/17] libuv: Uses uv_async_send to dispatch callback. Dispatches callback to uv_default_loop. --- src/binding.cpp | 96 +++++++++++++++++++++++++------------- src/libsass | 2 +- src/sass_context_wrapper.h | 6 +++ 3 files changed, 70 insertions(+), 34 deletions(-) diff --git a/src/binding.cpp b/src/binding.cpp index 5a3aee602..c64e2ee16 100644 --- a/src/binding.cpp +++ b/src/binding.cpp @@ -2,61 +2,84 @@ #include "sass_context_wrapper.h" char* CreateString(Local value) { - if(value->IsNull() || !value->IsString()) { + if (value->IsNull() || !value->IsString()) { return const_cast(""); // return empty string. } String::Utf8Value string(value); - char *str = (char *) malloc(string.length() + 1); + char *str = (char *)malloc(string.length() + 1); strcpy(str, *string); return str; } -struct Sass_Import** sass_importer(const char* file, void* cookie) -{ +uv_async_t async; + +void dispatched_async_uv_callback(uv_async_t *req){ NanScope(); + TryCatch try_catch; + import_bag* bag = static_cast(req->data); + Handle argv[] = { - NanNew(file) + NanNew(bag->file) }; - Local returned_value = NanNew(((NanCallback*)cookie)->Call(2, argv)); + Local returned_value = NanNew(((NanCallback*)bag->cookie)->Call(1, argv)); - if(returned_value->IsArray()) { + if (returned_value->IsArray()) { Handle array = Handle::Cast(returned_value); - struct Sass_Import** incs = sass_make_import_list(array->Length()); + bag->incs = sass_make_import_list(array->Length()); - for(size_t i = 0; i < array->Length(); ++i) { + for (size_t i = 0; i < array->Length(); ++i) { Local value = array->Get(i); - if(!value->IsObject()) + if (!value->IsObject()) continue; Local object = Local::Cast(value); - char* path = CreateString(object->Get(String::New("path"))); + char* path = CreateString(object->Get(String::New("file"))); char* contents = CreateString(object->Get(String::New("contents"))); - incs[i] = sass_make_import_entry(path, (!contents || contents[0] == '\0') ? 0 : strdup(contents), 0); + bag->incs[i] = sass_make_import_entry(path, (!contents || contents[0] == '\0') ? 0 : strdup(contents), 0); } - - return incs; - } else if(returned_value->IsObject()) { - struct Sass_Import** incs = sass_make_import_list(1); + } + else if (returned_value->IsObject()) { + bag->incs = sass_make_import_list(1); Local object = Local::Cast(returned_value); - char* path = CreateString(object->Get(String::New("path"))); + char* path = CreateString(object->Get(String::New("file"))); char* contents = CreateString(object->Get(String::New("contents"))); - incs[0] = sass_make_import_entry(path, (!contents || contents[0] == '\0') ? 0 : strdup(contents), 0); + bag->incs[0] = sass_make_import_entry(path, (!contents || contents[0] == '\0') ? 0 : strdup(contents), 0); + } + else { + bag->incs = sass_make_import_list(1); + bag->incs[0] = sass_make_import_entry(bag->file, 0, 0); + } - return incs; + if (try_catch.HasCaught()) { + node::FatalException(try_catch); } +} - struct Sass_Import** incs = sass_make_import_list(1); +struct Sass_Import** sass_importer(const char* file, void* cookie) +{ + import_bag* bag = (import_bag*)calloc(1, sizeof(import_bag)); + + bag->cookie = cookie; + bag->file = file; + + async.data = (void*)bag; + uv_async_send(&async); + + // Dispatch immediately + uv_run(async.loop, UV_RUN_DEFAULT); + + Sass_Import** import = bag->incs; - incs[0] = sass_make_import_entry(file, 0, 0); + free(bag); - return incs; + return import; } void ExtractOptions(Local options, void* cptr, sass_context_wrapper* ctx_w, bool isFile) { @@ -64,7 +87,8 @@ void ExtractOptions(Local options, void* cptr, sass_context_wrapper* ctx if (isFile) { ctx = sass_file_context_get_context((struct Sass_File_Context*) cptr); - } else { + } + else { ctx = sass_data_context_get_context((struct Sass_Data_Context*) cptr); } @@ -80,7 +104,8 @@ void ExtractOptions(Local options, void* cptr, sass_context_wrapper* ctx if (isFile) { ctx_w->fctx = (struct Sass_File_Context*) cptr; - } else { + } + else { ctx_w->dctx = (struct Sass_Data_Context*) cptr; } ctx_w->request.data = ctx_w; @@ -88,8 +113,10 @@ void ExtractOptions(Local options, void* cptr, sass_context_wrapper* ctx ctx_w->error_callback = new NanCallback(error_callback); ctx_w->importer_callback = new NanCallback(importer_callback); - if(!importer_callback->IsUndefined()) + if (!importer_callback->IsUndefined()){ sass_option_set_importer(sass_options, sass_make_importer(sass_importer, ctx_w->importer_callback)); + uv_async_init(uv_default_loop(), &async, (uv_async_cb)dispatched_async_uv_callback); + } } sass_option_set_output_path(sass_options, CreateString(options->Get(NanNew("outFile")))); @@ -109,7 +136,7 @@ void FillStatsObj(Handle stats, Sass_Context* ctx) { char** included_files = sass_context_get_included_files(ctx); Handle arr = NanNew(); - if(included_files) { + if (included_files) { for (int i = 0; included_files[i] != nullptr; ++i) { arr->Set(i, NanNew(included_files[i])); } @@ -125,14 +152,15 @@ void FillStatsObj(Handle stats, Sass_Context* ctx) { if (sass_context_get_source_map_string(ctx)) { source_map = NanNew(sass_context_get_source_map_string(ctx)); - } else { + } + else { source_map = NanNew("{}"); } - (*stats)->Set(NanNew("sourceMap"), source_map); + (*stats)->Set(NanNew("sourceMap"), source_map); } -void MakeCallback(uv_work_t* req) { +void make_callback(uv_work_t* req) { NanScope(); TryCatch try_catch; @@ -144,7 +172,8 @@ void MakeCallback(uv_work_t* req) { ctx = sass_data_context_get_context(ctx_w->dctx); FillStatsObj(NanNew(ctx_w->stats), ctx); error_status = sass_context_get_error_status(ctx); - } else { + } + else { ctx = sass_file_context_get_context(ctx_w->fctx); FillStatsObj(NanNew(ctx_w->stats), ctx); error_status = sass_context_get_error_status(ctx); @@ -158,7 +187,8 @@ void MakeCallback(uv_work_t* req) { NanNew(ctx_w->stats)->Get(NanNew("sourceMap")) }; ctx_w->success_callback->Call(2, argv); - } else { + } + else { // if error, do callback(error) const char* err = sass_context_get_error_json(ctx); Local argv[] = { @@ -186,7 +216,7 @@ NAN_METHOD(Render) { ExtractOptions(options, dctx, ctx_w, false); - int status = uv_queue_work(uv_default_loop(), &ctx_w->request, compile_it, (uv_after_work_cb)MakeCallback); + int status = uv_queue_work(uv_default_loop(), &ctx_w->request, compile_it, (uv_after_work_cb)make_callback); assert(status == 0); @@ -231,7 +261,7 @@ NAN_METHOD(RenderFile) { ctx_w->fctx = fctx; ExtractOptions(options, fctx, ctx_w, true); - int status = uv_queue_work(uv_default_loop(), &ctx_w->request, compile_it, (uv_after_work_cb)MakeCallback); + int status = uv_queue_work(uv_default_loop(), &ctx_w->request, compile_it, (uv_after_work_cb)make_callback); assert(status == 0); free(input_path); diff --git a/src/libsass b/src/libsass index 5f3558d7c..21688e197 160000 --- a/src/libsass +++ b/src/libsass @@ -1 +1 @@ -Subproject commit 5f3558d7ce36bb61202f1585ed8e32a52209e940 +Subproject commit 21688e1979bff089a13d9a44ad0608357b2a91cc diff --git a/src/sass_context_wrapper.h b/src/sass_context_wrapper.h index 6fdeded5c..a86fb2b5c 100644 --- a/src/sass_context_wrapper.h +++ b/src/sass_context_wrapper.h @@ -21,6 +21,12 @@ struct sass_context_wrapper { NanCallback* importer_callback; }; +struct import_bag { + const char* file; + void* cookie; + Sass_Import** incs; +}; + struct sass_context_wrapper* sass_make_context_wrapper(void); void sass_free_context_wrapper(struct sass_context_wrapper* ctx_w); From 292e1ba5612337041ab0268a2bf7a127df3243be Mon Sep 17 00:00:00 2001 From: Adeel Date: Fri, 21 Nov 2014 22:50:23 +0200 Subject: [PATCH 05/17] Importer-cb: Adds lock to acquire v8 main thread. --- src/binding.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/binding.cpp b/src/binding.cpp index c64e2ee16..a2831fbef 100644 --- a/src/binding.cpp +++ b/src/binding.cpp @@ -1,3 +1,4 @@ +#include #include #include "sass_context_wrapper.h" @@ -12,9 +13,12 @@ char* CreateString(Local value) { return str; } -uv_async_t async; +static std::mutex importer_mutex; void dispatched_async_uv_callback(uv_async_t *req){ + std::unique_lock v8_lock(importer_mutex); + v8_lock.lock(); + //importer_mutex.lock(); NanScope(); TryCatch try_catch; @@ -57,6 +61,8 @@ void dispatched_async_uv_callback(uv_async_t *req){ bag->incs[0] = sass_make_import_entry(bag->file, 0, 0); } + v8_lock.unlock(); + //importer_mutex.unlock(); if (try_catch.HasCaught()) { node::FatalException(try_catch); } @@ -64,16 +70,20 @@ void dispatched_async_uv_callback(uv_async_t *req){ struct Sass_Import** sass_importer(const char* file, void* cookie) { + std::try_lock(importer_mutex); import_bag* bag = (import_bag*)calloc(1, sizeof(import_bag)); bag->cookie = cookie; bag->file = file; + uv_async_t async; + + uv_async_init(uv_default_loop(), &async, (uv_async_cb)dispatched_async_uv_callback); async.data = (void*)bag; uv_async_send(&async); // Dispatch immediately - uv_run(async.loop, UV_RUN_DEFAULT); + //uv_run(async.loop, UV_RUN_DEFAULT); Sass_Import** import = bag->incs; @@ -115,7 +125,6 @@ void ExtractOptions(Local options, void* cptr, sass_context_wrapper* ctx if (!importer_callback->IsUndefined()){ sass_option_set_importer(sass_options, sass_make_importer(sass_importer, ctx_w->importer_callback)); - uv_async_init(uv_default_loop(), &async, (uv_async_cb)dispatched_async_uv_callback); } } From 800738a4aea9c4dd171258681b4f544b8d6bf27e Mon Sep 17 00:00:00 2001 From: Adeel Date: Sat, 22 Nov 2014 17:43:54 +0200 Subject: [PATCH 06/17] Importer: Moves mutex in context. --- src/binding.cpp | 62 ++++++++++++++++-------------------- src/sass_context_wrapper.cpp | 5 ++- src/sass_context_wrapper.h | 13 ++++---- 3 files changed, 39 insertions(+), 41 deletions(-) diff --git a/src/binding.cpp b/src/binding.cpp index a2831fbef..0a662357a 100644 --- a/src/binding.cpp +++ b/src/binding.cpp @@ -1,4 +1,3 @@ -#include #include #include "sass_context_wrapper.h" @@ -13,27 +12,22 @@ char* CreateString(Local value) { return str; } -static std::mutex importer_mutex; - void dispatched_async_uv_callback(uv_async_t *req){ - std::unique_lock v8_lock(importer_mutex); - v8_lock.lock(); - //importer_mutex.lock(); NanScope(); + sass_context_wrapper* ctx_w = static_cast(req->data); TryCatch try_catch; - import_bag* bag = static_cast(req->data); Handle argv[] = { - NanNew(bag->file) + NanNew(ctx_w->file) }; - Local returned_value = NanNew(((NanCallback*)bag->cookie)->Call(1, argv)); + Local returned_value = NanNew(ctx_w->importer_callback->Call(1, argv)); if (returned_value->IsArray()) { Handle array = Handle::Cast(returned_value); - bag->incs = sass_make_import_list(array->Length()); + ctx_w->imports = sass_make_import_list(array->Length()); for (size_t i = 0; i < array->Length(); ++i) { Local value = array->Get(i); @@ -45,24 +39,25 @@ void dispatched_async_uv_callback(uv_async_t *req){ char* path = CreateString(object->Get(String::New("file"))); char* contents = CreateString(object->Get(String::New("contents"))); - bag->incs[i] = sass_make_import_entry(path, (!contents || contents[0] == '\0') ? 0 : strdup(contents), 0); + ctx_w->imports[i] = sass_make_import_entry(path, (!contents || contents[0] == '\0') ? 0 : strdup(contents), 0); } } else if (returned_value->IsObject()) { - bag->incs = sass_make_import_list(1); + ctx_w->imports = sass_make_import_list(1); Local object = Local::Cast(returned_value); char* path = CreateString(object->Get(String::New("file"))); char* contents = CreateString(object->Get(String::New("contents"))); - bag->incs[0] = sass_make_import_entry(path, (!contents || contents[0] == '\0') ? 0 : strdup(contents), 0); + ctx_w->imports[0] = sass_make_import_entry(path, (!contents || contents[0] == '\0') ? 0 : strdup(contents), 0); } else { - bag->incs = sass_make_import_list(1); - bag->incs[0] = sass_make_import_entry(bag->file, 0, 0); + ctx_w->imports = sass_make_import_list(1); + ctx_w->imports[0] = sass_make_import_entry(ctx_w->file, 0, 0); } - v8_lock.unlock(); - //importer_mutex.unlock(); + //uv_mutex_unlock(ctx_w->mutex); + ctx_w->importer_mutex->unlock(); + if (try_catch.HasCaught()) { node::FatalException(try_catch); } @@ -70,26 +65,24 @@ void dispatched_async_uv_callback(uv_async_t *req){ struct Sass_Import** sass_importer(const char* file, void* cookie) { - std::try_lock(importer_mutex); - import_bag* bag = (import_bag*)calloc(1, sizeof(import_bag)); - - bag->cookie = cookie; - bag->file = file; - - uv_async_t async; - - uv_async_init(uv_default_loop(), &async, (uv_async_cb)dispatched_async_uv_callback); - async.data = (void*)bag; - uv_async_send(&async); + sass_context_wrapper* ctx_w = static_cast(cookie); - // Dispatch immediately - //uv_run(async.loop, UV_RUN_DEFAULT); + uv_mutex_t t; + ctx_w->importer_mutex->lock(); + //uv_mutex_lock(ctx_w->mutex); - Sass_Import** import = bag->incs; + // Enter critical section + ctx_w->file = file; + ctx_w->async.data = (void*)&ctx_w; + uv_async_send(&ctx_w->async); - free(bag); + // Reassurances + //uv_mutex_lock(ctx_w->mutex); + //uv_mutex_unlock(ctx_w->mutex); + ctx_w->importer_mutex->lock(); + ctx_w->importer_mutex->unlock(); - return import; + return ctx_w->imports; } void ExtractOptions(Local options, void* cptr, sass_context_wrapper* ctx_w, bool isFile) { @@ -124,7 +117,8 @@ void ExtractOptions(Local options, void* cptr, sass_context_wrapper* ctx ctx_w->importer_callback = new NanCallback(importer_callback); if (!importer_callback->IsUndefined()){ - sass_option_set_importer(sass_options, sass_make_importer(sass_importer, ctx_w->importer_callback)); + uv_async_init(uv_default_loop(), &ctx_w->async, (uv_async_cb)dispatched_async_uv_callback); + sass_option_set_importer(sass_options, sass_make_importer(sass_importer, ctx_w)); } } diff --git a/src/sass_context_wrapper.cpp b/src/sass_context_wrapper.cpp index d4b969bcf..2a4e52397 100644 --- a/src/sass_context_wrapper.cpp +++ b/src/sass_context_wrapper.cpp @@ -22,7 +22,10 @@ extern "C" { } sass_context_wrapper* sass_make_context_wrapper() { - return (sass_context_wrapper*) calloc(1, sizeof(sass_context_wrapper)); + // (sass_context_wrapper*) calloc(1, sizeof(sass_context_wrapper)); + auto ctx_w = (sass_context_wrapper*) calloc(1, sizeof(sass_context_wrapper)); + ctx_w->importer_mutex = new std::recursive_mutex(); + return ctx_w; } void sass_free_context_wrapper(sass_context_wrapper* ctx_w) { diff --git a/src/sass_context_wrapper.h b/src/sass_context_wrapper.h index a86fb2b5c..fc589438b 100644 --- a/src/sass_context_wrapper.h +++ b/src/sass_context_wrapper.h @@ -1,3 +1,4 @@ +#include #include #include "libsass/sass_context.h" @@ -16,17 +17,17 @@ struct sass_context_wrapper { Sass_File_Context* fctx; Persistent stats; uv_work_t request; + std::recursive_mutex* importer_mutex; + //uv_mutex_t* mutex; + uv_async_t async; + const char* file; + void* cookie; + Sass_Import** imports; NanCallback* success_callback; NanCallback* error_callback; NanCallback* importer_callback; }; -struct import_bag { - const char* file; - void* cookie; - Sass_Import** incs; -}; - struct sass_context_wrapper* sass_make_context_wrapper(void); void sass_free_context_wrapper(struct sass_context_wrapper* ctx_w); From 1d597d5f422335c408adf6a47ebadff0025a5c7a Mon Sep 17 00:00:00 2001 From: Adeel Date: Sat, 22 Nov 2014 19:23:42 +0200 Subject: [PATCH 07/17] Importer: Fixes issue with casting. --- src/binding.cpp | 8 ++++---- src/sass_context_wrapper.cpp | 2 +- src/sass_context_wrapper.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/binding.cpp b/src/binding.cpp index 0a662357a..941c8bcaa 100644 --- a/src/binding.cpp +++ b/src/binding.cpp @@ -1,3 +1,4 @@ +#include #include #include "sass_context_wrapper.h" @@ -19,7 +20,7 @@ void dispatched_async_uv_callback(uv_async_t *req){ TryCatch try_catch; Handle argv[] = { - NanNew(ctx_w->file) + NanNew(strdup(ctx_w->file)) }; Local returned_value = NanNew(ctx_w->importer_callback->Call(1, argv)); @@ -67,13 +68,12 @@ struct Sass_Import** sass_importer(const char* file, void* cookie) { sass_context_wrapper* ctx_w = static_cast(cookie); - uv_mutex_t t; ctx_w->importer_mutex->lock(); //uv_mutex_lock(ctx_w->mutex); // Enter critical section - ctx_w->file = file; - ctx_w->async.data = (void*)&ctx_w; + ctx_w->file = strdup(file); + ctx_w->async.data = (void*)ctx_w; uv_async_send(&ctx_w->async); // Reassurances diff --git a/src/sass_context_wrapper.cpp b/src/sass_context_wrapper.cpp index 2a4e52397..bbc3bfbe7 100644 --- a/src/sass_context_wrapper.cpp +++ b/src/sass_context_wrapper.cpp @@ -24,7 +24,7 @@ extern "C" { sass_context_wrapper* sass_make_context_wrapper() { // (sass_context_wrapper*) calloc(1, sizeof(sass_context_wrapper)); auto ctx_w = (sass_context_wrapper*) calloc(1, sizeof(sass_context_wrapper)); - ctx_w->importer_mutex = new std::recursive_mutex(); + ctx_w->importer_mutex = new std::mutex(); return ctx_w; } diff --git a/src/sass_context_wrapper.h b/src/sass_context_wrapper.h index fc589438b..80ec6be7a 100644 --- a/src/sass_context_wrapper.h +++ b/src/sass_context_wrapper.h @@ -17,7 +17,7 @@ struct sass_context_wrapper { Sass_File_Context* fctx; Persistent stats; uv_work_t request; - std::recursive_mutex* importer_mutex; + std::mutex* importer_mutex; //uv_mutex_t* mutex; uv_async_t async; const char* file; From 670cc89853aa49f9ab48b151c115299a945246c8 Mon Sep 17 00:00:00 2001 From: Adeel Date: Sat, 22 Nov 2014 19:26:19 +0200 Subject: [PATCH 08/17] Code: Cleanup and formatting. --- src/binding.cpp | 1 - src/sass_context_wrapper.cpp | 8 ++++--- src/sass_context_wrapper.h | 42 ++++++++++++++++++------------------ 3 files changed, 26 insertions(+), 25 deletions(-) diff --git a/src/binding.cpp b/src/binding.cpp index 941c8bcaa..3d912548d 100644 --- a/src/binding.cpp +++ b/src/binding.cpp @@ -1,4 +1,3 @@ -#include #include #include "sass_context_wrapper.h" diff --git a/src/sass_context_wrapper.cpp b/src/sass_context_wrapper.cpp index bbc3bfbe7..f6606e9c2 100644 --- a/src/sass_context_wrapper.cpp +++ b/src/sass_context_wrapper.cpp @@ -8,7 +8,8 @@ extern "C" { if (ctx_w->dctx) { compile_data(ctx_w->dctx); - } else if (ctx_w->fctx) { + } + else if (ctx_w->fctx) { compile_file(ctx_w->fctx); } } @@ -23,7 +24,7 @@ extern "C" { sass_context_wrapper* sass_make_context_wrapper() { // (sass_context_wrapper*) calloc(1, sizeof(sass_context_wrapper)); - auto ctx_w = (sass_context_wrapper*) calloc(1, sizeof(sass_context_wrapper)); + auto ctx_w = (sass_context_wrapper*)calloc(1, sizeof(sass_context_wrapper)); ctx_w->importer_mutex = new std::mutex(); return ctx_w; } @@ -31,7 +32,8 @@ extern "C" { void sass_free_context_wrapper(sass_context_wrapper* ctx_w) { if (ctx_w->dctx) { sass_delete_data_context(ctx_w->dctx); - } else if (ctx_w->fctx) { + } + else if (ctx_w->fctx) { sass_delete_file_context(ctx_w->fctx); } diff --git a/src/sass_context_wrapper.h b/src/sass_context_wrapper.h index 80ec6be7a..36b3964ca 100644 --- a/src/sass_context_wrapper.h +++ b/src/sass_context_wrapper.h @@ -6,30 +6,30 @@ extern "C" { #endif -using namespace v8; + using namespace v8; -void compile_data(struct Sass_Data_Context* dctx); -void compile_file(struct Sass_File_Context* fctx); -void compile_it(uv_work_t* req); + void compile_data(struct Sass_Data_Context* dctx); + void compile_file(struct Sass_File_Context* fctx); + void compile_it(uv_work_t* req); -struct sass_context_wrapper { - Sass_Data_Context* dctx; - Sass_File_Context* fctx; - Persistent stats; - uv_work_t request; - std::mutex* importer_mutex; - //uv_mutex_t* mutex; - uv_async_t async; - const char* file; - void* cookie; - Sass_Import** imports; - NanCallback* success_callback; - NanCallback* error_callback; - NanCallback* importer_callback; -}; + struct sass_context_wrapper { + Sass_Data_Context* dctx; + Sass_File_Context* fctx; + Persistent stats; + uv_work_t request; + std::mutex* importer_mutex; + //uv_mutex_t* mutex; + uv_async_t async; + const char* file; + void* cookie; + Sass_Import** imports; + NanCallback* success_callback; + NanCallback* error_callback; + NanCallback* importer_callback; + }; -struct sass_context_wrapper* sass_make_context_wrapper(void); -void sass_free_context_wrapper(struct sass_context_wrapper* ctx_w); + struct sass_context_wrapper* sass_make_context_wrapper(void); + void sass_free_context_wrapper(struct sass_context_wrapper* ctx_w); #ifdef __cplusplus } From b2ce0f6f48bf88f33a14c961bdc2a2d47e935fcc Mon Sep 17 00:00:00 2001 From: Adeel Date: Sat, 22 Nov 2014 22:57:32 +0200 Subject: [PATCH 09/17] Importer: Sleep() before second locks. --- src/binding.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/binding.cpp b/src/binding.cpp index 3d912548d..3fc461f9a 100644 --- a/src/binding.cpp +++ b/src/binding.cpp @@ -78,6 +78,7 @@ struct Sass_Import** sass_importer(const char* file, void* cookie) // Reassurances //uv_mutex_lock(ctx_w->mutex); //uv_mutex_unlock(ctx_w->mutex); + Sleep(5); ctx_w->importer_mutex->lock(); ctx_w->importer_mutex->unlock(); From 2e82e70f699c334784bf079d82d83da08d839e0f Mon Sep 17 00:00:00 2001 From: Adeel Date: Wed, 26 Nov 2014 16:46:05 +0200 Subject: [PATCH 10/17] Importer: Uses uv_cond to solve the puzzle. Credit goes to @txdv. --- src/binding.cpp | 14 ++------------ src/libsass | 2 +- src/sass_context_wrapper.cpp | 4 ++-- src/sass_context_wrapper.h | 5 ++--- 4 files changed, 7 insertions(+), 18 deletions(-) diff --git a/src/binding.cpp b/src/binding.cpp index 3fc461f9a..0f31412fc 100644 --- a/src/binding.cpp +++ b/src/binding.cpp @@ -55,8 +55,7 @@ void dispatched_async_uv_callback(uv_async_t *req){ ctx_w->imports[0] = sass_make_import_entry(ctx_w->file, 0, 0); } - //uv_mutex_unlock(ctx_w->mutex); - ctx_w->importer_mutex->unlock(); + uv_cond_signal(&ctx_w->importer_condition_variable); if (try_catch.HasCaught()) { node::FatalException(try_catch); @@ -67,20 +66,11 @@ struct Sass_Import** sass_importer(const char* file, void* cookie) { sass_context_wrapper* ctx_w = static_cast(cookie); - ctx_w->importer_mutex->lock(); - //uv_mutex_lock(ctx_w->mutex); - - // Enter critical section ctx_w->file = strdup(file); ctx_w->async.data = (void*)ctx_w; uv_async_send(&ctx_w->async); - // Reassurances - //uv_mutex_lock(ctx_w->mutex); - //uv_mutex_unlock(ctx_w->mutex); - Sleep(5); - ctx_w->importer_mutex->lock(); - ctx_w->importer_mutex->unlock(); + uv_cond_wait(&ctx_w->importer_condition_variable, &ctx_w->importer_mutex); return ctx_w->imports; } diff --git a/src/libsass b/src/libsass index 21688e197..a94377b5a 160000 --- a/src/libsass +++ b/src/libsass @@ -1 +1 @@ -Subproject commit 21688e1979bff089a13d9a44ad0608357b2a91cc +Subproject commit a94377b5aac6a10a6aa3ed90656557e7b9843fd1 diff --git a/src/sass_context_wrapper.cpp b/src/sass_context_wrapper.cpp index f6606e9c2..a846b9971 100644 --- a/src/sass_context_wrapper.cpp +++ b/src/sass_context_wrapper.cpp @@ -23,9 +23,9 @@ extern "C" { } sass_context_wrapper* sass_make_context_wrapper() { - // (sass_context_wrapper*) calloc(1, sizeof(sass_context_wrapper)); auto ctx_w = (sass_context_wrapper*)calloc(1, sizeof(sass_context_wrapper)); - ctx_w->importer_mutex = new std::mutex(); + uv_mutex_init(&ctx_w->importer_mutex); + uv_cond_init(&ctx_w->importer_condition_variable); return ctx_w; } diff --git a/src/sass_context_wrapper.h b/src/sass_context_wrapper.h index 36b3964ca..dd027756b 100644 --- a/src/sass_context_wrapper.h +++ b/src/sass_context_wrapper.h @@ -1,4 +1,3 @@ -#include #include #include "libsass/sass_context.h" @@ -17,8 +16,8 @@ extern "C" { Sass_File_Context* fctx; Persistent stats; uv_work_t request; - std::mutex* importer_mutex; - //uv_mutex_t* mutex; + uv_mutex_t importer_mutex; + uv_cond_t importer_condition_variable; uv_async_t async; const char* file; void* cookie; From f5a19be9243c26d6be97a01908ac8a74ba309fac Mon Sep 17 00:00:00 2001 From: Adeel Date: Wed, 26 Nov 2014 17:37:12 +0200 Subject: [PATCH 11/17] Importer: Destroys vars before leaving the scope. --- src/sass_context_wrapper.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sass_context_wrapper.cpp b/src/sass_context_wrapper.cpp index a846b9971..1a2a55bf2 100644 --- a/src/sass_context_wrapper.cpp +++ b/src/sass_context_wrapper.cpp @@ -38,9 +38,15 @@ extern "C" { } NanDisposePersistent(ctx_w->stats); + delete ctx_w->success_callback; delete ctx_w->error_callback; delete ctx_w->importer_callback; + delete ctx_w->file; + delete ctx_w->cookie; + + uv_mutex_destroy(&ctx_w->importer_mutex); + uv_cond_destroy(&ctx_w->importer_condition_variable); free(ctx_w); } From fd8c7f76918a26ef30fc5bf5d556895c4a4633b2 Mon Sep 17 00:00:00 2001 From: Adeel Date: Thu, 11 Dec 2014 09:22:51 +0200 Subject: [PATCH 12/17] Importer: Adds callback for asynchrony. --- lib/index.js | 12 ++++++ src/binding.cpp | 101 +++++++++++++++++++++++++++++++----------------- 2 files changed, 78 insertions(+), 35 deletions(-) diff --git a/lib/index.js b/lib/index.js index be514d16a..dca322d36 100644 --- a/lib/index.js +++ b/lib/index.js @@ -150,6 +150,7 @@ function getOptions(options) { var error = options.error; var success = options.success; + var importer = options.importer; options.error = function(err, code) { try { @@ -171,6 +172,17 @@ function getOptions(options) { } }; + if (importer) { + options.importer = function(file, key) { + importer(file, function(data) { + binding.importedCallback({ + index: key, + objectLiteral: data + }); + }); + }; + } + delete options.image_path; delete options.include_paths; delete options.includePaths; diff --git a/src/binding.cpp b/src/binding.cpp index 0f31412fc..379e46066 100644 --- a/src/binding.cpp +++ b/src/binding.cpp @@ -1,4 +1,5 @@ #include +#include #include "sass_context_wrapper.h" char* CreateString(Local value) { @@ -12,50 +13,22 @@ char* CreateString(Local value) { return str; } +std::vector imports_collection; + void dispatched_async_uv_callback(uv_async_t *req){ NanScope(); sass_context_wrapper* ctx_w = static_cast(req->data); TryCatch try_catch; + imports_collection.push_back(ctx_w); + Handle argv[] = { - NanNew(strdup(ctx_w->file)) + NanNew(strdup(ctx_w->file)), + NanNew(imports_collection.size() - 1) }; - Local returned_value = NanNew(ctx_w->importer_callback->Call(1, argv)); - - if (returned_value->IsArray()) { - Handle array = Handle::Cast(returned_value); - - ctx_w->imports = sass_make_import_list(array->Length()); - - for (size_t i = 0; i < array->Length(); ++i) { - Local value = array->Get(i); - - if (!value->IsObject()) - continue; - - Local object = Local::Cast(value); - char* path = CreateString(object->Get(String::New("file"))); - char* contents = CreateString(object->Get(String::New("contents"))); - - ctx_w->imports[i] = sass_make_import_entry(path, (!contents || contents[0] == '\0') ? 0 : strdup(contents), 0); - } - } - else if (returned_value->IsObject()) { - ctx_w->imports = sass_make_import_list(1); - Local object = Local::Cast(returned_value); - char* path = CreateString(object->Get(String::New("file"))); - char* contents = CreateString(object->Get(String::New("contents"))); - - ctx_w->imports[0] = sass_make_import_entry(path, (!contents || contents[0] == '\0') ? 0 : strdup(contents), 0); - } - else { - ctx_w->imports = sass_make_import_list(1); - ctx_w->imports[0] = sass_make_import_entry(ctx_w->file, 0, 0); - } - - uv_cond_signal(&ctx_w->importer_condition_variable); + NanNew(ctx_w->importer_callback->Call(2, argv)); if (try_catch.HasCaught()) { node::FatalException(try_catch); @@ -290,11 +263,69 @@ NAN_METHOD(RenderFileSync) { NanReturnUndefined(); } +NAN_METHOD(ImportedCallback) { + NanScope(); + + TryCatch try_catch; + + Local options = args[0]->ToObject(); + char* source_string = CreateString(options->Get(NanNew("index"))); + Local returned_value = options->Get(NanNew("objectLiteral")); + + size_t index = options->Get(NanNew("index"))->Int32Value(); + + if (index >= imports_collection.size()) { + NanReturnUndefined(); + } + + sass_context_wrapper* ctx_w = imports_collection[index]; + + if (returned_value->IsArray()) { + Handle array = Handle::Cast(returned_value); + + ctx_w->imports = sass_make_import_list(array->Length()); + + for (size_t i = 0; i < array->Length(); ++i) { + Local value = array->Get(i); + + if (!value->IsObject()) + continue; + + Local object = Local::Cast(value); + char* path = CreateString(object->Get(String::New("file"))); + char* contents = CreateString(object->Get(String::New("contents"))); + + ctx_w->imports[i] = sass_make_import_entry(path, (!contents || contents[0] == '\0') ? 0 : strdup(contents), 0); + } + } + else if (returned_value->IsObject()) { + ctx_w->imports = sass_make_import_list(1); + Local object = Local::Cast(returned_value); + char* path = CreateString(object->Get(String::New("file"))); + char* contents = CreateString(object->Get(String::New("contents"))); + + ctx_w->imports[0] = sass_make_import_entry(path, (!contents || contents[0] == '\0') ? 0 : strdup(contents), 0); + } + else { + ctx_w->imports = sass_make_import_list(1); + ctx_w->imports[0] = sass_make_import_entry(ctx_w->file, 0, 0); + } + + uv_cond_signal(&ctx_w->importer_condition_variable); + + NanReturnValue(NanNew(0)); + + if (try_catch.HasCaught()) { + node::FatalException(try_catch); + } +} + void RegisterModule(v8::Handle target) { NODE_SET_METHOD(target, "render", Render); NODE_SET_METHOD(target, "renderSync", RenderSync); NODE_SET_METHOD(target, "renderFile", RenderFile); NODE_SET_METHOD(target, "renderFileSync", RenderFileSync); + NODE_SET_METHOD(target, "importedCallback", ImportedCallback); } NODE_MODULE(binding, RegisterModule); From 5afecaf0dbc4ecf478482a6950701a18d64f133b Mon Sep 17 00:00:00 2001 From: Adeel Date: Thu, 11 Dec 2014 09:24:47 +0200 Subject: [PATCH 13/17] Upstream: Fetches latest libsass. --- src/libsass | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsass b/src/libsass index a94377b5a..7aaa45a97 160000 --- a/src/libsass +++ b/src/libsass @@ -1 +1 @@ -Subproject commit a94377b5aac6a10a6aa3ed90656557e7b9843fd1 +Subproject commit 7aaa45a979ce65d50b3158ff50bf9409f8955063 From eedc835d438bff4233b76f94a40d58b16bdba35d Mon Sep 17 00:00:00 2001 From: Adeel Date: Sun, 14 Dec 2014 06:59:51 +0200 Subject: [PATCH 14/17] Importer: Adds importer support for renderSync. * Adds code comments. --- src/binding.cpp | 71 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 25 deletions(-) diff --git a/src/binding.cpp b/src/binding.cpp index 379e46066..d4d4b5e7b 100644 --- a/src/binding.cpp +++ b/src/binding.cpp @@ -43,46 +43,58 @@ struct Sass_Import** sass_importer(const char* file, void* cookie) ctx_w->async.data = (void*)ctx_w; uv_async_send(&ctx_w->async); - uv_cond_wait(&ctx_w->importer_condition_variable, &ctx_w->importer_mutex); + if (ctx_w->success_callback) { + /* that is async: Render() or RenderFile(), + * the default even loop is unblocked so it + * can run uv_async_send without a push. + */ + uv_cond_wait(&ctx_w->importer_condition_variable, &ctx_w->importer_mutex); + } + else{ + /* that is sync: RenderSync() or RenderFileSync, + * we need to explicitly uv_run as the event loop + * is blocked; waiting down the chain. + */ + uv_run(ctx_w->async.loop, UV_RUN_DEFAULT); + } return ctx_w->imports; } -void ExtractOptions(Local options, void* cptr, sass_context_wrapper* ctx_w, bool isFile) { +void ExtractOptions(Local options, void* cptr, sass_context_wrapper* ctx_w, bool isFile, bool isSync) { struct Sass_Context* ctx; if (isFile) { ctx = sass_file_context_get_context((struct Sass_File_Context*) cptr); + ctx_w->fctx = (struct Sass_File_Context*) cptr; } else { ctx = sass_data_context_get_context((struct Sass_Data_Context*) cptr); + ctx_w->dctx = (struct Sass_Data_Context*) cptr; } struct Sass_Options* sass_options = sass_context_get_options(ctx); - if (ctx_w) { + if (!isSync) { NanAssignPersistent(ctx_w->stats, options->Get(NanNew("stats"))->ToObject()); + ctx_w->request.data = ctx_w; + // async (callback) style Local success_callback = Local::Cast(options->Get(NanNew("success"))); Local error_callback = Local::Cast(options->Get(NanNew("error"))); - Local importer_callback = Local::Cast(options->Get(NanNew("importer"))); - if (isFile) { - ctx_w->fctx = (struct Sass_File_Context*) cptr; - } - else { - ctx_w->dctx = (struct Sass_Data_Context*) cptr; - } - ctx_w->request.data = ctx_w; ctx_w->success_callback = new NanCallback(success_callback); ctx_w->error_callback = new NanCallback(error_callback); - ctx_w->importer_callback = new NanCallback(importer_callback); + } - if (!importer_callback->IsUndefined()){ - uv_async_init(uv_default_loop(), &ctx_w->async, (uv_async_cb)dispatched_async_uv_callback); - sass_option_set_importer(sass_options, sass_make_importer(sass_importer, ctx_w)); - } + Local importer_callback = Local::Cast(options->Get(NanNew("importer"))); + + ctx_w->importer_callback = new NanCallback(importer_callback); + + if (!importer_callback->IsUndefined()) { + uv_async_init(uv_default_loop(), &ctx_w->async, (uv_async_cb)dispatched_async_uv_callback); + sass_option_set_importer(sass_options, sass_make_importer(sass_importer, ctx_w)); } sass_option_set_output_path(sass_options, CreateString(options->Get(NanNew("outFile")))); @@ -178,9 +190,7 @@ NAN_METHOD(Render) { struct Sass_Data_Context* dctx = sass_make_data_context(source_string); sass_context_wrapper* ctx_w = sass_make_context_wrapper(); - ctx_w->dctx = dctx; - - ExtractOptions(options, dctx, ctx_w, false); + ExtractOptions(options, dctx, ctx_w, false, false); int status = uv_queue_work(uv_default_loop(), &ctx_w->request, compile_it, (uv_after_work_cb)make_callback); @@ -196,8 +206,9 @@ NAN_METHOD(RenderSync) { char* source_string = CreateString(options->Get(NanNew("data"))); struct Sass_Data_Context* dctx = sass_make_data_context(source_string); struct Sass_Context* ctx = sass_data_context_get_context(dctx); + sass_context_wrapper* ctx_w = sass_make_context_wrapper(); - ExtractOptions(options, dctx, NULL, false); + ExtractOptions(options, dctx, ctx_w, false, true); compile_data(dctx); FillStatsObj(options->Get(NanNew("stats"))->ToObject(), ctx); @@ -211,6 +222,7 @@ NAN_METHOD(RenderSync) { Local error = NanNew(sass_context_get_error_json(ctx)); sass_delete_data_context(dctx); + sass_free_context_wrapper(ctx_w); NanThrowError(error); NanReturnUndefined(); @@ -224,8 +236,7 @@ NAN_METHOD(RenderFile) { struct Sass_File_Context* fctx = sass_make_file_context(input_path); sass_context_wrapper* ctx_w = sass_make_context_wrapper(); - ctx_w->fctx = fctx; - ExtractOptions(options, fctx, ctx_w, true); + ExtractOptions(options, fctx, ctx_w, true, false); int status = uv_queue_work(uv_default_loop(), &ctx_w->request, compile_it, (uv_after_work_cb)make_callback); @@ -242,8 +253,9 @@ NAN_METHOD(RenderFileSync) { char* input_path = CreateString(options->Get(NanNew("file"))); struct Sass_File_Context* fctx = sass_make_file_context(input_path); struct Sass_Context* ctx = sass_file_context_get_context(fctx); + sass_context_wrapper* ctx_w = sass_make_context_wrapper(); - ExtractOptions(options, fctx, NULL, true); + ExtractOptions(options, fctx, ctx_w, true, true); compile_file(fctx); FillStatsObj(options->Get(NanNew("stats"))->ToObject(), ctx); free(input_path); @@ -258,6 +270,7 @@ NAN_METHOD(RenderFileSync) { Local error = NanNew(sass_context_get_error_json(ctx)); sass_delete_file_context(fctx); + sass_free_context_wrapper(ctx_w); NanThrowError(error); NanReturnUndefined(); @@ -313,11 +326,19 @@ NAN_METHOD(ImportedCallback) { uv_cond_signal(&ctx_w->importer_condition_variable); - NanReturnValue(NanNew(0)); - if (try_catch.HasCaught()) { node::FatalException(try_catch); } + + if (!ctx_w->success_callback) { + /* + * that is sync: RenderSync() or RenderFileSync, + * we ran it explictly, so we stop it similarly. + */ + uv_stop(ctx_w->async.loop); + } + + NanReturnValue(NanNew(0)); } void RegisterModule(v8::Handle target) { From b0013a0027cfc313bbdea887005a3a0c4ca52652 Mon Sep 17 00:00:00 2001 From: Adeel Date: Thu, 18 Dec 2014 13:18:40 +0200 Subject: [PATCH 15/17] Importer: Adds support for previous. --- lib/index.js | 4 ++-- src/binding.cpp | 6 ++++-- src/sass_context_wrapper.cpp | 1 + src/sass_context_wrapper.h | 1 + 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/index.js b/lib/index.js index dca322d36..a9feb90a1 100644 --- a/lib/index.js +++ b/lib/index.js @@ -173,8 +173,8 @@ function getOptions(options) { }; if (importer) { - options.importer = function(file, key) { - importer(file, function(data) { + options.importer = function(file, prev, key) { + importer(file, prev, function(data) { binding.importedCallback({ index: key, objectLiteral: data diff --git a/src/binding.cpp b/src/binding.cpp index d4d4b5e7b..49ebca164 100644 --- a/src/binding.cpp +++ b/src/binding.cpp @@ -25,21 +25,23 @@ void dispatched_async_uv_callback(uv_async_t *req){ Handle argv[] = { NanNew(strdup(ctx_w->file)), + NanNew(strdup(ctx_w->prev)), NanNew(imports_collection.size() - 1) }; - NanNew(ctx_w->importer_callback->Call(2, argv)); + NanNew(ctx_w->importer_callback->Call(3, argv)); if (try_catch.HasCaught()) { node::FatalException(try_catch); } } -struct Sass_Import** sass_importer(const char* file, void* cookie) +struct Sass_Import** sass_importer(const char* file, const char* prev, void* cookie) { sass_context_wrapper* ctx_w = static_cast(cookie); ctx_w->file = strdup(file); + ctx_w->prev = strdup(prev); ctx_w->async.data = (void*)ctx_w; uv_async_send(&ctx_w->async); diff --git a/src/sass_context_wrapper.cpp b/src/sass_context_wrapper.cpp index 1a2a55bf2..35023e1b1 100644 --- a/src/sass_context_wrapper.cpp +++ b/src/sass_context_wrapper.cpp @@ -43,6 +43,7 @@ extern "C" { delete ctx_w->error_callback; delete ctx_w->importer_callback; delete ctx_w->file; + delete ctx_w->prev; delete ctx_w->cookie; uv_mutex_destroy(&ctx_w->importer_mutex); diff --git a/src/sass_context_wrapper.h b/src/sass_context_wrapper.h index dd027756b..902a70df1 100644 --- a/src/sass_context_wrapper.h +++ b/src/sass_context_wrapper.h @@ -20,6 +20,7 @@ extern "C" { uv_cond_t importer_condition_variable; uv_async_t async; const char* file; + const char* prev; void* cookie; Sass_Import** imports; NanCallback* success_callback; From 3d035c3b7fc9293ea880e7d0e235de63a1f5cf03 Mon Sep 17 00:00:00 2001 From: Adeel Date: Thu, 18 Dec 2014 13:46:58 +0200 Subject: [PATCH 16/17] Importer: Removes free context from Sync handlers. --- src/binding.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/binding.cpp b/src/binding.cpp index 49ebca164..417dcc6f7 100644 --- a/src/binding.cpp +++ b/src/binding.cpp @@ -223,7 +223,6 @@ NAN_METHOD(RenderSync) { Local error = NanNew(sass_context_get_error_json(ctx)); - sass_delete_data_context(dctx); sass_free_context_wrapper(ctx_w); NanThrowError(error); @@ -271,7 +270,6 @@ NAN_METHOD(RenderFileSync) { Local error = NanNew(sass_context_get_error_json(ctx)); - sass_delete_file_context(fctx); sass_free_context_wrapper(ctx_w); NanThrowError(error); From 5a6bd67f26bab48266e8d372b2f2ed9ad932378e Mon Sep 17 00:00:00 2001 From: Adeel Date: Thu, 18 Dec 2014 13:57:56 +0200 Subject: [PATCH 17/17] Upstream: Updates spec to 3.1-apha equivalent mark --- test/fixtures/spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fixtures/spec b/test/fixtures/spec index b85c617a0..074ae3b24 160000 --- a/test/fixtures/spec +++ b/test/fixtures/spec @@ -1 +1 @@ -Subproject commit b85c617a0e7e5367dd347b0b301ad1c15b6d5087 +Subproject commit 074ae3b24bfc3ff19a98efdec02415ed6fd5759a