Linux C++ userspace app real time sleep function (POSIX, Raspberry Pi) - c++

I need a function which suspends my program in µs, it should be real time, so if I call it with 50µs the thread should stop for exactly 50µs.
My C++ program is running on a Raspberry Pi with normal Raspbian installed.
I wrote this example program which uses the posix time functions to suspend an measure the suspend time.
#include <cstdlib>
#include "stdint-gcc.h"
#include "signal.h"
#include <time.h>
#include <cerrno>
#include <cstdio>
#include <iostream>
#include <cstring>
#define S_IN_NS 1000000000UL
#define MS_IN_NS 1000000UL
#define US_IN_NS 1000UL
#define GET_TIME_CLOCK CLOCK_MONOTONIC
using namespace std;
int main(int argc, char** argv) {
struct timespec newTimeStamp;
struct timespec oldTimeStamp;
struct timespec sleeptime;
sleeptime.tv_sec = 0;
sleeptime.tv_nsec = 50000; //50us
if (clock_gettime(GET_TIME_CLOCK, &oldTimeStamp) == -1)
cout << "Could not get clock time! ERRNO: " << strerror(errno);
if ((clock_nanosleep(CLOCK_MONOTONIC, 0, &sleeptime, NULL)) == -1)
cout << "Sleep failed! ERRNO: " << strerror(errno);
if (clock_gettime(GET_TIME_CLOCK, &newTimeStamp) == -1)
cout << "Could not get clock time! ERRNO: " << strerror(errno);
uint64_t measuredSec = (newTimeStamp.tv_sec - oldTimeStamp.tv_sec);
int32_t measuredNs = (newTimeStamp.tv_nsec - oldTimeStamp.tv_nsec);
uint64_t diffus = (((measuredSec * S_IN_NS) + measuredNs + 500) / 1000UL);
uint64_t diffns = (((measuredSec * S_IN_NS) + measuredNs));
cout << "Diffns:" << diffns << " Diffus:" << diffus << endl;
return 0;
}
Build commands:
arm-bcm2708hardfp-linux-gnueabi-g++ -lrt -c -g -MMD -MP -MF "build/Debug/GNU_ARM_HARDFP-Linux-x86/main.o.d" -o build/Debug/GNU_ARM_HARDFP-Linux-x86/main.o main.cpp
arm-bcm2708hardfp-linux-gnueabi-g++ -lrt -o dist/Debug/GNU_ARM_HARDFP-Linux-x86/timetest build/Debug/GNU_ARM_HARDFP-Linux-x86/main.o
Result (chrt - manipulate real-time attributes of a process):
pi#raspberrypi ~ $ sudo chrt 99 ./timetest
Diffns:130994 Diffus:131
pi#raspberrypi ~ $ sudo chrt 99 ./timetest
Diffns:135994 Diffus:136
pi#raspberrypi ~ $ sudo chrt 99 ./timetest
Diffns:138993 Diffus:139
The program should sleep for exactly 50us but I measured 130-139us.
If I change the GET_TIME_CLOCK define to CLOCK_PROCESS_CPUTIME_ID the cpu time (excluding the sleeptime) is measured (So as I understand it).
Result:
pi#raspberrypi ~ $ sudo chrt 99 ./timetest
Diffns:89000 Diffus:89
pi#raspberrypi ~ $ sudo chrt 99 ./timetest
Diffns:86000 Diffus:86
pi#raspberrypi ~ $ sudo chrt 99 ./timetest
Diffns:88000 Diffus:88
It takes around 80-90µs to do the clock_nanosleep() function, even if I change the sleeptime to 500µs!
So is there any way to suspend a thread for exactly an amount of time (µs) in a C++ userspace application on Raspbian?
thx

If you need to sleep for such a precise amount of time, you probably need to use a spin loop with a check of the current time. This will consume rather a lot of power (and generate heat), but it's a fairly reliable and portable way to do it. Another idea is to try the ideas on this page: http://blog.regehr.org/archives/794

Related

