std::condition_variable wait_until surprising behaviour - c++11

Building with VS2013, specifying time_point::max() to a condition variable's wait_until results in an immediate timeout.
This seems unintuitive - I would naively expect time_point::max() to wait indefinitely (or at least a very long time). Can anyone confirm if this is documented, expected behaviour or something specific to MSVC?
Sample program below; note replacing time_point::max() with now + std::chrono::hours(1) gives the expected behaviour (wait_for exits once cv is notified, with no timeout)
#include <condition_variable>
#include <mutex>
#include <chrono>
#include <future>
#include <functional>
void fire_cv( std::mutex *mx, std::condition_variable *cv )
{
std::unique_lock<std::mutex> lock(*mx);
printf("firing cv\n");
cv->notify_one();
}
int main(int argc, char *argv[])
{
std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
std::condition_variable test_cv;
std::mutex test_mutex;
std::future<void> s;
{
std::unique_lock<std::mutex> lock(test_mutex);
s = std::async(std::launch::async, std::bind(fire_cv, &test_mutex, &test_cv));
printf("blocking on cv\n");
std::cv_status result = test_cv.wait_until( lock, std::chrono::steady_clock::time_point::max() );
//std::cv_status result = test_cv.wait_until( lock, now + std::chrono::hours(1) ); // <--- this works as expected!
printf("%s\n", (result==std::cv_status::timeout) ? "timeout" : "no timeout");
}
s.wait();
return 0;
}

I debugged MSCV 2015's implementation, and wait_until calls wait_for internally, which is implemented like this:
template<class _Rep,
class _Period>
_Cv_status wait_for(
unique_lock<mutex>& _Lck,
const chrono::duration<_Rep, _Period>& _Rel_time)
{ // wait for duration
_STDEXT threads::xtime _Tgt = _To_xtime(_Rel_time); // Bug!
return (wait_until(_Lck, &_Tgt));
}
The bug here is that _To_xtime overflows, which results in undefined behavior, and the result is a negative time_point:
template<class _Rep,
class _Period> inline
xtime _To_xtime(const chrono::duration<_Rep, _Period>& _Rel_time)
{ // convert duration to xtime
xtime _Xt;
if (_Rel_time <= chrono::duration<_Rep, _Period>::zero())
{ // negative or zero relative time, return zero
_Xt.sec = 0;
_Xt.nsec = 0;
}
else
{ // positive relative time, convert
chrono::nanoseconds _T0 =
chrono::system_clock::now().time_since_epoch();
_T0 += chrono::duration_cast<chrono::nanoseconds>(_Rel_time); //Overflow!
_Xt.sec = chrono::duration_cast<chrono::seconds>(_T0).count();
_T0 -= chrono::seconds(_Xt.sec);
_Xt.nsec = (long)_T0.count();
}
return (_Xt);
}
std::chrono::nanoseconds by default stores its value in a long long, and so after its definition, _T0 has a value of 1'471'618'263'082'939'000 (this changes obviously). Adding _Rel_time (9'223'244'955'544'505'510) results definitely in signed overflow.
We have already passed every negative time_point possible, so a timeout happens.

Related

How to use std::chrono::milliseconds as a default parameter

Scenario
I have a C++ function which intakes a parameter as std::chrono::milliseconds. It is basically a timeout value. And, it is a default parameter set to some value by default.
Code
#include <iostream>
#include <chrono>
void Fun(const std::chrono::milliseconds someTimeout = std::chrono::milliseconds(100)) {
if (someTimeout > 0) {
std::cout << "someNumberInMillis is: " << someNumberInMillis.count() << std::endl;
}
}
int main() {
unsigned int someValue = 500;
Fun(std::chrono::milliseconds(someValue))
}
Issue
All of above is okay but, when I call Fun with a value then fails to compile and I get the following error:
No viable conversion from 'bool' to 'std::chrono::milliseconds' (aka
'duration >')
Question:
What am I doing wrong here? I want the caller of Fun to be explicitly aware that it is using std::chrono::milliseconds when it invokes Fun. But the compiler doesn't seem to allow using std::chrono::milliseconds as a parameter?
How use std::chrono::milliseconds as a default parameter?
Environment
Compiler used is clang on macOS High Sierra
With the other syntax errors fixed, this compiles without warnings in GCC 9:
#include <iostream>
#include <chrono>
void Fun(const std::chrono::milliseconds someNumberInMillis
= std::chrono::milliseconds(100))
{
if (someNumberInMillis > std::chrono::milliseconds{0}) {
std::cout << "someNumberInMillis is: " << someNumberInMillis.count()
<< std::endl;
}
}
int main()
{
unsigned int someValue = 500;
Fun(std::chrono::milliseconds(someValue));
}

