From cf9234e856aa7e4ff6c8c40e4f5a36b338941586 Mon Sep 17 00:00:00 2001 From: Mathias Buus Date: Wed, 24 Jul 2019 16:52:17 +0200 Subject: [PATCH] reimpl --- binding.gyp | 23 ++++++ fuse-native.c | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++ index.js | 47 ++++++++++++ package.json | 28 +++++++ semaphore.h | 40 ++++++++++ 5 files changed, 339 insertions(+) create mode 100644 binding.gyp create mode 100644 fuse-native.c create mode 100644 index.js create mode 100644 package.json create mode 100644 semaphore.h diff --git a/binding.gyp b/binding.gyp new file mode 100644 index 0000000..0d91380 --- /dev/null +++ b/binding.gyp @@ -0,0 +1,23 @@ +{ + "targets": [{ + "target_name": "fuse", + "include_dirs": [ + " +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +typedef struct { + napi_env env; + pthread_t thread; + pthread_attr_t attr; + napi_ref ctx; + napi_ref on_op; + struct fuse *fuse; + uv_async_t async; +} fuse_thread_t; + +typedef struct { + int hello; + fuse_thread_t *fuse; + fuse_native_semaphore_t sem; + uv_async_t async; + + // char *reply; + +} fuse_thread_locals_t; + +static pthread_key_t thread_locals_key; + +// static fuse_thread_locals_t * thread_local_map[1024]; +// static int thread_local_map_length = 0; + +// static int get_free_thread_id () { +// for (int i = 0; i < thread_local_map_length; i++) { +// if (thread_local_map[i] == NULL) return i; +// } + +// return thread_local_map_length++; +// } + + +static void fin (napi_env env, void *fin_data, void* fin_hint) { + printf("finaliser is run\n"); + // exit(0); +} + +static void fuse_native_dispatch (uv_async_t* handle, int status) { + fuse_thread_locals_t *l = (fuse_thread_locals_t *) handle->data; + fuse_thread_t *ft = l->fuse; + + napi_env env = ft->env; + napi_handle_scope scope; + + napi_open_handle_scope(env, &scope); + + napi_value ctx; + napi_get_reference_value(env, ft->ctx, &ctx); + + napi_value callback; + napi_get_reference_value(env, ft->on_op, &callback); + + // int ptr = get_free_thread_id() + // thread_local_map[ptr] = l + + napi_value argv[1]; + napi_create_external_buffer(env, sizeof(fuse_thread_locals_t), l, &fin, NULL, &(argv[0])); + + NAPI_MAKE_CALLBACK(env, NULL, ctx, callback, 1, argv, NULL) + + napi_close_handle_scope(env, scope); +} + +static fuse_thread_locals_t* get_thread_locals () { + void *data = pthread_getspecific(thread_locals_key); + + if (data != NULL) { + return (fuse_thread_locals_t *) data; + } + + fuse_thread_locals_t* l = (fuse_thread_locals_t *) malloc(sizeof(fuse_thread_locals_t)); + + l->hello = 42; + + // TODO: mutex me?? + int err = uv_async_init(uv_default_loop(), &(l->async), (uv_async_cb) fuse_native_dispatch); + + l->async.data = l; + + if (err < 0) { + printf("uv_async failed: %i\n", err); + return NULL; + } + + fuse_native_semaphore_init(&(l->sem)); + pthread_setspecific(thread_locals_key, (void *) l); + + return l; +} + +static void* start_fuse_thread (void *data) { + fuse_thread_t *ft = (fuse_thread_t *) data; + fuse_loop_mt(ft->fuse); + + // printf("her nu\n"); + // fuse_unmount(mnt, ch); + // fuse_session_remove_chan(ch); + // fuse_destroy(fuse); + + return NULL; +} + +static int fuse_native_getattr (const char *path, struct stat *stat) { + printf("hi\n"); + + struct fuse_context *ctx = fuse_get_context(); + fuse_thread_t *ft = (fuse_thread_t *) ctx->private_data; + + fuse_thread_locals_t *l = get_thread_locals(); + + l->fuse = ft; + + // b->op = OP_GETATTR; + // b->path = (char *) path; + // b->data = stat; + + uv_async_send(&(l->async)); + fuse_native_semaphore_wait(&(l->sem)); + + return -1; +} + +NAPI_METHOD(fuse_native_signal) { + NAPI_ARGV(5) + NAPI_ARGV_BUFFER_CAST(fuse_thread_locals_t *, l, 0); + + fuse_native_semaphore_signal(&(l->sem)); +} + +NAPI_METHOD(fuse_native_mount) { + NAPI_ARGV(5) + + NAPI_ARGV_UTF8(mnt, 1024, 0); + NAPI_ARGV_UTF8(mntopts, 1024, 1); + NAPI_ARGV_BUFFER_CAST(fuse_thread_t *, ft, 2); + napi_create_reference(env, argv[3], 1, &(ft->ctx)); + napi_create_reference(env, argv[4], 1, &(ft->on_op)); + + ft->env = env; + + struct fuse_operations ops = { + .getattr = fuse_native_getattr + }; + + int _argc = 2; + char *_argv[] = { + (char *) "fuse_bindings_dummy", + (char *) mntopts + }; + + struct fuse_args args = FUSE_ARGS_INIT(_argc, _argv); + struct fuse_chan *ch = fuse_mount(mnt, &args); + + if (ch == NULL) { + napi_throw_error(env, "fuse failed", "fuse failed"); + return NULL; + } + + struct fuse *fuse = fuse_new(ch, &args, &ops, sizeof(struct fuse_operations), ft); + + ft->fuse = fuse; + + if (fuse == NULL) { + napi_throw_error(env, "fuse failed", "fuse failed"); + return NULL; + } + + pthread_attr_init(&(ft->attr)); + pthread_create(&(ft->thread), &(ft->attr), start_fuse_thread, ft); + + return NULL; +} + +NAPI_INIT() { + pthread_key_create(&(thread_locals_key), NULL); // TODO: add destructor + + NAPI_EXPORT_FUNCTION(fuse_native_mount) + NAPI_EXPORT_FUNCTION(fuse_native_signal) + NAPI_EXPORT_SIZEOF(fuse_thread_t) +} diff --git a/index.js b/index.js new file mode 100644 index 0000000..f0d6ec2 --- /dev/null +++ b/index.js @@ -0,0 +1,47 @@ +const binding = require('node-gyp-build')(__dirname) + +console.log(binding) + +class Fuse { + constructor () { + this.fuseThread = Buffer.alloc(binding.sizeof_fuse_thread_t) + } + + mount (mnt) { + binding.fuse_native_mount('mnt', '-odebug', data, this, on_op) + } +} + +const ctx = {} +const data = Buffer.alloc(binding.sizeof_fuse_thread_t) +let buffers = [] +let foo + +binding.fuse_native_mount('mnt', '-odebug', data, ctx, on_op) + +let to = 1 + +setTimeout(function () { + to = 5000 +}, 5000) + +setInterval(() => { + console.log(!!(data && buffers && ctx && on_op)) + gc() +}, 1000) + +function on_op (buf) { + // foo = buf + console.log('on_op is called', buf) + // buffers.push(buf) + + setTimeout(function () { + console.log('in timeout') + binding.fuse_native_signal(buf) + }, to) +} + +// setTimeout(function () { +// foo = null +// console.log('now!') +// }, 5000) diff --git a/package.json b/package.json new file mode 100644 index 0000000..70cfdbd --- /dev/null +++ b/package.json @@ -0,0 +1,28 @@ +{ + "name": "fuse-native", + "version": "0.0.0", + "description": "Fully maintained fuse bindings for Node that aims to cover the entire FUSE api", + "main": "index.js", + "scripts": { + "install": "node-gyp-build", + "prebuild": "prebuildify -a --strip", + "prebuild-ia32": "prebuildify -a --strip --arch=ia32" + }, + "gypfile": true, + "dependencies": { + "fuse-shared-library": "^1.0.1", + "napi-macros": "^2.0.0", + "node-gyp-build": "^3.2.2" + }, + "devDependencies": {}, + "repository": { + "type": "git", + "url": "https://github.com/fuse-friends/fuse-native.git" + }, + "author": "Mathias Buus (@mafintosh)", + "license": "MIT", + "bugs": { + "url": "https://github.com/fuse-friends/fuse-native/issues" + }, + "homepage": "https://github.com/fuse-friends/fuse-native" +} diff --git a/semaphore.h b/semaphore.h new file mode 100644 index 0000000..4f8eb30 --- /dev/null +++ b/semaphore.h @@ -0,0 +1,40 @@ + +#ifdef __APPLE__ + +#include +#include + +typedef dispatch_semaphore_t fuse_native_semaphore_t; + +static int fuse_native_semaphore_init (dispatch_semaphore_t *sem) { + *sem = dispatch_semaphore_create(0); + return *sem == NULL ? -1 : 0; +} + +static void fuse_native_semaphore_wait (dispatch_semaphore_t *sem) { + dispatch_semaphore_wait(*sem, DISPATCH_TIME_FOREVER); +} + +static void fuse_native_semaphore_signal (dispatch_semaphore_t *sem) { + dispatch_semaphore_signal(*sem); +} + +#else + +#include + +typedef sem_t fuse_native_semaphore_t; + +static int fuse_native_semaphore_init (sem_t *sem) { + return sem_init(sem, 0, 0); +} + +static void fuse_native_semaphore_wait (sem_t *sem) { + sem_wait(sem); +} + +static void fuse_native_semaphore_signal (sem_t *sem) { + sem_post(sem); +} + +#endif