Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add MonotonicTime for use with timeouts #55

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions rostime/include/ros/time.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,8 +256,41 @@ namespace ros
static bool isSystemTime() { return true; }
};

/**
* \brief Time representation. Always monotonic-clock time.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be noted here that it is unaffected by ROS time, just like "wall" time is not.

*
* ros::TimeBase provides most of its functionality.
*/
class ROSTIME_DECL MonotonicTime : public TimeBase<MonotonicTime, WallDuration>
{
public:
MonotonicTime()
: TimeBase<MonotonicTime, WallDuration>()
{}

MonotonicTime(uint32_t _sec, uint32_t _nsec)
: TimeBase<MonotonicTime, WallDuration>(_sec, _nsec)
{}

explicit MonotonicTime(double t) { fromSec(t); }

/**
* \brief Returns the current monotonic clock time.
*/
static MonotonicTime now();

/**
* \brief Sleep until a specific time has been reached.
* @return True if the desired sleep time was met, false otherwise.
*/
static bool sleepUntil(const MonotonicTime& end);

static bool isSystemTime() { return true; }
};

ROSTIME_DECL std::ostream &operator <<(std::ostream &os, const Time &rhs);
ROSTIME_DECL std::ostream &operator <<(std::ostream &os, const WallTime &rhs);
ROSTIME_DECL std::ostream &operator <<(std::ostream &os, const MonotonicTime &rhs);
}

#endif // ROS_TIME_H
Expand Down
42 changes: 42 additions & 0 deletions rostime/src/time.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,29 @@ namespace ros
nsec = nsec_sum;
#endif
}

void ros_monotonictime(uint32_t& sec, uint32_t& nsec)
#ifndef WIN32
throw(NoHighPerformanceTimersException)
#endif
{
#ifndef WIN32
#if HAS_CLOCK_GETTIME
timespec start;
clock_gettime(CLOCK_MONOTONIC, &start);
sec = start.tv_sec;
nsec = start.tv_nsec;
#else
// what to do if clock_gettime is not available???
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't merge this with this code path in here, since I'm pretty sure that it isn't monotonic.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct. I would actually just leave the case when clock_gettime is not available out completely, as I don't know of any way to get a monotonic clock otherwise and this should not be the case on any actually used Linux versions anymore...

struct timeval timeofday;
gettimeofday(&timeofday,NULL);
sec = timeofday.tv_sec;
nsec = timeofday.tv_usec * 1000;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is possible to avoid this on macOS (also other BSD systems which don't have clock_gettime), but I'm hesitant to ask for it since the existing wall time system doesn't use it.

I've implemented something that is monotonic and works on Linux, and macOS for ROS 2:

https://github.com/ros2/rcl/blob/545cb5602c4bf9d000f0ebe62b9d95cb9bf59469/rcl/src/rcl/time_unix.c#L73-L102

There's also something for Windows:

https://github.com/ros2/rcl/blob/66208db876bba344a6733f4aa33451a028085612/rcl/src/rcl/time_win32.c#L49-L65

You're welcome to steal those implementations if you like.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks...
On a sidenote:
I'm not convinced that it is a good idea to use the CLOCK_MONOTONIC_RAW (even if its available) for steady time. IMHO CLOCK_MONOTONIC is always what we want here, namely it doesn't jump, but the clock drift is adjusted...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, it's been too long since I've looked at it to respond intelligently 😄, but I'll review the use of CLOCK_MONOTONIC_RAW. Thanks!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#endif
#else
ros_walltime(sec, nsec);
#endif
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be a great place to use std::chrono::steady_clock or std::chrono::high_resolution_clock when it returns true for is_steady, since they're portable.

However, I'm not sure that would be acceptable within roscpp_core since it's a C++11 only feature.

}
/**
* @brief Simple representation of the rt library nanosleep function.
*/
Expand Down Expand Up @@ -389,6 +412,17 @@ namespace ros
return true;
}

bool MonotonicTime::sleepUntil(const MonotonicTime& end)
{
WallDuration d(end - MonotonicTime::now());
if (d > WallDuration(0))
{
return d.sleep();
}

return true;
}

bool Duration::sleep() const
{
if (Time::useSystemTime())
Expand Down Expand Up @@ -444,6 +478,13 @@ namespace ros
return t;
}

MonotonicTime MonotonicTime::now()
{
MonotonicTime t;
ros_monotonictime(t.sec, t.nsec);

return t;
}
std::ostream &operator<<(std::ostream& os, const WallDuration& rhs)
{
boost::io::ios_all_saver s(os);
Expand Down Expand Up @@ -505,6 +546,7 @@ namespace ros

template class TimeBase<Time, Duration>;
template class TimeBase<WallTime, WallDuration>;
template class TimeBase<MonotonicTime, WallDuration>;
}