From 123fdbac9b8f1e394fbe92e8b5359193e94ba5bf Mon Sep 17 00:00:00 2001 From: Emilio G. Cota Date: Sun, 23 Aug 2015 20:23:35 -0400 Subject: seqlock: add missing 'inline' to seqlock_read_retry Signed-off-by: Emilio G. Cota Message-Id: <1440375847-17603-7-git-send-email-cota@braap.org> Reviewed-by: Alex Bennée Signed-off-by: Paolo Bonzini --- include/qemu/seqlock.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/qemu/seqlock.h b/include/qemu/seqlock.h index 3ff118a1a1..f1256f5487 100644 --- a/include/qemu/seqlock.h +++ b/include/qemu/seqlock.h @@ -62,7 +62,7 @@ static inline unsigned seqlock_read_begin(QemuSeqLock *sl) return ret; } -static int seqlock_read_retry(const QemuSeqLock *sl, unsigned start) +static inline int seqlock_read_retry(const QemuSeqLock *sl, unsigned start) { /* Read other fields before reading final sequence. */ smp_rmb(); -- cgit v1.2.3-55-g7522 From d12f7309483e20d1bae9304f4b812bf53a8e6510 Mon Sep 17 00:00:00 2001 From: Emilio G. Cota Date: Sun, 23 Aug 2015 20:23:36 -0400 Subject: seqlock: read sequence number atomically With this change we make sure that the compiler will not optimise the read of the sequence number in any way. Signed-off-by: Emilio G. Cota Message-Id: <1440375847-17603-8-git-send-email-cota@braap.org> Signed-off-by: Paolo Bonzini --- include/qemu/seqlock.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/qemu/seqlock.h b/include/qemu/seqlock.h index f1256f5487..70b01fd60d 100644 --- a/include/qemu/seqlock.h +++ b/include/qemu/seqlock.h @@ -55,18 +55,18 @@ static inline void seqlock_write_unlock(QemuSeqLock *sl) static inline unsigned seqlock_read_begin(QemuSeqLock *sl) { /* Always fail if a write is in progress. */ - unsigned ret = sl->sequence & ~1; + unsigned ret = atomic_read(&sl->sequence); /* Read sequence before reading other fields. */ smp_rmb(); - return ret; + return ret & ~1; } static inline int seqlock_read_retry(const QemuSeqLock *sl, unsigned start) { /* Read other fields before reading final sequence. */ smp_rmb(); - return unlikely(sl->sequence != start); + return unlikely(atomic_read(&sl->sequence) != start); } #endif -- cgit v1.2.3-55-g7522 From f3926945c85689e8af324c0db0b39be771dbbebb Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Mon, 7 Sep 2015 11:28:58 +0800 Subject: iohandler: Use aio API iohandler.c shares the same interface with aio, but with duplicated code. It's better to rebase iohandler, also because that aio is a more friendly interface to multi-threads. Create a global AioContext instance and let its GSource handle the iohandler events. Signed-off-by: Fam Zheng Message-Id: <1441596538-4412-1-git-send-email-famz@redhat.com> Signed-off-by: Paolo Bonzini --- include/qemu/main-loop.h | 3 +- iohandler.c | 111 +++++++---------------------------------------- main-loop.c | 5 ++- 3 files changed, 19 insertions(+), 100 deletions(-) (limited to 'include') diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h index bc18ca30e4..99769093fc 100644 --- a/include/qemu/main-loop.h +++ b/include/qemu/main-loop.h @@ -203,6 +203,7 @@ void qemu_set_fd_handler(int fd, IOHandler *fd_write, void *opaque); +GSource *iohandler_get_g_source(void); #ifdef CONFIG_POSIX /** * qemu_add_child_watch: Register a child process for reaping. @@ -265,8 +266,6 @@ void qemu_mutex_unlock_iothread(void); /* internal interfaces */ void qemu_fd_register(int fd); -void qemu_iohandler_fill(GArray *pollfds); -void qemu_iohandler_poll(GArray *pollfds, int rc); QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque); void qemu_bh_schedule_idle(QEMUBH *bh); diff --git a/iohandler.c b/iohandler.c index 826f713e9f..55f8501524 100644 --- a/iohandler.c +++ b/iohandler.c @@ -32,111 +32,30 @@ #include #endif -typedef struct IOHandlerRecord { - IOHandler *fd_read; - IOHandler *fd_write; - void *opaque; - QLIST_ENTRY(IOHandlerRecord) next; - int fd; - int pollfds_idx; - bool deleted; -} IOHandlerRecord; - -static QLIST_HEAD(, IOHandlerRecord) io_handlers = - QLIST_HEAD_INITIALIZER(io_handlers); +/* This context runs on top of main loop. We can't reuse qemu_aio_context + * because iohandlers mustn't be polled by aio_poll(qemu_aio_context). */ +static AioContext *iohandler_ctx; -void qemu_set_fd_handler(int fd, - IOHandler *fd_read, - IOHandler *fd_write, - void *opaque) +static void iohandler_init(void) { - IOHandlerRecord *ioh; - - assert(fd >= 0); - - if (!fd_read && !fd_write) { - QLIST_FOREACH(ioh, &io_handlers, next) { - if (ioh->fd == fd) { - ioh->deleted = 1; - break; - } - } - } else { - QLIST_FOREACH(ioh, &io_handlers, next) { - if (ioh->fd == fd) - goto found; - } - ioh = g_malloc0(sizeof(IOHandlerRecord)); - QLIST_INSERT_HEAD(&io_handlers, ioh, next); - found: - ioh->fd = fd; - ioh->fd_read = fd_read; - ioh->fd_write = fd_write; - ioh->opaque = opaque; - ioh->pollfds_idx = -1; - ioh->deleted = 0; - qemu_notify_event(); + if (!iohandler_ctx) { + iohandler_ctx = aio_context_new(&error_abort); } } -void qemu_iohandler_fill(GArray *pollfds) +GSource *iohandler_get_g_source(void) { - IOHandlerRecord *ioh; - - QLIST_FOREACH(ioh, &io_handlers, next) { - int events = 0; - - if (ioh->deleted) - continue; - if (ioh->fd_read) { - events |= G_IO_IN | G_IO_HUP | G_IO_ERR; - } - if (ioh->fd_write) { - events |= G_IO_OUT | G_IO_ERR; - } - if (events) { - GPollFD pfd = { - .fd = ioh->fd, - .events = events, - }; - ioh->pollfds_idx = pollfds->len; - g_array_append_val(pollfds, pfd); - } else { - ioh->pollfds_idx = -1; - } - } + iohandler_init(); + return aio_get_g_source(iohandler_ctx); } -void qemu_iohandler_poll(GArray *pollfds, int ret) +void qemu_set_fd_handler(int fd, + IOHandler *fd_read, + IOHandler *fd_write, + void *opaque) { - if (ret > 0) { - IOHandlerRecord *pioh, *ioh; - - QLIST_FOREACH_SAFE(ioh, &io_handlers, next, pioh) { - int revents = 0; - - if (!ioh->deleted && ioh->pollfds_idx != -1) { - GPollFD *pfd = &g_array_index(pollfds, GPollFD, - ioh->pollfds_idx); - revents = pfd->revents; - } - - if (!ioh->deleted && ioh->fd_read && - (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR))) { - ioh->fd_read(ioh->opaque); - } - if (!ioh->deleted && ioh->fd_write && - (revents & (G_IO_OUT | G_IO_ERR))) { - ioh->fd_write(ioh->opaque); - } - - /* Do this last in case read/write handlers marked it for deletion */ - if (ioh->deleted) { - QLIST_REMOVE(ioh, next); - g_free(ioh); - } - } - } + iohandler_init(); + aio_set_fd_handler(iohandler_ctx, fd, fd_read, fd_write, opaque); } /* reaping of zombies. right now we're not passing the status to diff --git a/main-loop.c b/main-loop.c index 39970437f8..db600a37f1 100644 --- a/main-loop.c +++ b/main-loop.c @@ -161,6 +161,9 @@ int qemu_init_main_loop(Error **errp) src = aio_get_g_source(qemu_aio_context); g_source_attach(src, NULL); g_source_unref(src); + src = iohandler_get_g_source(); + g_source_attach(src, NULL); + g_source_unref(src); return 0; } @@ -487,7 +490,6 @@ int main_loop_wait(int nonblocking) #ifdef CONFIG_SLIRP slirp_pollfds_fill(gpollfds, &timeout); #endif - qemu_iohandler_fill(gpollfds); if (timeout == UINT32_MAX) { timeout_ns = -1; @@ -500,7 +502,6 @@ int main_loop_wait(int nonblocking) &main_loop_tlg)); ret = os_host_main_loop_wait(timeout_ns); - qemu_iohandler_poll(gpollfds, ret); #ifdef CONFIG_SLIRP slirp_pollfds_poll(gpollfds, (ret < 0)); #endif -- cgit v1.2.3-55-g7522 From 5f5b5942d56a138baad0ae01458d5d0e62d5be68 Mon Sep 17 00:00:00 2001 From: Andrey Smetanin Date: Fri, 3 Jul 2015 15:01:42 +0300 Subject: Added generic panic handler qemu_system_guest_panicked() There are pieces of guest panic handling code that can be shared in one generic function. These code replaced by call qemu_system_guest_panicked(). Signed-off-by: Andrey Smetanin Signed-off-by: Denis V. Lunev CC: Paolo Bonzini CC: Andreas Färber Message-Id: <1435924905-8926-10-git-send-email-den@openvz.org> Signed-off-by: Paolo Bonzini --- hw/misc/pvpanic.c | 3 +-- include/sysemu/sysemu.h | 1 + target-s390x/kvm.c | 11 ++--------- vl.c | 6 ++++++ 4 files changed, 10 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/hw/misc/pvpanic.c b/hw/misc/pvpanic.c index 994f8af8e6..3709488728 100644 --- a/hw/misc/pvpanic.c +++ b/hw/misc/pvpanic.c @@ -41,8 +41,7 @@ static void handle_event(int event) } if (event & PVPANIC_PANICKED) { - qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_PAUSE, &error_abort); - vm_stop(RUN_STATE_GUEST_PANICKED); + qemu_system_guest_panicked(); return; } } diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index 44570d17e6..1f6ff8f948 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -69,6 +69,7 @@ int qemu_reset_requested_get(void); void qemu_system_killed(int signal, pid_t pid); void qemu_devices_reset(void); void qemu_system_reset(bool report); +void qemu_system_guest_panicked(void); void qemu_add_exit_notifier(Notifier *notify); void qemu_remove_exit_notifier(Notifier *notify); diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index ae3a0affec..ba1201e93d 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -1796,13 +1796,6 @@ static bool is_special_wait_psw(CPUState *cs) return cs->kvm_run->psw_addr == 0xfffUL; } -static void guest_panicked(void) -{ - qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_PAUSE, - &error_abort); - vm_stop(RUN_STATE_GUEST_PANICKED); -} - static void unmanageable_intercept(S390CPU *cpu, const char *str, int pswoffset) { CPUState *cs = CPU(cpu); @@ -1811,7 +1804,7 @@ static void unmanageable_intercept(S390CPU *cpu, const char *str, int pswoffset) str, cs->cpu_index, ldq_phys(cs->as, cpu->env.psa + pswoffset), ldq_phys(cs->as, cpu->env.psa + pswoffset + 8)); s390_cpu_halt(cpu); - guest_panicked(); + qemu_system_guest_panicked(); } static int handle_intercept(S390CPU *cpu) @@ -1844,7 +1837,7 @@ static int handle_intercept(S390CPU *cpu) if (is_special_wait_psw(cs)) { qemu_system_shutdown_request(); } else { - guest_panicked(); + qemu_system_guest_panicked(); } } r = EXCP_HALTED; diff --git a/vl.c b/vl.c index 584ca88dda..c1508a658c 100644 --- a/vl.c +++ b/vl.c @@ -1740,6 +1740,12 @@ void qemu_system_reset(bool report) cpu_synchronize_all_post_reset(); } +void qemu_system_guest_panicked(void) +{ + qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_PAUSE, &error_abort); + vm_stop(RUN_STATE_GUEST_PANICKED); +} + void qemu_system_reset_request(void) { if (no_reboot) { -- cgit v1.2.3-55-g7522 From 19d2b5e6ff7202c2bf45c547efa85ae6c2d76bbd Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 16 Feb 2015 14:08:22 +0100 Subject: i8257: rewrite DMA_schedule to avoid hooking into the CPU loop The i8257 DMA controller uses an idle bottom half, which by default does not cause the main loop to exit. Therefore, the DMA_schedule function is there to ensure that the CPU relinquishes the iothread mutex to the iothread. However, this is not enough since the iothread will call aio_compute_timeout() and go to sleep again. In the iothread world, forcing execution of the idle bottom half is much simpler, and only requires a call to qemu_notify_event(). Do it, removing the need for the "cpu_request_exit" pseudo-irq. The next patch will remove it. Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- hw/block/fdc.c | 2 +- hw/dma/i8257.c | 18 ++++++++++++------ hw/sparc/sun4m.c | 2 +- hw/sparc64/sun4u.c | 2 +- include/hw/isa/isa.h | 2 +- 5 files changed, 16 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/hw/block/fdc.c b/hw/block/fdc.c index 5e1b67ee43..6686a72803 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -1417,7 +1417,7 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction) * recall us... */ DMA_hold_DREQ(fdctrl->dma_chann); - DMA_schedule(fdctrl->dma_chann); + DMA_schedule(); } else { /* Start transfer */ fdctrl_transfer_handler(fdctrl, fdctrl->dma_chann, 0, diff --git a/hw/dma/i8257.c b/hw/dma/i8257.c index a414029bea..409ba7d01f 100644 --- a/hw/dma/i8257.c +++ b/hw/dma/i8257.c @@ -358,6 +358,7 @@ static void channel_run (int ncont, int ichan) } static QEMUBH *dma_bh; +static bool dma_bh_scheduled; static void DMA_run (void) { @@ -390,12 +391,15 @@ static void DMA_run (void) running = 0; out: - if (rearm) + if (rearm) { qemu_bh_schedule_idle(dma_bh); + dma_bh_scheduled = true; + } } static void DMA_run_bh(void *unused) { + dma_bh_scheduled = false; DMA_run(); } @@ -458,12 +462,14 @@ int DMA_write_memory (int nchan, void *buf, int pos, int len) return len; } -/* request the emulator to transfer a new DMA memory block ASAP */ -void DMA_schedule(int nchan) +/* request the emulator to transfer a new DMA memory block ASAP (even + * if the idle bottom half would not have exited the iothread yet). + */ +void DMA_schedule(void) { - struct dma_cont *d = &dma_controllers[nchan > 3]; - - qemu_irq_pulse(*d->cpu_request_exit); + if (dma_bh_scheduled) { + qemu_notify_event(); + } } static void dma_reset(void *opaque) diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 68ac4d8bba..ebaae9df27 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -109,7 +109,7 @@ int DMA_write_memory (int nchan, void *buf, int pos, int size) } void DMA_hold_DREQ (int nchan) {} void DMA_release_DREQ (int nchan) {} -void DMA_schedule(int nchan) {} +void DMA_schedule(void) {} void DMA_init(int high_page_enable, qemu_irq *cpu_request_exit) { diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 30cfa0e0a0..44eb4ebb79 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -112,7 +112,7 @@ int DMA_write_memory (int nchan, void *buf, int pos, int size) } void DMA_hold_DREQ (int nchan) {} void DMA_release_DREQ (int nchan) {} -void DMA_schedule(int nchan) {} +void DMA_schedule(void) {} void DMA_init(int high_page_enable, qemu_irq *cpu_request_exit) { diff --git a/include/hw/isa/isa.h b/include/hw/isa/isa.h index f21ceaafc6..81b94ea264 100644 --- a/include/hw/isa/isa.h +++ b/include/hw/isa/isa.h @@ -112,7 +112,7 @@ int DMA_read_memory (int nchan, void *buf, int pos, int size); int DMA_write_memory (int nchan, void *buf, int pos, int size); void DMA_hold_DREQ (int nchan); void DMA_release_DREQ (int nchan); -void DMA_schedule(int nchan); +void DMA_schedule(void); void DMA_init(int high_page_enable, qemu_irq *cpu_request_exit); void DMA_register_channel (int nchan, DMA_transfer_handler transfer_handler, -- cgit v1.2.3-55-g7522 From 5039d6e23586fe6bbedc5e4fe302b48a66890ade Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 16 Feb 2015 14:13:11 +0100 Subject: i8257: remove cpu_request_exit irq This is unused. cpu_exit now is almost exclusively an internal function to the CPU execution loop. In a few patches, we'll change the remaining occurrences to qemu_cpu_kick, making it truly internal. Reviewed-by: Richard henderson Signed-off-by: Paolo Bonzini --- hw/dma/i82374.c | 5 +---- hw/dma/i8257.c | 13 ++++--------- hw/i386/pc.c | 13 +------------ hw/isa/i82378.c | 3 +-- hw/mips/mips_fulong2e.c | 13 +------------ hw/mips/mips_jazz.c | 13 +------------ hw/mips/mips_malta.c | 13 +------------ hw/ppc/prep.c | 11 ----------- hw/sparc/sun4m.c | 2 +- hw/sparc64/sun4u.c | 2 +- include/hw/isa/isa.h | 2 +- 11 files changed, 13 insertions(+), 77 deletions(-) (limited to 'include') diff --git a/hw/dma/i82374.c b/hw/dma/i82374.c index b8ad2e64ec..f63097154f 100644 --- a/hw/dma/i82374.c +++ b/hw/dma/i82374.c @@ -38,7 +38,6 @@ do { fprintf(stderr, "i82374 ERROR: " fmt , ## __VA_ARGS__); } while (0) typedef struct I82374State { uint8_t commands[8]; - qemu_irq out; PortioList port_list; } I82374State; @@ -101,7 +100,7 @@ static uint32_t i82374_read_descriptor(void *opaque, uint32_t nport) static void i82374_realize(I82374State *s, Error **errp) { - DMA_init(1, &s->out); + DMA_init(1); memset(s->commands, 0, sizeof(s->commands)); } @@ -145,8 +144,6 @@ static void i82374_isa_realize(DeviceState *dev, Error **errp) isa->iobase); i82374_realize(s, errp); - - qdev_init_gpio_out(dev, &s->out, 1); } static Property i82374_properties[] = { diff --git a/hw/dma/i8257.c b/hw/dma/i8257.c index 409ba7d01f..13984244a6 100644 --- a/hw/dma/i8257.c +++ b/hw/dma/i8257.c @@ -59,7 +59,6 @@ static struct dma_cont { uint8_t flip_flop; int dshift; struct dma_regs regs[4]; - qemu_irq *cpu_request_exit; MemoryRegion channel_io; MemoryRegion cont_io; } dma_controllers[2]; @@ -521,13 +520,11 @@ static const MemoryRegionOps cont_io_ops = { /* dshift = 0: 8 bit DMA, 1 = 16 bit DMA */ static void dma_init2(struct dma_cont *d, int base, int dshift, - int page_base, int pageh_base, - qemu_irq *cpu_request_exit) + int page_base, int pageh_base) { int i; d->dshift = dshift; - d->cpu_request_exit = cpu_request_exit; memory_region_init_io(&d->channel_io, NULL, &channel_io_ops, d, "dma-chan", 8 << d->dshift); @@ -591,12 +588,10 @@ static const VMStateDescription vmstate_dma = { } }; -void DMA_init(int high_page_enable, qemu_irq *cpu_request_exit) +void DMA_init(int high_page_enable) { - dma_init2(&dma_controllers[0], 0x00, 0, 0x80, - high_page_enable ? 0x480 : -1, cpu_request_exit); - dma_init2(&dma_controllers[1], 0xc0, 1, 0x88, - high_page_enable ? 0x488 : -1, cpu_request_exit); + dma_init2(&dma_controllers[0], 0x00, 0, 0x80, high_page_enable ? 0x480 : -1); + dma_init2(&dma_controllers[1], 0xc0, 1, 0x88, high_page_enable ? 0x488 : -1); vmstate_register (NULL, 0, &vmstate_dma, &dma_controllers[0]); vmstate_register (NULL, 1, &vmstate_dma, &dma_controllers[1]); diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 9f2924e5df..16d06c6bf8 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1446,15 +1446,6 @@ DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus) return dev; } -static void cpu_request_exit(void *opaque, int irq, int level) -{ - CPUState *cpu = current_cpu; - - if (cpu && level) { - cpu_exit(cpu); - } -} - static const MemoryRegionOps ioport80_io_ops = { .write = ioport80_write, .read = ioport80_read, @@ -1489,7 +1480,6 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, qemu_irq rtc_irq = NULL; qemu_irq *a20_line; ISADevice *i8042, *port92, *vmmouse, *pit = NULL; - qemu_irq *cpu_exit_irq; MemoryRegion *ioport80_io = g_new(MemoryRegion, 1); MemoryRegion *ioportF0_io = g_new(MemoryRegion, 1); @@ -1566,8 +1556,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, port92 = isa_create_simple(isa_bus, "port92"); port92_init(port92, &a20_line[1]); - cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1); - DMA_init(0, cpu_exit_irq); + DMA_init(0); for(i = 0; i < MAX_FD; i++) { fd[i] = drive_get(IF_FLOPPY, 0, i); diff --git a/hw/isa/i82378.c b/hw/isa/i82378.c index fcf97d86ac..d4c830684b 100644 --- a/hw/isa/i82378.c +++ b/hw/isa/i82378.c @@ -100,7 +100,6 @@ static void i82378_realize(PCIDevice *pci, Error **errp) /* 2 82C37 (dma) */ isa = isa_create_simple(isabus, "i82374"); - qdev_connect_gpio_out(DEVICE(isa), 0, s->out[1]); /* timer */ isa_create_simple(isabus, "mc146818rtc"); @@ -111,7 +110,7 @@ static void i82378_init(Object *obj) DeviceState *dev = DEVICE(obj); I82378State *s = I82378(obj); - qdev_init_gpio_out(dev, s->out, 2); + qdev_init_gpio_out(dev, s->out, 1); qdev_init_gpio_in(dev, i82378_request_pic_irq, 16); } diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c index dea941ad88..6d2ea30bb0 100644 --- a/hw/mips/mips_fulong2e.c +++ b/hw/mips/mips_fulong2e.c @@ -251,15 +251,6 @@ static void network_init (PCIBus *pci_bus) } } -static void cpu_request_exit(void *opaque, int irq, int level) -{ - CPUState *cpu = current_cpu; - - if (cpu && level) { - cpu_exit(cpu); - } -} - static void mips_fulong2e_init(MachineState *machine) { ram_addr_t ram_size = machine->ram_size; @@ -274,7 +265,6 @@ static void mips_fulong2e_init(MachineState *machine) long bios_size; int64_t kernel_entry; qemu_irq *i8259; - qemu_irq *cpu_exit_irq; PCIBus *pci_bus; ISABus *isa_bus; I2CBus *smbus; @@ -375,8 +365,7 @@ static void mips_fulong2e_init(MachineState *machine) /* init other devices */ pit = pit_init(isa_bus, 0x40, 0, NULL); - cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1); - DMA_init(0, cpu_exit_irq); + DMA_init(0); /* Super I/O */ isa_create_simple(isa_bus, "i8042"); diff --git a/hw/mips/mips_jazz.c b/hw/mips/mips_jazz.c index 9d60633efb..3906016ac4 100644 --- a/hw/mips/mips_jazz.c +++ b/hw/mips/mips_jazz.c @@ -104,15 +104,6 @@ static const MemoryRegionOps dma_dummy_ops = { #define MAGNUM_BIOS_SIZE_MAX 0x7e000 #define MAGNUM_BIOS_SIZE (BIOS_SIZE < MAGNUM_BIOS_SIZE_MAX ? BIOS_SIZE : MAGNUM_BIOS_SIZE_MAX) -static void cpu_request_exit(void *opaque, int irq, int level) -{ - CPUState *cpu = current_cpu; - - if (cpu && level) { - cpu_exit(cpu); - } -} - static CPUUnassignedAccess real_do_unassigned_access; static void mips_jazz_do_unassigned_access(CPUState *cpu, hwaddr addr, bool is_write, bool is_exec, @@ -150,7 +141,6 @@ static void mips_jazz_init(MachineState *machine, ISADevice *pit; DriveInfo *fds[MAX_FD]; qemu_irq esp_reset, dma_enable; - qemu_irq *cpu_exit_irq; MemoryRegion *ram = g_new(MemoryRegion, 1); MemoryRegion *bios = g_new(MemoryRegion, 1); MemoryRegion *bios2 = g_new(MemoryRegion, 1); @@ -234,8 +224,7 @@ static void mips_jazz_init(MachineState *machine, /* ISA devices */ i8259 = i8259_init(isa_bus, env->irq[4]); isa_bus_irqs(isa_bus, i8259); - cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1); - DMA_init(0, cpu_exit_irq); + DMA_init(0); pit = pit_init(isa_bus, 0x40, 0, NULL); pcspk_init(isa_bus, pit); diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c index 3082e75340..23b6fc36a5 100644 --- a/hw/mips/mips_malta.c +++ b/hw/mips/mips_malta.c @@ -905,15 +905,6 @@ static void main_cpu_reset(void *opaque) } } -static void cpu_request_exit(void *opaque, int irq, int level) -{ - CPUState *cpu = current_cpu; - - if (cpu && level) { - cpu_exit(cpu); - } -} - static void mips_malta_init(MachineState *machine) { @@ -939,7 +930,6 @@ void mips_malta_init(MachineState *machine) MIPSCPU *cpu; CPUMIPSState *env; qemu_irq *isa_irq; - qemu_irq *cpu_exit_irq; int piix4_devfn; I2CBus *smbus; int i; @@ -1175,8 +1165,7 @@ void mips_malta_init(MachineState *machine) smbus_eeprom_init(smbus, 8, smbus_eeprom_buf, smbus_eeprom_size); g_free(smbus_eeprom_buf); pit = pit_init(isa_bus, 0x40, 0, NULL); - cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1); - DMA_init(0, cpu_exit_irq); + DMA_init(0); /* Super I/O */ isa_create_simple(isa_bus, "i8042"); diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index 45b5f62d6e..81f0838cd9 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -336,15 +336,6 @@ static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr) #define NVRAM_SIZE 0x2000 -static void cpu_request_exit(void *opaque, int irq, int level) -{ - CPUState *cpu = current_cpu; - - if (cpu && level) { - cpu_exit(cpu); - } -} - static void ppc_prep_reset(void *opaque) { PowerPCCPU *cpu = opaque; @@ -626,8 +617,6 @@ static void ppc_prep_init(MachineState *machine) cpu = POWERPC_CPU(first_cpu); qdev_connect_gpio_out(&pci->qdev, 0, cpu->env.irq_inputs[PPC6xx_INPUT_INT]); - qdev_connect_gpio_out(&pci->qdev, 1, - qemu_allocate_irq(cpu_request_exit, NULL, 0)); sysbus_connect_irq(&pcihost->busdev, 0, qdev_get_gpio_in(&pci->qdev, 9)); sysbus_connect_irq(&pcihost->busdev, 1, qdev_get_gpio_in(&pci->qdev, 11)); sysbus_connect_irq(&pcihost->busdev, 2, qdev_get_gpio_in(&pci->qdev, 9)); diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index ebaae9df27..b5db8b7a00 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -111,7 +111,7 @@ void DMA_hold_DREQ (int nchan) {} void DMA_release_DREQ (int nchan) {} void DMA_schedule(void) {} -void DMA_init(int high_page_enable, qemu_irq *cpu_request_exit) +void DMA_init(int high_page_enable) { } diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 44eb4ebb79..a887a86b7d 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -114,7 +114,7 @@ void DMA_hold_DREQ (int nchan) {} void DMA_release_DREQ (int nchan) {} void DMA_schedule(void) {} -void DMA_init(int high_page_enable, qemu_irq *cpu_request_exit) +void DMA_init(int high_page_enable) { } diff --git a/include/hw/isa/isa.h b/include/hw/isa/isa.h index 81b94ea264..d758b39a2e 100644 --- a/include/hw/isa/isa.h +++ b/include/hw/isa/isa.h @@ -113,7 +113,7 @@ int DMA_write_memory (int nchan, void *buf, int pos, int size); void DMA_hold_DREQ (int nchan); void DMA_release_DREQ (int nchan); void DMA_schedule(void); -void DMA_init(int high_page_enable, qemu_irq *cpu_request_exit); +void DMA_init(int high_page_enable); void DMA_register_channel (int nchan, DMA_transfer_handler transfer_handler, void *opaque); -- cgit v1.2.3-55-g7522 From 9373e63297c43752f9cf085feb7f5aed57d959f8 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 18 Aug 2015 06:24:34 -0700 Subject: tcg: introduce tcg_current_cpu This is already useful on Windows in order to remove tls.h, because accesses to current_cpu are done from a different thread on that platform. It will be used on POSIX platforms as soon TCG stops using signals to interrupt the execution of translated code. Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- cpu-exec.c | 14 +++++--------- cpus.c | 5 +++-- include/exec/exec-all.h | 1 + 3 files changed, 9 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/cpu-exec.c b/cpu-exec.c index 713540fc8f..5153f1b632 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -342,6 +342,7 @@ static void cpu_handle_debug_exception(CPUState *cpu) /* main execution loop */ volatile sig_atomic_t exit_request; +CPUState *tcg_current_cpu; int cpu_exec(CPUState *cpu) { @@ -368,15 +369,7 @@ int cpu_exec(CPUState *cpu) } current_cpu = cpu; - - /* As long as current_cpu is null, up to the assignment just above, - * requests by other threads to exit the execution loop are expected to - * be issued using the exit_request global. We must make sure that our - * evaluation of the global value is performed past the current_cpu - * value transition point, which requires a memory barrier as well as - * an instruction scheduling constraint on modern architectures. */ - smp_mb(); - + atomic_mb_set(&tcg_current_cpu, cpu); rcu_read_lock(); if (unlikely(exit_request)) { @@ -579,5 +572,8 @@ int cpu_exec(CPUState *cpu) /* fail safe : never use current_cpu outside cpu_exec() */ current_cpu = NULL; + + /* Does not need atomic_mb_set because a spurious wakeup is okay. */ + atomic_set(&tcg_current_cpu, NULL); return ret; } diff --git a/cpus.c b/cpus.c index e831aa398f..6cebb7aa92 100644 --- a/cpus.c +++ b/cpus.c @@ -663,8 +663,9 @@ static void cpu_handle_guest_debug(CPUState *cpu) static void cpu_signal(int sig) { - if (current_cpu) { - cpu_exit(current_cpu); + CPUState *cpu = atomic_mb_read(&tcg_current_cpu); + if (cpu) { + cpu_exit(cpu); } exit_request = 1; } diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 83b925172f..d5dd48f759 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -387,6 +387,7 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr); extern int singlestep; /* cpu-exec.c */ +extern CPUState *tcg_current_cpu; extern volatile sig_atomic_t exit_request; #if !defined(CONFIG_USER_ONLY) -- cgit v1.2.3-55-g7522 From f240eb6fdcf63a5600e15fb44c6960586459a97f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 26 Aug 2015 00:17:58 +0200 Subject: remove qemu/tls.h TLS is now required on all platforms, so DECLARE_TLS/DEFINE_TLS is not needed anymore. Removing it does not break Windows because of the previous patch. Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- exec.c | 2 +- include/qemu/tls.h | 52 ---------------------------------------------------- include/qom/cpu.h | 4 +--- 3 files changed, 2 insertions(+), 56 deletions(-) delete mode 100644 include/qemu/tls.h (limited to 'include') diff --git a/exec.c b/exec.c index 54cd70ac1e..0f2feb9642 100644 --- a/exec.c +++ b/exec.c @@ -90,7 +90,7 @@ static MemoryRegion io_mem_unassigned; struct CPUTailQ cpus = QTAILQ_HEAD_INITIALIZER(cpus); /* current CPU in the current thread. It is only valid inside cpu_exec() */ -DEFINE_TLS(CPUState *, current_cpu); +__thread CPUState *current_cpu; /* 0 = Do not count executed instructions. 1 = Precise instruction counting. 2 = Adaptive rate instruction counting. */ diff --git a/include/qemu/tls.h b/include/qemu/tls.h deleted file mode 100644 index b92ea9d7da..0000000000 --- a/include/qemu/tls.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Abstraction layer for defining and using TLS variables - * - * Copyright (c) 2011 Red Hat, Inc - * Copyright (c) 2011 Linaro Limited - * - * Authors: - * Paolo Bonzini - * Peter Maydell - * - * 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, see . - */ - -#ifndef QEMU_TLS_H -#define QEMU_TLS_H - -/* Per-thread variables. Note that we only have implementations - * which are really thread-local on Linux; the dummy implementations - * define plain global variables. - * - * This means that for the moment use should be restricted to - * per-VCPU variables, which are OK because: - * - the only -user mode supporting multiple VCPU threads is linux-user - * - TCG system mode is single-threaded regarding VCPUs - * - KVM system mode is multi-threaded but limited to Linux - * - * TODO: proper implementations via Win32 .tls sections and - * POSIX pthread_getspecific. - */ -#ifdef __linux__ -#define DECLARE_TLS(type, x) extern DEFINE_TLS(type, x) -#define DEFINE_TLS(type, x) __thread __typeof__(type) tls__##x -#define tls_var(x) tls__##x -#else -/* Dummy implementations which define plain global variables */ -#define DECLARE_TLS(type, x) extern DEFINE_TLS(type, x) -#define DEFINE_TLS(type, x) __typeof__(type) tls__##x -#define tls_var(x) tls__##x -#endif - -#endif diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 39712ab7cb..8612655a27 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -28,7 +28,6 @@ #include "exec/memattrs.h" #include "qemu/queue.h" #include "qemu/thread.h" -#include "qemu/tls.h" #include "qemu/typedefs.h" typedef int (*WriteCoreDumpFunction)(const void *buf, size_t size, @@ -333,8 +332,7 @@ extern struct CPUTailQ cpus; QTAILQ_FOREACH_REVERSE(cpu, &cpus, CPUTailQ, node) #define first_cpu QTAILQ_FIRST(&cpus) -DECLARE_TLS(CPUState *, current_cpu); -#define current_cpu tls_var(current_cpu) +extern __thread CPUState *current_cpu; /** * cpu_paging_enabled: -- cgit v1.2.3-55-g7522 From e0c382113f768cc375a0d61b7cb3692f1b4bba58 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 26 Aug 2015 00:19:19 +0200 Subject: tcg: signal-free qemu_cpu_kick Signals are slow and do not exist on Win32. The previous patches have done most of the legwork to introduce memory barriers (some of them were even there already for the sake of Windows!) and we can now set the flags directly in the iothread. qemu_cpu_kick_thread is not used anymore on TCG, since the TCG thread is never outside usermode while the CPU is running (not halted). Instead run the content of the signal handler (now in qemu_cpu_kick_no_halt) directly. qemu_cpu_kick_no_halt is also used in qemu_mutex_lock_iothread to avoid the overhead of qemu_cond_broadcast. Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- cpu-exec.c | 2 +- cpus.c | 89 ++++++++++++------------------------------------- include/exec/exec-all.h | 4 +-- include/qom/cpu.h | 4 +-- 4 files changed, 27 insertions(+), 72 deletions(-) (limited to 'include') diff --git a/cpu-exec.c b/cpu-exec.c index ef9d74552e..6a30261a83 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -341,7 +341,7 @@ static void cpu_handle_debug_exception(CPUState *cpu) /* main execution loop */ -volatile sig_atomic_t exit_request; +bool exit_request; CPUState *tcg_current_cpu; int cpu_exec(CPUState *cpu) diff --git a/cpus.c b/cpus.c index e4079103ce..4f3374e201 100644 --- a/cpus.c +++ b/cpus.c @@ -661,19 +661,6 @@ static void cpu_handle_guest_debug(CPUState *cpu) cpu->stopped = true; } -static void cpu_signal(int sig) -{ - CPUState *cpu; - /* Ensure whatever caused the exit has reached the CPU threads before - * writing exit_request. - */ - atomic_mb_set(&exit_request, 1); - cpu = atomic_mb_read(&tcg_current_cpu); - if (cpu) { - cpu_exit(cpu); - } -} - #ifdef CONFIG_LINUX static void sigbus_reraise(void) { @@ -786,29 +773,11 @@ static void qemu_kvm_init_cpu_signals(CPUState *cpu) } } -static void qemu_tcg_init_cpu_signals(void) -{ - sigset_t set; - struct sigaction sigact; - - memset(&sigact, 0, sizeof(sigact)); - sigact.sa_handler = cpu_signal; - sigaction(SIG_IPI, &sigact, NULL); - - sigemptyset(&set); - sigaddset(&set, SIG_IPI); - pthread_sigmask(SIG_UNBLOCK, &set, NULL); -} - #else /* _WIN32 */ static void qemu_kvm_init_cpu_signals(CPUState *cpu) { abort(); } - -static void qemu_tcg_init_cpu_signals(void) -{ -} #endif /* _WIN32 */ static QemuMutex qemu_global_mutex; @@ -1046,7 +1015,6 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) rcu_register_thread(); qemu_mutex_lock_iothread(); - qemu_tcg_init_cpu_signals(); qemu_thread_get_self(cpu->thread); CPU_FOREACH(cpu) { @@ -1090,60 +1058,47 @@ static void qemu_cpu_kick_thread(CPUState *cpu) #ifndef _WIN32 int err; - if (!tcg_enabled()) { - if (cpu->thread_kicked) { - return; - } - cpu->thread_kicked = true; + if (cpu->thread_kicked) { + return; } + cpu->thread_kicked = true; err = pthread_kill(cpu->thread->thread, SIG_IPI); if (err) { fprintf(stderr, "qemu:%s: %s", __func__, strerror(err)); exit(1); } #else /* _WIN32 */ - if (!qemu_cpu_is_self(cpu)) { - CONTEXT tcgContext; - - if (SuspendThread(cpu->hThread) == (DWORD)-1) { - fprintf(stderr, "qemu:%s: GetLastError:%lu\n", __func__, - GetLastError()); - exit(1); - } - - /* On multi-core systems, we are not sure that the thread is actually - * suspended until we can get the context. - */ - tcgContext.ContextFlags = CONTEXT_CONTROL; - while (GetThreadContext(cpu->hThread, &tcgContext) != 0) { - continue; - } - - cpu_signal(0); + abort(); +#endif +} - if (ResumeThread(cpu->hThread) == (DWORD)-1) { - fprintf(stderr, "qemu:%s: GetLastError:%lu\n", __func__, - GetLastError()); - exit(1); - } +static void qemu_cpu_kick_no_halt(void) +{ + CPUState *cpu; + /* Ensure whatever caused the exit has reached the CPU threads before + * writing exit_request. + */ + atomic_mb_set(&exit_request, 1); + cpu = atomic_mb_read(&tcg_current_cpu); + if (cpu) { + cpu_exit(cpu); } -#endif } void qemu_cpu_kick(CPUState *cpu) { qemu_cond_broadcast(cpu->halt_cond); - qemu_cpu_kick_thread(cpu); + if (tcg_enabled()) { + qemu_cpu_kick_no_halt(); + } else { + qemu_cpu_kick_thread(cpu); + } } void qemu_cpu_kick_self(void) { -#ifndef _WIN32 assert(current_cpu); qemu_cpu_kick_thread(current_cpu); -#else - abort(); -#endif } bool qemu_cpu_is_self(CPUState *cpu) @@ -1175,7 +1130,7 @@ void qemu_mutex_lock_iothread(void) atomic_dec(&iothread_requesting_mutex); } else { if (qemu_mutex_trylock(&qemu_global_mutex)) { - qemu_cpu_kick_thread(first_cpu); + qemu_cpu_kick_no_halt(); qemu_mutex_lock(&qemu_global_mutex); } atomic_dec(&iothread_requesting_mutex); diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index d5dd48f759..4a09e6c599 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -386,9 +386,9 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr); /* vl.c */ extern int singlestep; -/* cpu-exec.c */ +/* cpu-exec.c, accessed with atomic_mb_read/atomic_mb_set */ extern CPUState *tcg_current_cpu; -extern volatile sig_atomic_t exit_request; +extern bool exit_request; #if !defined(CONFIG_USER_ONLY) void migration_bitmap_extend(ram_addr_t old, ram_addr_t new); diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 8612655a27..2b4936ad2f 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -268,7 +268,7 @@ struct CPUState { bool created; bool stop; bool stopped; - volatile sig_atomic_t exit_request; + bool exit_request; uint32_t interrupt_request; int singlestep_enabled; int64_t icount_extra; @@ -319,7 +319,7 @@ struct CPUState { offset from AREG0. Leave this field at the end so as to make the (absolute value) offset as small as possible. This reduces code size, especially for hosts without large memory offsets. */ - volatile sig_atomic_t tcg_exit_req; + uint32_t tcg_exit_req; }; QTAILQ_HEAD(CPUTailQ, CPUState); -- cgit v1.2.3-55-g7522 From 3c9589e180d98cdadb143bd2a792fb9d19d9aec6 Mon Sep 17 00:00:00 2001 From: Dr. David Alan Gilbert Date: Fri, 14 Aug 2015 11:25:14 +0100 Subject: Move RAMBlock and ram_list to ram_addr.h Signed-off-by: Dr. David Alan Gilbert Message-Id: <1439547914-18249-1-git-send-email-dgilbert@redhat.com> Signed-off-by: Paolo Bonzini --- include/exec/cpu-all.h | 41 ----------------------------------------- include/exec/ram_addr.h | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 41 deletions(-) (limited to 'include') diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 89db792767..f9998b9732 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -266,44 +266,6 @@ CPUArchState *cpu_copy(CPUArchState *env); #if !defined(CONFIG_USER_ONLY) -/* memory API */ - -typedef struct RAMBlock RAMBlock; - -struct RAMBlock { - struct rcu_head rcu; - struct MemoryRegion *mr; - uint8_t *host; - ram_addr_t offset; - ram_addr_t used_length; - ram_addr_t max_length; - void (*resized)(const char*, uint64_t length, void *host); - uint32_t flags; - /* Protected by iothread lock. */ - char idstr[256]; - /* RCU-enabled, writes protected by the ramlist lock */ - QLIST_ENTRY(RAMBlock) next; - int fd; -}; - -static inline void *ramblock_ptr(RAMBlock *block, ram_addr_t offset) -{ - assert(offset < block->used_length); - assert(block->host); - return (char *)block->host + offset; -} - -typedef struct RAMList { - QemuMutex mutex; - /* Protected by the iothread lock. */ - unsigned long *dirty_memory[DIRTY_MEMORY_NUM]; - RAMBlock *mru_block; - /* RCU-enabled, writes protected by the ramlist lock. */ - QLIST_HEAD(, RAMBlock) blocks; - uint32_t version; -} RAMList; -extern RAMList ram_list; - /* Flags stored in the low bits of the TLB virtual address. These are defined so that fast path ram access is all zeros. */ /* Zero if TLB entry is valid. */ @@ -316,9 +278,6 @@ extern RAMList ram_list; void dump_exec_info(FILE *f, fprintf_function cpu_fprintf); void dump_opcount_info(FILE *f, fprintf_function cpu_fprintf); -ram_addr_t last_ram_offset(void); -void qemu_mutex_lock_ramlist(void); -void qemu_mutex_unlock_ramlist(void); #endif /* !CONFIG_USER_ONLY */ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr, diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index c113f21140..c400a75a6a 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -22,6 +22,46 @@ #ifndef CONFIG_USER_ONLY #include "hw/xen/xen.h" +typedef struct RAMBlock RAMBlock; + +struct RAMBlock { + struct rcu_head rcu; + struct MemoryRegion *mr; + uint8_t *host; + ram_addr_t offset; + ram_addr_t used_length; + ram_addr_t max_length; + void (*resized)(const char*, uint64_t length, void *host); + uint32_t flags; + /* Protected by iothread lock. */ + char idstr[256]; + /* RCU-enabled, writes protected by the ramlist lock */ + QLIST_ENTRY(RAMBlock) next; + int fd; +}; + +static inline void *ramblock_ptr(RAMBlock *block, ram_addr_t offset) +{ + assert(offset < block->used_length); + assert(block->host); + return (char *)block->host + offset; +} + +typedef struct RAMList { + QemuMutex mutex; + /* Protected by the iothread lock. */ + unsigned long *dirty_memory[DIRTY_MEMORY_NUM]; + RAMBlock *mru_block; + /* RCU-enabled, writes protected by the ramlist lock. */ + QLIST_HEAD(, RAMBlock) blocks; + uint32_t version; +} RAMList; +extern RAMList ram_list; + +ram_addr_t last_ram_offset(void); +void qemu_mutex_lock_ramlist(void); +void qemu_mutex_unlock_ramlist(void); + ram_addr_t qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr, bool share, const char *mem_path, Error **errp); -- cgit v1.2.3-55-g7522 From 492e1ca9bd3f43ba417a5cf918e6c769aa2478b9 Mon Sep 17 00:00:00 2001 From: Emilio G. Cota Date: Sun, 23 Aug 2015 20:23:38 -0400 Subject: rcu: fix comment with s/rcu_gp_lock/rcu_registry_lock/ Signed-off-by: Emilio G. Cota Message-Id: <1440375847-17603-10-git-send-email-cota@braap.org> Signed-off-by: Paolo Bonzini --- include/qemu/rcu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/qemu/rcu.h b/include/qemu/rcu.h index 7df1e86622..f6d1d56375 100644 --- a/include/qemu/rcu.h +++ b/include/qemu/rcu.h @@ -71,7 +71,7 @@ struct rcu_reader_data { /* Data used by reader only */ unsigned depth; - /* Data used for registry, protected by rcu_gp_lock */ + /* Data used for registry, protected by rcu_registry_lock */ QLIST_ENTRY(rcu_reader_data) node; }; -- cgit v1.2.3-55-g7522 From 764e0fa497ff5bbc9c9d7c116da2f00f34e71716 Mon Sep 17 00:00:00 2001 From: Carlos L. Torres Date: Sun, 19 Jul 2015 18:02:17 -0500 Subject: cutils: Add qemu_strtol() wrapper Add wrapper for strtol() function. Include unit tests. Signed-off-by: Carlos L. Torres Message-Id: <07199f1c0ff3892790c6322123aee1e92f580550.1437346779.git.carlos.torres@rackspace.com> Signed-off-by: Paolo Bonzini --- include/qemu-common.h | 2 + tests/test-cutils.c | 319 ++++++++++++++++++++++++++++++++++++++++++++++++++ util/cutils.c | 58 +++++++++ 3 files changed, 379 insertions(+) (limited to 'include') diff --git a/include/qemu-common.h b/include/qemu-common.h index bbaffd12e7..1c1169f68a 100644 --- a/include/qemu-common.h +++ b/include/qemu-common.h @@ -203,6 +203,8 @@ int qemu_fls(int i); int qemu_fdatasync(int fd); int fcntl_setfl(int fd, int flag); int qemu_parse_fd(const char *param); +int qemu_strtol(const char *nptr, const char **endptr, int base, + long *result); int parse_uint(const char *s, unsigned long long *value, char **endptr, int base); diff --git a/tests/test-cutils.c b/tests/test-cutils.c index 2a4556d3aa..9219df06ee 100644 --- a/tests/test-cutils.c +++ b/tests/test-cutils.c @@ -226,6 +226,296 @@ static void test_parse_uint_full_correct(void) g_assert_cmpint(i, ==, 123); } +static void test_qemu_strtol_correct(void) +{ + const char *str = "12345 foo"; + char f = 'X'; + const char *endptr = &f; + long res = 999; + int err; + + err = qemu_strtol(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 12345); + g_assert(endptr == str + 5); +} + +static void test_qemu_strtol_null(void) +{ + char f = 'X'; + const char *endptr = &f; + long res = 999; + int err; + + err = qemu_strtol(NULL, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); + g_assert(endptr == NULL); +} + +static void test_qemu_strtol_empty(void) +{ + const char *str = ""; + char f = 'X'; + const char *endptr = &f; + long res = 999; + int err; + + err = qemu_strtol(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0); + g_assert(endptr == str); +} + +static void test_qemu_strtol_whitespace(void) +{ + const char *str = " \t "; + char f = 'X'; + const char *endptr = &f; + long res = 999; + int err; + + err = qemu_strtol(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0); + g_assert(endptr == str); +} + +static void test_qemu_strtol_invalid(void) +{ + const char *str = " xxxx \t abc"; + char f = 'X'; + const char *endptr = &f; + long res = 999; + int err; + + err = qemu_strtol(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0); + g_assert(endptr == str); +} + +static void test_qemu_strtol_trailing(void) +{ + const char *str = "123xxx"; + char f = 'X'; + const char *endptr = &f; + long res = 999; + int err; + + err = qemu_strtol(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 123); + g_assert(endptr == str + 3); +} + +static void test_qemu_strtol_octal(void) +{ + const char *str = "0123"; + char f = 'X'; + const char *endptr = &f; + long res = 999; + int err; + + err = qemu_strtol(str, &endptr, 8, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0123); + g_assert(endptr == str + strlen(str)); + + res = 999; + endptr = &f; + err = qemu_strtol(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0123); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtol_decimal(void) +{ + const char *str = "0123"; + char f = 'X'; + const char *endptr = &f; + long res = 999; + int err; + + err = qemu_strtol(str, &endptr, 10, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 123); + g_assert(endptr == str + strlen(str)); + + str = "123"; + res = 999; + endptr = &f; + err = qemu_strtol(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 123); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtol_hex(void) +{ + const char *str = "0123"; + char f = 'X'; + const char *endptr = &f; + long res = 999; + int err; + + err = qemu_strtol(str, &endptr, 16, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0x123); + g_assert(endptr == str + strlen(str)); + + str = "0x123"; + res = 999; + endptr = &f; + err = qemu_strtol(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0x123); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtol_max(void) +{ + const char *str = g_strdup_printf("%ld", LONG_MAX); + char f = 'X'; + const char *endptr = &f; + long res = 999; + int err; + + err = qemu_strtol(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, LONG_MAX); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtol_overflow(void) +{ + const char *str = "99999999999999999999999999999999999999999999"; + char f = 'X'; + const char *endptr = &f; + long res = 999; + int err; + + err = qemu_strtol(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, LONG_MAX); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtol_underflow(void) +{ + const char *str = "-99999999999999999999999999999999999999999999"; + char f = 'X'; + const char *endptr = &f; + long res = 999; + int err; + + err = qemu_strtol(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, LONG_MIN); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtol_negative(void) +{ + const char *str = " \t -321"; + char f = 'X'; + const char *endptr = &f; + long res = 999; + int err; + + err = qemu_strtol(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, -321); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtol_full_correct(void) +{ + const char *str = "123"; + long res = 999; + int err; + + err = qemu_strtol(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 123); +} + +static void test_qemu_strtol_full_null(void) +{ + char f = 'X'; + const char *endptr = &f; + long res = 999; + int err; + + err = qemu_strtol(NULL, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); + g_assert(endptr == NULL); +} + +static void test_qemu_strtol_full_empty(void) +{ + const char *str = ""; + long res = 999L; + int err; + + err = qemu_strtol(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0); +} + +static void test_qemu_strtol_full_negative(void) +{ + const char *str = " \t -321"; + long res = 999; + int err; + + err = qemu_strtol(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, -321); +} + +static void test_qemu_strtol_full_trailing(void) +{ + const char *str = "123xxx"; + long res; + int err; + + err = qemu_strtol(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); +} + +static void test_qemu_strtol_full_max(void) +{ + const char *str = g_strdup_printf("%ld", LONG_MAX); + long res; + int err; + + err = qemu_strtol(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, LONG_MAX); +} int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); @@ -247,5 +537,34 @@ int main(int argc, char **argv) g_test_add_func("/cutils/parse_uint_full/correct", test_parse_uint_full_correct); + /* qemu_strtol() tests */ + g_test_add_func("/cutils/qemu_strtol/correct", test_qemu_strtol_correct); + g_test_add_func("/cutils/qemu_strtol/null", test_qemu_strtol_null); + g_test_add_func("/cutils/qemu_strtol/empty", test_qemu_strtol_empty); + g_test_add_func("/cutils/qemu_strtol/whitespace", + test_qemu_strtol_whitespace); + g_test_add_func("/cutils/qemu_strtol/invalid", test_qemu_strtol_invalid); + g_test_add_func("/cutils/qemu_strtol/trailing", test_qemu_strtol_trailing); + g_test_add_func("/cutils/qemu_strtol/octal", test_qemu_strtol_octal); + g_test_add_func("/cutils/qemu_strtol/decimal", test_qemu_strtol_decimal); + g_test_add_func("/cutils/qemu_strtol/hex", test_qemu_strtol_hex); + g_test_add_func("/cutils/qemu_strtol/max", test_qemu_strtol_max); + g_test_add_func("/cutils/qemu_strtol/overflow", test_qemu_strtol_overflow); + g_test_add_func("/cutils/qemu_strtol/underflow", + test_qemu_strtol_underflow); + g_test_add_func("/cutils/qemu_strtol/negative", test_qemu_strtol_negative); + g_test_add_func("/cutils/qemu_strtol_full/correct", + test_qemu_strtol_full_correct); + g_test_add_func("/cutils/qemu_strtol_full/null", + test_qemu_strtol_full_null); + g_test_add_func("/cutils/qemu_strtol_full/empty", + test_qemu_strtol_full_empty); + g_test_add_func("/cutils/qemu_strtol_full/negative", + test_qemu_strtol_full_negative); + g_test_add_func("/cutils/qemu_strtol_full/trailing", + test_qemu_strtol_full_trailing); + g_test_add_func("/cutils/qemu_strtol_full/max", + test_qemu_strtol_full_max); + return g_test_run(); } diff --git a/util/cutils.c b/util/cutils.c index 5d1c9ebe05..3330360abf 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -358,6 +358,64 @@ int64_t strtosz(const char *nptr, char **end) return strtosz_suffix(nptr, end, STRTOSZ_DEFSUFFIX_MB); } +/** + * Helper function for qemu_strto*l() functions. + */ +static int check_strtox_error(const char **next, char *endptr, + int err) +{ + if (!next && *endptr) { + return -EINVAL; + } + if (next) { + *next = endptr; + } + return -err; +} + +/** + * QEMU wrappers for strtol(), strtoll(), strtoul(), strotull() C functions. + * + * Convert ASCII string @nptr to a long integer value + * from the given @base. Parameters @nptr, @endptr, @base + * follows same semantics as strtol() C function. + * + * Unlike from strtol() function, if @endptr is not NULL, this + * function will return -EINVAL whenever it cannot fully convert + * the string in @nptr with given @base to a long. This function returns + * the result of the conversion only through the @result parameter. + * + * If NULL is passed in @endptr, then the whole string in @ntpr + * is a number otherwise it returns -EINVAL. + * + * RETURN VALUE + * Unlike from strtol() function, this wrapper returns either + * -EINVAL or the errno set by strtol() function (e.g -ERANGE). + * If the conversion overflows, -ERANGE is returned, and @result + * is set to the max value of the desired type + * (e.g. LONG_MAX, LLONG_MAX, ULONG_MAX, ULLONG_MAX). If the case + * of underflow, -ERANGE is returned, and @result is set to the min + * value of the desired type. For strtol(), strtoll(), @result is set to + * LONG_MIN, LLONG_MIN, respectively, and for strtoul(), strtoull() it + * is set to 0. + */ +int qemu_strtol(const char *nptr, const char **endptr, int base, + long *result) +{ + char *p; + int err = 0; + if (!nptr) { + if (endptr) { + *endptr = nptr; + } + err = -EINVAL; + } else { + errno = 0; + *result = strtol(nptr, &p, base); + err = check_strtox_error(endptr, p, errno); + } + return err; +} /** * parse_uint: * -- cgit v1.2.3-55-g7522 From c817c01548b1500753d0bea3852938d919161778 Mon Sep 17 00:00:00 2001 From: Carlos L. Torres Date: Sun, 19 Jul 2015 18:02:18 -0500 Subject: cutils: Add qemu_strtoul() wrapper Add wrapper for strtoul() function. Include unit tests. Signed-off-by: Carlos L. Torres Message-Id: <9621b4ae8e35fded31c715c2ae2a98f904f07ad0.1437346779.git.carlos.torres@rackspace.com> [Fix tests for 32-bit build. - Paolo] Signed-off-by: Paolo Bonzini --- include/qemu-common.h | 2 + tests/test-cutils.c | 318 ++++++++++++++++++++++++++++++++++++++++++++++++++ util/cutils.c | 32 +++++ 3 files changed, 352 insertions(+) (limited to 'include') diff --git a/include/qemu-common.h b/include/qemu-common.h index 1c1169f68a..558a14fa5f 100644 --- a/include/qemu-common.h +++ b/include/qemu-common.h @@ -205,6 +205,8 @@ int fcntl_setfl(int fd, int flag); int qemu_parse_fd(const char *param); int qemu_strtol(const char *nptr, const char **endptr, int base, long *result); +int qemu_strtoul(const char *nptr, const char **endptr, int base, + unsigned long *result); int parse_uint(const char *s, unsigned long long *value, char **endptr, int base); diff --git a/tests/test-cutils.c b/tests/test-cutils.c index 9219df06ee..39b2e963b3 100644 --- a/tests/test-cutils.c +++ b/tests/test-cutils.c @@ -516,6 +516,292 @@ static void test_qemu_strtol_full_max(void) g_assert_cmpint(err, ==, 0); g_assert_cmpint(res, ==, LONG_MAX); } + +static void test_qemu_strtoul_correct(void) +{ + const char *str = "12345 foo"; + char f = 'X'; + const char *endptr = &f; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 12345); + g_assert(endptr == str + 5); +} + +static void test_qemu_strtoul_null(void) +{ + char f = 'X'; + const char *endptr = &f; + unsigned long res = 999; + int err; + + err = qemu_strtoul(NULL, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); + g_assert(endptr == NULL); +} + +static void test_qemu_strtoul_empty(void) +{ + const char *str = ""; + char f = 'X'; + const char *endptr = &f; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0); + g_assert(endptr == str); +} + +static void test_qemu_strtoul_whitespace(void) +{ + const char *str = " \t "; + char f = 'X'; + const char *endptr = &f; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0); + g_assert(endptr == str); +} + +static void test_qemu_strtoul_invalid(void) +{ + const char *str = " xxxx \t abc"; + char f = 'X'; + const char *endptr = &f; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert(endptr == str); +} + +static void test_qemu_strtoul_trailing(void) +{ + const char *str = "123xxx"; + char f = 'X'; + const char *endptr = &f; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 123); + g_assert(endptr == str + 3); +} + +static void test_qemu_strtoul_octal(void) +{ + const char *str = "0123"; + char f = 'X'; + const char *endptr = &f; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, &endptr, 8, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0123); + g_assert(endptr == str + strlen(str)); + + res = 999; + endptr = &f; + err = qemu_strtoul(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0123); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoul_decimal(void) +{ + const char *str = "0123"; + char f = 'X'; + const char *endptr = &f; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, &endptr, 10, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 123); + g_assert(endptr == str + strlen(str)); + + str = "123"; + res = 999; + endptr = &f; + err = qemu_strtoul(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 123); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoul_hex(void) +{ + const char *str = "0123"; + char f = 'X'; + const char *endptr = &f; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, &endptr, 16, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0x123); + g_assert(endptr == str + strlen(str)); + + str = "0x123"; + res = 999; + endptr = &f; + err = qemu_strtoul(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0x123); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoul_max(void) +{ + const char *str = g_strdup_printf("%lu", ULONG_MAX); + char f = 'X'; + const char *endptr = &f; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, ULONG_MAX); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoul_overflow(void) +{ + const char *str = "99999999999999999999999999999999999999999999"; + char f = 'X'; + const char *endptr = &f; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, ULONG_MAX); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoul_underflow(void) +{ + const char *str = "-99999999999999999999999999999999999999999999"; + char f = 'X'; + const char *endptr = &f; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, -1ul); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoul_negative(void) +{ + const char *str = " \t -321"; + char f = 'X'; + const char *endptr = &f; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, -321ul); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoul_full_correct(void) +{ + const char *str = "123"; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 123); +} + +static void test_qemu_strtoul_full_null(void) +{ + unsigned long res = 999; + int err; + + err = qemu_strtoul(NULL, NULL, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); +} + +static void test_qemu_strtoul_full_empty(void) +{ + const char *str = ""; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0); +} +static void test_qemu_strtoul_full_negative(void) +{ + const char *str = " \t -321"; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, NULL, 0, &res); + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, -321ul); +} + +static void test_qemu_strtoul_full_trailing(void) +{ + const char *str = "123xxx"; + unsigned long res; + int err; + + err = qemu_strtoul(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); +} + +static void test_qemu_strtoul_full_max(void) +{ + const char *str = g_strdup_printf("%lu", ULONG_MAX); + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, ULONG_MAX); +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); @@ -566,5 +852,37 @@ int main(int argc, char **argv) g_test_add_func("/cutils/qemu_strtol_full/max", test_qemu_strtol_full_max); + /* qemu_strtoul() tests */ + g_test_add_func("/cutils/qemu_strtoul/correct", test_qemu_strtoul_correct); + g_test_add_func("/cutils/qemu_strtoul/null", test_qemu_strtoul_null); + g_test_add_func("/cutils/qemu_strtoul/empty", test_qemu_strtoul_empty); + g_test_add_func("/cutils/qemu_strtoul/whitespace", + test_qemu_strtoul_whitespace); + g_test_add_func("/cutils/qemu_strtoul/invalid", test_qemu_strtoul_invalid); + g_test_add_func("/cutils/qemu_strtoul/trailing", + test_qemu_strtoul_trailing); + g_test_add_func("/cutils/qemu_strtoul/octal", test_qemu_strtoul_octal); + g_test_add_func("/cutils/qemu_strtoul/decimal", test_qemu_strtoul_decimal); + g_test_add_func("/cutils/qemu_strtoul/hex", test_qemu_strtoul_hex); + g_test_add_func("/cutils/qemu_strtoul/max", test_qemu_strtoul_max); + g_test_add_func("/cutils/qemu_strtoul/overflow", + test_qemu_strtoul_overflow); + g_test_add_func("/cutils/qemu_strtoul/underflow", + test_qemu_strtoul_underflow); + g_test_add_func("/cutils/qemu_strtoul/negative", + test_qemu_strtoul_negative); + g_test_add_func("/cutils/qemu_strtoul_full/correct", + test_qemu_strtoul_full_correct); + g_test_add_func("/cutils/qemu_strtoul_full/null", + test_qemu_strtoul_full_null); + g_test_add_func("/cutils/qemu_strtoul_full/empty", + test_qemu_strtoul_full_empty); + g_test_add_func("/cutils/qemu_strtoul_full/negative", + test_qemu_strtoul_full_negative); + g_test_add_func("/cutils/qemu_strtoul_full/trailing", + test_qemu_strtoul_full_trailing); + g_test_add_func("/cutils/qemu_strtoul_full/max", + test_qemu_strtoul_full_max); + return g_test_run(); } diff --git a/util/cutils.c b/util/cutils.c index 3330360abf..8ee3d5ee9d 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -416,6 +416,38 @@ int qemu_strtol(const char *nptr, const char **endptr, int base, } return err; } + +/** + * Converts ASCII string to an unsigned long integer. + * + * If string contains a negative number, value will be converted to + * the unsigned representation of the signed value, unless the original + * (nonnegated) value would overflow, in this case, it will set @result + * to ULONG_MAX, and return ERANGE. + * + * The same behavior holds, for qemu_strtoull() but sets @result to + * ULLONG_MAX instead of ULONG_MAX. + * + * See qemu_strtol() documentation for more info. + */ +int qemu_strtoul(const char *nptr, const char **endptr, int base, + unsigned long *result) +{ + char *p; + int err = 0; + if (!nptr) { + if (endptr) { + *endptr = nptr; + } + err = -EINVAL; + } else { + errno = 0; + *result = strtoul(nptr, &p, base); + err = check_strtox_error(endptr, p, errno); + } + return err; +} + /** * parse_uint: * -- cgit v1.2.3-55-g7522 From 8ac4df40cc5de606a8ac9174e2340c21093b4e3b Mon Sep 17 00:00:00 2001 From: Carlos L. Torres Date: Sun, 19 Jul 2015 18:02:19 -0500 Subject: cutils: Add qemu_strtoll() wrapper Add wrapper for strtoll() function. Include unit tests. Signed-off-by: Carlos L. Torres Message-Id: <7454a6bb9ec03b629e8beb4f109dd30dc2c9804c.1437346779.git.carlos.torres@rackspace.com> [Use int64_t in prototype, since that's what QEMU uses. - Paolo] Signed-off-by: Paolo Bonzini --- include/qemu-common.h | 2 + tests/test-cutils.c | 320 ++++++++++++++++++++++++++++++++++++++++++++++++++ util/cutils.c | 23 ++++ 3 files changed, 345 insertions(+) (limited to 'include') diff --git a/include/qemu-common.h b/include/qemu-common.h index 558a14fa5f..29cf0a0765 100644 --- a/include/qemu-common.h +++ b/include/qemu-common.h @@ -207,6 +207,8 @@ int qemu_strtol(const char *nptr, const char **endptr, int base, long *result); int qemu_strtoul(const char *nptr, const char **endptr, int base, unsigned long *result); +int qemu_strtoll(const char *nptr, const char **endptr, int base, + int64_t *result); int parse_uint(const char *s, unsigned long long *value, char **endptr, int base); diff --git a/tests/test-cutils.c b/tests/test-cutils.c index 39b2e963b3..8b2afebdb0 100644 --- a/tests/test-cutils.c +++ b/tests/test-cutils.c @@ -802,6 +802,294 @@ static void test_qemu_strtoul_full_max(void) g_assert_cmpint(res, ==, ULONG_MAX); } +static void test_qemu_strtoll_correct(void) +{ + const char *str = "12345 foo"; + char f = 'X'; + const char *endptr = &f; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 12345); + g_assert(endptr == str + 5); +} + +static void test_qemu_strtoll_null(void) +{ + char f = 'X'; + const char *endptr = &f; + int64_t res = 999; + int err; + + err = qemu_strtoll(NULL, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); + g_assert(endptr == NULL); +} + +static void test_qemu_strtoll_empty(void) +{ + const char *str = ""; + char f = 'X'; + const char *endptr = &f; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0); + g_assert(endptr == str); +} + +static void test_qemu_strtoll_whitespace(void) +{ + const char *str = " \t "; + char f = 'X'; + const char *endptr = &f; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0); + g_assert(endptr == str); +} + +static void test_qemu_strtoll_invalid(void) +{ + const char *str = " xxxx \t abc"; + char f = 'X'; + const char *endptr = &f; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert(endptr == str); +} + +static void test_qemu_strtoll_trailing(void) +{ + const char *str = "123xxx"; + char f = 'X'; + const char *endptr = &f; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 123); + g_assert(endptr == str + 3); +} + +static void test_qemu_strtoll_octal(void) +{ + const char *str = "0123"; + char f = 'X'; + const char *endptr = &f; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, &endptr, 8, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0123); + g_assert(endptr == str + strlen(str)); + + endptr = &f; + res = 999; + err = qemu_strtoll(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0123); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoll_decimal(void) +{ + const char *str = "0123"; + char f = 'X'; + const char *endptr = &f; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, &endptr, 10, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 123); + g_assert(endptr == str + strlen(str)); + + str = "123"; + endptr = &f; + res = 999; + err = qemu_strtoll(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 123); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoll_hex(void) +{ + const char *str = "0123"; + char f = 'X'; + const char *endptr = &f; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, &endptr, 16, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0x123); + g_assert(endptr == str + strlen(str)); + + str = "0x123"; + endptr = &f; + res = 999; + err = qemu_strtoll(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0x123); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoll_max(void) +{ + const char *str = g_strdup_printf("%lld", LLONG_MAX); + char f = 'X'; + const char *endptr = &f; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, LLONG_MAX); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoll_overflow(void) +{ + const char *str = "99999999999999999999999999999999999999999999"; + char f = 'X'; + const char *endptr = &f; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, LLONG_MAX); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoll_underflow(void) +{ + const char *str = "-99999999999999999999999999999999999999999999"; + char f = 'X'; + const char *endptr = &f; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, LLONG_MIN); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoll_negative(void) +{ + const char *str = " \t -321"; + char f = 'X'; + const char *endptr = &f; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, -321); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoll_full_correct(void) +{ + const char *str = "123"; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 123); +} + +static void test_qemu_strtoll_full_null(void) +{ + int64_t res = 999; + int err; + + err = qemu_strtoll(NULL, NULL, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); +} + +static void test_qemu_strtoll_full_empty(void) +{ + const char *str = ""; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0); +} + +static void test_qemu_strtoll_full_negative(void) +{ + const char *str = " \t -321"; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, -321); +} + +static void test_qemu_strtoll_full_trailing(void) +{ + const char *str = "123xxx"; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); +} + +static void test_qemu_strtoll_full_max(void) +{ + + const char *str = g_strdup_printf("%lld", LLONG_MAX); + int64_t res; + int err; + + err = qemu_strtoll(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, LLONG_MAX); +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); @@ -884,5 +1172,37 @@ int main(int argc, char **argv) g_test_add_func("/cutils/qemu_strtoul_full/max", test_qemu_strtoul_full_max); + /* qemu_strtoll() tests */ + g_test_add_func("/cutils/qemu_strtoll/correct", test_qemu_strtoll_correct); + g_test_add_func("/cutils/qemu_strtoll/null", test_qemu_strtoll_null); + g_test_add_func("/cutils/qemu_strtoll/empty", test_qemu_strtoll_empty); + g_test_add_func("/cutils/qemu_strtoll/whitespace", + test_qemu_strtoll_whitespace); + g_test_add_func("/cutils/qemu_strtoll/invalid", test_qemu_strtoll_invalid); + g_test_add_func("/cutils/qemu_strtoll/trailing", + test_qemu_strtoll_trailing); + g_test_add_func("/cutils/qemu_strtoll/octal", test_qemu_strtoll_octal); + g_test_add_func("/cutils/qemu_strtoll/decimal", test_qemu_strtoll_decimal); + g_test_add_func("/cutils/qemu_strtoll/hex", test_qemu_strtoll_hex); + g_test_add_func("/cutils/qemu_strtoll/max", test_qemu_strtoll_max); + g_test_add_func("/cutils/qemu_strtoll/overflow", + test_qemu_strtoll_overflow); + g_test_add_func("/cutils/qemu_strtoll/underflow", + test_qemu_strtoll_underflow); + g_test_add_func("/cutils/qemu_strtoll/negative", + test_qemu_strtoll_negative); + g_test_add_func("/cutils/qemu_strtoll_full/correct", + test_qemu_strtoll_full_correct); + g_test_add_func("/cutils/qemu_strtoll_full/null", + test_qemu_strtoll_full_null); + g_test_add_func("/cutils/qemu_strtoll_full/empty", + test_qemu_strtoll_full_empty); + g_test_add_func("/cutils/qemu_strtoll_full/negative", + test_qemu_strtoll_full_negative); + g_test_add_func("/cutils/qemu_strtoll_full/trailing", + test_qemu_strtoll_full_trailing); + g_test_add_func("/cutils/qemu_strtoll_full/max", + test_qemu_strtoll_full_max); + return g_test_run(); } diff --git a/util/cutils.c b/util/cutils.c index 8ee3d5ee9d..7084d6f1ce 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -448,6 +448,29 @@ int qemu_strtoul(const char *nptr, const char **endptr, int base, return err; } +/** + * Converts ASCII string to a long long integer. + * + * See qemu_strtol() documentation for more info. + */ +int qemu_strtoll(const char *nptr, const char **endptr, int base, + int64_t *result) +{ + char *p; + int err = 0; + if (!nptr) { + if (endptr) { + *endptr = nptr; + } + err = -EINVAL; + } else { + errno = 0; + *result = strtoll(nptr, &p, base); + err = check_strtox_error(endptr, p, errno); + } + return err; +} + /** * parse_uint: * -- cgit v1.2.3-55-g7522 From 3904e6bf042391abc749d717465022e96e276fc7 Mon Sep 17 00:00:00 2001 From: Carlos L. Torres Date: Sun, 19 Jul 2015 18:02:20 -0500 Subject: cutils: Add qemu_strtoull() wrapper Add wrapper for strtoull() function. Include unit tests. Signed-off-by: Carlos L. Torres Message-Id: [Use uint64_t in prototype. - Paolo] Signed-off-by: Paolo Bonzini --- include/qemu-common.h | 2 + tests/test-cutils.c | 323 ++++++++++++++++++++++++++++++++++++++++++++++++++ util/cutils.c | 23 ++++ 3 files changed, 348 insertions(+) (limited to 'include') diff --git a/include/qemu-common.h b/include/qemu-common.h index 29cf0a0765..2e684fee77 100644 --- a/include/qemu-common.h +++ b/include/qemu-common.h @@ -209,6 +209,8 @@ int qemu_strtoul(const char *nptr, const char **endptr, int base, unsigned long *result); int qemu_strtoll(const char *nptr, const char **endptr, int base, int64_t *result); +int qemu_strtoull(const char *nptr, const char **endptr, int base, + uint64_t *result); int parse_uint(const char *s, unsigned long long *value, char **endptr, int base); diff --git a/tests/test-cutils.c b/tests/test-cutils.c index 8b2afebdb0..a7a15a5efe 100644 --- a/tests/test-cutils.c +++ b/tests/test-cutils.c @@ -1090,6 +1090,293 @@ static void test_qemu_strtoll_full_max(void) g_assert_cmpint(res, ==, LLONG_MAX); } +static void test_qemu_strtoull_correct(void) +{ + const char *str = "12345 foo"; + char f = 'X'; + const char *endptr = &f; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 12345); + g_assert(endptr == str + 5); +} + +static void test_qemu_strtoull_null(void) +{ + char f = 'X'; + const char *endptr = &f; + uint64_t res = 999; + int err; + + err = qemu_strtoull(NULL, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); + g_assert(endptr == NULL); +} + +static void test_qemu_strtoull_empty(void) +{ + const char *str = ""; + char f = 'X'; + const char *endptr = &f; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0); + g_assert(endptr == str); +} + +static void test_qemu_strtoull_whitespace(void) +{ + const char *str = " \t "; + char f = 'X'; + const char *endptr = &f; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0); + g_assert(endptr == str); +} + +static void test_qemu_strtoull_invalid(void) +{ + const char *str = " xxxx \t abc"; + char f = 'X'; + const char *endptr = &f; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert(endptr == str); +} + +static void test_qemu_strtoull_trailing(void) +{ + const char *str = "123xxx"; + char f = 'X'; + const char *endptr = &f; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 123); + g_assert(endptr == str + 3); +} + +static void test_qemu_strtoull_octal(void) +{ + const char *str = "0123"; + char f = 'X'; + const char *endptr = &f; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, &endptr, 8, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0123); + g_assert(endptr == str + strlen(str)); + + endptr = &f; + res = 999; + err = qemu_strtoull(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0123); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoull_decimal(void) +{ + const char *str = "0123"; + char f = 'X'; + const char *endptr = &f; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, &endptr, 10, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 123); + g_assert(endptr == str + strlen(str)); + + str = "123"; + endptr = &f; + res = 999; + err = qemu_strtoull(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 123); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoull_hex(void) +{ + const char *str = "0123"; + char f = 'X'; + const char *endptr = &f; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, &endptr, 16, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0x123); + g_assert(endptr == str + strlen(str)); + + str = "0x123"; + endptr = &f; + res = 999; + err = qemu_strtoull(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0x123); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoull_max(void) +{ + const char *str = g_strdup_printf("%llu", ULLONG_MAX); + char f = 'X'; + const char *endptr = &f; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, ULLONG_MAX); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoull_overflow(void) +{ + const char *str = "99999999999999999999999999999999999999999999"; + char f = 'X'; + const char *endptr = &f; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, ULLONG_MAX); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoull_underflow(void) +{ + const char *str = "-99999999999999999999999999999999999999999999"; + char f = 'X'; + const char *endptr = &f; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, -1); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoull_negative(void) +{ + const char *str = " \t -321"; + char f = 'X'; + const char *endptr = &f; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, -321); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoull_full_correct(void) +{ + const char *str = "18446744073709551614"; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 18446744073709551614LLU); +} + +static void test_qemu_strtoull_full_null(void) +{ + uint64_t res = 999; + int err; + + err = qemu_strtoull(NULL, NULL, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); +} + +static void test_qemu_strtoull_full_empty(void) +{ + const char *str = ""; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0); +} + +static void test_qemu_strtoull_full_negative(void) +{ + const char *str = " \t -321"; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 18446744073709551295LLU); +} + +static void test_qemu_strtoull_full_trailing(void) +{ + const char *str = "18446744073709551614xxxxxx"; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); +} + +static void test_qemu_strtoull_full_max(void) +{ + const char *str = g_strdup_printf("%lld", ULLONG_MAX); + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, ULLONG_MAX); +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); @@ -1204,5 +1491,41 @@ int main(int argc, char **argv) g_test_add_func("/cutils/qemu_strtoll_full/max", test_qemu_strtoll_full_max); + /* qemu_strtoull() tests */ + g_test_add_func("/cutils/qemu_strtoull/correct", + test_qemu_strtoull_correct); + g_test_add_func("/cutils/qemu_strtoull/null", + test_qemu_strtoull_null); + g_test_add_func("/cutils/qemu_strtoull/empty", test_qemu_strtoull_empty); + g_test_add_func("/cutils/qemu_strtoull/whitespace", + test_qemu_strtoull_whitespace); + g_test_add_func("/cutils/qemu_strtoull/invalid", + test_qemu_strtoull_invalid); + g_test_add_func("/cutils/qemu_strtoull/trailing", + test_qemu_strtoull_trailing); + g_test_add_func("/cutils/qemu_strtoull/octal", test_qemu_strtoull_octal); + g_test_add_func("/cutils/qemu_strtoull/decimal", + test_qemu_strtoull_decimal); + g_test_add_func("/cutils/qemu_strtoull/hex", test_qemu_strtoull_hex); + g_test_add_func("/cutils/qemu_strtoull/max", test_qemu_strtoull_max); + g_test_add_func("/cutils/qemu_strtoull/overflow", + test_qemu_strtoull_overflow); + g_test_add_func("/cutils/qemu_strtoull/underflow", + test_qemu_strtoull_underflow); + g_test_add_func("/cutils/qemu_strtoull/negative", + test_qemu_strtoull_negative); + g_test_add_func("/cutils/qemu_strtoull_full/correct", + test_qemu_strtoull_full_correct); + g_test_add_func("/cutils/qemu_strtoull_full/null", + test_qemu_strtoull_full_null); + g_test_add_func("/cutils/qemu_strtoull_full/empty", + test_qemu_strtoull_full_empty); + g_test_add_func("/cutils/qemu_strtoull_full/negative", + test_qemu_strtoull_full_negative); + g_test_add_func("/cutils/qemu_strtoull_full/trailing", + test_qemu_strtoull_full_trailing); + g_test_add_func("/cutils/qemu_strtoull_full/max", + test_qemu_strtoull_full_max); + return g_test_run(); } diff --git a/util/cutils.c b/util/cutils.c index 7084d6f1ce..67c50e5ae7 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -471,6 +471,29 @@ int qemu_strtoll(const char *nptr, const char **endptr, int base, return err; } +/** + * Converts ASCII string to an unsigned long long integer. + * + * See qemu_strtol() documentation for more info. + */ +int qemu_strtoull(const char *nptr, const char **endptr, int base, + uint64_t *result) +{ + char *p; + int err = 0; + if (!nptr) { + if (endptr) { + *endptr = nptr; + } + err = -EINVAL; + } else { + errno = 0; + *result = strtoull(nptr, &p, base); + err = check_strtox_error(endptr, p, errno); + } + return err; +} + /** * parse_uint: * -- cgit v1.2.3-55-g7522 From 376692b9dc6f02303ee07a4146d08d8727d79c0c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 10 Jul 2015 12:32:32 +0200 Subject: cpus: protect work list with work_mutex Protect the list of queued work items with something other than the BQL, as a preparation for running the work items outside it. Reviewed-by: Peter Maydell Signed-off-by: KONRAD Frederic Signed-off-by: Paolo Bonzini --- cpus.c | 22 ++++++++++++++++++---- include/qom/cpu.h | 6 +++++- qom/cpu.c | 1 + 3 files changed, 24 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/cpus.c b/cpus.c index 4f3374e201..ea3ffdb900 100644 --- a/cpus.c +++ b/cpus.c @@ -819,6 +819,8 @@ void run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data) wi.func = func; wi.data = data; wi.free = false; + + qemu_mutex_lock(&cpu->work_mutex); if (cpu->queued_work_first == NULL) { cpu->queued_work_first = &wi; } else { @@ -827,9 +829,10 @@ void run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data) cpu->queued_work_last = &wi; wi.next = NULL; wi.done = false; + qemu_mutex_unlock(&cpu->work_mutex); qemu_cpu_kick(cpu); - while (!wi.done) { + while (!atomic_mb_read(&wi.done)) { CPUState *self_cpu = current_cpu; qemu_cond_wait(&qemu_work_cond, &qemu_global_mutex); @@ -850,6 +853,8 @@ void async_run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data) wi->func = func; wi->data = data; wi->free = true; + + qemu_mutex_lock(&cpu->work_mutex); if (cpu->queued_work_first == NULL) { cpu->queued_work_first = wi; } else { @@ -858,6 +863,7 @@ void async_run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data) cpu->queued_work_last = wi; wi->next = NULL; wi->done = false; + qemu_mutex_unlock(&cpu->work_mutex); qemu_cpu_kick(cpu); } @@ -870,15 +876,23 @@ static void flush_queued_work(CPUState *cpu) return; } - while ((wi = cpu->queued_work_first)) { + qemu_mutex_lock(&cpu->work_mutex); + while (cpu->queued_work_first != NULL) { + wi = cpu->queued_work_first; cpu->queued_work_first = wi->next; + if (!cpu->queued_work_first) { + cpu->queued_work_last = NULL; + } + qemu_mutex_unlock(&cpu->work_mutex); wi->func(wi->data); - wi->done = true; + qemu_mutex_lock(&cpu->work_mutex); if (wi->free) { g_free(wi); + } else { + atomic_mb_set(&wi->done, true); } } - cpu->queued_work_last = NULL; + qemu_mutex_unlock(&cpu->work_mutex); qemu_cond_broadcast(&qemu_work_cond); } diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 2b4936ad2f..c3d610b988 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -243,6 +243,8 @@ struct kvm_run; * @mem_io_pc: Host Program Counter at which the memory was accessed. * @mem_io_vaddr: Target virtual address at which the memory was accessed. * @kvm_fd: vCPU file descriptor for KVM. + * @work_mutex: Lock to prevent multiple access to queued_work_*. + * @queued_work_first: First asynchronous work pending. * * State of one CPU core or thread. */ @@ -263,7 +265,6 @@ struct CPUState { uint32_t host_tid; bool running; struct QemuCond *halt_cond; - struct qemu_work_item *queued_work_first, *queued_work_last; bool thread_kicked; bool created; bool stop; @@ -274,6 +275,9 @@ struct CPUState { int64_t icount_extra; sigjmp_buf jmp_env; + QemuMutex work_mutex; + struct qemu_work_item *queued_work_first, *queued_work_last; + AddressSpace *as; struct AddressSpaceDispatch *memory_dispatch; MemoryListener *tcg_as_listener; diff --git a/qom/cpu.c b/qom/cpu.c index 02b56f7076..3841f0de5b 100644 --- a/qom/cpu.c +++ b/qom/cpu.c @@ -316,6 +316,7 @@ static void cpu_common_initfn(Object *obj) cpu->cpu_index = -1; cpu->gdb_num_regs = cpu->gdb_num_g_regs = cc->gdb_num_core_regs; + qemu_mutex_init(&cpu->work_mutex); QTAILQ_INIT(&cpu->breakpoints); QTAILQ_INIT(&cpu->watchpoints); } -- cgit v1.2.3-55-g7522 From 677ef6230b603571ae05125db469f7b4c8912a77 Mon Sep 17 00:00:00 2001 From: KONRAD Frederic Date: Mon, 10 Aug 2015 17:27:02 +0200 Subject: replace spinlock by QemuMutex. spinlock is only used in two cases: * cpu-exec.c: to protect TranslationBlock * mem_helper.c: for lock helper in target-i386 (which seems broken). It's a pthread_mutex_t in user-mode, so we can use QemuMutex directly, with an #ifdef. The #ifdef will be removed when multithreaded TCG will need the mutex as well. Signed-off-by: KONRAD Frederic Message-Id: <1439220437-23957-5-git-send-email-fred.konrad@greensocs.com> Signed-off-by: Emilio G. Cota [Merge Emilio G. Cota's patch to remove volatile. - Paolo] Signed-off-by: Paolo Bonzini --- cpu-exec.c | 14 +++----------- include/exec/exec-all.h | 4 ++-- linux-user/main.c | 6 +++--- target-i386/cpu.h | 3 +++ target-i386/mem_helper.c | 25 ++++++++++++++++++++++--- target-i386/translate.c | 2 ++ tcg/tcg.h | 4 ++++ translate-all.c | 34 ++++++++++++++++++++++++++++++++++ 8 files changed, 73 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/cpu-exec.c b/cpu-exec.c index 6a30261a83..2c0a6f642d 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -357,9 +357,6 @@ int cpu_exec(CPUState *cpu) uintptr_t next_tb; SyncClocks sc; - /* This must be volatile so it is not trashed by longjmp() */ - volatile bool have_tb_lock = false; - if (cpu->halted) { if (!cpu_has_work(cpu)) { return EXCP_HALTED; @@ -468,8 +465,7 @@ int cpu_exec(CPUState *cpu) cpu->exception_index = EXCP_INTERRUPT; cpu_loop_exit(cpu); } - spin_lock(&tcg_ctx.tb_ctx.tb_lock); - have_tb_lock = true; + tb_lock(); tb = tb_find_fast(cpu); /* Note: we do it here to avoid a gcc bug on Mac OS X when doing it in tb_find_slow */ @@ -491,8 +487,7 @@ int cpu_exec(CPUState *cpu) tb_add_jump((TranslationBlock *)(next_tb & ~TB_EXIT_MASK), next_tb & TB_EXIT_MASK, tb); } - have_tb_lock = false; - spin_unlock(&tcg_ctx.tb_ctx.tb_lock); + tb_unlock(); if (likely(!cpu->exit_request)) { trace_exec_tb(tb, tb->pc); tc_ptr = tb->tc_ptr; @@ -558,10 +553,7 @@ int cpu_exec(CPUState *cpu) x86_cpu = X86_CPU(cpu); env = &x86_cpu->env; #endif - if (have_tb_lock) { - spin_unlock(&tcg_ctx.tb_ctx.tb_lock); - have_tb_lock = false; - } + tb_lock_reset(); } } /* for(;;) */ diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 4a09e6c599..59544d4d89 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -225,7 +225,7 @@ struct TranslationBlock { struct TranslationBlock *jmp_first; }; -#include "exec/spinlock.h" +#include "qemu/thread.h" typedef struct TBContext TBContext; @@ -235,7 +235,7 @@ struct TBContext { TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; int nb_tbs; /* any access to the tbs or the page table must use this lock */ - spinlock_t tb_lock; + QemuMutex tb_lock; /* statistics */ int tb_flush_count; diff --git a/linux-user/main.c b/linux-user/main.c index 2c9658e90d..1cecc4c850 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -105,7 +105,7 @@ static int pending_cpus; /* Make sure everything is in a consistent state for calling fork(). */ void fork_start(void) { - pthread_mutex_lock(&tcg_ctx.tb_ctx.tb_lock); + qemu_mutex_lock(&tcg_ctx.tb_ctx.tb_lock); pthread_mutex_lock(&exclusive_lock); mmap_fork_start(); } @@ -127,11 +127,11 @@ void fork_end(int child) pthread_mutex_init(&cpu_list_mutex, NULL); pthread_cond_init(&exclusive_cond, NULL); pthread_cond_init(&exclusive_resume, NULL); - pthread_mutex_init(&tcg_ctx.tb_ctx.tb_lock, NULL); + qemu_mutex_init(&tcg_ctx.tb_ctx.tb_lock); gdbserver_fork(thread_cpu); } else { pthread_mutex_unlock(&exclusive_lock); - pthread_mutex_unlock(&tcg_ctx.tb_ctx.tb_lock); + qemu_mutex_unlock(&tcg_ctx.tb_ctx.tb_lock); } } diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 74b674d524..0337838d55 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -1318,6 +1318,9 @@ static inline MemTxAttrs cpu_get_mem_attrs(CPUX86State *env) void cpu_set_mxcsr(CPUX86State *env, uint32_t val); void cpu_set_fpuc(CPUX86State *env, uint16_t val); +/* mem_helper.c */ +void helper_lock_init(void); + /* svm_helper.c */ void cpu_svm_check_intercept_param(CPUX86State *env1, uint32_t type, uint64_t param); diff --git a/target-i386/mem_helper.c b/target-i386/mem_helper.c index 1aec8a5f19..8bf0da2433 100644 --- a/target-i386/mem_helper.c +++ b/target-i386/mem_helper.c @@ -23,18 +23,37 @@ /* broken thread support */ -static spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; +#if defined(CONFIG_USER_ONLY) +QemuMutex global_cpu_lock; void helper_lock(void) { - spin_lock(&global_cpu_lock); + qemu_mutex_lock(&global_cpu_lock); } void helper_unlock(void) { - spin_unlock(&global_cpu_lock); + qemu_mutex_unlock(&global_cpu_lock); } +void helper_lock_init(void) +{ + qemu_mutex_init(&global_cpu_lock); +} +#else +void helper_lock(void) +{ +} + +void helper_unlock(void) +{ +} + +void helper_lock_init(void) +{ +} +#endif + void helper_cmpxchg8b(CPUX86State *env, target_ulong a0) { uint64_t d; diff --git a/target-i386/translate.c b/target-i386/translate.c index 82e2245bfd..443bf604d8 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -7899,6 +7899,8 @@ void optimize_flags_init(void) offsetof(CPUX86State, regs[i]), reg_names[i]); } + + helper_lock_init(); } /* generate intermediate code in gen_opc_buf and gen_opparam_buf for diff --git a/tcg/tcg.h b/tcg/tcg.h index f437824ba9..aa295b9554 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -595,6 +595,10 @@ void *tcg_malloc_internal(TCGContext *s, int size); void tcg_pool_reset(TCGContext *s); void tcg_pool_delete(TCGContext *s); +void tb_lock(void); +void tb_unlock(void); +void tb_lock_reset(void); + static inline void *tcg_malloc(int size) { TCGContext *s = &tcg_ctx; diff --git a/translate-all.c b/translate-all.c index a75aeed538..37bb56ca42 100644 --- a/translate-all.c +++ b/translate-all.c @@ -128,6 +128,39 @@ static void *l1_map[V_L1_SIZE]; /* code generation context */ TCGContext tcg_ctx; +/* translation block context */ +#ifdef CONFIG_USER_ONLY +__thread int have_tb_lock; +#endif + +void tb_lock(void) +{ +#ifdef CONFIG_USER_ONLY + assert(!have_tb_lock); + qemu_mutex_lock(&tcg_ctx.tb_ctx.tb_lock); + have_tb_lock++; +#endif +} + +void tb_unlock(void) +{ +#ifdef CONFIG_USER_ONLY + assert(have_tb_lock); + have_tb_lock--; + qemu_mutex_unlock(&tcg_ctx.tb_ctx.tb_lock); +#endif +} + +void tb_lock_reset(void) +{ +#ifdef CONFIG_USER_ONLY + if (have_tb_lock) { + qemu_mutex_unlock(&tcg_ctx.tb_ctx.tb_lock); + have_tb_lock = 0; + } +#endif +} + static void tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc, tb_page_addr_t phys_page2); static TranslationBlock *tb_find_pc(uintptr_t tc_ptr); @@ -675,6 +708,7 @@ static inline void code_gen_alloc(size_t tb_size) CODE_GEN_AVG_BLOCK_SIZE; tcg_ctx.tb_ctx.tbs = g_malloc(tcg_ctx.code_gen_max_blocks * sizeof(TranslationBlock)); + qemu_mutex_init(&tcg_ctx.tb_ctx.tb_lock); } /* Must be called before using the QEMU cpus. 'tb_size' is the size -- cgit v1.2.3-55-g7522 From 2496ff1311283480f9de3614080b8842d838ade4 Mon Sep 17 00:00:00 2001 From: KONRAD Frederic Date: Mon, 10 Aug 2015 17:27:03 +0200 Subject: remove unused spinlock. This just removes spinlock as it is not used anymore. Signed-off-by: KONRAD Frederic Message-Id: <1439220437-23957-6-git-send-email-fred.konrad@greensocs.com> Signed-off-by: Paolo Bonzini --- include/exec/spinlock.h | 49 ------------------------------------------------- 1 file changed, 49 deletions(-) delete mode 100644 include/exec/spinlock.h (limited to 'include') diff --git a/include/exec/spinlock.h b/include/exec/spinlock.h deleted file mode 100644 index a72edda1d2..0000000000 --- a/include/exec/spinlock.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2003 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - */ - -/* configure guarantees us that we have pthreads on any host except - * mingw32, which doesn't support any of the user-only targets. - * So we can simply assume we have pthread mutexes here. - */ -#if defined(CONFIG_USER_ONLY) - -#include -#define spin_lock pthread_mutex_lock -#define spin_unlock pthread_mutex_unlock -#define spinlock_t pthread_mutex_t -#define SPIN_LOCK_UNLOCKED PTHREAD_MUTEX_INITIALIZER - -#else - -/* Empty implementations, on the theory that system mode emulation - * is single-threaded. This means that these functions should only - * be used from code run in the TCG cpu thread, and cannot protect - * data structures which might also be accessed from the IO thread - * or from signal handlers. - */ -typedef int spinlock_t; -#define SPIN_LOCK_UNLOCKED 0 - -static inline void spin_lock(spinlock_t *lock) -{ -} - -static inline void spin_unlock(spinlock_t *lock) -{ -} - -#endif -- cgit v1.2.3-55-g7522 From 8fd19e6cfd5b6cdf028c6ac2ff4157ed831ea3a6 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 11 Aug 2015 10:57:52 +0200 Subject: exec: make mmap_lock/mmap_unlock globally available There is some iffy lock hierarchy going on in translate-all.c. To fix it, we need to take the mmap_lock in cpu-exec.c. Make the functions globally available. Reviewed-by: Peter Maydell Signed-off-by: Paolo Bonzini --- bsd-user/qemu.h | 2 -- include/exec/exec-all.h | 6 ++++++ linux-user/qemu.h | 2 -- translate-all.c | 5 ----- 4 files changed, 6 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index 21cc6023ee..735cb4042a 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -211,8 +211,6 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, abi_ulong new_addr); int target_msync(abi_ulong start, abi_ulong len, int flags); extern unsigned long last_brk; -void mmap_lock(void); -void mmap_unlock(void); void cpu_list_lock(void); void cpu_list_unlock(void); #if defined(CONFIG_USE_NPTL) diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 59544d4d89..05a5d5c53b 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -374,11 +374,17 @@ void tlb_fill(CPUState *cpu, target_ulong addr, int is_write, int mmu_idx, #endif #if defined(CONFIG_USER_ONLY) +void mmap_lock(void); +void mmap_unlock(void); + static inline tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr) { return addr; } #else +static inline void mmap_lock(void) {} +static inline void mmap_unlock(void) {} + /* cputlb.c */ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr); #endif diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 8012cc2f5b..e8606b290c 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -261,8 +261,6 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, int target_msync(abi_ulong start, abi_ulong len, int flags); extern unsigned long last_brk; extern abi_ulong mmap_next_start; -void mmap_lock(void); -void mmap_unlock(void); abi_ulong mmap_find_vma(abi_ulong, abi_ulong); void cpu_list_lock(void); void cpu_list_unlock(void); diff --git a/translate-all.c b/translate-all.c index a12139ba01..e3c5c5e20a 100644 --- a/translate-all.c +++ b/translate-all.c @@ -466,11 +466,6 @@ static inline PageDesc *page_find(tb_page_addr_t index) return page_find_alloc(index, 0); } -#if !defined(CONFIG_USER_ONLY) -#define mmap_lock() do { } while (0) -#define mmap_unlock() do { } while (0) -#endif - #if defined(CONFIG_USER_ONLY) /* Currently it is not recommended to allocate big chunks of data in user mode. It will change when a dedicated libc will be used. */ -- cgit v1.2.3-55-g7522