[Title] Add a feature to enable/disable usb keyboard at run time.
authordon.hong <don.hong@samsung.com>
Tue, 13 Mar 2012 10:05:33 +0000 (19:05 +0900)
committerdon.hong <don.hong@samsung.com>
Tue, 13 Mar 2012 10:05:33 +0000 (19:05 +0900)
[Type] Feature
[Module] tizen/src/mloop_event.c
[Priority]
[CQ#] BOT-21,BOT-23,BOT-31,BOT-307,BOT-323,BOT-631
[Redmine#]
[Problem]
[Cause]
[Solution]
[TestCase]

tizen/src/Makefile.in
tizen/src/config_x86.ini
tizen/src/emul_debug.bat
tizen/src/emulator.sh
tizen/src/menu_callback.c
tizen/src/mloop_event.c [new file with mode: 0644]
tizen/src/mloop_event.h [new file with mode: 0644]
tizen/src/vtm.c
vl.c

index bf0192b..78b7a31 100644 (file)
@@ -108,6 +108,7 @@ OBJS_COMMON = \
        utils.o \
        vt_utils.o \
        debug_ch.o \
+       mloop_event.o \
        vinit_process.o
 
 OBJS_X86 += $(OBJS_COMMON) arch_x86.o
index fab03a9..16ebc5d 100644 (file)
@@ -18,7 +18,7 @@ KVM=1
 
 [ADDITIONAL_OPTION]
 EMULATOR_OPTION=
-QEMU_OPTION=-M tizen-x86-machine -usb -usbdevice maru-touchscreen -usbdevice keyboard -net nic,model=virtio -net user -rtc base=utc
+QEMU_OPTION=-M tizen-x86-machine -usb -usbdevice maru-touchscreen -net nic,model=virtio -net user -rtc base=utc
 
 [HARDWARE]
 RESOLUTION=480x800
index 4cb0433..b0d31b8 100644 (file)
@@ -1 +1 @@
-gdb --args emulator-x86.exe --vtm default -- -net nic,model=virtio -usb -usbdevice maru-touchscreen -vga tizen -bios bios.bin -L ..\x86\data\pc-bios -kernel ..\x86\data\kernel-img\bzImage -usbdevice keyboard -rtc base=utc -net user -redir tcp:1202:10.0.2.16:22
+gdb --args emulator-x86.exe --vtm default -- -net nic,model=virtio -usb -usbdevice maru-touchscreen -vga tizen -bios bios.bin -L ..\x86\data\pc-bios -kernel ..\x86\data\kernel-img\bzImage -rtc base=utc -net user -redir tcp:1202:10.0.2.16:22
index 3b842e1..85cda54 100755 (executable)
@@ -348,7 +348,7 @@ set_qemu_hw_options () {
        qemu_x86_opts="$qemu_x86_opts -vga tizen -bios bios.bin -L ${QEMU_BIOS_PATH}"
 
        #keyboard
-       qemu_common_opts="-usbdevice keyboard $qemu_common_opts"
+#      qemu_common_opts="-usbdevice keyboard $qemu_common_opts"
 }
 
 set_qemu_options () {
index f9e3b15..886cf37 100644 (file)
@@ -56,6 +56,7 @@
 
 #include "debug_ch.h"
 #include "sdb.h"
+#include "tizen/src/mloop_event.h"
 
 //DEFAULT_DEBUG_CHANNEL(tizen);
 MULTI_DEBUG_CHANNEL(tizen, menu_callback);
@@ -302,10 +303,12 @@ void menu_rotate_callback(PHONEMODELINFO *device, int nMode)
             sprintf(buf, "1\n270\n");
             break;
         case 7:
-            sprintf(buf, "7\n1\n");
+//            sprintf(buf, "7\n1\n");
+            mloop_evcmd_usbkbd_on();
             break;
         case 8:
-            sprintf(buf, "7\n0\n");
+//            sprintf(buf, "7\n0\n");
+            mloop_evcmd_usbkbd_off();
             break;
     }
 
diff --git a/tizen/src/mloop_event.c b/tizen/src/mloop_event.c
new file mode 100644 (file)
index 0000000..7720fa5
--- /dev/null
@@ -0,0 +1,255 @@
+/*\r
+ * mainloop_evhandle.c\r
+ *\r
+ * Copyright (C) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.\r
+ *\r
+ * Contact:\r
+ * DoHyung Hong <don.hong@samsung.com>\r
+ *\r
+ * This program is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU General Public License\r
+ * as published by the Free Software Foundation; either version 2\r
+ * of the License, or (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+ *\r
+ * Contributors:\r
+ * - S-Core Co., Ltd\r
+ *\r
+ */\r
+\r
+\r
+#ifdef _WIN32\r
+#include <winsock.h>\r
+#else\r
+#include <netinet/in.h>\r
+#include <sys/ioctl.h>\r
+#endif\r
+\r
+#include "qobject.h"\r
+#include "qemu-common.h"\r
+#include "hw/usb.h"\r
+#include "mloop_event.h"\r
+\r
+#define error_report(x, ...)\r
+\r
+struct mloop_evsock {\r
+    int sockno;\r
+    unsigned short portno;\r
+    unsigned char status;\r
+};\r
+\r
+#define MLOOP_EVSOCK_NULL        0\r
+#define MLOOP_EVSOCK_CREATED    1\r
+#define MLOOP_EVSOCK_NOTBOUND    2\r
+#define MLOOP_EVSOCK_BOUND        3\r
+#define MLOOP_EVSOCK_CONNECTED    4\r
+\r
+#define PACKET_LEN 128\r
+struct mloop_evpack {\r
+    short type;\r
+    short size;\r
+    char data[PACKET_LEN-4];\r
+};\r
+\r
+#define MLOOP_EVTYPE_USB_ADD    1\r
+#define MLOOP_EVTYPE_USB_DEL    2\r
+\r
+static struct mloop_evsock mloop = {-1,0,0};\r
+\r
+static int mloop_evsock_create(struct mloop_evsock *ev)\r
+{\r
+    struct sockaddr sa;\r
+    socklen_t sa_size;\r
+    int ret;\r
+    unsigned long nonblock = 1;\r
+\r
+    if (ev == NULL) {\r
+        error_report("mloop_evsock: null point");\r
+        return -1;\r
+    }\r
+\r
+    ev->sockno = socket(AF_INET, SOCK_DGRAM, 0);\r
+    if( ev->sockno == -1 ) {\r
+        error_report("mloop_evsock: socket() failed");\r
+        return -1;\r
+    }\r
+\r
+#ifdef _WIN32\r
+    ioctlsocket(ev->sockno, FIONBIO, &nonblock );\r
+#else\r
+    ioctl(ev->sockno, FIONBIO, &nonblock);\r
+#endif // _WIN32\r
+\r
+    nonblock = 1 ;\r
+    setsockopt( ev->sockno, SOL_SOCKET, SO_REUSEADDR, (char *)&nonblock, sizeof(nonblock) ) ;\r
+\r
+    memset(&sa, '\0', sizeof(sa));\r
+    ((struct sockaddr_in *) &sa)->sin_family = AF_INET;\r
+    memcpy(&((struct sockaddr_in *) &sa)->sin_addr, "\177\000\000\001", 4); // 127.0.0.1\r
+    ((struct sockaddr_in *) &sa)->sin_port = htons(ev->portno);\r
+    sa_size = sizeof(struct sockaddr_in);\r
+\r
+    ret = bind(ev->sockno, &sa, sa_size);\r
+    if (ret) {\r
+        error_report("mloop_evsock: bind() failed");\r
+        goto mloop_evsock_init_cleanup;\r
+    }\r
+\r
+    if (ev->portno == 0) {\r
+        memset(&sa, '\0', sizeof(sa));\r
+        getsockname(ev->sockno, (struct sockaddr *) &sa, &sa_size);\r
+        ev->portno = ntohs(((struct sockaddr_in *) &sa)->sin_port);\r
+    }\r
+\r
+    ret = connect(ev->sockno, (struct sockaddr *) &sa, sa_size);\r
+    if (ret) {\r
+        error_report("mloop_evsock: connect() failed");\r
+        goto mloop_evsock_init_cleanup;\r
+    }\r
+\r
+    ev->status = MLOOP_EVSOCK_CONNECTED;\r
+    return 0;\r
+\r
+mloop_evsock_init_cleanup:\r
+#ifdef _WIN32\r
+    closesocket(ev->sockno);\r
+#else\r
+    close(ev->sockno);\r
+#endif\r
+    ev->sockno = -1;\r
+    ev->status = 0;\r
+    return ret;\r
+}\r
+\r
+static void mloop_evsock_remove(struct mloop_evsock *ev)\r
+{\r
+    if (!ev) {\r
+        return ;\r
+    }\r
+\r
+    if (ev->sockno > 0) {\r
+#ifdef _WIN32\r
+        shutdown(ev->sockno, SD_BOTH);\r
+        closesocket(ev->sockno);\r
+#else\r
+        shutdown(ev->sockno, SHUT_RDWR);\r
+        close(ev->sockno);\r
+#endif\r
+        ev->sockno = -1;\r
+        ev->status = 0;\r
+    }\r
+}\r
+\r
+static int mloop_evsock_send(struct mloop_evsock *ev, struct mloop_evpack *p)\r
+{\r
+    int ret;\r
+\r
+    if (ev == NULL || ev->sockno == -1) {\r
+        error_report("invalid mloop_evsock");\r
+        return -1;\r
+    }\r
+\r
+    if (p == NULL || p->size <= 0) {\r
+        error_report("invalid mloop_evpack");\r
+        return -1;\r
+    }\r
+\r
+    do {\r
+        ret = send(ev->sockno, p, ntohs(p->size), 0);\r
+#ifdef _WIN32\r
+    } while (ret == -1 && (WSAGetLastError() == WSAEWOULDBLOCK));\r
+#else\r
+    } while (ret == -1 && (errno == EWOULDBLOCK || errno == EINTR));\r
+#endif // _WIN32\r
+\r
+    return ret;\r
+}\r
+\r
+static USBDevice *usbkbd = NULL;\r
+static void mloop_evhandle_usb_add(char *name)\r
+{\r
+    if (name == NULL) {\r
+        return;\r
+    }\r
+\r
+    if (strcmp(name, "keyboard") == 0) {\r
+        if (usbkbd == NULL) {\r
+            usbkbd = usbdevice_create(name);\r
+        }\r
+        else if (usbkbd->attached == 0) {\r
+            usb_device_attach(usbkbd);\r
+        }\r
+    }\r
+}\r
+\r
+static void mloop_evhandle_usb_del(char *name)\r
+{\r
+    if (name == NULL) {\r
+        return;\r
+    }\r
+\r
+    if (strcmp(name, "keyboard") == 0) {\r
+        if (usbkbd && usbkbd->attached != 0) {\r
+            usb_device_detach(usbkbd);\r
+        }\r
+    }\r
+}\r
+\r
+static void mloop_evcb_recv(struct mloop_evsock *ev)\r
+{\r
+    struct mloop_evpack pack;\r
+    int ret = read(ev->sockno, (void *)&pack, sizeof(pack));\r
+\r
+    if (ret == 0 ) {\r
+        return;\r
+    }\r
+\r
+    pack.type = ntohs(pack.type);\r
+    pack.size = ntohs(pack.size);\r
+\r
+    switch (pack.type) {\r
+    case MLOOP_EVTYPE_USB_ADD:\r
+        mloop_evhandle_usb_add(pack.data);\r
+        break;\r
+    case MLOOP_EVTYPE_USB_DEL:\r
+        mloop_evhandle_usb_del(pack.data);\r
+        break;\r
+    default:\r
+        break;\r
+    }\r
+}\r
+\r
+extern int qemu_set_fd_handler(int fd, IOHandler *fd_read, IOHandler *fd_write, void *opaque);\r
+void mloop_ev_init(void)\r
+{\r
+    int ret = mloop_evsock_create(&mloop);\r
+    if (ret == 0) {\r
+        qemu_set_fd_handler(mloop.sockno, (IOHandler *)mloop_evcb_recv, NULL, &mloop);\r
+    }\r
+}\r
+\r
+void mloop_ev_stop(void)\r
+{\r
+    qemu_set_fd_handler(mloop.sockno, NULL, NULL, NULL);\r
+    mloop_evsock_remove(&mloop);\r
+}\r
+\r
+void mloop_evcmd_usbkbd_on(void)\r
+{\r
+    struct mloop_evpack pack = { htons(MLOOP_EVTYPE_USB_ADD), htons(13), "keyboard" };\r
+    mloop_evsock_send(&mloop, &pack);\r
+}\r
+\r
+void mloop_evcmd_usbkbd_off(void)\r
+{\r
+    struct mloop_evpack pack = { htons(MLOOP_EVTYPE_USB_DEL), htons(13), "keyboard" };\r
+    mloop_evsock_send(&mloop, &pack);\r
+}\r
diff --git a/tizen/src/mloop_event.h b/tizen/src/mloop_event.h
new file mode 100644 (file)
index 0000000..cc656a9
--- /dev/null
@@ -0,0 +1,45 @@
+/*\r
+ * mainloop_evhandle.c\r
+ *\r
+ * Copyright (C) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.\r
+ *\r
+ * Contact:\r
+ * DoHyung Hong <don.hong@samsung.com>\r
+ *\r
+ * This program is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU General Public License\r
+ * as published by the Free Software Foundation; either version 2\r
+ * of the License, or (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
+ *\r
+ * Contributors:\r
+ * - S-Core Co., Ltd\r
+ *\r
+ */\r
+\r
+#ifndef MLOOP_EVENT_H_\r
+#define MLOOP_EVENT_H_\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+void mloop_ev_init(void);\r
+void mloop_ev_stop(void);\r
+\r
+void mloop_evcmd_usbkbd_on(void);\r
+void mloop_evcmd_usbkbd_off(void);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* MLOOP_EVENT_H_ */\r
index 2433ef5..c513ac6 100644 (file)
@@ -1623,9 +1623,9 @@ int create_config_file(gchar* filepath)
         g_fprintf (fp, "\n[%s]\n", ADDITIONAL_OPTION_GROUP);
         g_fprintf (fp, "%s=\n", EMULATOR_OPTION_KEY);
         if(strcmp(arch, X86) == 0)
-            g_fprintf (fp, "%s=%s\n", QEMU_OPTION_KEY,"-M tizen-x86-machine -usb -usbdevice maru-touchscreen -usbdevice keyboard -net user -net nic,model=virtio -rtc base=utc");
+            g_fprintf (fp, "%s=%s\n", QEMU_OPTION_KEY,"-M tizen-x86-machine -usb -usbdevice maru-touchscreen -net user -net nic,model=virtio -rtc base=utc");
         else if(strcmp(arch, ARM) == 0)
-            g_fprintf (fp, "%s=%s\n", QEMU_OPTION_KEY," -M s5pc110 -net user -net nic,model=s5pc1xx-usb-otg -usbdevice keyboard -rtc base=utc -redir tcp:1202:10.0.2.16:22");
+            g_fprintf (fp, "%s=%s\n", QEMU_OPTION_KEY," -M s5pc110 -net user -net nic,model=s5pc1xx-usb-otg -rtc base=utc -redir tcp:1202:10.0.2.16:22");
         g_fprintf (fp, "[%s]\n", HARDWARE_GROUP);
         g_fprintf (fp, "%s=\n", RESOLUTION_KEY);
         g_fprintf (fp, "%s=1\n", BUTTON_TYPE_KEY);
diff --git a/vl.c b/vl.c
index 7684393..ab4d141 100644 (file)
--- a/vl.c
+++ b/vl.c
@@ -167,6 +167,7 @@ int main(int argc, char **argv)
 #include "vl.h"
 #include "ui/qemu-spice.h"
 #include "sdb.h"
+#include "tizen/src/mloop_event.h"
 
 #include "tizen/src/debug_ch.h"
 
@@ -907,8 +908,8 @@ static void smp_parse(const char *optarg)
             cores = smp / (sockets * threads);
         } else {
           if (sockets) {
-                       threads = smp / (cores * sockets);
-                 }
+            threads = smp / (cores * sockets);
+          }
         }
     }
     smp_cpus = smp;
