重新定向C++ chrono的newlib

3
我正在使用arm-none-eabi工具链和newlib来针对一个ARM Cortex-M0+的自定义板进行编程(特别是工具链的MCU-on-eclipse版本)。我使用-nostartfiles--specs=nano.specs进行编译/链接,并已将stdout和stderr重新定向到USB和串行端口。我已经为大多数C系统调用创建了实现。
我正在使用chrono库和两个自定义时钟,now()函数获取RTC时间或我的systick计时器。这似乎反映了标准steady_clock和system_clock的目的,因此我想尝试使用它们。
为此,我必须实现gettimeofday系统调用,我已经完成了这个任务。
// returning a set time of one second just for testing
int _gettimeofday(struct timeval* tv, void* tz) {
    tv->tv_sec  = 1;
    tv->tv_usec = 255;
    return 0;
}

我的主要代码如下:

int main(void)
{
    HWInit();

    static std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
    static std::chrono::system_clock::time_point t2 = std::chrono::system_clock::now();
    int64_t count1 = t1.time_since_epoch().count();
    int64_t count2 = t2.time_since_epoch().count();

    printf("Time 1: %lld\n Time 2: %lld\n", count1, count2);
    for(;;){}
    return 0;
}

使用调试器,我可以看到steady_clock::now()system_clock::now()都调用了我的_gettimeofday()函数,并且最终得到了完全相同的时间点。

当然,如果我尝试执行以下操作,我会得到多个定义错误:

using SysClock = std::chrono::system_clock;

SysClock::time_point SysClock::now() noexcept {
    return SysClock::time_point( SysClock::duration(1983) );
}

那么,我是否可以以某种方式重载标准chrono时钟的now()函数?或者用自己的duration和rep typedefs覆盖整个时钟实现,以更好地匹配硬件?我可以为嵌入式系统重载new和delete(也应该这样做),因此为chrono执行此操作也很好。
2个回答

3

来自 gcc的libstdc++ chrono.cc

  • system_clock::now() 使用gettimeofday(&tv, 0);clock_gettime(CLOCK_REALTIME, &tp); 或系统调用。如果gettimeofday适用于您,那么它就使用它。
  • steady_clock::now() 使用clock_gettime(CLOCK_MONOTONIC, &tp);。因此,您应该重载clock_gettime并处理CLOCK_MONOTONIC参数。
  • 新的libc库中没有提供_clock_gettime_r函数,类似于在_gettimeofday_t中传递newlib的struct reent的函数。如果您想在newlib中处理多线程,建议编写自己的类似包装器,以处理_reent->errno值。但是,最好重载_gettimeofday_r函数,因为您只针对newlib。

看起来gettimeofday是唯一可用的,这意味着我的副本是使用_GLIBCXX_USE_GETTIMEOFDAY而不是_GLIBCXX_USE_CLOCK_REALTIME编译的。reent结构没有任何关于所请求时钟类型的指示,因此我可能需要重新编译libstdc++才能使clock_gettime()工作。感谢提供代码链接。 - CrustyAuklet
_GLIBCXX_USE_GETTIMEOFDAY 影响 system_clock::now()。因为 arm-none-eabi-gcclibstdc++ 是没有使用 _GLIBCXX_USE_CLOCK_GETTIME_SYSCALL 编译的,所以你需要提供 extern "C" int clock_gettime(clockid_t clk_id, struct timespec *tp); 的定义。clk_id 正好用于指定时钟... - KamilCuk

0

不要试图改变system_clocksteady_clock的行为,我建议您编写自己的自定义时钟并使用它们。这样,您可以更好地将其定制为适合硬件和需求的形式。如果您有一种获取当前时间的方法,那么创建一个自定义的chrono时钟来包装该函数非常容易。

class SysClock
{
public:
    // 500MHz, or whatever you need
    using period                    = std::ratio<1, 500'000'000>;
    using rep                       = long long;
    using duration                  = std::chrono::duration<rep, period>;
    using time_point                = std::chrono::time_point<SysClcok>;
    static constexpr bool is_steady = true;

    static time_point now() noexcept
    {
        return time_point{duration{
            /*turn SysTick_getValue() into the number of ticks since epoch*/}};
    }
};

现在在您的代码中使用SysClock::now()而不是system_clock::now()。这将为您提供从两个SysClock::time_point相减得到的SysClock::time_pointchrono::durations结果。

如果您可以将低级别的“now”转换为某个时期内的滴答数,并且可以将这些滴答描述为period的编译时秒的一部分,则可以开始了。


1
这是我现在正在做的事情,使用我的自定义时钟在头文件sealChrono.h中(它是基于鳍足动物的框架),然后包括chrono和date.h(顺便说一句,这是一个很棒的库!)。我只是希望/尝试使框架对用户更加透明。重新编译标准库有点超出范围,所以我可能会坚持这个解决方案。 - CrustyAuklet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接