+ struct hostsim_ittimer *tim;
+ uint64_t clk;
+ uint64_t cur, next;
+ int c;
+ unsigned head;
+
+ clk = get_clk();
+
+ /* do the uart events if data is available */
+ if (irq_flags == IRQ_ALLOWED) {
+ while ((int)(out_tail - out_head) > 0) {
+ irq_flags = IRQ_LOCKED;
+ head = out_head;
+ c = out_buf[out_head & RG_MASK];
+ if (__sync_val_compare_and_swap(&out_head,
+ head, head + 1) != head)
+ continue;
+ uart_host_tx_event(c);
+ irq_flags = IRQ_ALLOWED;
+ }
+ while ((int)(in_tail - in_head) > 0) {
+ irq_flags = IRQ_LOCKED;
+ head = in_head;
+ c = in_buf[in_head & RG_MASK];
+ uart_host_rx_event(c);
+ if (__sync_val_compare_and_swap(&in_head,
+ head, head + 1) != head)
+ continue;
+ irq_flags = IRQ_ALLOWED;
+ }
+ }
+
+ /* browse all timers */
+ LIST_FOREACH(tim, &tim_list, next) {
+
+ /* Call the handler if it's time to. We use an atomic operation
+ * because we can be interrupted by our own signal any moment */
+ do {
+ cur = tim->prev_tick;
+ next = tim->prev_tick + tim->period_ns;
+
+ if (next > clk)
+ break;
+
+ if (__sync_val_compare_and_swap(&tim->prev_tick,
+ cur, next) != cur)
+ continue;
+
+ /* if irq are disabled, just mark the timer as pending,
+ * it will be executed from hostsim_irq_restore(). We
+ * may loose interrupts if they stay locked too long,
+ * like on the real hw */
+ if (irq_flags == IRQ_LOCKED)
+ tim->pending = 1;
+ else {
+ irq_flags = IRQ_LOCKED;
+ tim->pending = 0;
+ tim->handler();
+ irq_flags = IRQ_ALLOWED;
+ }
+ } while (1);
+
+ /* also execute the irq if it was pending */
+ if (irq_flags == IRQ_ALLOWED && tim->pending == 1) {
+ irq_flags = IRQ_LOCKED;
+ tim->pending = 0;
+ tim->handler();
+ irq_flags = IRQ_ALLOWED;
+ }
+ }