Skip to content

Instantly share code, notes, and snippets.

@jesperp
Created May 13, 2012 18:34
Show Gist options
  • Save jesperp/2689667 to your computer and use it in GitHub Desktop.
Save jesperp/2689667 to your computer and use it in GitHub Desktop.
GraphicsMagick in node binding freezes
#include <node.h>
#include <Magick++.h>
#include <iostream>
#include <string>
using namespace v8;
Handle<Value> Async(const Arguments& args);
void AsyncWork(uv_work_t* req);
void AsyncAfter(uv_work_t* req);
struct Baton {
uv_work_t request;
Persistent<Function> callback;
bool error;
std::string error_message;
int32_t result;
};
Handle<Value> Async(const Arguments& args) {
HandleScope scope;
if (!args[0]->IsFunction()) {
return ThrowException(Exception::TypeError(
String::New("First argument must be a callback function")));
}
Local<Function> callback = Local<Function>::Cast(args[0]);
Baton* baton = new Baton();
baton->error = false;
baton->request.data = baton;
baton->callback = Persistent<Function>::New(callback);
int status = uv_queue_work(uv_default_loop(), &baton->request, AsyncWork, AsyncAfter);
assert(status == 0);
return Undefined();
}
void AsyncWork(uv_work_t* req) {
std::cout << "AsyncWork..." << std::endl;
Baton* baton = static_cast<Baton*>(req->data);
baton->result = 42;
Magick::Image image; // <---- Freezes here!
image.read("snow.jpg");
std::cout << "Scaling..." << std::endl;
image.scale("200");
std::cout << "Done!" << std::endl;
image.write("snow-scaled.jpg");
// and baton->error to true.
}
void AsyncAfter(uv_work_t* req) {
HandleScope scope;
Baton* baton = static_cast<Baton*>(req->data);
if (baton->error) {
Local<Value> err = Exception::Error(String::New(baton->error_message.c_str()));
const unsigned argc = 1;
Local<Value> argv[argc] = { err };
TryCatch try_catch;
baton->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
} else {
const unsigned argc = 2;
Local<Value> argv[argc] = {
Local<Value>::New(Null()),
Local<Value>::New(Integer::New(baton->result))
};
TryCatch try_catch;
baton->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
}
baton->callback.Dispose();
delete baton;
}
void RegisterModule(Handle<Object> target) {
target->Set(String::NewSymbol("async"), FunctionTemplate::New(Async)->GetFunction());
}
void init (Handle<Object> target){
Magick::InitializeMagick(0);
RegisterModule(target);
}
NODE_MODULE(modulename, init);
#!/usr/bin/env python
from os import popen
def set_options(ctx):
ctx.tool_options('compiler_cxx')
def configure(ctx):
ctx.check_tool('compiler_cxx')
ctx.check_tool('node_addon')
gmagick_config = ctx.find_program('GraphicsMagick++-config', mandatory=True)
ctx.env.append_value("CPPFLAGS", ''.join(popen("%s --cxxflags --cppflags" % gmagick_config).readlines()).strip().split())
ctx.env.append_value("LINKFLAGS", ''.join(popen("%s --ldflags --libs" % gmagick_config).readlines()).strip().split())
def build(ctx):
t = ctx.new_task_gen('cxx', 'shlib', 'node_addon')
t.source = ['modulename.cpp']
t.target = 'modulename'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment