Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions generate/templates/manual/include/async_libgit2_queue_worker.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#ifndef ASYNC_LIBGIT2_QUEUE_WORKER_H
#define ASYNC_LIBGIT2_QUEUE_WORKER_H

#include <nan.h>
#include <uv.h>
#include "nodegit.h"

// Frees the uv_async_t handle
NAN_INLINE void AsyncLibgit2Free(uv_handle_t* uv_async) {
// freeing the handle can crash the app... perhaps libuv needs it
// after the async callback returns, in which case we can't free it from
// within the async callback...
// free(uv_async);
}

// Runs WorkComplete of the scheduled AsyncWorker,
// and destroys it. This is run in the uv_default_loop event loop.
NAN_INLINE void AsyncLibgit2Complete (uv_async_t* uv_async) {
Nan::AsyncWorker *worker = static_cast<Nan::AsyncWorker*>(uv_async->data);
worker->WorkComplete();
worker->Destroy();
// it doesn't look like this is a good place to close the handle
// - it can cause the tests to hang - perhaps libuv expects it to be
// upen throughout the callback
// uv_close((uv_handle_t *)uv_async, AsyncLibgit2Free);
}

// Runs Execute of the scheduled AyncWorker on the dedicated libgit2 thread /
// event loop, and schedules the WorkComplete callback to run on the
// uv_default_loop event loop
NAN_INLINE void AsyncLibgit2Execute (uv_async_t* uv_async) {
Nan::AsyncWorker *worker = static_cast<Nan::AsyncWorker*>(uv_async->data);
worker->Execute();
// it doesn't look like this is a good place to clean up the handle
// - it can cause the tests to hang - perhaps libuv expects it to be
// upen throughout the callback
// uv_close((uv_handle_t *)uv_async, AsyncLibgit2Free);

// maybe we can reuse the first handle? not sure, making a new one
uv_async = (uv_async_t *)malloc(sizeof(uv_async_t));
uv_async_init(uv_default_loop(), uv_async, AsyncLibgit2Complete);
uv_async->data = worker;
uv_async_send(uv_async);
}

// Schedules the AsyncWorker to run on the dedicated libgit2 thread / event loop.
NAN_INLINE void AsyncLibgit2QueueWorker (Nan::AsyncWorker* worker) {
uv_async_t *uv_async = (uv_async_t *)malloc(sizeof(uv_async_t));
uv_async_init(libgit2_loop, uv_async, AsyncLibgit2Execute);
uv_async->data = worker;
uv_async_send(uv_async);
}

#endif
9 changes: 9 additions & 0 deletions generate/templates/manual/include/nodegit.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#ifndef NODEGIT_H
#define NODEGIT_H

#include "nan.h"

extern uv_loop_t *libgit2_loop;
extern uv_mutex_t *libgit2_mutex;

#endif
6 changes: 5 additions & 1 deletion generate/templates/partials/async_function.cc
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,13 @@ NAN_METHOD({{ cppClassName }}::{{ cppFunctionName }}) {
{%endif%}
{%endeach%}

Nan::AsyncQueueWorker(worker);
AsyncLibgit2QueueWorker(worker);
return;
}

