I'm writing a C program to run on my raspberry pi 3b that monitors the temperature of the CPU in real-time.
In order to avoid polling, I'm using the sys/inotify
library to watch /sys/class/thermal/thermal_zone0/temp
for file updates.
However, this doesn't seem to pick up changes to the file.
To test this:
- I polled the file repeatedly (using
cat
) while running main, and I saw that the value in the file did change, but the change was not detected by main. - I tried
tail -f /sys/class/thermal/thermal_zone0/temp
, but this did not detect any changes either. - I created a script to periodically write to another file, and had my program watch this file, and it detected changes there.
Is it possible that this file is being updated without propagating an event that is detectable by inotify? I am trying to avoid having to implement a periodic polling of this file to monitor for changes at all cost.
temperatureMonitor.cpp
#include <iostream>
#include <unistd.h>
#include <sys/inotify.h>
#include <sys/types.h>
#include "./temperatureMonitor.hpp"
#define EVENT_SIZE ( sizeof (struct inotify_event) )
#define BUF_LEN ( 1024 * ( EVENT_SIZE 16 ) )
namespace Performance {
void TemperatureMonitor::monitor_temperature(void(*callback)(double)){
};
void TemperatureMonitor::monitor_temperature_file(){
int length, i = 0;
int fd;
int wd;
char buffer[BUF_LEN];
fd = inotify_init();
wd = inotify_add_watch(fd,"/sys/class/thermal/thermal_zone0/temp" , IN_MODIFY|IN_CREATE|IN_DELETE);
while (true){
length = read(fd, buffer, BUF_LEN);
std::cout << "detected file change\n";
};
};
};
main.cpp
#include "Performance/temperatureMonitor.hpp"
#define EVENT_SIZE ( sizeof (struct inotify_event) )
#define BUF_LEN ( 1024 ∗ ( EVENT_SIZE 16 ) )
int main(){
Performance::TemperatureMonitor tm = Performance::TemperatureMonitor();
tm.monitor_temperature_file();
return 0;
};
fwriter.go
package main
import (
"os"
"time"
)
func main() {
f, err := os.Create("foo.txt")
if err != nil {
panic(err)
}
for {
f.Write([]byte("test\n"))
time.Sleep(time.Second)
}
}
CodePudding user response:
It's not a real file, whenever you read it, the driver is asked to produce the data in it. There is no way to get notified when its contents would change. Polling is the answer.
https://www.kernel.org/doc/html/latest/filesystems/sysfs.html
On read(2), the show() method should fill the entire buffer. Recall that an attribute should only be exporting one value, or an array of similar values, so this shouldn’t be that expensive.
This allows userspace to do partial reads and forward seeks arbitrarily over the entire file at will. If userspace seeks back to zero or does a pread(2) with an offset of ‘0’ the show() method will be called again, rearmed, to fill the buffer.
You don't have to open and close it every time, seeking to the beginning should refresh it. Although this will probably not save much.