Catch system calls on Mac OS X

I'm trying to catch all systems-calls called by a given PID with a self-made program (I cant use any of strace, dtruss, gdb...). So i used the function
kern_return_t task_set_emulation(task_t target_port, vm_address_t routine_entry_pt, int routine_number) declared in /usr/include/mach/task.h .
I've written a little program to catch the syscall write :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <mach/mach.h>
#include <mach/mach_vm.h>
void do_exit(char *msg)
{
printf("Error::%s\n", msg);
exit(42);
}
int main(void)
{
mach_port_t the_task;
mach_vm_address_t address;
mach_vm_size_t size;
mach_port_t the_thread;
kern_return_t kerr;
//Initialisation
address = 0;
size = 1ul * 1024;
the_task = mach_task_self(); //Get the current program task
kerr = mach_vm_allocate(the_task, &address, size, VM_MEMORY_MALLOC); //Allocate a new address for the test
if (kerr != KERN_SUCCESS)
{ do_exit("vm_allocate"); }
printf("address::%llx, size::%llu\n", address, size); //debug
//Process
kerr = task_set_emulation(the_task, address, SYS_write); //About to catch write syscalls
the_thread = mach_thread_self(); //Verify if a thread is opened (even if it's obvious)
printf("kerr::%d, thread::%d\n", kerr, the_thread); //debug
if (kerr != KERN_SUCCESS)
{ do_exit("set_emulation"); }
//Use some writes for the example
write(1, "Bonjour\n", 8);
write(1, "Bonjour\n", 8);
}
The Output is :
address::0x106abe000, size::1024
kerr::46, thread::1295
Error::set_emulation
The kernel error 46 corresponds to the macro KERN_NOT_SUPPORTED described as an "Empty thread activation (No thread linked to it)" in /usr/include/mach/kern_return.h, and happend even before i'm calling write.
My question is: What did I do wrong in this process? Kern_not_supported does mean that it's not implemented yet, instead of a meaningless thread problem?
The source code in XNU for the task_set_emulation is:
kern_return_t
task_set_emulation(
__unused task_t task,
__unused vm_offset_t routine_entry_pt,
__unused int routine_number)
{
return KERN_NOT_SUPPORTED;
}
Which means task_set_emulation is not supported.

std::condition_variable::wait_for exits immediately when given std::chrono::duration::max

