node-serialport icon indicating copy to clipboard operation
node-serialport copied to clipboard

serialport + electron, "close" event causes CPU spike

Open sabetts opened this issue 4 years ago • 4 comments
trafficstars

node 10.20.1

serial port 8.0.8

electron 13.1.7

platform: OSX 10.14.6

I open a serialport in electron's "main" process and use Electron's IPC functions to bridge between renderer and main process. main process opens a serial port and creates an event handler for "close" and "data" events. "data" events work fine and so does writing to the serial port. But if I unplug the USB plug, disconnecting the arduino from the computer, the "close" event does not fire. Instead I get a CPU spike in the electron process (as seen in Activity Monitor app).

sabetts avatar Sep 27 '21 17:09 sabetts

Would you be able to share your project or example code? While I'm not able to test on Mac myself, if I can recreate the issue on another platform it might help get to the bottom of the problem

GazHank avatar Sep 29 '21 18:09 GazHank

Getting the same problem. Using a BLuetooth legacy device. Pairing it with Bluettoth first and then connecting via Serial port. If I disconnect the Bluetooth connection, the close event is not firing.

If I manually close the serial port connection via https://serialport.io/docs/api-stream#close-1, it is getting fired.

maneetgoyal avatar Aug 10 '22 09:08 maneetgoyal

Seeing the same thing here using zwave-js. After a successful initial connection, unplugging the Zwave USB stick does not trigger an onError event. Instead the CPU spikes and memory use creeps up until it consumes 5GB, then an exception occurs.

It is hard to share my application environment that uses zwave-js and you probably don't have a zwave USB stick handy so below this is what I've noticed:

Pausing the debugger while this is ongoing stops at 'unix-read.js'. See snippet below. Some observations:

  1. This section of code is recursing at breakneck speed, causing the CPU spike.
  2. The stack trace is too big to display but is basically a list of unixRead calls.
  3. binding.isOpen is true because the fd is still set, even though that port is closed.
  4. fsReadAsync returns without throwing an exception
  5. bytesRead is 0, which might explain the recursion. (not sure myself)

Speculation: I suspect that normally readAsync would wait for data but as the port is closed it returns immediately. The code expects an exception to be thrown which doesn't happen in my case.

Maybe this is node dependent? This happens on:

  • node v16.20.2 and v20.10.0
  • ubuntu 23.10
  • serialport v12.0.0.
const unixRead = async ({ binding, buffer, offset, length, fsReadAsync = readAsync, }) => {
    logger('Starting read');
    if (!binding.isOpen || !binding.fd) {
        throw new errors_1.BindingsError('Port is not open', { canceled: true });
    }
    try {
        const { bytesRead } = await fsReadAsync(binding.fd, buffer, offset, length, null);
        if (bytesRead === 0) {
            return (0, exports.unixRead)({ binding, buffer, offset, length, fsReadAsync });
        }
        logger('Finished read', bytesRead, 'bytes');
        return { bytesRead, buffer };
    }
    catch (err) {
        logger('read error', err);
     

Stack trace: image

hspaay avatar Nov 26 '23 04:11 hspaay

This might be related to Issue https://github.com/serialport/node-serialport/issues/2043

hspaay avatar Nov 26 '23 05:11 hspaay