command to kill/stop the program if it runs more than a certain time limit

If I have a C++ code with an infinite loop inside i want a command that will kill the execution after certain time.
so i came up with something like this-
g++ -std=c++20 -DLOCAL_PROJECT solution.cpp -o solution.exe & solution.exe & timeout /t 0 & taskkill /im solution.exe /f
But the problem with this was that it would first execute the program so due to the infinite loop it won't even come to timeout and taskkill part.
Does anybody have any solution to it or other alternatives instead of timeout?
I am using windows 10 and my compiler is gnu 11.2.0
Also in case there is No TLE i don't want taskkill to show this error
ERROR: The process "solution.exe" not found.
Your main loop could exit after a certain time limit, if you're confident it is called regularly enough.
#include <chrono>
using namespace std::chrono_literals;
using Clock = std::chrono::system_clock;
int main()
{
auto timeLimit = Clock::now() + 1s;
while (Clock::now() < timeLimit) {
//...
}
}
Alternatively you could launch a thread in your main throwing an exception after a certain delay:
#include <chrono>
#include <thread>
using namespace std::chrono_literals;
struct TimeOutException {};
int main()
{
std::thread([]{
std::this_thread::sleep_for(1s);
std::cerr << "TLE" << std::endl;
throw TimeOutException{};
}).detach();
//...
}
terminate called after throwing an instance of 'TimeOutException'

Why does mingw-w64 mintty not signal() my program when I CTRL+C?

MinTTY does not seem to raise a signal to my mingw-w64 program when I hit CTRL+C. In CMD with the same identical program the signal is correctly raised. Why is this?
The program is compiled under msys2 mingw-w64 with g++ -static -static-libstdc++ -std=c++14 -Wall -Wextra -pedantic testan.cpp. In both cases, signal() does not return SIG_ERR so the handler seems to be correctly installed.
code:
#include <chrono>
#include <thread>
#include <iostream>
#include <csignal>
using namespace std;
void signalHandler( int x ) {
cout << "Interrupt: " << x << endl;
exit( 123 );
}
int main () {
if( signal(SIGINT, signalHandler) == SIG_ERR )
cout << "received SIG_ERR" << endl;
while( true ) {
cout << "waiting for CTRL+C" << endl;
this_thread::sleep_for( 1s );
}
return 0;
}
mintty output:
$ ./a.exe
waiting for CTRL+C
waiting for CTRL+C
waiting for CTRL+C
$
CMD output:
C:\Users\Xunie\Desktop\project>a.exe
waiting for CTRL+C
waiting for CTRL+C
Interrupt: 2
C:\Users\Xunie\Desktop\project>
MinTTY is a POSIX-oriented terminal emulator, it's using Cygwin/MSYS2 PTYs which don't interface well with native (non-Cygwin non-MSYS2) programs. This includes signals, detection of interactive input etc. MinTTY doesn't attempt to fix this, but Cygwin has recently (since v3.1.0) improved its support of this use case by using the new ConPTY API. As of May 2020, MSYS2 hasn't yet integrated these changes to its runtime, so you can't see the benefits there yet. In the meantime (and on older Windows versions), you can use the winpty wrapper, installable using pacman.

Why is my program exiting before main is called?

