blob: 0b63d4a49480706d68d880684216eb3e9bd8af05 [file] [log] [blame]
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +02001/*
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 Chtchetkine17ecca62011-02-07 14:14:14 -080030#ifndef _WIN32
David 'Digit' Turner07db3492011-02-02 17:36:34 +010031#include <sys/wait.h>
Vladimir Chtchetkine17ecca62011-02-07 14:14:14 -080032#endif // _WIN32
33
34#ifdef _WIN32
35#include <windows.h>
36#include <sys/timeb.h>
37#endif
David 'Digit' Turner07db3492011-02-02 17:36:34 +010038
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +020039#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 Chtchetkined87b0802010-12-06 10:55:11 -080045#include "sockets.h"
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +020046#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' Turner18fe86e2010-10-19 08:07:11 +020052#include "android/utils/system.h"
David 'Digit' Turnere9931262011-02-02 14:05:23 +010053#include "android/protocol/core-connection.h"
Vladimir Chtchetkine85276802011-01-31 15:18:45 -080054#include "android/protocol/attach-ui-impl.h"
Vladimir Chtchetkine94a2fba2011-01-31 10:49:06 -080055#include "android/protocol/fb-updates-impl.h"
Vladimir Chtchetkine85276802011-01-31 15:18:45 -080056#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' Turner07db3492011-02-02 17:36:34 +010059#include "android/qemulator.h"
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +020060
David 'Digit' Turner07db3492011-02-02 17:36:34 +010061static Looper* mainLooper;
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +020062
63/***********************************************************/
Vladimir Chtchetkine17ecca62011-02-07 14:14:14 -080064/* I/O handling */
65
66typedef 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
76static IOHandlerRecord *first_io_handler;
77
78static 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
95int 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' Turnerf59442f2010-10-08 16:22:10 +0200148/* main execution loop */
149
David 'Digit' Turner07db3492011-02-02 17:36:34 +0100150static LoopTimer gui_timer[1];
151
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +0200152static void gui_update(void *opaque)
153{
David 'Digit' Turner07db3492011-02-02 17:36:34 +0100154 LoopTimer* timer = opaque;
155 qframebuffer_pulse();
156 loopTimer_startRelative(timer, GUI_REFRESH_INTERVAL);
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +0200157}
158
David 'Digit' Turner07db3492011-02-02 17:36:34 +0100159static void init_gui_timer(Looper* looper)
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +0200160{
David 'Digit' Turner07db3492011-02-02 17:36:34 +0100161 loopTimer_init(gui_timer, looper, gui_update, gui_timer);
162 loopTimer_startRelative(gui_timer, 0);
163 qframebuffer_invalidate_all();
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +0200164}
165
David 'Digit' Turner07db3492011-02-02 17:36:34 +0100166/* Called from qemulator.c */
David 'Digit' Turner73f31662010-10-13 16:52:14 +0200167void qemu_system_shutdown_request(void)
168{
David 'Digit' Turner07db3492011-02-02 17:36:34 +0100169 looper_forceQuit(mainLooper);
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +0200170}
171
172#ifndef _WIN32
173
174static void termsig_handler(int signal)
175{
David 'Digit' Turner07db3492011-02-02 17:36:34 +0100176 qemu_system_shutdown_request();
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +0200177}
178
179static void sigchld_handler(int signal)
180{
181 waitpid(-1, NULL, WNOHANG);
182}
183
184static 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' Turner894086d2010-10-13 17:48:13 +0200201#ifdef _WIN32
202static BOOL WINAPI qemu_ctrl_handler(DWORD type)
203{
204 exit(STATUS_CONTROL_C_EXIT);
205 return TRUE;
206}
207#endif
208
David 'Digit' Turner07db3492011-02-02 17:36:34 +0100209int qemu_main(int argc, char **argv, char **envp)
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +0200210{
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +0200211#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' Turnerf59442f2010-10-08 16:22:10 +0200241#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' Turner07db3492011-02-02 17:36:34 +0100250 mainLooper = looper_newGeneric();
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +0200251
David 'Digit' Turner07db3492011-02-02 17:36:34 +0100252 /* Register a timer to call qframebuffer_pulse periodically */
253 init_gui_timer(mainLooper);
254
255 // Connect to the core's framebuffer service
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +0100256 if (fbUpdatesImpl_create(attachUiImpl_get_console_socket(), "-raw",
257 qemulator_get_first_framebuffer(qemulator_get()),
258 mainLooper)) {
David 'Digit' Turner07db3492011-02-02 17:36:34 +0100259 return -1;
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +0200260 }
261
David 'Digit' Turner07db3492011-02-02 17:36:34 +0100262 // Attach the recepient of UI commands.
David 'Digit' Turnerb6c168b2011-02-02 21:39:10 +0100263 if (uiCmdImpl_create(attachUiImpl_get_console_socket(), mainLooper)) {
David 'Digit' Turner07db3492011-02-02 17:36:34 +0100264 return -1;
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +0200265 }
266
David 'Digit' Turner07db3492011-02-02 17:36:34 +0100267 looper_run(mainLooper);
Vladimir Chtchetkined87b0802010-12-06 10:55:11 -0800268
David 'Digit' Turner21cbdd22011-02-02 22:57:35 +0100269 fbUpdatesImpl_destroy();
Vladimir Chtchetkine85276802011-01-31 15:18:45 -0800270 userEventsProxy_destroy();
271 coreCmdProxy_destroy();
272 uiCmdImpl_destroy();
273 attachUiImpl_destroy();
Vladimir Chtchetkinee95660a2010-12-20 08:28:03 -0800274
David 'Digit' Turnerf59442f2010-10-08 16:22:10 +0200275 return 0;
276}