Skip to content

Instantly share code, notes, and snippets.

@TooTallNate
Created November 16, 2011 00:57
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save TooTallNate/1368935 to your computer and use it in GitHub Desktop.
A C header file to make your node bindings backwards and forwards compatible that use eio_custom()

node_async_shim.h

Use this header file to conditionally invoke eio_custom() or uv_queue_work(), depending on the node version that the module is being compiled for.

See the usage.cc file for a partial example.

Comments, forks, and improvements are welcome!

/**
* eio_custom() vs. uv_queue_work() file.
* Original gist: https://gist.github.com/1368935
*
* Copyright (c) 2011-2012, Nathan Rajlich <nathan@tootallnate.net>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <node.h>
#include <node_version.h>
/* Node Thread Pool version compat */
#if NODE_VERSION_AT_LEAST(0, 5, 6)
#define BEGIN_ASYNC(_data, async, after) \
uv_work_t *_req = new uv_work_t; \
_req->data = _data; \
uv_queue_work(uv_default_loop(), _req, async, after);
typedef void async_rtn;
#define RETURN_ASYNC
#define RETURN_ASYNC_AFTER delete req;
#else
#define BEGIN_ASYNC(data, async, after) \
ev_ref(EV_DEFAULT_UC); \
eio_custom(async, EIO_PRI_DEFAULT, after, data);
typedef int async_rtn;
typedef eio_req uv_work_t;
#define RETURN_ASYNC return 0;
#define RETURN_ASYNC_AFTER \
ev_unref(EV_DEFAULT_UC); \
RETURN_ASYNC;
#endif
/**
* The "Thread Pool" function
*/
async_rtn doing_work (uv_work_t *req) {
my_struct *m = (my_struct *)req->data;
/* Something computationally expensive here */
r->rtn = 1 + 1;
RETURN_ASYNC
}
/**
* The "After" function
*/
async_rtn after_doing_work (uv_work_t *req) {
HandleScope scope;
my_struct *m = (my_struct *)req->data;
Handle<Value> argv[1];
argv[0] = Integer::New(r->rtn);
TryCatch try_catch;
m->callback->Call(Context::GetCurrent()->Global(), 1, argv);
if (try_catch.HasCaught())
FatalException(try_catch);
// cleanup
m->callback.Dispose();
delete m;
RETURN_ASYNC_AFTER
}
/**
* The JS Entry Point
*/
Handle<Value> start_doing_work (const Arguments& args) {
HandleScope scope;
my_struct *m = new my_struct;
m->callback = Persistent<Function>::New(Local<Function>::Cast(args[0]));
/* Start the async function on the thread pool */
BEGIN_ASYNC(m, doing_work, after_doing_work);
return Undefined();
}
@Sannis
Copy link

Sannis commented Mar 31, 2012

Regardles to your defines, RETURN_ASYNC_AFTER and RETURN_ASYNC should be used without semicolon?)

@TooTallNate
Copy link
Author

@Sannis Ya you're right. It hasn't caused any compiler error for me though. I've updated the gist, thanks :)

@Sannis
Copy link

Sannis commented Mar 31, 2012

Thanks, it will be more conform with node.h macroses.

@teeler
Copy link

teeler commented Oct 31, 2012

This looks broken - you mention r->rtn - what is r?

@victusfate
Copy link

Heyo Nate, I'm seeing maybe a missing header?

error: no matching function for call to 'uv_queue_work'
BEGIN_ASYNC(pm, asyncWriteTask, afterWriteTask);

checking recent v0.10.0 docs to see if uv_queue_work moved

oh, this may help

/Users/messel/.node-gyp/0.10.0/deps/uv/include/uv.h:1397:15: note: candidate function not viable: no known conversion from
      'async_rtn (uv_work_t *)' to 'uv_after_work_cb' (aka 'void (*)(uv_work_t *, int)') for 4th argument
UV_EXTERN int uv_queue_work(uv_loop_t* loop, uv_work_t* req,

looks like I need to convert the callback to
void (*)(uv_work_t *, int)

got it, just need to cast it.

#include 
#include 

/* Node Thread Pool version compat */
#if NODE_VERSION_AT_LEAST(0, 5, 6)
  #define BEGIN_ASYNC(_data, async, after) \
    uv_work_t *_req = new uv_work_t; \
    _req->data = _data; \
    uv_queue_work(uv_default_loop(), _req, async, (uv_after_work_cb)after);
  typedef void async_rtn;
  #define RETURN_ASYNC
  #define RETURN_ASYNC_AFTER delete req;
#else
  #define BEGIN_ASYNC(data, async, after) \
    ev_ref(EV_DEFAULT_UC); \
    eio_custom(async, EIO_PRI_DEFAULT, after, data);
  typedef int async_rtn;
  typedef eio_req uv_work_t;
  #define RETURN_ASYNC return 0;
  #define RETURN_ASYNC_AFTER \
    ev_unref(EV_DEFAULT_UC); \
    RETURN_ASYNC;
#endif

@tim-kos
Copy link

tim-kos commented Jan 14, 2014

This does not work for 0.10.24 right? I tried it and it seemed to work, but then it said it could not find symbol module.

It seems a call to NODE_MODULE() is required now. Do you guys have any insights into this? If not, then I'd go and try to get it to work with https://github.com/rvagg/nan.

Thanks in advance for any pointers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment