diff --git a/common/src/platform/linux/CMakeLists.txt b/common/src/platform/linux/CMakeLists.txt index 8e193a2d..ac04effb 100644 --- a/common/src/platform/linux/CMakeLists.txt +++ b/common/src/platform/linux/CMakeLists.txt @@ -11,6 +11,7 @@ add_library(lg_common_platform_code STATIC thread.c event.c ivshmem.c + time.c ) if(ENABLE_BACKTRACE) @@ -20,4 +21,5 @@ endif() target_link_libraries(lg_common_platform_code lg_common pthread + rt ) diff --git a/common/src/platform/linux/time.c b/common/src/platform/linux/time.c new file mode 100644 index 00000000..3fc234d9 --- /dev/null +++ b/common/src/platform/linux/time.c @@ -0,0 +1,109 @@ +/* +Looking Glass - KVM FrameRelay (KVMFR) Client +Copyright (C) 2020-2020 Max Sistemich +https://looking-glass.hostfission.com + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "common/time.h" +#include "common/debug.h" + +#include +#include +#include +#include +#include + +struct LGTimer +{ + LGTimerFn fn; + void * udata; + timer_t id; + bool running; +}; + +static void TimerProc(union sigval arg) +{ + LGTimer * timer = (LGTimer *)arg.sival_ptr; + if (!timer->fn(timer->udata)) + { + if (timer_delete(timer->id)) + DEBUG_ERROR("failed to destroy the timer: %s", strerror(errno)); + timer->running = false; + } +} + +bool lgCreateTimer(const unsigned int intervalMS, LGTimerFn fn, + void * udata, LGTimer ** result) +{ + LGTimer * ret = malloc(sizeof(LGTimer)); + + if (!ret) + { + DEBUG_ERROR("failed to malloc LGTimer struct"); + return false; + } + + ret->fn = fn; + ret->udata = udata; + ret->running = true; + + struct sigevent sev = + { + .sigev_notify = SIGEV_THREAD, + .sigev_notify_function = &TimerProc, + .sigev_value.sival_ptr = ret, + }; + + if (timer_create(CLOCK_MONOTONIC, &sev, &ret->id)) + { + DEBUG_ERROR("failed to create timer: %s", strerror(errno)); + free(ret); + return false; + } + + struct timespec interval = + { + .tv_sec = 0, + .tv_nsec = intervalMS * 1000 * 1000, + }; + struct itimerspec spec = + { + .it_interval = interval, + .it_value = interval, + }; + + if (timer_settime(ret->id, 0, &spec, NULL)) + { + DEBUG_ERROR("failed to set timer: %s", strerror(errno)); + timer_delete(ret->id); + free(ret); + return false; + } + + *result = ret; + return true; +} + +void lgTimerDestroy(LGTimer * timer) +{ + if (timer->running) + { + if (timer_delete(timer->id)) + DEBUG_ERROR("failed to destroy the timer: %s", strerror(errno)); + } + + free(timer); +}