I have a wrapper around std::queue using C++11 semantics to allow concurrent access. The std::queue is protected with a std::mutex. When an item is pushed to the queue, a std::condition_variable is notified with a call to notify_one.
There are two methods for popping an item from the queue. One method will block indefinitely until an item has been pushed on the queue, using std::condition_variable::wait(). The second will block for an amount of time given by a std::chrono::duration unit using std::condition_variable::wait_for():
template <typename T> template <typename Rep, typename Period>
void ConcurrentQueue<T>::Pop(T &item, std::chrono::duration<Rep, Period> waitTime)
{
std::cv_status cvStatus = std::cv_status::no_timeout;
std::unique_lock<std::mutex> lock(m_queueMutex);
while (m_queue.empty() && (cvStatus == std::cv_status::no_timeout))
{
cvStatus = m_pushCondition.wait_for(lock, waitTime);
}
if (cvStatus == std::cv_status::no_timeout)
{
item = std::move(m_queue.front());
m_queue.pop();
}
}
When I call this method like this on an empty queue:
ConcurrentQueue<int> intQueue;
int value = 0;
std::chrono::seconds waitTime(12);
intQueue.Pop(value, waitTime);
Then 12 seconds later, the call to Pop() will exit. But if waitTime is instead set to std::chrono::seconds::max(), then the call to Pop() will exit immediately. The same occurs for milliseconds::max() and hours::max(). But, days::max() works as expected (doesn't exit immediately).
What causes seconds::max() to exit right away?
This is compiled with mingw64:
g++ --version
g++ (rev5, Built by MinGW-W64 project) 4.8.1
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
To begin with, the timed wait should likely be a wait_until(lock, std::chrono::steady_clock::now() + waitTime);, not wait_for because the loop will now simply repeat the wait multiple times until finally the condition (m_queue.empty()) becomes true. The repeats can also be caused by spurious wake-ups.
Fix that part of the code by using the predicated wait methods:
template <typename Rep, typename Period>
bool pop(std::chrono::duration<Rep, Period> waitTime, int& popped)
{
std::unique_lock<std::mutex> lock(m_queueMutex);
if (m_pushCondition.wait_for(lock, waitTime, [] { return !m_queue.empty(); }))
{
popped = m_queue.back();
m_queue.pop_back();
return true;
} else
{
return false;
}
}
On my implementation at least seconds::max() yields 0x7fffffffffffffff
§30.5.1 ad 26 states:
Effects: as if
return wait_until(lock, chrono::steady_clock::now() + rel_time);
Doing
auto time = steady_clock::now() + seconds::max();
std::cout << std::dec << duration_cast<seconds>(time.time_since_epoch()).count() << "\n";
On my system, prints
265521
Using date --date='#265521' --rfc-822 told me that that is Sun, 04 Jan 1970 02:45:21 +0100
There's a wrap around bug going on for GCC and Clang, see below
Tester
Live On Coliru
#include <thread>
#include <condition_variable>
#include <iostream>
#include <deque>
#include <chrono>
#include <iomanip>
std::mutex m_queueMutex;
std::condition_variable m_pushCondition;
std::deque<int> m_queue;
template <typename Rep, typename Period>
bool pop(std::chrono::duration<Rep, Period> waitTime, int& popped)
{
std::unique_lock<std::mutex> lock(m_queueMutex);
if (m_pushCondition.wait_for(lock, waitTime, [] { return !m_queue.empty(); }))
{
popped = m_queue.back();
m_queue.pop_back();
return true;
} else
{
return false;
}
}
int main()
{
int data;
using namespace std::chrono;
pop(seconds(2) , data);
std::cout << std::hex << std::showbase << seconds::max().count() << "\n";
auto time = steady_clock::now() + seconds::max();
std::cout << std::dec << duration_cast<seconds>(time.time_since_epoch()).count() << "\n";
pop(seconds::max(), data);
}
The reason for the problem is this nasty bit in the description for rel_time parameter:
Note that rel_time must be small enough not to overflow when added to std::chrono::steady_clock::now().
So when you do m_pushCondition.wait_for(lock, std::chrono::seconds::max()); the parameter overflows inside the function. In fact, if you enable undefined sanitizer, (e.g. -fsanitize=undefined option for GCC and Clang), and run the app, you may see the following runtime warning:
/usr/include/c++/9.1.0/chrono:456:34: runtime error: signed integer overflow: 473954758945968 + 9223372036854775807 cannot be represented in type 'long int'
Worth noting though that for some reason I did not have this warning for the actual app I was working on, probably a sanitizer bug. Anyway.
So what you can do. First: do not try to work around that by simply using the wait_for() overload with predicate because you gonna make yourself a bad spinlock burning your CPU core. Second: substracting max() - now() doesn't seem to work because it changes the type.
One way to work that around is using conditionally condition_variable::wait() and condition_variable::wait_for().
Another one may be to just declare declare big timespan, and use it. E.g.:
// This is a replacement to chrono::seconds::max(). The latter doesn't work with
// `wait_for` call because its `rel_time` parameter description has the following
// sentence: "Note that rel_time must be small enough not to overflow when added to
// std::chrono::steady_clock::now()".
const chrono::seconds many_hours = 99h;
// …[snip]…
m_pushCondition.wait_for(lock, many_hours);
// …[snip]…
You probably can tolerate a "spurious" wakeup once a 99 hours :)

C shell printing output infinitely without stopping at gets()

I am trying to use the SIGCHLD handler but for some reason it prints of the command I gave infinitely. If I remove the struct act it works fine.
Can anyone take a look at it, I am not able to understand what the problem is.
Thanks in advance!!
/* Simplest dead child cleanup in a SIGCHLD handler. Prevent zombie processes
but dont actually do anything with the information that a child died. */
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
typedef char *string;
/* SIGCHLD handler. */
static void sigchld_hdl (int sig)
{
/* Wait for all dead processes.
* We use a non-blocking call to be sure this signal handler will not
* block if a child was cleaned up in another part of the program. */
while (waitpid(-1, NULL, WNOHANG) > 0) {
}
}
int main (int argc, char *argv[])
{
struct sigaction act;
int i;
int nbytes = 100;
char my_string[nbytes];
string arg_list[5];
char *str;
memset (&act, 0, sizeof(act));
act.sa_handler = sigchld_hdl;
if (sigaction(SIGCHLD, &act, 0)) {
perror ("sigaction");
return 1;
}
while(1){
printf("myshell>> ");
gets(my_string);
str=strtok(my_string," \n");
arg_list[0]=str;
i =1;
while ( (str=strtok (NULL," \n")) != NULL){
arg_list[i]= str;
i++;
}
if (i==1)
arg_list[i]=NULL;
else
arg_list[i+1]=NULL;
pid_t child_pid;
child_pid=fork();
if (child_pid == (pid_t)-1){
printf("ERROR OCCURED");
exit(0);
}
if(child_pid!=0){
printf("this is the parent process id is %d\n", (int) getpid());
printf("the child's process ID is %d\n",(int)child_pid);
}
else{
printf("this is the child process, with id %d\n", (int) getpid());
execvp(arg_list[0],arg_list);
printf("this should not print - ERROR occured");
abort();
}
}
return 0;
}
I haven't run your code, and am merely hypothesizing:
SIGCHLD is arriving and interrupting fgets (I'll just pretend you didn't use gets). fgets returns before actually reading any data, my_string contains the tokenized list that it had on the previous loop, you fork again, enter fgets, which is interrupted before reading any data, and repeat indefinitely.
In other words, check the return value of fgets. If it is NULL and has set errno to EINTR, then call fgets again. (Or set act.sa_flags = SA_RESTART.)

