Add a thread watching the xenbus shutdown control path and notifies a wait queue. Add HYPERVISOR_shutdown convenient inline for minios shutdown. Add proper shutdown to the minios test application. Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org> diff -r fdf241ea6ff4 extras/mini-os/include/kernel.h --- a/extras/mini-os/include/kernel.h Wed Nov 28 21:29:18 2012 +0100 +++ b/extras/mini-os/include/kernel.h Wed Nov 28 22:53:42 2012 +0100 @@ -1,6 +1,9 @@ #ifndef _KERNEL_H_ #define _KERNEL_H_ +extern unsigned int do_shutdown; +extern unsigned int shutdown_reason; +extern struct wait_queue_head shutdown_queue; extern void do_exit(void) __attribute__((noreturn)); extern void stop_kernel(void); diff -r fdf241ea6ff4 extras/mini-os/include/x86/x86_32/hypercall-x86_32.h --- a/extras/mini-os/include/x86/x86_32/hypercall-x86_32.h Wed Nov 28 21:29:18 2012 +0100 +++ b/extras/mini-os/include/x86/x86_32/hypercall-x86_32.h Wed Nov 28 22:53:42 2012 +0100 @@ -172,6 +172,14 @@ return _hypercall2(int, sched_op, cmd, arg); } +static inline int +HYPERVISOR_shutdown( + unsigned int reason) +{ + struct sched_shutdown shutdown = { .reason = reason }; + return _hypercall2(int, sched_op, SCHEDOP_shutdown, &shutdown); +} + static inline long HYPERVISOR_set_timer_op( uint64_t timeout) diff -r fdf241ea6ff4 extras/mini-os/include/x86/x86_64/hypercall-x86_64.h --- a/extras/mini-os/include/x86/x86_64/hypercall-x86_64.h Wed Nov 28 21:29:18 2012 +0100 +++ b/extras/mini-os/include/x86/x86_64/hypercall-x86_64.h Wed Nov 28 22:53:42 2012 +0100 @@ -176,6 +176,14 @@ return _hypercall2(int, sched_op, cmd, arg); } +static inline int +HYPERVISOR_shutdown( + unsigned int reason) +{ + struct sched_shutdown shutdown = { .reason = reason }; + return _hypercall2(int, sched_op, SCHEDOP_shutdown, &shutdown); +} + static inline long HYPERVISOR_set_timer_op( uint64_t timeout) diff -r fdf241ea6ff4 extras/mini-os/kernel.c --- a/extras/mini-os/kernel.c Wed Nov 28 21:29:18 2012 +0100 +++ b/extras/mini-os/kernel.c Wed Nov 28 22:53:42 2012 +0100 @@ -48,6 +48,10 @@ uint8_t xen_features[XENFEAT_NR_SUBMAPS * 32]; +unsigned int do_shutdown = 0; +unsigned int shutdown_reason; +DECLARE_WAIT_QUEUE_HEAD(shutdown_queue); + void setup_xen_features(void) { xen_feature_info_t fi; @@ -64,6 +68,36 @@ } } +static void shutdown_thread(void *p) +{ + const char *path = "control/shutdown"; + const char *token = path; + xenbus_event_queue events = NULL; + char *shutdown, *err; + xenbus_watch_path_token(XBT_NIL, path, token, &events); + while ((err = xenbus_read(XBT_NIL, path, &shutdown)) != NULL) + { + free(err); + xenbus_wait_for_watch(&events); + } + xenbus_unwatch_path_token(XBT_NIL, path, token); + xenbus_write(XBT_NIL, path, ""); + printk("Shutting down (%s)\n", shutdown); + + if (!strcmp(shutdown, "poweroff")) + shutdown_reason = SHUTDOWN_poweroff; + else if (!strcmp(shutdown, "reboot")) + shutdown_reason = SHUTDOWN_reboot; + else + /* Unknown */ + shutdown_reason = SHUTDOWN_crash; + wmb(); + do_shutdown = 1; + wmb(); + wake_up(&shutdown_queue); +} + + /* This should be overridden by the application we are linked against. */ __attribute__((weak)) int app_main(start_info_t *si) { @@ -126,6 +160,8 @@ /* Init XenBus */ init_xenbus(); + create_thread("shutdown", shutdown_thread, NULL); + /* Call (possibly overridden) app_main() */ app_main(&start_info); diff -r fdf241ea6ff4 extras/mini-os/test.c --- a/extras/mini-os/test.c Wed Nov 28 21:29:18 2012 +0100 +++ b/extras/mini-os/test.c Wed Nov 28 22:53:42 2012 +0100 @@ -46,6 +46,7 @@ #include <xen/version.h> static struct netfront_dev *net_dev; +static struct semaphore net_sem = __SEMAPHORE_INITIALIZER(net_sem, 0); void test_xenbus(void); @@ -70,12 +71,14 @@ static void netfront_thread(void *p) { net_dev = init_netfront(NULL, NULL, NULL, NULL); + up(&net_sem); } static struct blkfront_dev *blk_dev; static struct blkfront_info blk_info; static uint64_t blk_size_read; static uint64_t blk_size_write; +static struct semaphore blk_sem = __SEMAPHORE_INITIALIZER(blk_sem, 0);; struct blk_req { struct blkfront_aiocb aiocb; @@ -189,8 +192,10 @@ time_t lasttime = 0; blk_dev = init_blkfront(NULL, &blk_info); - if (!blk_dev) + if (!blk_dev) { + up(&blk_sem); return; + } if (blk_info.info & VDISK_CDROM) printk("Block device is a CDROM\n"); @@ -210,7 +215,7 @@ blk_read_sector(blk_info.sectors-1); } - while (1) { + while (!do_shutdown) { uint64_t sector = rand() % blk_info.sectors; struct timeval tv; #ifdef BLKTEST_WRITE @@ -235,6 +240,7 @@ } #endif } + up(&blk_sem); } #define WIDTH 800 @@ -293,7 +299,6 @@ xfree(mfns); if (!fb_dev) { xfree(fb); - return; } up(&fbfront_sem); } @@ -330,17 +335,21 @@ } static struct kbdfront_dev *kbd_dev; +static struct semaphore kbd_sem = __SEMAPHORE_INITIALIZER(kbd_sem, 0); static void kbdfront_thread(void *p) { DEFINE_WAIT(w); DEFINE_WAIT(w2); + DEFINE_WAIT(w3); int x = WIDTH / 2, y = HEIGHT / 2, z = 0; kbd_dev = init_kbdfront(NULL, 1); - if (!kbd_dev) + down(&fbfront_sem); + if (!kbd_dev) { + up(&kbd_sem); return; + } - down(&fbfront_sem); refresh_cursor(x, y); while (1) { union xenkbd_in_event kbdevent; @@ -349,6 +358,11 @@ add_waiter(w, kbdfront_queue); add_waiter(w2, fbfront_queue); + add_waiter(w3, shutdown_queue); + + rmb(); + if (do_shutdown) + break; while (kbdfront_receive(kbd_dev, &kbdevent, 1) != 0) { sleep = 0; @@ -391,9 +405,11 @@ fbfront_update(fb_dev, x - 16, y - 16, 33, 33); } } else if (kbdevent.key.keycode == KEY_Q) { - struct sched_shutdown sched_shutdown = { .reason = SHUTDOWN_poweroff }; - HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown); - do_exit(); + shutdown_reason = SHUTDOWN_poweroff; + wmb(); + do_shutdown = 1; + wmb(); + wake_up(&shutdown_queue); } break; } @@ -410,11 +426,16 @@ } if (sleep) schedule(); + remove_waiter(w3, shutdown_queue); + remove_waiter(w2, fbfront_queue); + remove_waiter(w, kbdfront_queue); } + up(&kbd_sem); } #ifdef CONFIG_PCIFRONT static struct pcifront_dev *pci_dev; +static struct semaphore pci_sem = __SEMAPHORE_INITIALIZER(pci_sem, 0); static void print_pcidev(unsigned int domain, unsigned int bus, unsigned int slot, unsigned int fun) { @@ -432,13 +453,60 @@ { pcifront_watches(NULL); pci_dev = init_pcifront(NULL); - if (!pci_dev) + if (!pci_dev) { + up(&pci_sem); return; + } printk("PCI devices:\n"); pcifront_scan(pci_dev, print_pcidev); + up(&pci_sem); } #endif +void shutdown_frontends(void) +{ + down(&net_sem); + if (net_dev) + shutdown_netfront(net_dev); + + down(&blk_sem); + if (blk_dev) + shutdown_blkfront(blk_dev); + + if (fb_dev) + shutdown_fbfront(fb_dev); + + down(&kbd_sem); + if (kbd_dev) + shutdown_kbdfront(kbd_dev); + +#ifdef CONFIG_PCIFRONT + down(&pci_sem); + if (pci_dev) + shutdown_pcifront(pci_dev); +#endif +} + +static void shutdown_thread(void *p) +{ + DEFINE_WAIT(w); + + while (1) { + add_waiter(w, shutdown_queue); + rmb(); + if (do_shutdown) { + rmb(); + break; + } + schedule(); + remove_waiter(w, shutdown_queue); + } + + shutdown_frontends(); + + HYPERVISOR_shutdown(shutdown_reason); +} + int app_main(start_info_t *si) { printk("Test main: start_info=%p\n", si); @@ -451,25 +519,6 @@ #ifdef CONFIG_PCIFRONT create_thread("pcifront", pcifront_thread, si); #endif + create_thread("shutdown", shutdown_thread, si); return 0; } - -void shutdown_frontends(void) -{ - if (net_dev) - shutdown_netfront(net_dev); - - if (blk_dev) - shutdown_blkfront(blk_dev); - - if (fb_dev) - shutdown_fbfront(fb_dev); - - if (kbd_dev) - shutdown_kbdfront(kbd_dev); - -#ifdef CONFIG_PCIFRONT - if (pci_dev) - shutdown_pcifront(pci_dev); -#endif -}
On Wed, 2012-11-28 at 21:57 +0000, Samuel Thibault wrote:> Add a thread watching the xenbus shutdown control path and notifies a > wait queue.Why a wait queue rather than a weak function call?> Add HYPERVISOR_shutdown convenient inline for minios shutdown. > > Add proper shutdown to the minios test application.The use of locks in here is pretty exciting, with the up/downs being spread over various places, but I think I''ve worked it out and it''s only a test app ;-)> Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org> > > diff -r fdf241ea6ff4 extras/mini-os/include/kernel.h > --- a/extras/mini-os/include/kernel.h Wed Nov 28 21:29:18 2012 +0100 > +++ b/extras/mini-os/include/kernel.h Wed Nov 28 22:53:42 2012 +0100 > @@ -1,6 +1,9 @@ > #ifndef _KERNEL_H_ > #define _KERNEL_H_ > > +extern unsigned int do_shutdown; > +extern unsigned int shutdown_reason; > +extern struct wait_queue_head shutdown_queue; > extern void do_exit(void) __attribute__((noreturn)); > extern void stop_kernel(void); > > diff -r fdf241ea6ff4 extras/mini-os/include/x86/x86_32/hypercall-x86_32.h > --- a/extras/mini-os/include/x86/x86_32/hypercall-x86_32.h Wed Nov 28 21:29:18 2012 +0100 > +++ b/extras/mini-os/include/x86/x86_32/hypercall-x86_32.h Wed Nov 28 22:53:42 2012 +0100 > @@ -172,6 +172,14 @@ > return _hypercall2(int, sched_op, cmd, arg); > } > > +static inline int > +HYPERVISOR_shutdown( > + unsigned int reason) > +{ > + struct sched_shutdown shutdown = { .reason = reason }; > + return _hypercall2(int, sched_op, SCHEDOP_shutdown, &shutdown); > +} > + > static inline long > HYPERVISOR_set_timer_op( > uint64_t timeout) > diff -r fdf241ea6ff4 extras/mini-os/include/x86/x86_64/hypercall-x86_64.h > --- a/extras/mini-os/include/x86/x86_64/hypercall-x86_64.h Wed Nov 28 21:29:18 2012 +0100 > +++ b/extras/mini-os/include/x86/x86_64/hypercall-x86_64.h Wed Nov 28 22:53:42 2012 +0100 > @@ -176,6 +176,14 @@ > return _hypercall2(int, sched_op, cmd, arg); > } > > +static inline int > +HYPERVISOR_shutdown( > + unsigned int reason) > +{ > + struct sched_shutdown shutdown = { .reason = reason }; > + return _hypercall2(int, sched_op, SCHEDOP_shutdown, &shutdown); > +} > + > static inline long > HYPERVISOR_set_timer_op( > uint64_t timeout) > diff -r fdf241ea6ff4 extras/mini-os/kernel.c > --- a/extras/mini-os/kernel.c Wed Nov 28 21:29:18 2012 +0100 > +++ b/extras/mini-os/kernel.c Wed Nov 28 22:53:42 2012 +0100 > @@ -48,6 +48,10 @@ > > uint8_t xen_features[XENFEAT_NR_SUBMAPS * 32]; > > +unsigned int do_shutdown = 0; > +unsigned int shutdown_reason; > +DECLARE_WAIT_QUEUE_HEAD(shutdown_queue); > + > void setup_xen_features(void) > { > xen_feature_info_t fi; > @@ -64,6 +68,36 @@ > } > } > > +static void shutdown_thread(void *p) > +{ > + const char *path = "control/shutdown"; > + const char *token = path; > + xenbus_event_queue events = NULL; > + char *shutdown, *err; > + xenbus_watch_path_token(XBT_NIL, path, token, &events); > + while ((err = xenbus_read(XBT_NIL, path, &shutdown)) != NULL) > + { > + free(err); > + xenbus_wait_for_watch(&events); > + } > + xenbus_unwatch_path_token(XBT_NIL, path, token); > + xenbus_write(XBT_NIL, path, ""); > + printk("Shutting down (%s)\n", shutdown); > + > + if (!strcmp(shutdown, "poweroff")) > + shutdown_reason = SHUTDOWN_poweroff; > + else if (!strcmp(shutdown, "reboot")) > + shutdown_reason = SHUTDOWN_reboot; > + else > + /* Unknown */ > + shutdown_reason = SHUTDOWN_crash; > + wmb(); > + do_shutdown = 1; > + wmb(); > + wake_up(&shutdown_queue); > +} > + > + > /* This should be overridden by the application we are linked against. */ > __attribute__((weak)) int app_main(start_info_t *si) > { > @@ -126,6 +160,8 @@ > /* Init XenBus */ > init_xenbus(); > > + create_thread("shutdown", shutdown_thread, NULL); > + > /* Call (possibly overridden) app_main() */ > app_main(&start_info); > > diff -r fdf241ea6ff4 extras/mini-os/test.c > --- a/extras/mini-os/test.c Wed Nov 28 21:29:18 2012 +0100 > +++ b/extras/mini-os/test.c Wed Nov 28 22:53:42 2012 +0100 > @@ -46,6 +46,7 @@ > #include <xen/version.h> > > static struct netfront_dev *net_dev; > +static struct semaphore net_sem = __SEMAPHORE_INITIALIZER(net_sem, 0); > > void test_xenbus(void); > > @@ -70,12 +71,14 @@ > static void netfront_thread(void *p) > { > net_dev = init_netfront(NULL, NULL, NULL, NULL); > + up(&net_sem); > } > > static struct blkfront_dev *blk_dev; > static struct blkfront_info blk_info; > static uint64_t blk_size_read; > static uint64_t blk_size_write; > +static struct semaphore blk_sem = __SEMAPHORE_INITIALIZER(blk_sem, 0);; > > struct blk_req { > struct blkfront_aiocb aiocb; > @@ -189,8 +192,10 @@ > time_t lasttime = 0; > > blk_dev = init_blkfront(NULL, &blk_info); > - if (!blk_dev) > + if (!blk_dev) { > + up(&blk_sem); > return; > + } > > if (blk_info.info & VDISK_CDROM) > printk("Block device is a CDROM\n"); > @@ -210,7 +215,7 @@ > blk_read_sector(blk_info.sectors-1); > } > > - while (1) { > + while (!do_shutdown) { > uint64_t sector = rand() % blk_info.sectors; > struct timeval tv; > #ifdef BLKTEST_WRITE > @@ -235,6 +240,7 @@ > } > #endif > } > + up(&blk_sem); > } > > #define WIDTH 800 > @@ -293,7 +299,6 @@ > xfree(mfns); > if (!fb_dev) { > xfree(fb); > - return; > } > up(&fbfront_sem); > } > @@ -330,17 +335,21 @@ > } > > static struct kbdfront_dev *kbd_dev; > +static struct semaphore kbd_sem = __SEMAPHORE_INITIALIZER(kbd_sem, 0); > static void kbdfront_thread(void *p) > { > DEFINE_WAIT(w); > DEFINE_WAIT(w2); > + DEFINE_WAIT(w3); > int x = WIDTH / 2, y = HEIGHT / 2, z = 0; > > kbd_dev = init_kbdfront(NULL, 1); > - if (!kbd_dev) > + down(&fbfront_sem); > + if (!kbd_dev) { > + up(&kbd_sem); > return; > + } > > - down(&fbfront_sem); > refresh_cursor(x, y); > while (1) { > union xenkbd_in_event kbdevent; > @@ -349,6 +358,11 @@ > > add_waiter(w, kbdfront_queue); > add_waiter(w2, fbfront_queue); > + add_waiter(w3, shutdown_queue); > + > + rmb(); > + if (do_shutdown) > + break; > > while (kbdfront_receive(kbd_dev, &kbdevent, 1) != 0) { > sleep = 0; > @@ -391,9 +405,11 @@ > fbfront_update(fb_dev, x - 16, y - 16, 33, 33); > } > } else if (kbdevent.key.keycode == KEY_Q) { > - struct sched_shutdown sched_shutdown = { .reason = SHUTDOWN_poweroff }; > - HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown); > - do_exit(); > + shutdown_reason = SHUTDOWN_poweroff; > + wmb(); > + do_shutdown = 1; > + wmb(); > + wake_up(&shutdown_queue); > } > break; > } > @@ -410,11 +426,16 @@ > } > if (sleep) > schedule(); > + remove_waiter(w3, shutdown_queue); > + remove_waiter(w2, fbfront_queue); > + remove_waiter(w, kbdfront_queue); > } > + up(&kbd_sem); > } > > #ifdef CONFIG_PCIFRONT > static struct pcifront_dev *pci_dev; > +static struct semaphore pci_sem = __SEMAPHORE_INITIALIZER(pci_sem, 0); > > static void print_pcidev(unsigned int domain, unsigned int bus, unsigned int slot, unsigned int fun) > { > @@ -432,13 +453,60 @@ > { > pcifront_watches(NULL); > pci_dev = init_pcifront(NULL); > - if (!pci_dev) > + if (!pci_dev) { > + up(&pci_sem); > return; > + } > printk("PCI devices:\n"); > pcifront_scan(pci_dev, print_pcidev); > + up(&pci_sem); > } > #endif > > +void shutdown_frontends(void) > +{ > + down(&net_sem); > + if (net_dev) > + shutdown_netfront(net_dev); > + > + down(&blk_sem); > + if (blk_dev) > + shutdown_blkfront(blk_dev); > + > + if (fb_dev) > + shutdown_fbfront(fb_dev); > + > + down(&kbd_sem); > + if (kbd_dev) > + shutdown_kbdfront(kbd_dev); > + > +#ifdef CONFIG_PCIFRONT > + down(&pci_sem); > + if (pci_dev) > + shutdown_pcifront(pci_dev); > +#endif > +} > + > +static void shutdown_thread(void *p) > +{ > + DEFINE_WAIT(w); > + > + while (1) { > + add_waiter(w, shutdown_queue); > + rmb(); > + if (do_shutdown) { > + rmb(); > + break; > + } > + schedule(); > + remove_waiter(w, shutdown_queue); > + } > + > + shutdown_frontends(); > + > + HYPERVISOR_shutdown(shutdown_reason); > +} > + > int app_main(start_info_t *si) > { > printk("Test main: start_info=%p\n", si); > @@ -451,25 +519,6 @@ > #ifdef CONFIG_PCIFRONT > create_thread("pcifront", pcifront_thread, si); > #endif > + create_thread("shutdown", shutdown_thread, si); > return 0; > } > - > -void shutdown_frontends(void) > -{ > - if (net_dev) > - shutdown_netfront(net_dev); > - > - if (blk_dev) > - shutdown_blkfront(blk_dev); > - > - if (fb_dev) > - shutdown_fbfront(fb_dev); > - > - if (kbd_dev) > - shutdown_kbdfront(kbd_dev); > - > -#ifdef CONFIG_PCIFRONT > - if (pci_dev) > - shutdown_pcifront(pci_dev); > -#endif > -} > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xen.org > http://lists.xen.org/xen-devel
Re, Ian Campbell, le Thu 29 Nov 2012 11:14:19 +0000, a écrit :> On Wed, 2012-11-28 at 21:57 +0000, Samuel Thibault wrote: > > Add a thread watching the xenbus shutdown control path and notifies a > > wait queue. > > Why a wait queue rather than a weak function call?Because it integrates well with existing wait loops. Samuel
On Tue, 2012-12-04 at 00:30 +0000, Samuel Thibault wrote:> Re, > > Ian Campbell, le Thu 29 Nov 2012 11:14:19 +0000, a écrit : > > On Wed, 2012-11-28 at 21:57 +0000, Samuel Thibault wrote: > > > Add a thread watching the xenbus shutdown control path and notifies a > > > wait queue. > > > > Why a wait queue rather than a weak function call? > > Because it integrates well with existing wait loops.I was imagining that someone using such a wait loop would simply provide the weak function to kick the queue themselves, rather than imposing this design on them from the core. It's not a big deal though. Ian. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Ian Campbell, le Tue 04 Dec 2012 09:32:45 +0000, a écrit :> On Tue, 2012-12-04 at 00:30 +0000, Samuel Thibault wrote: > > Ian Campbell, le Thu 29 Nov 2012 11:14:19 +0000, a écrit : > > > On Wed, 2012-11-28 at 21:57 +0000, Samuel Thibault wrote: > > > > Add a thread watching the xenbus shutdown control path and notifies a > > > > wait queue. > > > > > > Why a wait queue rather than a weak function call? > > > > Because it integrates well with existing wait loops. > > I was imagining that someone using such a wait loop would simply provide > the weak function to kick the queue themselves,Ah, right, in that case it doesn''t need much synchronization with the shutdown event, so it doesn''t pose problem.> rather than imposing this design on them from the core. It''s not a big > deal though.But it''s nicer to get it the way people would prefer. Daniel, Matthew, what do you think? Samuel
Seemingly Similar Threads
- mini-os: Notify shutdown through weak function call instead of wake queue
- [RFC] PVFB: Add refresh period to XenStore parameters?
- [PATCH v4 00/23] Xenstore stub domain
- xen-unstable stubdom build error version(3432abcf9380)
- [PATCH 4 of 13] DisplayState interface change