When I execute the following program on the my embedded Linux nothing happens:
#include <boost/thread/thread.hpp>
#include <boost/lockfree/spsc_queue.hpp>
#include <iostream>
#include <boost/atomic.hpp>
void Test(void)
{
std::cout << "Hello World" << std::endl;
}
int main(int argc, char* argv[])
{
std::cout << "init";
boost::thread producer_thread(Test);
producer_thread.join();
std::cout << "end";
}
# ./prog -> nothing happens here
The last few lines from strace output are:
open("/lib/libboost_thread.so.1.55.0", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0(\0\1\0\0\0\240\272\0\0004\0\0\0"..., 512) = 512
lseek(3, 95536, SEEK_SET) = 95536
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1200) = 1200
lseek(3, 95226, SEEK_SET) = 95226
read(3, "A'\0\0\0aeabi\0\1\35\0\0\0\0055T\0\6\3\10\1\t\1\22\4\24\1\25\1"..., 40) = 40
exit_group(1) = ?
+++ exited with 1 +++
#
The cross compiled libbost_thread is right installed at /lib.
The program exit before main() being called. The program runs normal under my Ubuntu.
Target: ARM with buildroot (sama5d3)
Toolchain: arm-linux-gnueabihf-
Regards
Maybe as a hint:
Have you linked against libpthread with compile and link option -pthread for your target?
If not it can have the same effect as seen in your environment: The prog starts, try to start a new thread, have no threading enabled and call the abort() function. Because abort() simply leave the prog with error in exit code nothing else happens.
Can you also add your compile & link commands for debugging purpose please!
In addition:
Your outputs without endl will not be printed because cout is buffered. The buffer will be printed only if you call flush or send a endl. Maybe you change this in your example.
Hope that helps...
strace is a tool that traces system calls. In your example, this consists of calls to open(), lseek(), and read(). Specifically, the snippet that you pasted shows the OS's dynamic library loader opening the libboost_thread.so.1.55.0 file and reading its contents; nothing more. It doesn't really demonstrate anything about your program except that it is linked against that library.
I found the problem.
The boost library was compiled with arm-linux-gnueabi- (elibc) and the buildroot is compiled with uClibc.

how to compile blacklib (c++)

I am running a beaglebone and want to write a program to sample the ADC. I am trying to use the blacklib (http://blacklib.yigityuce.com/index.html) from here. I cloned the git:
https://github.com/yigityuce/BlackLib
and tried to compile the example with
g++ exampleAndTiming.cpp -std=c++11
This however gives me a ton of errors like these:
In file included from exampleAndTiming.cpp:33:0:
exampleAndTiming/exampleAndTiming_GPIO.h: In function 'void exampleAndTiming_GPIO()':
exampleAndTiming/exampleAndTiming_GPIO.h:97:12: error: 'sleep' was not declared in this scope
sleep(1);
^
In file included from exampleAndTiming.cpp:34:0:
exampleAndTiming/exampleAndTiming_ADC.h: In function 'void exampleAndTiming_ADC()':
exampleAndTiming/exampleAndTiming_ADC.h:67:16: error: 'usleep' was not declared in this scope
usleep(1000);
^
so I include unistd.h (in exampleAndTiming.cpp), but then I get errors like these:
/tmp/ccbgiXE9.o: In function `exampleAndTiming_GPIO()':
exampleAndTiming.cpp:(.text+0x50): undefined reference to `Timing::startMeasure(std::string)'
exampleAndTiming.cpp:(.text+0x80): undefined reference to `BlackLib::BlackGPIO::BlackGPIO(BlackLib::gpioName, BlackLib::direction, BlackLib::workingMode)'
exampleAndTiming.cpp:(.text+0xbc): undefined reference to `Timing::endMeasure(std::string)'
exampleAndTiming.cpp:(.text+0xec): undefined reference to `BlackLib::BlackGPIO::BlackGPIO(BlackLib::gpioName, BlackLib::direction, BlackLib::workingMode)'
exampleAndTiming.cpp:(.text+0x104): undefined reference to `BlackLib::BlackGPIO::BlackGPIO(BlackLib::gpioName, BlackLib::direction, BlackLib::workingMode)'
exampleAndTiming.cpp:(.text+0x11c): undefined reference to `BlackLib::BlackGPIO::BlackGPIO(BlackLib::gpioName, BlackLib::direction, BlackLib::workingMode)'
exampleAndTiming.cpp:(.text+0x158): undefined reference to `Timing::startMeasure(std::string)'
I've been looking at some library examples and compiling it, but I cannot make sense of it all. I've compiled plenty of c++ and c programs before, but I can't get this one to work. So any help will be appreciated.
COMPLETE GUIDE how to compile BLACKLIB directly on BEAGLEBONE BLACK (rev C) running ANGSTROM:
Programs:
Putty - to communicate with BBB from Windows (using SSH with USB cable)
WinSCP - to manage (upload, create, delete) files directly on BBB
Code::Blocks - to write C++ programs
optionally
Termite 2.9 - to send and receive UART transmission from UART<->USB converter (actually Putty could be used to do that as well)
1) get the BlackLib from official site
2) unzip the library and copy following files into separate folder :
BlackADC.cpp, BlackADC.h, BlackCore.cpp, BlackCore.h, BlackDef.h, BlackErr.h, BlackGPIO.cpp, BlackGPIO.h, BlackI2C.cpp, BlackI2C.h, BlackLib.h, BlackPWM.cpp, BlackPWM.h, BlackSPI.cpp, BlackSPI.h, BlackUART.cpp, BlackUART.h
3) open following files in Code::Blocks BlackUART.cpp, BlackSPI.cpp, BlackI2C.cpp and add
#include <unistd.h>
right after #include "BlackUART.h", the "unistd.h" includes all the functions like sleep(), open(), close(), ... that otherwise seems missing
4) create your own program main.cpp, you may use the following code for testing UART1 and UART2:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sstream>
#include <string>
#include <iostream>
#include "BlackLib.h"
int main(){
std::string writeToUart1;
std::string writeToUart2;
std::string readFromUart1;
std::string readFromUart2;
int counter;
std::ostringstream os1;
std::ostringstream os2;
BlackLib::BlackUART Uart1(BlackLib::UART1,
BlackLib::Baud9600,
BlackLib::ParityEven,
BlackLib::StopOne,
BlackLib::Char8 );
// Pins on BeagleBone Black REV C
// UART1_RX -> GPIO_15 (P9.24)
// UART1_RX -> GPIO_14 (P9.26)
BlackLib::BlackUART Uart2(BlackLib::UART2,
BlackLib::Baud9600,
BlackLib::ParityEven,
BlackLib::StopOne,
BlackLib::Char8 );
// Pins on BeagleBone Black REV C
// UART2_RX -> GPIO_2 (P9.22)
// UART2_RX -> GPIO_3 (P9.21)
std::cout << "Program UART start" << std::endl << std::flush;
Uart1.open( BlackLib::ReadWrite | BlackLib::NonBlock );
Uart2.open( BlackLib::ReadWrite | BlackLib::NonBlock );
counter = 0;
while (true){
os1.str("");
os1.clear();
os1 << "Uart1 to TX: " << counter << "\n";
writeToUart1 = os1.str();
Uart1 << writeToUart1;
readFromUart1 = "";
Uart1 >> readFromUart1;
if (readFromUart1.compare("") != 0){
std::cout << "Uart1 from RX: " << readFromUart1 << "\n" << std::flush;
}
Uart1.flush( BlackLib::bothDirection );
counter++;
sleep(2);
os2.str("");
os2.clear();
os2 << "Uart2 to TX: " << counter << "\n";
writeToUart2 = os2.str();
Uart2 << writeToUart2;
readFromUart2 = "";
Uart2 >> readFromUart2;
if (readFromUart2.compare("") != 0){
std::cout << "Uart2 from RX: " << readFromUart2 << "\n" << std::flush;
}
Uart2.flush( BlackLib::bothDirection );
counter++;
sleep(2);
}
return 1;
}
5) save the main.cpp to the same folder as the BlackLib files
6) using WinSCP, create directory on the BBB (e.g. /home/uart) and copy all the BlackLib files and main.cpp into this folder
7) open Putty and navigate to the folder by :
cd /home/uart
8) compile the files by using :
gcc *.cpp -o main -std=c++11
9) run the program :
./main
10) connect the wires to UART<->USB converter and BBB. The ouput from BBB should look like :
Uart2 to TX: 1 OR Uart1 to TX: 0
Uart2 to TX: 3 OR Uart1 to TX: 2
depending on connection of wires
It seems I managed to fix it myself, some nooblike behaviour not including all the cpp files, but even more, I also needed to add #include to BlackCore.h to avoid tons of undefined function errors.
final command:
g++ exampleAndTiming.cpp exampleAndTiming/Timing.cpp BlackADC.cpp BlackCore.cpp BlackGPIO.cpp BlackI2C.cpp BlackPWM.cpp BlackSPI.cpp BlackUART.cpp -std=c++11
I'd probably need to make a makefile to compile the library seperately, time to do some more digging and learning.
I am the creator of BlackLib, Yiğit YÜCE. You found your answer by yourself. The makefile which you mentioned on your comment will be published shortly.

