Home | History | Annotate | Download | only in qemu
      1 /*
      2  * QEMU System Emulator
      3  *
      4  * Copyright (c) 2003-2008 Fabrice Bellard
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a copy
      7  * of this software and associated documentation files (the "Software"), to deal
      8  * in the Software without restriction, including without limitation the rights
      9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10  * copies of the Software, and to permit persons to whom the Software is
     11  * furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     22  * THE SOFTWARE.
     23  */
     24 
     25 /* the following is needed on Linux to define ptsname() in stdlib.h */
     26 #if defined(__linux__)
     27 #define _GNU_SOURCE 1
     28 #endif
     29 
     30 #ifndef _WIN32
     31 #include <sys/wait.h>
     32 #endif  // _WIN32
     33 
     34 #ifdef _WIN32
     35 #include <windows.h>
     36 #include <sys/timeb.h>
     37 #endif
     38 
     39 #include "qemu-common.h"
     40 #include "net.h"
     41 #include "console.h"
     42 #include "qemu-timer.h"
     43 #include "qemu-char.h"
     44 #include "block.h"
     45 #include "sockets.h"
     46 #include "audio/audio.h"
     47 
     48 #include "android/android.h"
     49 #include "charpipe.h"
     50 #include "android/globals.h"
     51 #include "android/utils/bufprint.h"
     52 #include "android/utils/system.h"
     53 #include "android/protocol/core-connection.h"
     54 #include "android/protocol/attach-ui-impl.h"
     55 #include "android/protocol/fb-updates-impl.h"
     56 #include "android/protocol/user-events-proxy.h"
     57 #include "android/protocol/core-commands-proxy.h"
     58 #include "android/protocol/ui-commands-impl.h"
     59 #include "android/qemulator.h"
     60 
     61 static Looper*  mainLooper;
     62 
     63 /***********************************************************/
     64 /* I/O handling */
     65 
     66 typedef struct IOHandlerRecord {
     67     LoopIo  io[1];
     68     IOHandler* fd_read;
     69     IOHandler* fd_write;
     70     int        running;
     71     int        deleted;
     72     void*      opaque;
     73     struct IOHandlerRecord *next;
     74 } IOHandlerRecord;
     75 
     76 static IOHandlerRecord *first_io_handler;
     77 
     78 static void ioh_callback(void* opaque, int fd, unsigned events)
     79 {
     80     IOHandlerRecord* ioh = opaque;
     81     ioh->running = 1;
     82     if ((events & LOOP_IO_READ) != 0) {
     83         ioh->fd_read(ioh->opaque);
     84     }
     85     if (!ioh->deleted && (events & LOOP_IO_WRITE) != 0) {
     86         ioh->fd_write(ioh->opaque);
     87     }
     88     ioh->running = 0;
     89     if (ioh->deleted) {
     90         loopIo_done(ioh->io);
     91         free(ioh);
     92     }
     93 }
     94 
     95 int qemu_set_fd_handler(int fd,
     96                         IOHandler *fd_read,
     97                         IOHandler *fd_write,
     98                         void *opaque)
     99 {
    100     IOHandlerRecord **pioh, *ioh;
    101 
    102     if (!fd_read && !fd_write) {
    103         pioh = &first_io_handler;
    104         for(;;) {
    105             ioh = *pioh;
    106             if (ioh == NULL)
    107                 return 0;
    108             if (ioh->io->fd == fd) {
    109                 break;
    110             }
    111             pioh = &ioh->next;
    112         }
    113         if (ioh->running) {
    114             ioh->deleted = 1;
    115         } else {
    116             *pioh = ioh->next;
    117             loopIo_done(ioh->io);
    118             free(ioh);
    119         }
    120     } else {
    121         for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) {
    122             if (ioh->io->fd == fd)
    123                 goto found;
    124         }
    125         ANEW0(ioh);
    126         ioh->next = first_io_handler;
    127         first_io_handler = ioh;
    128         loopIo_init(ioh->io, mainLooper, fd, ioh_callback, ioh);
    129     found:
    130         ioh->fd_read  = fd_read;
    131         ioh->fd_write = fd_write;
    132         ioh->opaque   = opaque;
    133 
    134         if (fd_read != NULL)
    135             loopIo_wantRead(ioh->io);
    136         else
    137             loopIo_dontWantRead(ioh->io);
    138 
    139         if (fd_write != NULL)
    140             loopIo_wantWrite(ioh->io);
    141         else
    142             loopIo_dontWantWrite(ioh->io);
    143     }
    144     return 0;
    145 }
    146 
    147 /***********************************************************/
    148 /* main execution loop */
    149 
    150 static LoopTimer  gui_timer[1];
    151 
    152 static void gui_update(void *opaque)
    153 {
    154     LoopTimer* timer = opaque;
    155     qframebuffer_pulse();
    156     loopTimer_startRelative(timer, GUI_REFRESH_INTERVAL);
    157 }
    158 
    159 static void init_gui_timer(Looper* looper)
    160 {
    161     loopTimer_init(gui_timer, looper, gui_update, gui_timer);
    162     loopTimer_startRelative(gui_timer, 0);
    163     qframebuffer_invalidate_all();
    164 }
    165 
    166 /* Called from qemulator.c */
    167 void qemu_system_shutdown_request(void)
    168 {
    169     looper_forceQuit(mainLooper);
    170 }
    171 
    172 #ifndef _WIN32
    173 
    174 static void termsig_handler(int signal)
    175 {
    176     qemu_system_shutdown_request();
    177 }
    178 
    179 static void sigchld_handler(int signal)
    180 {
    181     waitpid(-1, NULL, WNOHANG);
    182 }
    183 
    184 static void sighandler_setup(void)
    185 {
    186     struct sigaction act;
    187 
    188     memset(&act, 0, sizeof(act));
    189     act.sa_handler = termsig_handler;
    190     sigaction(SIGINT,  &act, NULL);
    191     sigaction(SIGHUP,  &act, NULL);
    192     sigaction(SIGTERM, &act, NULL);
    193 
    194     act.sa_handler = sigchld_handler;
    195     act.sa_flags = SA_NOCLDSTOP;
    196     sigaction(SIGCHLD, &act, NULL);
    197 }
    198 
    199 #endif
    200 
    201 #ifdef _WIN32
    202 static BOOL WINAPI qemu_ctrl_handler(DWORD type)
    203 {
    204     exit(STATUS_CONTROL_C_EXIT);
    205     return TRUE;
    206 }
    207 #endif
    208 
    209 int qemu_main(int argc, char **argv, char **envp)
    210 {
    211 #ifndef _WIN32
    212     {
    213         struct sigaction act;
    214         sigfillset(&act.sa_mask);
    215         act.sa_flags = 0;
    216         act.sa_handler = SIG_IGN;
    217         sigaction(SIGPIPE, &act, NULL);
    218     }
    219 #else
    220     SetConsoleCtrlHandler(qemu_ctrl_handler, TRUE);
    221     /* Note: cpu_interrupt() is currently not SMP safe, so we force
    222        QEMU to run on a single CPU */
    223     {
    224         HANDLE h;
    225         DWORD mask, smask;
    226         int i;
    227         h = GetCurrentProcess();
    228         if (GetProcessAffinityMask(h, &mask, &smask)) {
    229             for(i = 0; i < 32; i++) {
    230                 if (mask & (1 << i))
    231                     break;
    232             }
    233             if (i != 32) {
    234                 mask = 1 << i;
    235                 SetProcessAffinityMask(h, mask);
    236             }
    237         }
    238     }
    239 #endif
    240 
    241 #ifdef _WIN32
    242     socket_init();
    243 #endif
    244 
    245 #ifndef _WIN32
    246     /* must be after terminal init, SDL library changes signal handlers */
    247     sighandler_setup();
    248 #endif
    249 
    250     mainLooper = looper_newGeneric();
    251 
    252     /* Register a timer to call qframebuffer_pulse periodically */
    253     init_gui_timer(mainLooper);
    254 
    255     // Connect to the core's framebuffer service
    256     if (fbUpdatesImpl_create(attachUiImpl_get_console_socket(), "-raw",
    257                              qemulator_get_first_framebuffer(qemulator_get()),
    258                              mainLooper)) {
    259         return -1;
    260     }
    261 
    262     // Attach the recepient of UI commands.
    263     if (uiCmdImpl_create(attachUiImpl_get_console_socket(), mainLooper)) {
    264         return -1;
    265     }
    266 
    267     looper_run(mainLooper);
    268 
    269     fbUpdatesImpl_destroy();
    270     userEventsProxy_destroy();
    271     coreCmdProxy_destroy();
    272     uiCmdImpl_destroy();
    273     attachUiImpl_destroy();
    274 
    275     return 0;
    276 }
    277