fuse-friends / fuse-native

Multithreaded FUSE bindings for Node JS.
203 stars 29 forks source link

Fuse-native does not work on worker-thread (FATAL ERROR) #23

Open Tunga37 opened 3 years ago

Tunga37 commented 3 years ago

When we put fuse code into worker thread (instead of main thread) we get an error :

FATAL ERROR: HandleScope::HandleScope Entering the V8 API without proper locking in place

FUSE library version: 2.9.7 nullpath_ok: 0 nopath: 0 utime_omit_ok: 0 unique: 1, opcode: INIT (26), nodeid: 0, insize: 56, pid: 0 INIT: 7.26 flags=0x001ffffb max_readahead=0x00020000 FATAL ERROR: HandleScope::HandleScope Entering the V8 API without proper locking in place 1: 0xa5d530 node::Abort() [/usr/local/bin/node] 2: 0x9927fd node::FatalError(char const, char const) [/usr/local/bin/node] 3: 0xc34eca v8::Utils::ReportApiFailure(char const, char const) [/usr/local/bin/node] 4: 0xc3665c v8::HandleScope::HandleScope(v8::Isolate) [/usr/local/bin/node] 5: 0xa19866 napi_open_handle_scope [/usr/local/bin/node] 6: 0x7fe038da5882 7: 0x143dd96 [/usr/local/bin/node] 8: 0x1450875 [/usr/local/bin/node] 9: 0x143e6c8 uv_run [/usr/local/bin/node] 10: 0x9b1ed5 node::SpinEventLoop(node::Environment) [/usr/local/bin/node] 11: 0xa9e790 node::NodeMainInstance::Run(node::EnvSerializeInfo const*) [/usr/local/bin/node] 12: 0xa2a9ba node::Start(int, char**) [/usr/local/bin/node] 13: 0x7fe03bbdabf7 __libc_start_main [/lib/x86_64-linux-gnu/libc.so.6] 14: 0x9afc1c [/usr/local/bin/node] Aborted (core dumped)

Code example

const USE_THREADS = true; //to switch between 

(async function () {
    const {
        Worker, isMainThread, parentPort, workerData
    } = require('worker_threads');

    if (USE_THREADS && isMainThread) {
        function runFuseOnWorkerThread() {
            return new Promise((resolve, reject) => {
                const worker = new Worker(__filename, {
                    workerData: {}
                });
                worker.on('message', resolve);
                worker.on('error', reject);
                worker.on('exit', (code) => {
                    if (code !== 0)
                        reject(new Error(`Worker stopped with exit code ${code}`));
                });
            });
        };

        try {

            await runFuseOnWorkerThread()
        }
        catch(e) {
            console.log(e);
        }

    } else {

        if (isMainThread) {
           console.log('this is main and only thread');
        } else {
            console.log('this is worker thread');
        }

        const Fuse = require("fuse-native");
        const fs = require("fs");
        const pfs = require("fs").promises;
        const path = require("path");
        const os = require("os");

        const ops = {
            readdir: function (path, cb) {
                if (path === '/') return cb(null, ['test'])
                return cb(Fuse.ENOENT)
            },
            getattr: function (path, cb) {
                if (path === '/') return cb(null,
                    {
                        mtime: new Date(),
                        atime: new Date(),
                        ctime: new Date(),
                        nlink: 1,
                        size: 0,
                        mode: 16877,
                        uid: 0,
                        gid: 0,
                    });
                if (path === '/test') return cb(null, {
                    mtime: new Date(),
                    atime: new Date(),
                    ctime: new Date(),
                    nlink: 1,
                    size: 'hello world'.length,
                    mode: 33188,
                    uid: 0,
                    gid: 0,
                })
                return cb(Fuse.ENOENT)
            },
            open: function (path, flags, cb) {
                return cb(0, 42)
            },
            release: function (path, fd, cb) {
                return cb(0)
            },
            read: function (path, fd, buf, len, pos, cb) {
                var str = 'hello world'.slice(pos, pos + len)
                if (!str) return cb(0)
                buf.write(str)
                return cb(str.length)
            }
        }

        const mnt = '/tmp/fuse';
        const fuse = new Fuse(mnt, ops, {debug: true, force: true, mkdir: true})
        fuse.mount(function (err) {
            console.log('err', err);
            //parentPort.postMessage(true);
            fs.readFile(path.join(mnt, 'test'), function (err, buf) {
                // buf should be 'hello world'
                if (err) {
                    console.log('fuse error', err);
                }
                if (buf) {
                    console.log('buf should be hello world', buf.toString());
                }
            })
        })
    }
}());