2

I cannot get my nodejs application to quit using process.exit() from within a signal handler. This is because I have a pending read operation on a Linux input event node (/dev/input/mouse1). I have spent several hours researching, but all I could find was this SO question. I tried using an fs.ReadStream like it is used there and call its destroy method, but it also did not work. Even by reading the nodejs source code I couldn't come up with an idea. Then there is this issue on github, which is somehow related.

So far, I came up with some hacks to work around this problem, but nothing clean:

  1. Use something stronger than process.exit, maybe process.abort
  2. Spawn a child process (childProcess.fork) to read which I can terminate from the parent process. But this will create a new nodejs instance with ~10mb memory usage.
  3. Write a program in a language (C++) where I have better control over what's going on (using threads etc.) and call this from javascript. Although I would prefer staying in js-land.
  4. Or maybe someone knows a tool which can help me achieve my goals in a different way? (See background information below). Maybe I don't have to use /dev/input/

Basically, I need a way to cancel pending read operations, either directly or indirectly (e.g. by clearing them from the active_handles list).
Thanks in advance for your answers!

Example

In the code example below, I can press ctrl+c, but nodejs will only exit after I move my mouse:

'use strict'
const fs = require('fs');

const buf = new Buffer(24);
const mouse = fs.openSync('/dev/input/mouse1', 'r');
const onRead = (err, bytesRead, buffer) => {
    console.log('read');
    if (!err) {
        process.nextTick(fs.read, mouse, buf, 0, buf.length, null, onRead);
    }
};
fs.read(mouse, buf, 0, buf.length, null, onRead);

process.on('SIGINT', () => {
    fs.closeSync(mouse);
    process.exit();
});

Background information

I am working on a small project based on a raspberry pi running a nodejs script. I want the program to respond both to user input via a usb mouse's scroll wheel as well as a GPIO-attached button. Therefore, I make use of the onoff library for the GPIO stuff. The onoff docs suggest to install a custom SIGINT handler to free resources before the program exits, so that's where this desire comes from. For handling the scroll wheel data without a window system or even a terminal, I eventually want to get this library to work, but now I have encountered the above problem.

suluke
  • 683
  • 5
  • 14
  • Have you checked that the signal handler is actually called? Any specific reason you use `fs.openSync` andl `fs.read` rather than `fs.createReadStream` and adding a `read` event handler? What state is the process in in `ps` or `top` when you try to interrupt it? – jcaron Dec 31 '15 at 17:37
  • 1
    @jcaron Thanks for your reply. This code is just straight-forward as an example. I mentioned in the question that I already tested alternative implementations using ReadStream. Also, fs.ReadStream is just some kind of wrapper around fs.read, see [here](https://github.com/nodejs/node/blob/master/lib/fs.js#L1804). The handler is called, you can even `console.log` from it. Can you elaborate on how to find the process state in top/ps? – suluke Dec 31 '15 at 18:43
  • I also stumbled upon this today. One solution is to use a library such as node-hid, which uses hidapi, and does sufficient cleanup internally, but I wanted to avoid adding another library that requires compilation. Thanks for providing the list of workarounds. Did you, in the end, manage to find another solution for this? – Andre T Apr 08 '21 at 11:54
  • @AndreT this was over 5 years ago :D But IIRC this was for an uni course that I ended up abandoning altogether. So no solution, I'm afraid. The last approach I followed was to feed my own events into the device so that the blocked thread in nodejs' io lib would resume and allow me to shut down properly. Not sure if I got that working... – suluke Apr 09 '21 at 12:05

1 Answers1

0

Maybe a bit crude, but what about the following:

process.on('SIGINT', () => {
    fs.closeSync(mouse);
    setTimeout(process.exit, 1000);
});
Joost Vunderink
  • 1,178
  • 6
  • 14
  • 2
    Hi, thanks for answering. Did this work for you? I tried that before I posted this question, but it didn't work for me. – suluke Jan 04 '16 at 08:07