Skip to content

Commit 7e46e9f

Browse files
committed
Use TSFN threaded callbacks
1 parent 97bc642 commit 7e46e9f

21 files changed

+329
-330
lines changed

index.d.ts

Lines changed: 107 additions & 106 deletions
Large diffs are not rendered by default.

index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ cl.Wrapper.prototype[inspect.custom] = cl.Wrapper.prototype.toString;
2020
let cached = null;
2121

2222
const showDevices = (devices, mainDevice) => {
23-
console.log(
23+
console.info(
2424
'AVAILABLE DEVICES:',
2525
devices.map(({ name, version }) => `${version} ${name}`),
2626
);
27-
console.log('ACTIVE DEVICE:', `${mainDevice.version} ${mainDevice.name}`);
27+
console.info('ACTIVE DEVICE:', `${mainDevice.version} ${mainDevice.name}`);
2828
};
2929

3030
cl.quickStart = (isLoggingDevices = false) => {

src/cpp/bindings.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include "./wrapper.cpp"
12
#include "./queue.cpp"
23
#include "./common.cpp"
34
#include "./context.cpp"
@@ -8,7 +9,6 @@
89
#include "./platform.cpp"
910
#include "./program.cpp"
1011
#include "./sampler.cpp"
11-
#include "./types.cpp"
1212

1313

1414
#define JS_CL_CONSTANT(name) \

src/cpp/common.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ void getPtrAndLen(Napi::Object obj, void** ptr, size_t *len) {
1616
}
1717
}
1818

19-
#define CASE_RET(CODE, MSG) case CODE: return MSG;
20-
2119
const char* getExceptionMessage(const cl_int code) {
2220
switch (code) {
2321
case CL_SUCCESS:
@@ -143,7 +141,7 @@ const char* getExceptionMessage(const cl_int code) {
143141
case CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR:
144142
return "Invalid GL sharegroup reference";
145143
default:
146-
printf("OpenCL Unknown error: %d\n", code);
144+
fprintf(stderr, "OpenCL Unknown error: %d\n", code);
147145
return "Unknown error";
148146
}
149147
}

src/cpp/context.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#include "types.hpp"
1+
#include "wrapper.hpp"
22

33

44
namespace opencl {
@@ -128,7 +128,7 @@ JS_METHOD(getContextInfo) { NAPI_ENV;
128128
Napi::Array arr = Napi::Array::New(env);
129129
for(size_t i = 0; i < n; i++) {
130130
CHECK_ERR(clRetainDevice(devices[i]))
131-
arr.Set(i, Wrapper::fromRaw(env, devices[i]));
131+
arr.Set(i, Wrapper::from(env, devices[i]));
132132
}
133133
RET_VALUE(arr);
134134
}

src/cpp/device.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#include "types.hpp"
1+
#include "wrapper.hpp"
22

33

44
namespace opencl {
@@ -26,7 +26,7 @@ JS_METHOD(getDeviceIDs) { NAPI_ENV;
2626
for (uint32_t i = 0; i < n; i++) {
2727
// This is a noop for root-level devices but properly retains sub-devices.
2828
CHECK_ERR(clRetainDevice(devices[i]));
29-
deviceArray.Set(i, Wrapper::fromRaw(env, devices[i]));
29+
deviceArray.Set(i, Wrapper::from(env, devices[i]));
3030
}
3131

3232
RET_VALUE(deviceArray);
@@ -386,7 +386,7 @@ JS_METHOD(createSubDevices) { NAPI_ENV;
386386

387387
Napi::Array subDevicesArray = Napi::Array::New(env);
388388
for (uint32_t i = 0; i<capacity; i++) {
389-
subDevicesArray.Set(i, Wrapper::fromRaw(env, subDevices[i]));
389+
subDevicesArray.Set(i, Wrapper::from(env, subDevices[i]));
390390
}
391391

392392
RET_VALUE(subDevicesArray);

src/cpp/event.cpp

Lines changed: 8 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
#include <uv.h>
22

3-
#include "types.hpp"
3+
#include "wrapper.hpp"
44
#include "common.hpp"
5+
#include "notify-helper.hpp"
56

67

78
namespace opencl {
@@ -132,91 +133,17 @@ JS_METHOD(getEventProfilingInfo) { NAPI_ENV;
132133
THROW_ERR(CL_INVALID_VALUE);
133134
}
134135

135-
136-
class EventWorker : public Napi::AsyncWorker {
137-
public:
138-
EventWorker(Napi::Function callback, Napi::Object userData, Napi::Object wrapper):
139-
Napi::AsyncWorker(callback, "CL::EventWorker") {
140-
_refEvent.Reset(wrapper, 1);
141-
_refData.Reset(userData, 1);
142-
this->async = new uv_async_t();
143-
this->async->data = reinterpret_cast<void*>(this);
144-
uv_async_init(
145-
uv_default_loop(),
146-
this->async,
147-
(uv_async_cb)
148-
dispatched_async_uv_callback
149-
);
150-
}
151-
152-
~EventWorker() {
153-
uv_close(reinterpret_cast<uv_handle_t*>(this->async), &delete_async_handle);
154-
}
155-
156-
uv_async_t *async;
157-
158-
void setStatus(int status) {
159-
_status = status;
160-
}
161-
162-
// Executed inside the worker-thread.
163-
void Execute() {
164-
}
165-
166-
// Executed when the async work is complete
167-
// this function will be run inside the main event loop
168-
void OnOK () {
169-
Napi::Env env = Env();
170-
NAPI_HS;
171-
Callback().Call({
172-
_refData.Value(), // userdata
173-
JS_NUM(_status), // error status
174-
_refEvent.Value() // event
175-
});
176-
}
177-
178-
protected:
179-
static void delete_async_handle(uv_handle_t *handle);
180-
// The callback invoked by the call to uv_async_send() in notifyCB.
181-
// Invoked on the main thread, so it's safe to call AsyncQueueWorker.
182-
static void dispatched_async_uv_callback(uv_async_t*);
183-
184-
private:
185-
int _status = 0;
186-
Napi::ObjectReference _refEvent;
187-
Napi::ObjectReference _refData;
188-
};
189-
190-
void EventWorker::delete_async_handle(uv_handle_t *handle) {
191-
delete reinterpret_cast<uv_async_t*>(handle);
192-
}
193-
194-
void EventWorker::dispatched_async_uv_callback(uv_async_t *req) {
195-
EventWorker* asyncCB = static_cast<EventWorker*>(req->data);
196-
asyncCB->Queue();
197-
}
198-
199-
// callback invoked off the main thread by clSetEventCallback
200-
void CL_CALLBACK notifyCB (cl_event event, cl_int event_command_exec_status, void *user_data) {
201-
EventWorker* asyncCB = reinterpret_cast<EventWorker*>(user_data);
202-
asyncCB->setStatus(event_command_exec_status);
203-
// send a message to the main thread to safely invoke the JS callback
204-
uv_async_send(asyncCB->async);
205-
}
206-
207136
JS_METHOD(setEventCallback) { NAPI_ENV;
208137
REQ_CL_ARG(0, ev, cl_event);
209138
REQ_UINT32_ARG(1, callbackStatusType);
210139
REQ_FUN_ARG(2, callback);
211-
LET_OBJ_ARG(3, userData);
212140

213-
EventWorker* asyncCB = new EventWorker(
214-
callback,
215-
userData,
216-
info[0].As<Napi::Object>()
217-
);
218-
219-
CHECK_ERR(clSetEventCallback(ev, callbackStatusType, notifyCB, asyncCB));
141+
CHECK_ERR(clSetEventCallback(
142+
ev,
143+
callbackStatusType,
144+
NotifyHelper<cl_event>::callNotifyStatus,
145+
new NotifyHelper<cl_event>(callback, info[3])
146+
));
220147

221148
RET_NUM(CL_SUCCESS);
222149
}

src/cpp/kernel.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#include <utility>
44
#include <tuple>
55

6-
#include "types.hpp"
6+
#include "wrapper.hpp"
77

88

99
namespace opencl {
@@ -33,7 +33,7 @@ JS_METHOD(createKernelsInProgram) { NAPI_ENV;
3333

3434
Napi::Array karr = Napi::Array::New(env);
3535
for(cl_uint i = 0; i < numkernels; i++) {
36-
karr.Set(i, Wrapper::fromRaw(env, kernels[i]));
36+
karr.Set(i, Wrapper::from(env, kernels[i]));
3737
}
3838
delete[] kernels;
3939

src/cpp/memobj.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#include "types.hpp"
1+
#include "wrapper.hpp"
22

33

44
namespace opencl {

src/cpp/notify-helper.hpp

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#pragma once
2+
3+
#include "wrapper.hpp"
4+
5+
namespace opencl {
6+
7+
template<typename T>
8+
class NotifyHelper {
9+
public:
10+
NotifyHelper(Napi::Function callback, Napi::Value userData) {
11+
Napi::Env env = callback.Env();
12+
_tsfn = Napi::ThreadSafeFunction::New(
13+
env, callback, Napi::Object(), "NotifyHelper", 0, 1, _delete
14+
);
15+
16+
_ref.Reset(Napi::Object::New(env), 1);
17+
_ref.Set("cb", callback);
18+
_ref.Set("data", userData);
19+
}
20+
21+
~NotifyHelper() {
22+
Napi::Env env = _ref.Env();
23+
_ref.Set("cb", JS_NULL);
24+
_ref.Set("data", JS_NULL);
25+
_ref.Reset();
26+
}
27+
28+
static void CL_CALLBACK callNotify(T resource, void *ptr) {
29+
NotifyHelper *notifier = reinterpret_cast<NotifyHelper*>(ptr);
30+
notifier->_notify(resource);
31+
}
32+
static void CL_CALLBACK callNotifyStatus(T resource, cl_int status, void *ptr) {
33+
NotifyHelper *notifier = reinterpret_cast<NotifyHelper*>(ptr);
34+
notifier->_notifyStatus(resource, status);
35+
}
36+
37+
private:
38+
Napi::ObjectReference _ref;
39+
Napi::ThreadSafeFunction _tsfn;
40+
41+
static void _delete(napi_env env, void* data, void*) {
42+
if (data != nullptr) {
43+
NotifyHelper* that = static_cast<NotifyHelper*>(data);
44+
delete that;
45+
}
46+
}
47+
48+
void _notify(T resource) {
49+
NotifyHelper *that = this;
50+
napi_status result = _tsfn.NonBlockingCall(
51+
[that, resource](Napi::Env env, Napi::Function callback) {
52+
callback.Call(
53+
that->_ref.Value(),
54+
{ Wrapper::from(env, resource), that->_ref.Get("data") }
55+
);
56+
}
57+
);
58+
if (result != napi_ok) {
59+
fprintf(stderr, "Error: can't call TSFN (#%d).\n", result);
60+
}
61+
62+
_tsfn.Release();
63+
}
64+
65+
void _notifyStatus(T resource, cl_int status) {
66+
NotifyHelper *that = this;
67+
napi_status result = _tsfn.NonBlockingCall(
68+
[that, resource, status](Napi::Env env, Napi::Function callback) {
69+
callback.Call(
70+
that->_ref.Value(),
71+
{ Wrapper::from(env, resource), JS_NUM(status), that->_ref.Get("data") }
72+
);
73+
}
74+
);
75+
if (result != napi_ok) {
76+
fprintf(stderr, "Error: can't call TSFN (#%d).\n", result);
77+
}
78+
79+
_tsfn.Release();
80+
}
81+
};
82+
83+
} // namespace opencl

0 commit comments

Comments
 (0)