Process management code behaves different on Linux and Windows - Why?

(Context) I'm developing a cross-platform (Windows and Linux) application for distributing files among computers, based on BitTorrent Sync. I've made it in C# already, and am now porting to C++ as an exercise.
BTSync can be started in API mode, and for such, one must start the 'btsync' executable passing the name and location of a config file as arguments.
At this point, my greatest problem is getting my application to deal with the executable. I've come to found Boost.Process when searching for a cross-platform process management library, and decided to give it a try. It seems that v0.5 is it's latest working release, as some evidence suggests, and it can be infered there's a number of people using it.
I implemented the library as follows (relevant code only):
File: test.hpp
namespace testingBoostProcess
{
class Test
{
void StartSyncing();
};
}
File: Test.cpp
#include <string>
#include <vector>
#include <iostream>
#include <boost/process.hpp>
#include <boost/process/mitigate.hpp>
#include "test.hpp"
using namespace std;
using namespace testingBoostProcess;
namespace bpr = ::boost::process;
#ifdef _WIN32
const vector<wstring> EXE_NAME_ARGS = { L"btsync.exe", L"/config", L"conf.json" };
#else
const vector<string> EXE_NAME_ARGS = { "btsync", "--config", "conf.json" };
#endif
void Test::StartSyncing()
{
cout << "Starting Server...";
try
{
bpr::child exeServer = bpr::execute(bpr::initializers::set_args(EXE_NAME_ARGS),
bpr::initializers::throw_on_error(), bpr::initializers::inherit_env());
auto exitStatus = bpr::wait_for_exit(exeServer); // type will be either DWORD or int
int exitCode = BOOST_PROCESS_EXITSTATUS(exitStatus);
cout << " ok" << "\tstatus: " << exitCode << "\n";
}
catch (const exception& excStartExeServer)
{
cout << "\n" << "Error: " << excStartExeServer.what() << "\n";
}
}
(Problem) On Windows, the above code will start btsync and wait (block) until the process is terminated (either by using Task Manager or by the API's shutdown method), just like desired.
But on Linux, it finishes execution immediately after starting the process, as if wait_for_exit() isn't there at all, though the btsync process isn't terminated.
In an attempt to see if that has something to do with the btsync executable itself, I replaced it by this simple program:
File: Fake-Btsync.cpp
#include <cstdio>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#define SLEEP Sleep(20000)
#include <Windows.h>
#else
#include <unistd.h>
#define SLEEP sleep(20)
#endif
using namespace std;
int main(int argc, char* argv[])
{
for (int i = 0; i < argc; i++)
{
printf(argv[i]);
printf("\n");
}
SLEEP;
return 0;
}
When used with this program, instead of the original btsync downloaded from the official website, my application works as desired. It will block for 20 seconds and then exit.
Question: What is the reason for the described behavior? The only thing I can think of is that btsync restarts itself on Linux. But how to confirm that? Or what else could it be?
Update: All I needed to do was to know about what forking is and how it works, as pointed in sehe's answer (thanks!).
Question 2: If I use the System Monitor to send an End command to the child process 'Fake-Btsync' while my main application is blocked, wait_for_exit() will throw an exception saying:
waitpid(2) failed: No child processes
Which is a different behavior than on Windows, where it simply says "ok" and terminates with status 0.
Update 2: sehe's answer is great, but didn't quite address Question 2 in a way I could actually understand. I'll write a new question about that and post the link here.
The problem is your assumption about btsync. Let's start it:
./btsync
By using this application, you agree to our Privacy Policy, Terms of Use and End User License Agreement.
http://www.bittorrent.com/legal/privacy
http://www.bittorrent.com/legal/terms-of-use
http://www.bittorrent.com/legal/eula
BitTorrent Sync forked to background. pid = 24325. default port = 8888
So, that's the whole story right there: BitTorrent Sync forked to background. Nothing more. Nothing less. If you want to, btsync --help tells you to pass --nodaemon.
Testing Process Termination
Let's pass --nodaemon run btsync using the test program. In a separate subshell, let's kill the child btsync process after 5 seconds:
sehe#desktop:/tmp$ (./test; echo exit code $?) & (sleep 5; killall btsync)& time wait
[1] 24553
[2] 24554
By using this application, you agree to our Privacy Policy, Terms of Use and End User License Agreement.
http://www.bittorrent.com/legal/privacy
http://www.bittorrent.com/legal/terms-of-use
http://www.bittorrent.com/legal/eula
[20141029 10:51:16.344] total physical memory 536870912 max disk cache 2097152
[20141029 10:51:16.344] Using IP address 192.168.2.136
[20141029 10:51:16.346] Loading config file version 1.4.93
[20141029 10:51:17.389] UPnP: Device error "http://192.168.2.1:49000/l2tpv3.xml": (-2)
[20141029 10:51:17.407] UPnP: ERROR mapping TCP port 43564 -> 192.168.2.136:43564. Deleting mapping and trying again: (403) Unknown result code (UPnP protocol violation?)
[20141029 10:51:17.415] UPnP: ERROR removing TCP port 43564: (403) Unknown result code (UPnP protocol violation?)
[20141029 10:51:17.423] UPnP: ERROR mapping TCP port 43564 -> 192.168.2.136:43564: (403) Unknown result code (UPnP protocol violation?)
[20141029 10:51:21.428] Received shutdown request via signal 15
[20141029 10:51:21.428] Shutdown. Saving config sync.dat
Starting Server... ok status: 0
exit code 0
[1]- Done ( ./test; echo exit code $? )
[2]+ Done ( sleep 5; killall btsync )
real 0m6.093s
user 0m0.003s
sys 0m0.026s
No problem!
A Better Fake Btsync
This should still be portable and be (much) better behaved when killed/terminated/interrupted:
#include <boost/asio/signal_set.hpp>
#include <boost/asio.hpp>
#include <iostream>
int main(int argc, char* argv[])
{
boost::asio::io_service is;
boost::asio::signal_set ss(is);
boost::asio::deadline_timer timer(is, boost::posix_time::seconds(20));
ss.add(SIGINT);
ss.add(SIGTERM);
auto stop = [&]{
ss.cancel(); // one of these will be redundant
timer.cancel();
};
ss.async_wait([=](boost::system::error_code ec, int sig){
std::cout << "Signal received: " << sig << " (ec: '" << ec.message() << "')\n";
stop();
});
timer.async_wait([&](boost::system::error_code ec){
std::cout << "Timer: '" << ec.message() << "'\n";
stop();
});
std::copy(argv, argv+argc, std::ostream_iterator<std::string>(std::cout, "\n"));
is.run();
return 0;
}
You can test whether it is well-behaved
(./btsync --nodaemon; echo exit code $?) & (sleep 5; killall btsync)& time wait
The same test can be run with "official" btsync and "fake" btsync. Output on my linux box:
sehe#desktop:/tmp$ (./btsync --nodaemon; echo exit code $?) & (sleep 5; killall btsync)& time wait
[1] 24654
[2] 24655
./btsync
--nodaemon
Signal received: 15 (ec: 'Success')
Timer: 'Operation canceled'
exit code 0
[1]- Done ( ./btsync --nodaemon; echo exit code $? )
[2]+ Done ( sleep 5; killall btsync )
real 0m5.014s
user 0m0.001s
sys 0m0.014s