Visual Studio 2010 (C++): suppress C4706 warning temporarily

When you compile the following C++ source file in Visual Studio 2010 with warning level /W4 enabled
#include <cstdio> // for printf
#include <cstring> // for strcmp
char str0[] = "Hello";
char str1[] = "World";
int main()
{
int result;
if (result = strcmp(str0, str1)) // line 11
{
printf("Strings are different\n");
}
}
you get the following warning
warning C4706: assignment within conditional expression
for line 11.
I want to suppress this warning exactly at this place. So I tried Google and found this page: http://msdn.microsoft.com/en-us/library/2c8f766e(v=VS.100).aspx
So I changed the code to the following - hoping this would solve the problem:
#include <cstdio> // for printf
#include <cstring> // for strcmp
char str0[] = "Hello";
char str1[] = "World";
int main()
{
int result;
#pragma warning(push)
#pragma warning(disable : 4706)
if (result = strcmp(str0, str1))
#pragma warning(pop)
{
printf("Strings are different\n");
}
}
It didn't help.
This variant didn't help either:
#include <cstdio> // for printf
#include <cstring> // for strcmp
char str0[] = "Hello";
char str1[] = "World";
int main()
{
int result;
#pragma warning(push)
#pragma warning(disable : 4706)
if (result = strcmp(str0, str1))
{
#pragma warning(pop)
printf("Strings are different\n");
}
}
To avoid one further inquiry: I cleaned the solution before each compilation. So this is probably not the fault.
So in conclusion: how do I suppress the C4706 exactly at this place?
Edit Yes, rewriting is possible - but I really want to know why the way I try to suppress the warning (that is documented officially on MSDN) doesn't work - where is the mistake?
Instead of trying to hide your warning, fix the issue it's complaining about; your assignment has a value (the value on the left side of the assignment) that can be legally used in another expression.
You can fix this by explicitly testing the result of the assignment:
if ((result = strcmp(str0, str1)) != 0)
{
printf("Strings are different\n");
}
In MSDN Libray: http://msdn.microsoft.com/en-us/library/2c8f766e(v=VS.100).aspx, There is the section as follows.
For warning numbers in the range 4700-4999, which are the ones
associated with code generation, the state of the warning in effect
when the compiler encounters the open curly brace of a function will
be in effect for the rest of the function. Using the warning pragma in
the function to change the state of a warning that has a number larger
than 4699 will only take effect after the end of the function. The
following example shows the correct placement of warning pragmas to
disable a code-generation warning message, and then to restore it.
So '#pragma warning' only works for an each function/method.
Please see the following code for more detail.
#include <cstdio> // for printf
#include <cstring> // for strcmp
char str0[] = "Hello";
char str1[] = "World";
#pragma warning(push)
#pragma warning( disable : 4706 )
void func()
{
int result;
if (result = strcmp(str0, str1)) // No warning
{
printf("Strings are different\n");
}
#pragma warning(pop)
}
int main()
{
int result;
if (result = strcmp(str0, str1)) // 4706 Warning.
{
printf("Strings are different\n");
}
}
The sane solution is to rewrite the condition to
if( (result = strcmp(str0, str1)) != 0 )
which will inform any C compiler that you really want to assign, and is almost certain to generate the same object code.
There is another solution which avoids the warning: the comma operator.
The main advantage here will be that you don't need parentheses so it's a bit shorter than the !=0 solution when your variable name is short.
For example:
if (result = strcmp(str0, str1), result)
{
printf("Strings are different\n");
}
There is a simple construction !! to cast a type to bool. Like this:
if (!!(result = strcmp(str0, str1)))
However, in some cases direct comparison != 0 might be more clear to a reader.

Resources