/* * Copyright (C) yajin 2008 * * This file is part of the virtualmips distribution. * See LICENSE file for terms of the license. * */ /* Timer routine. Emulator has many timers. Every 1ms, emulator will check whether there is timer request and pause the cpu when processing timer event. Codes are from qemu. yajin */ #include #include #include "vp_timer.h" #include "vp_clock.h" vp_timer_t *active_timers[2]; m_int64_t ticks_per_sec; vp_timer_t *vp_new_timer (vp_clock_t * clock, vp_timer_cb * cb, void *opaque) { vp_timer_t *ts; ts = malloc (sizeof (vp_timer_t)); memset (ts, 0x0, sizeof (*ts)); if (ts == NULL) return NULL; ts->clock = clock; ts->cb = cb; ts->opaque = opaque; return ts; } void vp_free_timer (vp_timer_t * ts) { ASSERT (ts != NULL, "ts==NULL. NULL can not be freed\n"); free (ts); } /* stop a timer, but do not dealloc it */ void vp_del_timer (vp_timer_t * ts) { vp_timer_t **pt, *t; /* NOTE: this code must be signal safe because * qemu_timer_expired() can be called from a signal. */ pt = &active_timers[ts->clock->type]; for (;;) { t = *pt; if (!t) break; if (t == ts) { *pt = t->next; break; } pt = &t->next; } } /* modify the current timer so that it will be fired when current_time >= expire_time. The corresponding callback will be called. */ void vp_mod_timer (vp_timer_t * ts, m_int64_t expire_time) { vp_timer_t **pt, *t; vp_del_timer (ts); /* add the timer in the sorted list */ /* NOTE: this code must be signal safe because * qemu_timer_expired() can be called from a signal. */ pt = &active_timers[ts->clock->type]; for (;;) { t = *pt; if (!t) break; if (t->expire_time > expire_time) break; pt = &t->next; } ts->expire_time = expire_time; ts->next = *pt; *pt = ts; } int vp_timer_pending (vp_timer_t * ts) { vp_timer_t *t; for (t = active_timers[ts->clock->type]; t != NULL; t = t->next) { if (t == ts) return 1; } return 0; } inline int vp_timer_expired (vp_timer_t * timer_head, m_int64_t current_time) { if (!timer_head) return 0; return (timer_head->expire_time <= current_time); } void vp_run_timers (vp_timer_t ** ptimer_head, m_int64_t current_time) { vp_timer_t *ts; for (;;) { ts = *ptimer_head; if (!ts || ts->expire_time > current_time) break; /* remove timer from the list before calling the callback */ *ptimer_head = ts->next; ts->next = NULL; /* run the callback (the timer list can be modified) */ ts->cb (ts->opaque); } } void init_timers (void) { init_get_clock (); ticks_per_sec = VP_TIMER_BASE; rt_clock = vp_new_clock (VP_TIMER_REALTIME); vm_clock = vp_new_clock (VP_TIMER_VIRTUAL); }