- Notifications
You must be signed in to change notification settings - Fork13
A low-level Node.js binding for the Linux epoll API
License
fivdi/epoll
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
A low-levelNode.js binding for the Linux epoll API for monitoring multiplefile descriptors to see if I/O is possible on any of them.
This module was initially written to detect EPOLLPRI events indicating thaturgent data is available for reading. EPOLLPRI events are triggered byinterrupt generatingGPIOpins. The epoll module is used byonoffto detect such interrupts.
epoll supports Node.js versions 10, 12, 14, 16, 18 and 20.
Note that although it should be possible to install epoll on non-Linux systemsthe functionality offered by epoll is only available on Linux systems.
npm install epoll
- Epoll(callback) - Constructor. The callback is called when epoll eventsoccur and it gets three arguments (err, fd, events).
- add(fd, events) - Register file descriptor fd for the event types specifiedby events.
- remove(fd) - Deregister file descriptor fd.
- modify(fd, events) - Change the event types associated with file descriptorfd to those specified by events.
- close() - Deregisters all file descriptors and free resources.
Event Types
- Epoll.EPOLLIN
- Epoll.EPOLLOUT
- Epoll.EPOLLRDHUP
- Epoll.EPOLLPRI
- Epoll.EPOLLERR
- Epoll.EPOLLHUP
- Epoll.EPOLLET
- Epoll.EPOLLONESHOT
Event types can be combined with | when calling add or modify. For example,Epoll.EPOLLPRI | Epoll.EPOLLONESHOT could be passed to add to detect a singleGPIO interrupt.
The following example shows how epoll can be used to detect interrupts from amomentary push-button connected to GPIO4 (pin P1-7) on the Raspberry Pi.The source code is available in theexample directoryand can easily be modified for using a different GPIO on the Pi or a differentplatform such as the BeagleBone.
The first step is to export GPIO4 as an interrupt generating input usingthe export bash script from the examples directory.
./export
export:
#!/bin/shecho 4> /sys/class/gpio/exportsleep 1echoin> /sys/class/gpio/gpio4/directionecho both> /sys/class/gpio/gpio4/edge
Then run watch-button to be notified every time the button is pressed andreleased. If there is no hardware debounce circuit for the push-button, contactbounce issues are very likely to be visible on the console output.watch-button terminates automatically after 30 seconds.
node watch-button
watch-button:
constEpoll=require('epoll').Epoll;constfs=require('fs');constvaluefd=fs.openSync('/sys/class/gpio/gpio4/value','r');constbuffer=Buffer.alloc(1);// Create a new Epoll. The callback is the interrupt handler.constpoller=newEpoll((err,fd,events)=>{// Read GPIO value file. Reading also clears the interrupt.fs.readSync(fd,buffer,0,1,0);console.log(buffer.toString()==='1' ?'pressed' :'released');});// Read the GPIO value file before watching to// prevent an initial unauthentic interrupt.fs.readSync(valuefd,buffer,0,1,0);// Start watching for interrupts.poller.add(valuefd,Epoll.EPOLLPRI);// Stop watching after 30 seconds.setTimeout(_=>{poller.remove(valuefd).close();},30000);
When watch-button has terminated, GPIO4 can be unexported using theunexport bash script.
./unexport
unexport:
#!/bin/shecho 4> /sys/class/gpio/unexport
The following example shows how epoll can be used to determine the number ofhardware interrupts that can be handled per second on the Raspberry Pi.The source code is available in theexample directoryand can easily be modified to use different GPIOs on the Raspberry Pi or adifferent platform such as the BeagleBone.
In this example, GPIO7 is wired to one end of a 1kΩ current limitingresistor and GPIO8 is wired to the other end of the resistor. GPIO7 is aninput and GPIO8 is an output.
The first step is to export GPIOs #7 and #8 using the export bash script fromthe examples directory.
./export
export:
#!/bin/shecho 7> /sys/class/gpio/exportecho 8> /sys/class/gpio/exportsleep 1echoin> /sys/class/gpio/gpio7/directionecho both> /sys/class/gpio/gpio7/edgeecho out> /sys/class/gpio/gpio8/direction
Then run interrupts-per-second. interrupts-per-second toggles the state of theoutput every time it detects an interrupt on the input. Each toggle willtrigger the next interrupt. After five seconds, interrupts-per-second printsthe number of interrupts it detected per second.
node interrupts-per-second
interrupts-per-second:
constEpoll=require('../../').Epoll;constfs=require('fs');constvalue=Buffer.alloc(1);// The three Buffers here are globalconstzero=Buffer.from('0');// to improve performance.constone=Buffer.from('1');constinputfd=fs.openSync('/sys/class/gpio/gpio7/value','r+');constoutputfd=fs.openSync('/sys/class/gpio/gpio8/value','r+');letcount=0;// Create a new Epoll. The callback is the interrupt handler.constpoller=newEpoll((err,fd,events)=>{count+=1;// Read GPIO value file. Reading also clears the interrupt.fs.readSync(inputfd,value,0,1,0);// Toggle GPIO value. This will eventually result// in the next interrupt being triggered.constnextValue=value[0]===zero[0] ?one :zero;fs.writeSync(outputfd,nextValue,0,nextValue.length,0);});lettime=process.hrtime();// Get start time.// Start watching for interrupts. This will trigger the first interrupt// as the value file already has data waiting for a read.poller.add(inputfd,Epoll.EPOLLPRI);// Print interrupt rate to console after 5 seconds.setTimeout(_=>{time=process.hrtime(time);// Get run time.constrate=Math.floor(count/(time[0]+time[1]/1E9));console.log(rate+' interrupts per second');// Stop watching.poller.remove(inputfd).close();},5000);
When interrupts-per-second has terminated, GPIOs #7 and #8 can be unexportedusing the unexport bash script.
./unexport
unexport:
#!/bin/shecho 7> /sys/class/gpio/unexportecho 8> /sys/class/gpio/unexport
Here are some results from the "Interrupts Per Second" example.
Raspberry Pi 4 Model B, Raspberry Pi OS (March 4th 2021, Debian 10.8):
node | epoll | kernel | interrupts / sec |
---|---|---|---|
v16.0.0 | v4.0.1 | 5.10.17-v7l+ | 20112 |
About
A low-level Node.js binding for the Linux epoll API