Reputation: 2603
The example:
boost::interprocess::interprocess_semaphore semDone(0);
long sec = 10;
boost::posix_time::ptime until = boost::posix_time::second_clock::universal_time() + boost::posix_time::seconds(sec);
bool ret = semDone.timed_wait(until);
It works perfectly on Linux at the time - the timed_wait
waits for 10 seconds and then returns false
.
However if I move the system date to 2116 year and re-run the app, the timed_wait
call returns false
immediately. There is the same problem with the boost's condition vars.
Could please anybody explain what's wrong with it?
Info:
UPD As I already wrote above, I'm running the test on 64bit platform, and the size of time_t
equals 8. So the answers advising to use 64bit time_t
instead of 32bit are not applicable for the question.
Upvotes: 3
Views: 385
Reputation: 2603
The root cause of the problem is that boost::posix_time::time_duration::total_seconds()
explicitly casts the return value to time_resolution_traits::sec_type
while converting ptime
to timespec
via boost::interprocess::ipcdetail::ptime_to_timespec()
during the timed_wait()
call.
The time_resolution_traits::sec_type
is a typedef to int32_t
type (see the typedef chain in boost/date_time/time_resolution_traits.hpp file).
At the same time documentation says that time_duration::total_seconds()
returns long
(http://www.boost.org/doc/libs/1_62_0/doc/html/date_time/posix_time.html). But for LP64 models (e.g. Linux, 64bit) it returns signed 32bit integer, not long
(signed 64bit integer).
So obviously there is a bug in boost. The first ticket for the bug was created in 2009. And it is still not fixed.
The tickets:
https://svn.boost.org/trac/boost/ticket/12214
I created the new one: https://svn.boost.org/trac/boost/ticket/12609.
UPD: The bug was fixed in Boost 1.66 as it's described at the bug's comments.
Upvotes: 2
Reputation: 446
Let me try to describe what happens with a small stacktrace to the line where the problem occurs (btw, I am using boost 1.58):
#0 boost::interprocess::ipcdetail::ptime_to_timespec (tm=...) at /usr/include/boost/interprocess/sync/posix/ptime_to_timespec.hpp:38
#1 0x402983 in boost::interprocess::ipcdetail::semaphore_timed_wait (handle=0x7fffffffe100, abs_time=...) at /usr/include/boost/interprocess/sync/posix/semaphore_wrapper.hpp:224
#2 0x402ab7 in boost::interprocess::ipcdetail::posix_semaphore::timed_wait (this=0x7fffffffe100, abs_time=...) at /usr/include/boost/interprocess/sync/posix/semaphore.hpp:55
#3 0x402b1d in boost::interprocess::interprocess_semaphore::timed_wait (this=0x7fffffffe100, abs_time=...) at /usr/include/boost/interprocess/sync/interprocess_semaphore.hpp:139
#4 0x40184d in main () at /tmp/t.cpp:10
Ok, so lets have a look what happens in the method ptime_to_timespec. Your previously created ptime object (line 3)
boost::posix_time::ptime until = boost::posix_time::second_clock::universal_time() + boost::posix_time::seconds(sec);
is passed to this function and is converted into a timespec object. The timespec object is defined in time.h and can be used to compute the duration since 00:00:00 January 1, 1970. (see http://pubs.opengroup.org/onlinepubs/7908799/xsh/time.h.html) It contains members like tv_sec (duration in seconds, type time_t), tv_nsec (type long), etc.
The problem simply is that the duration in seconds (starting at 01/01/1970 and ending at XX/XX/2116) is too large and does not fit into tv_sec (time_t is basically a signed int). The problem is also described here: https://stackoverflow.com/a/471287/5967798
I tested it with year 2116 and the timespec that was returned by the function described the date
9:18:59 am CET | Wednesday, October 8, 1980
Upvotes: 4