David 'Digit' Turner | f59442f | 2010-10-08 16:22:10 +0200 | [diff] [blame] | 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 | |
Vladimir Chtchetkine | 17ecca6 | 2011-02-07 14:14:14 -0800 | [diff] [blame] | 30 | #ifndef _WIN32 |
David 'Digit' Turner | 07db349 | 2011-02-02 17:36:34 +0100 | [diff] [blame] | 31 | #include <sys/wait.h> |
Vladimir Chtchetkine | 17ecca6 | 2011-02-07 14:14:14 -0800 | [diff] [blame] | 32 | #endif // _WIN32 |
| 33 | |
| 34 | #ifdef _WIN32 |
| 35 | #include <windows.h> |
| 36 | #include <sys/timeb.h> |
| 37 | #endif |
David 'Digit' Turner | 07db349 | 2011-02-02 17:36:34 +0100 | [diff] [blame] | 38 | |
David 'Digit' Turner | f59442f | 2010-10-08 16:22:10 +0200 | [diff] [blame] | 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" |
Vladimir Chtchetkine | d87b080 | 2010-12-06 10:55:11 -0800 | [diff] [blame] | 45 | #include "sockets.h" |
David 'Digit' Turner | f59442f | 2010-10-08 16:22:10 +0200 | [diff] [blame] | 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" |
David 'Digit' Turner | 18fe86e | 2010-10-19 08:07:11 +0200 | [diff] [blame] | 52 | #include "android/utils/system.h" |
David 'Digit' Turner | e993126 | 2011-02-02 14:05:23 +0100 | [diff] [blame] | 53 | #include "android/protocol/core-connection.h" |
Vladimir Chtchetkine | 8527680 | 2011-01-31 15:18:45 -0800 | [diff] [blame] | 54 | #include "android/protocol/attach-ui-impl.h" |
Vladimir Chtchetkine | 94a2fba | 2011-01-31 10:49:06 -0800 | [diff] [blame] | 55 | #include "android/protocol/fb-updates-impl.h" |
Vladimir Chtchetkine | 8527680 | 2011-01-31 15:18:45 -0800 | [diff] [blame] | 56 | #include "android/protocol/user-events-proxy.h" |
| 57 | #include "android/protocol/core-commands-proxy.h" |
| 58 | #include "android/protocol/ui-commands-impl.h" |
David 'Digit' Turner | 07db349 | 2011-02-02 17:36:34 +0100 | [diff] [blame] | 59 | #include "android/qemulator.h" |
David 'Digit' Turner | f59442f | 2010-10-08 16:22:10 +0200 | [diff] [blame] | 60 | |
David 'Digit' Turner | 07db349 | 2011-02-02 17:36:34 +0100 | [diff] [blame] | 61 | static Looper* mainLooper; |
David 'Digit' Turner | f59442f | 2010-10-08 16:22:10 +0200 | [diff] [blame] | 62 | |
| 63 | /***********************************************************/ |
Vladimir Chtchetkine | 17ecca6 | 2011-02-07 14:14:14 -0800 | [diff] [blame] | 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 | /***********************************************************/ |
David 'Digit' Turner | f59442f | 2010-10-08 16:22:10 +0200 | [diff] [blame] | 148 | /* main execution loop */ |
| 149 | |
David 'Digit' Turner | 07db349 | 2011-02-02 17:36:34 +0100 | [diff] [blame] | 150 | static LoopTimer gui_timer[1]; |
| 151 | |
David 'Digit' Turner | f59442f | 2010-10-08 16:22:10 +0200 | [diff] [blame] | 152 | static void gui_update(void *opaque) |
| 153 | { |
David 'Digit' Turner | 07db349 | 2011-02-02 17:36:34 +0100 | [diff] [blame] | 154 | LoopTimer* timer = opaque; |
| 155 | qframebuffer_pulse(); |
| 156 | loopTimer_startRelative(timer, GUI_REFRESH_INTERVAL); |
David 'Digit' Turner | f59442f | 2010-10-08 16:22:10 +0200 | [diff] [blame] | 157 | } |
| 158 | |
David 'Digit' Turner | 07db349 | 2011-02-02 17:36:34 +0100 | [diff] [blame] | 159 | static void init_gui_timer(Looper* looper) |
David 'Digit' Turner | f59442f | 2010-10-08 16:22:10 +0200 | [diff] [blame] | 160 | { |
David 'Digit' Turner | 07db349 | 2011-02-02 17:36:34 +0100 | [diff] [blame] | 161 | loopTimer_init(gui_timer, looper, gui_update, gui_timer); |
| 162 | loopTimer_startRelative(gui_timer, 0); |
| 163 | qframebuffer_invalidate_all(); |
David 'Digit' Turner | f59442f | 2010-10-08 16:22:10 +0200 | [diff] [blame] | 164 | } |
| 165 | |
David 'Digit' Turner | 07db349 | 2011-02-02 17:36:34 +0100 | [diff] [blame] | 166 | /* Called from qemulator.c */ |
David 'Digit' Turner | 73f3166 | 2010-10-13 16:52:14 +0200 | [diff] [blame] | 167 | void qemu_system_shutdown_request(void) |
| 168 | { |
David 'Digit' Turner | 07db349 | 2011-02-02 17:36:34 +0100 | [diff] [blame] | 169 | looper_forceQuit(mainLooper); |
David 'Digit' Turner | f59442f | 2010-10-08 16:22:10 +0200 | [diff] [blame] | 170 | } |
| 171 | |
| 172 | #ifndef _WIN32 |
| 173 | |
| 174 | static void termsig_handler(int signal) |
| 175 | { |
David 'Digit' Turner | 07db349 | 2011-02-02 17:36:34 +0100 | [diff] [blame] | 176 | qemu_system_shutdown_request(); |
David 'Digit' Turner | f59442f | 2010-10-08 16:22:10 +0200 | [diff] [blame] | 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 | |
David 'Digit' Turner | 894086d | 2010-10-13 17:48:13 +0200 | [diff] [blame] | 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 | |
David 'Digit' Turner | 07db349 | 2011-02-02 17:36:34 +0100 | [diff] [blame] | 209 | int qemu_main(int argc, char **argv, char **envp) |
David 'Digit' Turner | f59442f | 2010-10-08 16:22:10 +0200 | [diff] [blame] | 210 | { |
David 'Digit' Turner | f59442f | 2010-10-08 16:22:10 +0200 | [diff] [blame] | 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 | |
David 'Digit' Turner | f59442f | 2010-10-08 16:22:10 +0200 | [diff] [blame] | 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 | |
David 'Digit' Turner | 07db349 | 2011-02-02 17:36:34 +0100 | [diff] [blame] | 250 | mainLooper = looper_newGeneric(); |
David 'Digit' Turner | f59442f | 2010-10-08 16:22:10 +0200 | [diff] [blame] | 251 | |
David 'Digit' Turner | 07db349 | 2011-02-02 17:36:34 +0100 | [diff] [blame] | 252 | /* Register a timer to call qframebuffer_pulse periodically */ |
| 253 | init_gui_timer(mainLooper); |
| 254 | |
| 255 | // Connect to the core's framebuffer service |
David 'Digit' Turner | 21cbdd2 | 2011-02-02 22:57:35 +0100 | [diff] [blame] | 256 | if (fbUpdatesImpl_create(attachUiImpl_get_console_socket(), "-raw", |
| 257 | qemulator_get_first_framebuffer(qemulator_get()), |
| 258 | mainLooper)) { |
David 'Digit' Turner | 07db349 | 2011-02-02 17:36:34 +0100 | [diff] [blame] | 259 | return -1; |
David 'Digit' Turner | f59442f | 2010-10-08 16:22:10 +0200 | [diff] [blame] | 260 | } |
| 261 | |
David 'Digit' Turner | 07db349 | 2011-02-02 17:36:34 +0100 | [diff] [blame] | 262 | // Attach the recepient of UI commands. |
David 'Digit' Turner | b6c168b | 2011-02-02 21:39:10 +0100 | [diff] [blame] | 263 | if (uiCmdImpl_create(attachUiImpl_get_console_socket(), mainLooper)) { |
David 'Digit' Turner | 07db349 | 2011-02-02 17:36:34 +0100 | [diff] [blame] | 264 | return -1; |
David 'Digit' Turner | f59442f | 2010-10-08 16:22:10 +0200 | [diff] [blame] | 265 | } |
| 266 | |
David 'Digit' Turner | 07db349 | 2011-02-02 17:36:34 +0100 | [diff] [blame] | 267 | looper_run(mainLooper); |
Vladimir Chtchetkine | d87b080 | 2010-12-06 10:55:11 -0800 | [diff] [blame] | 268 | |
David 'Digit' Turner | 21cbdd2 | 2011-02-02 22:57:35 +0100 | [diff] [blame] | 269 | fbUpdatesImpl_destroy(); |
Vladimir Chtchetkine | 8527680 | 2011-01-31 15:18:45 -0800 | [diff] [blame] | 270 | userEventsProxy_destroy(); |
| 271 | coreCmdProxy_destroy(); |
| 272 | uiCmdImpl_destroy(); |
| 273 | attachUiImpl_destroy(); |
Vladimir Chtchetkine | e95660a | 2010-12-20 08:28:03 -0800 | [diff] [blame] | 274 | |
David 'Digit' Turner | f59442f | 2010-10-08 16:22:10 +0200 | [diff] [blame] | 275 | return 0; |
| 276 | } |