void {{ cppClassName }}::{{ cppFunctionName }}Worker::Execute() {
uv_mutex_lock(libgit2_mutex);

{%if .|hasReturnType %}
{{ return.cType }} result = {{ cFunctionName }}(
{%else%}
Expand All @@ -92,6 +94,8 @@ void {{ cppClassName }}::{{ cppFunctionName }}Worker::Execute() {
{%endeach%}
);

uv_mutex_unlock(libgit2_mutex);

{%if return.isErrorCode %}
baton->error_code = result;

Expand Down
7 changes: 7 additions & 0 deletions generate/templates/partials/callback_helpers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,19 @@
baton->done = false;

uv_async_init(uv_default_loop(), &baton->req, (uv_async_cb) {{ cppFunctionName }}_{{ cbFunction.name }}_async);

// release the libgit2_mutex so the callback can call libgit2 functions
// from the sync thread
uv_mutex_unlock(libgit2_mutex);

uv_async_send(&baton->req);

while(!baton->done) {
sleep_for_ms(1);
}

uv_mutex_lock(libgit2_mutex);

{% each cbFunction|returnsInfo false true as _return %}
{% if _return.isOutParam %}
*{{ _return.name }} = *baton->{{ _return.name }};
Expand Down
7 changes: 7 additions & 0 deletions generate/templates/partials/field_accessors.cc
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,19 @@
baton->done = false;

uv_async_init(uv_default_loop(), &baton->req, (uv_async_cb) {{ field.name }}_async);

// release the libgit2_mutex so the callback can call libgit2 functions
// from the sync thread
uv_mutex_unlock(libgit2_mutex);

uv_async_send(&baton->req);

while(!baton->done) {
sleep_for_ms(1);
}

uv_mutex_lock(libgit2_mutex);

{% each field|returnsInfo false true as _return %}
{% if _return.isOutParam %}
*{{ _return.name }} = *baton->{{ _return.name }};
Expand Down
5 changes: 5 additions & 0 deletions generate/templates/partials/sync_function.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ NAN_METHOD({{ cppClassName }}::{{ cppFunctionName }}) {
if (Nan::ObjectWrap::Unwrap<{{ cppClassName }}>(info.This())->GetValue() != NULL) {
{% endif %}

uv_mutex_lock(libgit2_mutex);

{%if .|hasReturnValue %}
{{ return.cType }} result = {%endif%}{{ cFunctionName }}(
{%each args|argsInfo as arg %}
Expand All @@ -51,6 +53,9 @@ from_{{ arg.name }}
{%endeach%}
);

uv_mutex_unlock(libgit2_mutex);


{%if .|hasReturnValue |and return.isErrorCode %}
if (result != GIT_OK) {
{%each args|argsInfo as arg %}
Expand Down
1 change: 1 addition & 0 deletions generate/templates/templates/class_content.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ extern "C" {
#include "../include/functions/copy.h"
#include "../include/{{ filename }}.h"
#include "../include/functions/sleep_for_ms.h"
#include "../include/async_libgit2_queue_worker.h"

{% each dependencies as dependency %}
#include "{{ dependency }}"
Expand Down
31 changes: 31 additions & 0 deletions generate/templates/templates/nodegit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <node.h>
#include <git2.h>

#include "../include/nodegit.h"
#include "../include/wrapper.h"
#include "../include/functions/copy.h"
{% each %}
Expand All @@ -11,6 +12,8 @@
{% endif %}
{% endeach %}

void run_libgit2_event_queue(void *);

extern "C" void init(Local<v8::Object> target) {
Nan::HandleScope scope;

Expand All @@ -20,6 +23,34 @@ extern "C" void init(Local<v8::Object> target) {
{{ cppClassName }}::InitializeComponent(target);
{% endif %}
{% endeach %}

// initialize a thread on which we will execute all libgit2 calls
// for async NodeGit wrappers
libgit2_loop = (uv_loop_t *)malloc(sizeof(uv_loop_t));
uv_loop_init(libgit2_loop);

uv_thread_t libgit2_thread_id;
uv_thread_create(&libgit2_thread_id, run_libgit2_event_queue, NULL);

// initialize a mutex to control exclusive access to libgit2 between
// the async thread and the sync thread
libgit2_mutex = (uv_mutex_t *)malloc(sizeof(uv_mutex_t));
uv_mutex_init(libgit2_mutex);
}

NODE_MODULE(nodegit, init)

uv_loop_t *libgit2_loop;
uv_mutex_t *libgit2_mutex;

void run_libgit2_event_queue(void *)
{
// run, CPU, run
for ( ; ; ) {
uv_run(libgit2_loop, UV_RUN_DEFAULT);
// TODO: break out of loop
}

uv_loop_close(libgit2_loop);
free(libgit2_loop);
}
3 changes: 2 additions & 1 deletion generate/templates/templates/struct_content.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ extern "C" {
}

#include <iostream>
#include "../include/nodegit.h"
#include "../include/functions/copy.h"
#include "../include/{{ filename }}.h"
#include "../include/functions/sleep_for_ms.h"
Expand Down Expand Up @@ -61,7 +62,7 @@ using namespace std;
{% endif %}
{% endif %}
{% endeach %}

if (this->selfFreeing) {
free(this->raw);
}
Expand Down