DM: add acrn_timer api for timer emulation
We will use timerfd and epoll mechanism to emulate kinds of timers like PIT/RTC/WDT/PMTIMER/... in device model under Linux. The api is unified in this patch. Compare with sigevent mechanism, timerfd has a advantage that it could avoid race condition on resource accessing in the async sigev thread. change log: v1 -> v2: add NULL pointer check for function parameter; v2 -> v3: rename file name of vtimer.* to timer.*; rename structure name of vtimer to acrn_timer; add read() in timer handler to consume I/O event; v3 -> v4: replace bool clock_realtime with int clockid; close acrn_timer->fd properly; Tracked-On: #1489 Signed-off-by: Victor Sun <victor.sun@intel.com> Reviewed-by: Jian Jun Chen <jian.jun.chen@intel.com> Acked-by: Yin Fengwei <fengwei.yin@intel.com>
This commit is contained in:
parent
d9df6e93f3
commit
6ffa1aa367
|
@ -122,6 +122,7 @@ SRCS += core/mptbl.c
|
|||
SRCS += core/main.c
|
||||
SRCS += core/hugetlb.c
|
||||
SRCS += core/vrpmb.c
|
||||
SRCS += core/timer.c
|
||||
|
||||
# arch
|
||||
SRCS += arch/x86/pm.c
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* Copyright (C) <2018> Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/timerfd.h>
|
||||
|
||||
#include "vmmapi.h"
|
||||
#include "mevent.h"
|
||||
#include "timer.h"
|
||||
|
||||
/* We can use timerfd and epoll mechanism to emulate kinds of timers like
|
||||
* PIT/RTC/WDT/PMTIMER/... in device model under Linux.
|
||||
* Compare with sigevent mechanism, timerfd has a advantage that it could
|
||||
* avoid race condition on resource accessing in the async sigev thread.
|
||||
*
|
||||
* Please note timerfd and epoll are all Linux specific. If the code need to be
|
||||
* ported to other OS, we can modify the api with POSIX timers and sigevent
|
||||
* mechanism.
|
||||
*/
|
||||
|
||||
static void
|
||||
timer_handler(int fd __attribute__((unused)),
|
||||
enum ev_type t __attribute__((unused)),
|
||||
void *arg)
|
||||
{
|
||||
struct acrn_timer *timer = arg;
|
||||
uint64_t buf;
|
||||
int32_t size;
|
||||
|
||||
if (timer == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Consume I/O event for default EPOLLLT type.
|
||||
* Here is a temporary solution, the processing could be moved to
|
||||
* mevent.c once EVF_TIMER is supported.
|
||||
*/
|
||||
size = read(timer->fd, &buf, sizeof(buf));
|
||||
if (size < 1) {
|
||||
fprintf(stderr, "acrn_timer read timerfd error!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (timer->callback != NULL) {
|
||||
(*timer->callback)(timer->callback_param);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t
|
||||
acrn_timer_init(struct acrn_timer *timer, void (*cb)(void *), void *param)
|
||||
{
|
||||
if ((timer == NULL) || (cb == NULL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
timer->fd = -1;
|
||||
if ((timer->clockid == CLOCK_REALTIME) ||
|
||||
(timer->clockid == CLOCK_MONOTONIC)) {
|
||||
timer->fd = timerfd_create(timer->clockid,
|
||||
TFD_NONBLOCK | TFD_CLOEXEC);
|
||||
} else {
|
||||
perror("acrn_timer clockid is not supported.\n");
|
||||
}
|
||||
|
||||
if (timer->fd <= 0) {
|
||||
perror("acrn_timer create failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
timer->mevp = mevent_add(timer->fd, EVF_READ, timer_handler, timer);
|
||||
if (timer->mevp == NULL) {
|
||||
close(timer->fd);
|
||||
perror("acrn_timer mevent add failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
timer->callback = cb;
|
||||
timer->callback_param = param;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
acrn_timer_deinit(struct acrn_timer *timer)
|
||||
{
|
||||
if (timer == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (timer->mevp != NULL) {
|
||||
mevent_delete_close(timer->mevp);
|
||||
timer->mevp = NULL;
|
||||
}
|
||||
|
||||
timer->fd = -1;
|
||||
timer->callback = NULL;
|
||||
timer->callback_param = NULL;
|
||||
}
|
||||
|
||||
int32_t
|
||||
acrn_timer_settime(struct acrn_timer *timer, struct itimerspec *new_value)
|
||||
{
|
||||
if (timer == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return timerfd_settime(timer->fd, 0, new_value, NULL);
|
||||
}
|
||||
|
||||
int32_t
|
||||
acrn_timer_gettime(struct acrn_timer *timer, struct itimerspec *cur_value)
|
||||
{
|
||||
if (timer == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return timerfd_gettime(timer->fd, cur_value);
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (C) <2018> Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef _TIMER_H_
|
||||
#define _TIMER_H_
|
||||
|
||||
struct acrn_timer {
|
||||
int32_t fd;
|
||||
int32_t clockid;
|
||||
struct mevent *mevp;
|
||||
void (*callback)(void *);
|
||||
void *callback_param;
|
||||
};
|
||||
|
||||
int32_t
|
||||
acrn_timer_init(struct acrn_timer *timer, void (*cb)(void *), void *param);
|
||||
void
|
||||
acrn_timer_deinit(struct acrn_timer *timer);
|
||||
int32_t
|
||||
acrn_timer_settime(struct acrn_timer *timer, struct itimerspec *new_value);
|
||||
int32_t
|
||||
acrn_timer_gettime(struct acrn_timer *timer, struct itimerspec *cur_value);
|
||||
|
||||
#endif /* _VTIMER_ */
|
Loading…
Reference in New Issue