Перенацеливание newlib для c ++ chrono

Я использую набор инструментов arm-none-eabi с newlib, чтобы настроить таргетинг на настраиваемую плату с ARM Cortex-M0 + (в частности, MCU-on-eclipse версии набора инструментов). Я компилирую / связываю с -nostartfiles и --specs=nano.specs и переназначил stdout и stderr на USB и последовательный порт соответственно. Я создал реализации для большинства системных вызовов C.

Я использую библиотеку chrono с двумя пользовательскими часами, функциями now () получить время RTC или мой таймер systick. Похоже, что это отражает назначение стандартных stable_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(), и sysytem_clock::now() вызывают мою функцию _gettimeofday (), и обе в конечном итоге имеют один и тот же момент времени.

конечно, если я попытаюсь сделать следующее, я получу несколько ошибок определения:

using SysClock = std::chrono::system_clock;

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

Так можно как-то перегрузить функции now () стандартных хронометров? или, может быть, вся реализация часов с моей собственной продолжительностью и определениями типов реплик, которые лучше соответствуют оборудованию? Я могу перегрузить новые и удалить для своей встроенной системы (и должен), поэтому было бы неплохо сделать это для chrono.


person CrustyAuklet    schedule 24.03.2019    source источник


Ответы (2)


Из gccs 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.
  • В newlib нет функции _clock_gettime_r, как в _gettimeofday_t, который передает struct reent newlib. Если вы хотите обрабатывать многопоточность в newlib, хорошо написать собственную аналогичную оболочку, которая обрабатывает значение _reent->errno. Но ставка будет заключаться в перегрузке _gettimeofday_r функции, поскольку вы нацелены только на newlib.
person KamilCuk    schedule 24.03.2019
comment
похоже, что gettimeofday - единственный, который работает, что означает, что моя копия была скомпилирована с _GLIBCXX_USE_GETTIMEOFDAY вместо _GLIBCXX_USE_CLOCK_REALTIME. В структуре reent не указан тип запрошенных часов, поэтому мне, вероятно, придется перекомпилировать libstdc ++, чтобы заставить clock_gettime () работать. спасибо за ссылки на код. - person CrustyAuklet; 24.03.2019
comment
_GLIBCXX_USE_GETTIMEOFDAY влияет на system_clock::now(). Поскольку libstdc++ для arm-none-eabi-gcc скомпилирован без _GLIBCXX_USE_CLOCK_GETTIME_SYSCALL, вам необходимо предоставить определение extern "C" int clock_gettime(clockid_t clk_id, struct timespec *tp);. clk_id точно используется для указания часов ... - person KamilCuk; 24.03.2019

Вместо того, чтобы пытаться изменить поведение system_clock и steady_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 и chrono::durations результат вычитания двух SysClock::time_point.

Если вы можете превратить свое низкоуровневое «сейчас» в подсчет тиков для некоторой эпохи, и вы можете описать эти тики как долю секунды времени компиляции с period, тогда все готово.

person Howard Hinnant    schedule 24.03.2019
comment
Это то, что я делаю сейчас, с моими пользовательскими часами в заголовке sealChrono.h (это фреймворк на основе ластоногих), который затем включает chrono и date.h (кстати, классная библиотека!). Я просто надеялся / экспериментировал с тем, чтобы сделать фреймворк более прозрачным для пользователя. Однако перекомпиляция стандартной библиотеки немного выходит за рамки, поэтому я, вероятно, буду придерживаться этого решения. - person CrustyAuklet; 24.03.2019