]> xenbits.xensource.com Git - people/liuw/libxenctrl-split/mini-os.git/commitdiff
[minios] Add xenbus shutdown control support
authorSamuel Thibault <samuel.thibault@ens-lyon.org>
Fri, 30 Nov 2012 09:32:27 +0000 (09:32 +0000)
committerSamuel Thibault <samuel.thibault@ens-lyon.org>
Fri, 30 Nov 2012 09:32:27 +0000 (09:32 +0000)
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>
Committed-by: Keir Fraser <keir@xen.org>
include/kernel.h
include/x86/x86_32/hypercall-x86_32.h
include/x86/x86_64/hypercall-x86_64.h
kernel.c
test.c

index b36f172ed80bb651d22438cbd2487d882ab9319d..78692e6c127a2d5e75422344cfb356dfff794572 100644 (file)
@@ -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);
 
index 43028eea0ab671fe499058c8fc016231b1376473..ef52ecdd8f6d84f8ab38f27aee50c5b3ddbd62b1 100644 (file)
@@ -172,6 +172,14 @@ HYPERVISOR_sched_op(
        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)
index b874f039fe3217ff5ea9f5b5827c109bbd09dc8b..513d74e09f44389de7483c569d6f598b0b48c6d1 100644 (file)
@@ -176,6 +176,14 @@ HYPERVISOR_sched_op(
        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)
index a8dfe6d9850cad544f590480553cbf1c658f6287..378ce1202feb9ea1c56fd5013e6cb0cb4dae2acb 100644 (file)
--- a/kernel.c
+++ b/kernel.c
 
 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 @@ void setup_xen_features(void)
     }
 }
 
+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 @@ void start_kernel(start_info_t *si)
     /* Init XenBus */
     init_xenbus();
 
+    create_thread("shutdown", shutdown_thread, NULL);
+
     /* Call (possibly overridden) app_main() */
     app_main(&start_info);
 
diff --git a/test.c b/test.c
index 7baf1fbe5735b23f4f4178c1d0ba43d4c2ce36e7..95e2d697f8b3423d5a602bdd40b2c7b223398145 100644 (file)
--- a/test.c
+++ b/test.c
@@ -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 periodic_thread(void *p)
 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 @@ static void blkfront_thread(void *p)
     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 @@ static void blkfront_thread(void *p)
         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 @@ static void blkfront_thread(void *p)
         }
 #endif
     }
+    up(&blk_sem);
 }
 
 #define WIDTH 800
@@ -293,7 +299,6 @@ static void fbfront_thread(void *p)
     xfree(mfns);
     if (!fb_dev) {
         xfree(fb);
-        return;
     }
     up(&fbfront_sem);
 }
@@ -330,17 +335,21 @@ static void refresh_cursor(int new_x, int new_y)
 }
 
 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 @@ static void kbdfront_thread(void *p)
 
         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 @@ static void kbdfront_thread(void *p)
                         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 @@ static void kbdfront_thread(void *p)
         }
         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,44 +453,72 @@ static void pcifront_thread(void *p)
 {
     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
 
-int app_main(start_info_t *si)
-{
-    printk("Test main: start_info=%p\n", si);
-    create_thread("xenbus_tester", xenbus_tester, si);
-    create_thread("periodic_thread", periodic_thread, si);
-    create_thread("netfront", netfront_thread, si);
-    create_thread("blkfront", blkfront_thread, si);
-    create_thread("fbfront", fbfront_thread, si);
-    create_thread("kbdfront", kbdfront_thread, si);
-#ifdef CONFIG_PCIFRONT
-    create_thread("pcifront", pcifront_thread, si);
-#endif
-    return 0;
-}
-
 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);
+    create_thread("xenbus_tester", xenbus_tester, si);
+    create_thread("periodic_thread", periodic_thread, si);
+    create_thread("netfront", netfront_thread, si);
+    create_thread("blkfront", blkfront_thread, si);
+    create_thread("fbfront", fbfront_thread, si);
+    create_thread("kbdfront", kbdfront_thread, si);
+#ifdef CONFIG_PCIFRONT
+    create_thread("pcifront", pcifront_thread, si);
+#endif
+    create_thread("shutdown", shutdown_thread, si);
+    return 0;
+}