@@ -1321,11 +1322,11 @@ void qemu_system_shutdown_request(void)
 
 #if 1 /* graceful shutdown */
     /* graceful shutdown starts with 'qemu_system_shutdown_request'. */
-       exit_emulator_post_process();
+    exit_emulator_post_process();
 #endif
 
 #ifndef _SDK_SIMULATOR
-       emul_kill_all_process();
+    emul_kill_all_process();
 #endif
     shutdown_requested = 1;
     qemu_notify_event();
@@ -1408,13 +1409,13 @@ void main_loop_wait(int nonblocking)
     slirp_select_poll(&rfds, &wfds, &xfds, (ret < 0));
 
 #ifndef _SDK_SIMULATOR  
-       emulator_mutex_lock();
+    emulator_mutex_lock();
 #endif
 
-       qemu_run_all_timers();
+    qemu_run_all_timers();
 
 #ifndef _SDK_SIMULATOR  
-       emulator_mutex_unlock();
+    emulator_mutex_unlock();
 #endif
 
     /* Check bottom-halves last in case any of the earlier events triggered
@@ -2045,7 +2046,7 @@ int qemu_main(int argc, char **argv, char **envp)
         if (optind >= argc)
             break;
         if (argv[optind][0] != '-') {
-           hda_opts = drive_add(IF_DEFAULT, 0, argv[optind++], HD_OPTS);
+        hda_opts = drive_add(IF_DEFAULT, 0, argv[optind++], HD_OPTS);
         } else {
             const QEMUOption *popt;
 
@@ -2109,15 +2110,15 @@ int qemu_main(int argc, char **argv, char **envp)
                 if (drive_def(optarg) == NULL) {
                     exit(1);
                 }
-               break;
+            break;
             case QEMU_OPTION_set:
                 if (qemu_set_option(optarg) != 0)
                     exit(1);
-               break;
+            break;
             case QEMU_OPTION_global:
                 if (qemu_global_option(optarg) != 0)
                     exit(1);
-               break;
+            break;
             case QEMU_OPTION_mtdblock:
                 drive_add(IF_MTD, -1, optarg, MTD_OPTS);
                 break;
@@ -2164,7 +2165,7 @@ int qemu_main(int argc, char **argv, char **envp)
                         fprintf(stderr, "qemu: invalid physical CHS format\n");
                         exit(1);
                     }
-                   if (hda_opts != NULL) {
+            if (hda_opts != NULL) {
                         char num[16];
                         snprintf(num, sizeof(num), "%d", cyls);
                         qemu_opt_set(hda_opts, "cyls", num);
@@ -2360,9 +2361,9 @@ int qemu_main(int argc, char **argv, char **envp)
             case QEMU_OPTION_S:
                 autostart = 0;
                 break;
-           case QEMU_OPTION_k:
-               keyboard_layout = optarg;
-               break;
+        case QEMU_OPTION_k:
+        keyboard_layout = optarg;
+        break;
             case QEMU_OPTION_localtime:
                 rtc_utc = 0;
                 break;
@@ -2545,9 +2546,9 @@ int qemu_main(int argc, char **argv, char **envp)
             case QEMU_OPTION_debugcon:
                 add_device_config(DEV_DEBUGCON, optarg);
                 break;
-           case QEMU_OPTION_loadvm:
-               loadvm = optarg;
-               break;
+        case QEMU_OPTION_loadvm:
+        loadvm = optarg;
+        break;
             case QEMU_OPTION_full_screen:
                 full_screen = 1;
                 break;
@@ -2614,10 +2615,10 @@ int qemu_main(int argc, char **argv, char **envp)
                     exit(1);
                 }
                 break;
-           case QEMU_OPTION_vnc:
+        case QEMU_OPTION_vnc:
                 display_remote++;
-               vnc_display = optarg;
-               break;
+        vnc_display = optarg;
+        break;
             case QEMU_OPTION_no_acpi:
                 acpi_enabled = 0;
                 break;
@@ -2646,11 +2647,11 @@ int qemu_main(int argc, char **argv, char **envp)
                     exit(1);
                 }
                 break;
-           case QEMU_OPTION_option_rom:
-               if (nb_option_roms >= MAX_OPTION_ROMS) {
-                   fprintf(stderr, "Too many option ROMs\n");
-                   exit(1);
-               }
+        case QEMU_OPTION_option_rom:
+        if (nb_option_roms >= MAX_OPTION_ROMS) {
+            fprintf(stderr, "Too many option ROMs\n");
+            exit(1);
+        }
                 opts = qemu_opts_parse(qemu_find_opts("option-rom"), optarg, 1);
                 option_rom[nb_option_roms].name = qemu_opt_get(opts, "romfile");
                 option_rom[nb_option_roms].bootindex =
@@ -2659,25 +2660,25 @@ int qemu_main(int argc, char **argv, char **envp)
                     fprintf(stderr, "Option ROM file is not specified\n");
                     exit(1);
                 }
-               nb_option_roms++;
-               break;
+        nb_option_roms++;
+        break;
             case QEMU_OPTION_semihosting:
                 semihosting_enabled = 1;
                 break;
             case QEMU_OPTION_name:
                 qemu_name = qemu_strdup(optarg);
-                {
-                    char *p = strchr(qemu_name, ',');
-                    if (p != NULL) {
-                       *p++ = 0;
-                       if (strncmp(p, "process=", 8)) {
-                           fprintf(stderr, "Unknown subargument %s to -name\n", p);
-                           exit(1);
-                       }
-                       p += 8;
-                       os_set_proc_name(p);
-                    }  
-                }      
+         {
+             char *p = strchr(qemu_name, ',');
+             if (p != NULL) {
+                *p++ = 0;
+            if (strncmp(p, "process=", 8)) {
+                fprintf(stderr, "Unknown subargument %s to -name\n", p);
+                exit(1);
+            }
+            p += 8;
+            os_set_proc_name(p);
+             }
+         }
                 break;
             case QEMU_OPTION_prom_env:
                 if (nb_prom_envs >= MAX_PROM_ENVS) {
@@ -3091,15 +3092,15 @@ int qemu_main(int argc, char **argv, char **envp)
 #endif
 #if defined(CONFIG_SDL)
     case DT_SDL:{
-                       if (use_qemu_display) {
-                               /* use qemu SDL */
-                               sdl_display_init(ds, full_screen, no_frame);
-                       }
-                       else {
-                               /* use qemu_gtk_widget */
-                               qemu_display_init(ds);
-                       }
-               }
+            if (use_qemu_display) {
+                /* use qemu SDL */
+                sdl_display_init(ds, full_screen, no_frame);
+            }
+            else {
+                /* use qemu_gtk_widget */
+                qemu_display_init(ds);
+            }
+        }
         break;
 #elif defined(CONFIG_COCOA)
     case DT_SDL:
@@ -3160,9 +3161,12 @@ int qemu_main(int argc, char **argv, char **envp)
      * when bus is created by qdev.c */
     qemu_register_reset(qbus_reset_all_fn, sysbus_get_default());
     qemu_run_machine_init_done_notifiers();
-       
-       /* call sdb setup function */
-       sdb_setup();
+
+    /* call sdb setup function */
+    sdb_setup();
+
+    /* init mloop_event */
+    mloop_ev_init();
 
     qemu_system_reset();
     if (loadvm) {
@@ -3185,6 +3189,9 @@ int qemu_main(int argc, char **argv, char **envp)
     os_setup_post();
 
     main_loop();
+
+    /* clean up mloop_event */
+    mloop_ev_stop();
     quit_timers();
     net_cleanup();