From 3fe4c3f2a8b451cbdd9a714e70cfe28ec6bf1644 Mon Sep 17 00:00:00 2001 From: Peter Fang Date: Thu, 10 Jan 2019 19:03:30 -0800 Subject: [PATCH] dm: provide timer callback handlers the number of expirations It is possible for multiple timeouts to occur in one mevent epoll iteration. Providing the number of timer expirations to the timer callback handlers can be useful. E.g., this could improve emulation of timing-sensitive hardware components. Tracked-On: #2319 Signed-off-by: Peter Fang Acked-by: Anthony Xu --- devicemodel/core/timer.c | 25 +++++++++++++++++-------- devicemodel/hw/pci/virtio/virtio.c | 2 +- devicemodel/hw/pci/wdt_i6300esb.c | 2 +- devicemodel/hw/platform/rtc.c | 5 +++-- devicemodel/include/timer.h | 4 ++-- 5 files changed, 24 insertions(+), 14 deletions(-) diff --git a/devicemodel/core/timer.c b/devicemodel/core/timer.c index bb9c5fb9b..e7bb766a7 100644 --- a/devicemodel/core/timer.c +++ b/devicemodel/core/timer.c @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include #include "vmmapi.h" @@ -28,8 +30,9 @@ timer_handler(int fd __attribute__((unused)), void *arg) { struct acrn_timer *timer = arg; - uint64_t buf; - int32_t size; + uint64_t nexp; + ssize_t size; + void (*cb)(void *, uint64_t); if (timer == NULL) { return; @@ -39,19 +42,25 @@ timer_handler(int fd __attribute__((unused)), * 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!"); + size = read(timer->fd, &nexp, sizeof(nexp)); + + if (size < 0) { + if (errno != EAGAIN) { + perror("acrn_timer read timerfd error"); + } return; } - if (timer->callback != NULL) { - (*timer->callback)(timer->callback_param); + assert(size > 0 && nexp > 0); + + if ((cb = timer->callback) != NULL) { + (*cb)(timer->callback_param, nexp); } } int32_t -acrn_timer_init(struct acrn_timer *timer, void (*cb)(void *), void *param) +acrn_timer_init(struct acrn_timer *timer, void (*cb)(void *, uint64_t), + void *param) { if ((timer == NULL) || (cb == NULL)) { return -1; diff --git a/devicemodel/hw/pci/virtio/virtio.c b/devicemodel/hw/pci/virtio/virtio.c index d8c6895c3..62f603559 100644 --- a/devicemodel/hw/pci/virtio/virtio.c +++ b/devicemodel/hw/pci/virtio/virtio.c @@ -66,7 +66,7 @@ virtio_start_timer(struct acrn_timer *timer, time_t sec, time_t nsec) } static void -virtio_poll_timer(void *arg) +virtio_poll_timer(void *arg, uint64_t nexp) { struct virtio_base *base; struct virtio_ops *vops; diff --git a/devicemodel/hw/pci/wdt_i6300esb.c b/devicemodel/hw/pci/wdt_i6300esb.c index e8f4cf359..7a428a9d1 100644 --- a/devicemodel/hw/pci/wdt_i6300esb.c +++ b/devicemodel/hw/pci/wdt_i6300esb.c @@ -110,7 +110,7 @@ static void start_wdt_timer(void); * action to guest OS */ static void -wdt_expired_handler(void *arg) +wdt_expired_handler(void *arg, uint64_t nexp) { struct pci_vdev *dev = (struct pci_vdev *)arg; diff --git a/devicemodel/hw/platform/rtc.c b/devicemodel/hw/platform/rtc.c index bbb218975..ea4b130b0 100644 --- a/devicemodel/hw/platform/rtc.c +++ b/devicemodel/hw/platform/rtc.c @@ -660,7 +660,7 @@ vrtc_time_update(struct vrtc *vrtc, time_t newtime, time_t newbase) } static void -vrtc_periodic_timer(void *arg) +vrtc_periodic_timer(void *arg, uint64_t nexp) { struct vrtc *vrtc = arg; @@ -673,13 +673,14 @@ vrtc_periodic_timer(void *arg) } static void -vrtc_update_timer(void *arg) +vrtc_update_timer(void *arg, uint64_t nexp) { struct vrtc *vrtc = arg; time_t basetime; time_t curtime; pthread_mutex_lock(&vrtc->mtx); + if (aintr_enabled(vrtc) || uintr_enabled(vrtc)) { curtime = vrtc_curtime(vrtc, &basetime); vrtc_time_update(vrtc, curtime, basetime); diff --git a/devicemodel/include/timer.h b/devicemodel/include/timer.h index 937976b3d..7631e944f 100644 --- a/devicemodel/include/timer.h +++ b/devicemodel/include/timer.h @@ -10,12 +10,12 @@ struct acrn_timer { int32_t fd; int32_t clockid; struct mevent *mevp; - void (*callback)(void *); + void (*callback)(void *, uint64_t); void *callback_param; }; int32_t -acrn_timer_init(struct acrn_timer *timer, void (*cb)(void *), void *param); +acrn_timer_init(struct acrn_timer *timer, void (*cb)(void *, uint64_t), void *param); void acrn_timer_deinit(struct acrn_timer *timer); int32_t