Overview
Examples
Screenshots
Comparisons
Applications
Download
Documentation
Tutorials
Bazaar
Status & Roadmap
FAQ
Authors & License
Forums
Funding Ultimate++
Search on this site
Search in forums












SourceForge.net Logo
Home » U++ Library support » U++ Core » LoadFile("/sys/devices/virtual/thermal/ ...") does not work
LoadFile("/sys/devices/virtual/thermal/ ...") does not work [message #58259] Wed, 06 April 2022 12:29 Go to next message
Tom1
Messages: 1212
Registered: March 2007
Senior Contributor
Hi,

I attempted to read Raspberry Pi 4 SoC temperature with the below code. For some reason using LoadFile does not work:
double	GetRaspberryPiTemperature(){
	String result = LoadFile("/sys/devices/virtual/thermal/thermal_zone0/temp");
	if(!result.IsEmpty()) return 0.001*ScanDouble(~result);
	return -55.0;
}

So I had to revert using FILE and fgets instead:
double	GetRaspberryPiTemperature(){
	FILE *in=fopen("/sys/devices/virtual/thermal/thermal_zone0/temp","rb");
	char s[8];
	if(fgets(s,8,in)) return 0.001*ScanDouble(s);
	return -55.0;
}

Is this expected or is this a bug?

Best regards,

Tom
Re: LoadFile("/sys/devices/virtual/thermal/ ...") does not work [message #58278 is a reply to message #58259] Fri, 08 April 2022 16:11 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
Tom1 wrote on Wed, 06 April 2022 12:29
Hi,

I attempted to read Raspberry Pi 4 SoC temperature with the below code. For some reason using LoadFile does not work:
double	GetRaspberryPiTemperature(){
	String result = LoadFile("/sys/devices/virtual/thermal/thermal_zone0/temp");
	if(!result.IsEmpty()) return 0.001*ScanDouble(~result);
	return -55.0;
}

So I had to revert using FILE and fgets instead:
double	GetRaspberryPiTemperature(){
	FILE *in=fopen("/sys/devices/virtual/thermal/thermal_zone0/temp","rb");
	char s[8];
	if(fgets(s,8,in)) return 0.001*ScanDouble(s);
	return -55.0;
}

Is this expected or is this a bug?

Best regards,

Tom


Have you tried the exact equivalent? (like reading 8 bytes only).
Re: LoadFile("/sys/devices/virtual/thermal/ ...") does not work [message #58292 is a reply to message #58278] Tue, 12 April 2022 08:54 Go to previous messageGo to next message
Tom1
Messages: 1212
Registered: March 2007
Senior Contributor
Hi Mirek,

None of the options below work. The file opens OK, but reading fails with all means:
	FileIn in;
	in.Open("/sys/devices/virtual/thermal/thermal_zone0/temp");
	if(in.IsError()) return -100;
	
//	String result = in.GetLine();
//	String result = in.Get(5);
	String result = in.GetAll(8);
	if(!result.IsEmpty()) return 0.001*ScanInt(~result);
	return -55.0;


Best regards,

Tom
Re: LoadFile("/sys/devices/virtual/thermal/ ...") does not work [message #58296 is a reply to message #58292] Tue, 12 April 2022 14:46 Go to previous messageGo to next message
Tom1
Messages: 1212
Registered: March 2007
Senior Contributor
Hi Mirek,

First it seems the problem is that the Stream::GetSize() returns 4096 for some reason. (The file is more like five bytes long.) Then it breaks in BlockStream::_Get(void *data, dword size) in a way that causes error.

Best regards,

Tom
Re: LoadFile("/sys/devices/virtual/thermal/ ...") does not work [message #58297 is a reply to message #58296] Wed, 13 April 2022 09:13 Go to previous messageGo to next message
Tom1
Messages: 1212
Registered: March 2007
Senior Contributor
Hi Mirek,

There is also an easier way to test this -- the following does not work on Linux Mint on normal x86_64 platform:
#include <Core/Core.h>

using namespace Upp;

CONSOLE_APP_MAIN
{
	String meminfo = LoadFile("/proc/meminfo");
	Cout() << meminfo << "\n";
}

Best regards,

Tom
Re: LoadFile("/sys/devices/virtual/thermal/ ...") does not work [message #58299 is a reply to message #58297] Wed, 13 April 2022 14:44 Go to previous messageGo to next message
Tom1
Messages: 1212
Registered: March 2007
Senior Contributor
Hi,

This does work on both Raspberry Pi OS (on RPi4) and Linux Mint (on x86_64):
#include <Core/Core.h>

using namespace Upp;

String LoadFileRaw(const char *filename){
	int fd = open(filename,O_RDONLY);
	if(fd!=-1){
		char buf[4096];
		StringBuffer s;
		int len;
		while((len=read(fd,buf,4096))==4096) s.Cat(buf,len);
		if(len>0) s.Cat(buf,len);
		close(fd);
		if(s.GetCount()>0) return s;
	}
	return String::GetVoid();
}

CONSOLE_APP_MAIN
{
	String meminfo = LoadFileRaw("/proc/meminfo");
	Cout() << meminfo << "\n\n";
}

Also:
LoadFileRaw("/sys/devices/virtual/thermal/thermal_zone0/temp");

works fine on RPi4.

Best regards,

Tom
Re: LoadFile("/sys/devices/virtual/thermal/ ...") does not work [message #58300 is a reply to message #58299] Wed, 13 April 2022 17:39 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
Tom1 wrote on Wed, 13 April 2022 14:44
Hi,

This does work on both Raspberry Pi OS (on RPi4) and Linux Mint (on x86_64):
#include <Core/Core.h>

using namespace Upp;

String LoadFileRaw(const char *filename){
	int fd = open(filename,O_RDONLY);
	if(fd!=-1){
		char buf[4096];
		StringBuffer s;
		int len;
		while((len=read(fd,buf,4096))==4096) s.Cat(buf,len);
		if(len>0) s.Cat(buf,len);
		close(fd);
		if(s.GetCount()>0) return s;
	}
	return String::GetVoid();
}

CONSOLE_APP_MAIN
{
	String meminfo = LoadFileRaw("/proc/meminfo");
	Cout() << meminfo << "\n\n";
}

Also:
LoadFileRaw("/sys/devices/virtual/thermal/thermal_zone0/temp");

works fine on RPi4.

Best regards,

Tom


I suspect that the problem is somewhere here: Core/BlockStream.cpp:474

Probably that S_IFREG flag test. Maybe using S_IFBLK would fix it?

Mirek
Re: LoadFile("/sys/devices/virtual/thermal/ ...") does not work [message #58301 is a reply to message #58300] Wed, 13 April 2022 18:45 Go to previous messageGo to next message
Tom1
Messages: 1212
Registered: March 2007
Senior Contributor
mirek wrote on Wed, 13 April 2022 18:39


I suspect that the problem is somewhere here: Core/BlockStream.cpp:474

Probably that S_IFREG flag test. Maybe using S_IFBLK would fix it?

Mirek


Hi,

Unfortunately this does not help. I think, it opens OK, but fails to read.

Best regards,

Tom
Re: LoadFile("/sys/devices/virtual/thermal/ ...") does not work [message #58302 is a reply to message #58301] Wed, 13 April 2022 20:33 Go to previous messageGo to next message
Tom1
Messages: 1212
Registered: March 2007
Senior Contributor
Hi Mirek,

OK, the problem is here:
bool FileStream::Open(const char *name, dword mode, mode_t tmode) {
	Close();
	LLOG("Open " << name);
	int iomode = mode & ~SHAREMASK;
	handle = open(ToSystemCharset(name), iomode == READ ? O_RDONLY :
	                    iomode == CREATE ? O_CREAT|O_RDWR|O_TRUNC :
	                    O_RDWR|O_CREAT,
	              tmode);
	if(handle >= 0) {
		struct stat st[1];
		fstat(handle, st);
		if(!(st->st_mode & S_IFREG) ||  // not a regular file, e.g. folder - bad things would happen
		   (mode & NOWRITESHARE) && flock(handle, LOCK_EX|LOCK_NB) < 0) { // lock if not sharing
			close(handle);
			handle = -1;
			return false;
		}
		int64 fsz = st->st_size;

The 'st->st_size' returned from fstat() above is zero for e.g. "/proc/meminfo". This causes the contents of the file not being read at all. (I tested with a fake length of five bytes and received the five first characters of "/proc/meminfo", so this explains the behavior.)

Best regards,

Tom

More edit: It turns out that files in "/proc" or "/sys" are not really files. Not on disk, but not even in memory. Their contents is generated by the kernel on the fly. So, there is no way to tell their size and so fstat() returns zero. Only way to read them is to just read() them in until EOF.

Maybe they could be read up to the buffer (page) size and if the EOF is encountered, the filesize becomes determined...?

[Updated on: Wed, 13 April 2022 20:46]

Report message to a moderator

Re: LoadFile("/sys/devices/virtual/thermal/ ...") does not work [message #58386 is a reply to message #58302] Mon, 16 May 2022 10:48 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
Quote:

More edit: It turns out that files in "/proc" or "/sys" are not really files. Not on disk, but not even in memory. Their contents is generated by the kernel on the fly. So, there is no way to tell their size and so fstat() returns zero. Only way to read them is to just read() them in until EOF.

Maybe they could be read up to the buffer (page) size and if the EOF is encountered, the filesize becomes determined...?


Well, one simple possible solution is to change LoadFile... However, it will then need to be implemented for every platform.

Mirek
Re: LoadFile("/sys/devices/virtual/thermal/ ...") does not work [message #58404 is a reply to message #58386] Wed, 18 May 2022 09:05 Go to previous messageGo to next message
Tom1
Messages: 1212
Registered: March 2007
Senior Contributor
Hi Mirek,

Well, the LoadFileRaw() implementation above (a couple of messages up) could likely replace LoadFile() on Linux (or POSIX) and Windows does not need any changes. So, I guess it is just Mac that possibly needs attention. (I do not have a Mac, so I cannot really tell.)

EDIT: Or maybe we could use LoadFileRaw() just for files in POSIX that fail to open with LoadFile(). Then allocation of String would be better optimized for normal files.

Best regards,

Tom

[Updated on: Wed, 18 May 2022 09:15]

Report message to a moderator

Re: LoadFile("/sys/devices/virtual/thermal/ ...") does not work [message #58405 is a reply to message #58404] Wed, 18 May 2022 09:58 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
OK, this should do the job:

String LoadFile(const char *filename) {
	FindFile ff(filename);
	if(ff && ff.IsFile()) {
	#ifdef PLATFORM_POSIX
		if(ff.GetLength() == 0) { // handle special cases like /proc/...
			int fd = open(filename,O_RDONLY);
			if(fd >= 0) {
				const int CHUNK = 32768;
				StringBuffer s;
				for(;;) {
					int n = s.GetCount();
					s.SetCount(n + CHUNK);
					int len = read(fd, ~s + n, CHUNK);
					if(len != CHUNK) {
						if(len > 0)
							s.SetCount(n + len);
						return s;
					}
				}
			}
			return String::GetVoid();
		}
	#endif
		FileIn in(filename);
		return LoadStream(in);
	}
	return String::GetVoid();
}
Re: LoadFile("/sys/devices/virtual/thermal/ ...") does not work [message #58407 is a reply to message #58405] Wed, 18 May 2022 10:15 Go to previous messageGo to next message
Tom1
Messages: 1212
Registered: March 2007
Senior Contributor
Mirek,

A nice idea. Now it works in /proc too. Unfortunately, now a truly empty file comes in as garbage sized at 32769 bytes. The StringBuffer sizing needs some tuning...

Best regards,

Tom

[Updated on: Wed, 18 May 2022 10:16]

Report message to a moderator

Re: LoadFile("/sys/devices/virtual/thermal/ ...") does not work [message #58408 is a reply to message #58407] Wed, 18 May 2022 10:26 Go to previous messageGo to next message
Tom1
Messages: 1212
Registered: March 2007
Senior Contributor
EDIT: My mistake, IsVoid() works correctly for String::GetVoid().

Best regards,

Tom

[Updated on: Wed, 18 May 2022 10:33]

Report message to a moderator

Re: LoadFile("/sys/devices/virtual/thermal/ ...") does not work [message #58409 is a reply to message #58408] Wed, 18 May 2022 10:29 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
Empty file issue fixed (with len >= 0).

Not sure what do you mean with IsVoid problem, piece of code maybe?
Re: LoadFile("/sys/devices/virtual/thermal/ ...") does not work [message #58410 is a reply to message #58409] Wed, 18 May 2022 10:36 Go to previous messageGo to next message
Tom1
Messages: 1212
Registered: March 2007
Senior Contributor
Thanks Mirek!

Now it works perfectly.

Sorry, GetVoid() / IsVoid() issue was my mistake in testing...

Best regards,

Tom
Re: LoadFile("/sys/devices/virtual/thermal/ ...") does not work [message #58413 is a reply to message #58409] Wed, 18 May 2022 10:47 Go to previous messageGo to next message
Tom1
Messages: 1212
Registered: March 2007
Senior Contributor
mirek wrote on Wed, 18 May 2022 11:29
Empty file issue fixed (with len >= 0).

Not sure what do you mean with IsVoid problem, piece of code maybe?

OK, I found the reason causing part of my testing issues:
	if(String::GetVoid().IsVoid()) Cout() << "String::GetVoid().IsVoid() works!\n";
	else Cout() << "String::GetVoid().IsVoid() fails!\n";
	if(IsVoid(String::GetVoid())) Cout() << "IsVoid(String::GetVoid()) works!\n";
	else Cout() << "IsVoid(String::GetVoid()) fails!\n";



Best regards,

Tom

EDIT: Improved test code.

[Updated on: Wed, 18 May 2022 10:54]

Report message to a moderator

Re: LoadFile("/sys/devices/virtual/thermal/ ...") does not work [message #58414 is a reply to message #58410] Wed, 18 May 2022 10:50 Go to previous messageGo to next message
pvictor is currently offline  pvictor
Messages: 67
Registered: December 2015
Member
Hi Mirek,

You should close(fd) in the above code.

Best regards,
Victor
Re: LoadFile("/sys/devices/virtual/thermal/ ...") does not work [message #58415 is a reply to message #58414] Wed, 18 May 2022 10:58 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
pvictor wrote on Wed, 18 May 2022 10:50
Hi Mirek,

You should close(fd) in the above code.

Best regards,
Victor


Thanks, not my best morning....

Mirek
Re: LoadFile("/sys/devices/virtual/thermal/ ...") does not work [message #58416 is a reply to message #58413] Wed, 18 May 2022 11:04 Go to previous messageGo to previous message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
Tom1 wrote on Wed, 18 May 2022 10:47
mirek wrote on Wed, 18 May 2022 11:29
Empty file issue fixed (with len >= 0).

Not sure what do you mean with IsVoid problem, piece of code maybe?

OK, I found the reason causing part of my testing issues:
	if(String::GetVoid().IsVoid()) Cout() << "String::GetVoid().IsVoid() works!\n";
	else Cout() << "String::GetVoid().IsVoid() fails!\n";
	if(IsVoid(String::GetVoid())) Cout() << "IsVoid(String::GetVoid()) works!\n";
	else Cout() << "IsVoid(String::GetVoid()) fails!\n";



Best regards,

Tom

EDIT: Improved test code.


Uhm, that is actually API problem:

IsVoid(const Value&) function is about Value - it tells you that Value was not assigned anything. In above example you assign it a String, so it must return false.

I agree this is a bit confusing, but I am not sure there is a solution to that.

Mirek
Previous Topic: BiArray::Create{Head,Tail} with variadic args
Next Topic: Serialize long as uint64 on some platforms
Goto Forum:
  


Current Time: Fri Mar 29 14:52:31 CET 2024

Total time taken to generate the page: 0.01431 seconds