From: Struan Bartlett <struan@praguespringpeople.org>
To: qemu-devel@nongnu.org
Subject: [patch] on-quit-v0.21 with resume/suspend/power-off dialog Re: [patch] Re: [Qemu-devel] Suggestion - trap window-close of VM
Date: Sat, 07 May 2005 18:30:16 +0200 [thread overview]
Message-ID: <427CED18.4030607@praguespringpeople.org> (raw)
In-Reply-To: <4247EBB0.6090409@praguespringpeople.org>
[-- Attachment #1.1: Type: text/plain, Size: 10218 bytes --]
Hi,
Having had the APM bios fixed in the 0.7 Qemu release, which allows
Windows 2000 to correctly signal Qemu when it wants to shutdown the VM,
I've updated my '-on-quit' patch - which prevented the VM from being
crudely shut down by accidentally pressing Ctrl-C or closing the VM
window - to remove the nasty i386-specific "halt-instruction-detection"
code and provide what I hope you will agree is a cleaner replacement.
The new patch instead relies on APM/SDL/Cocoa/Cuda each specifying
whether the shutdown request originated from the hardware or from the
user. In the case of user request, Qemu's behaviour will depend on the
command line option specified: 1. '-on-quit ignore' means ignore the
Ctrl-C; 2. '-on-quit suspend' means suspend the VM. In the case of a
hardware shutdown, the VM will shut down normally (but if '-on-quit
suspend' was selected it will delete the named suspend file first).
The patch features extra options '-on-quit ask' and '-on-quit
<filepath>' which both cause Qemu to run a script to ask the user
whether they want to resume, suspend or power off the VM. For non-WIN32
platforms, this is easily implemented it using a script that the
xmessage command i.e.:
#!/bin/sh
exec /usr/bin/X11/xmessage -center -timeout 10 -buttons
'Resume:0,Suspend:1,Power Off:2' 'Do you want to resume, suspend, or
power off this virtual machine?'
The '-on-quit ask' option assumes a default script filename
"on_quit_ask", assumed to be in the CONFIG_QEMU_SHAREDIR directory (i.e.
usually /usr/local/share/qemu).
Example command (Linux) which should correctly buffer naive users from
accidental VM shutdown and suspend file overwriting: it resumes from
suspended.qemu file if it exists; asks user whether to resume, power off
or suspend on CTRL-C or window close; suspend saves to the same file;
power off deleted the suspend file.
qemu -hda win2k.raw -m 64 -monitor null -loadvm suspended.qemu -on-quit ask
Feedback welcome!
Struan
Struan Bartlett wrote:
> Hi,
>
> I've attached a patch against the 2005-03-26 snapshot that implements
> two '-on-quit' options for the emulator window: ignore-unless-halted
> and suspend-unless-halted, that aim to make it safe to allow naive
> users to (try to) close the VM window by trapping requests to shutdown
> and either ignoring them or forcing a save of the VM state before
> obeying them.
>
> Caveat: I'll come clean straight away that the patch is implemented
> using a nasty TARGET_i386-specific hack that detects whether the guest
> operating system has permanently halted by looking to see if the last
> instruction executed was 0xF4 and, if so, whether the IF flag is
> cleared. Saying that, this system appears to work reasonably well on
> my Pentium host running a Windows 2000 guest, but I have not tested it
> on any other systems.
>
> Usage:
>
> 1. If you provide naive users with a variation on the following
> command line, then you can let your naive users (try to) close the VM
> window as much as they like. Unless the guest has permanently halted,
> attempts to close the VM window should save the VM state to
> 'suspended.qemu' in the current working directory before qemu exits.
> The same command line will restart the VM where it left off. Then,
> once the guest has permanently halted, qemu will delete the
> suspended.qemu file so that the next launch of qemu will boot afresh:
>
> qemu -hda win2k.raw -m 64 -monitor null -loadvm suspended.qemu
> -on-quit suspend-unless-halted
>
> 2. Alternatively, the following command will make qemu ignore the
> user's request to close the emulator window unless the guest has
> already permanently halted:
>
> qemu -hda win2k.raw -m 64 -monitor null -on-quit ignore-unless-halted
>
> 3. If you combine this with a test of whether qemu is already running,
> then it should be safe to let naive users try to both launch and to
> close qemu as much as they like. e.g.
>
> killall -0 qemu 2>/dev/null; if [ $? == 1 ]; then qemu -hda win2k.raw
> -m 64 -monitor null -loadvm suspended.qemu -on-quit
> suspend-unless-halted; fi &
>
> 4. Finally, if your leave out the -on-quit option altogether, then
> qemu's behaviour should remain completely unchanged.
>
> I hope this is useful for some i386/W2K users out there. Any
> constructive criticism appreciated. If you know how I could improve
> permanent halt detection (that doesn't require in-depth knowledge of
> APM or ACPI) then please let me know.
>
> Struan
>
> Struan Bartlett wrote:
>
>> Ryan Rempel wrote:
>>
>>>On Mon, Nov 29, 2004 at 21:46:54 +0100, Lennert Buytenhek wrote
>>>
>>>
>>>>On Mon, Nov 29, 2004 at 08:43:56PM +0000, Richard Neill wrote:
>>>>
>>>>
>>>>>A thought that occurred to me. If one is running a virtual machine (eg
>>>>>copy of WinXP), then simply closing the qemu window is a really bad
>>>>>idea, since it will effectively crash the guest.
>>>>>
>>>>>
>>>>Related thought -- it would be way cool if we could make killing qemu
>>>>do exactly happens when you press the power button on an ACPI-capable
>>>>machine with any recent OS on it (auto shutdown.)
>>>>
>>>>
>>>I was wondering if anyone has followed up on this suggestion. I'm
>>>putting together a Qemu-based setup for some relatively naive users,
>>>and ideally I'd like to be able to deal with this in a reasonable
>>>elegant way (the ACPI hook sounds very elegant indeed).
>>>
>>>Alternatively, how do people deal with the problem of naive users who
>>>might just close the Qemu window without shutting down the guest
>>>properly? I'm working in a KDE environment -- perhaps there is a way
>>>in KDE to prevent the close button from appearing? But that wouldn't
>>>catch every case either (for instance, if the user were to shut down
>>>the host).
>>>
>> This sounds like a good idea. An alternative solution, that might be
>> more straightforward to implement if Qemu doesn't implement ACPI yet,
>> would be for the kill signal to simply cause Qemu to do the
>> equivalent of entering 'stop' and 'savevm <somefilepath>' into the
>> monitor.
>>
>>------------------------------------------------------------------------
>>
>>_______________________________________________
>>Qemu-devel mailing list
>>Qemu-devel@nongnu.org
>>http://lists.nongnu.org/mailman/listinfo/qemu-devel
>>
>>
>------------------------------------------------------------------------
>
>--- qemu-snapshot-2005-03-26_23/vl.c Sun Mar 13 17:59:37 2005
>+++ qemu-snapshot-2005-03-26_23-on-quit/vl.c Mon Mar 28 02:06:52 2005
>@@ -139,6 +139,9 @@
> int graphic_height = 600;
> int graphic_depth = 15;
> int full_screen = 0;
>+#ifdef TARGET_I386
>+int on_quit = 0;
>+#endif
> TextConsole *vga_console;
> CharDriverState *serial_hds[MAX_SERIAL_PORTS];
> CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
>@@ -2675,6 +2678,17 @@
> qemu_get_clock(rt_clock));
> }
>
>+#ifdef TARGET_I386
>+int ishalted() {
>+ uint8_t buf[16];
>+ uint64_t v;
>+
>+ cpu_memory_rw_debug(cpu_single_env, cpu_single_env->eip-1, buf, 16, 0);
>+ v = ldub_raw(buf);
>+ return (v == 0xf4) && ( !(cpu_single_env->eflags & 0x200) );
>+}
>+#endif
>+
> int main_loop(void)
> {
> int ret, timeout;
>@@ -2684,9 +2698,16 @@
> if (vm_running) {
> ret = cpu_exec(env);
> if (shutdown_requested) {
>+#ifdef TARGET_I386
>+ if( on_quit == 0 || on_quit == 2 || ( on_quit == 1 && ishalted() ) ) {
>+#endif
> ret = EXCP_INTERRUPT;
> break;
> }
>+#ifdef TARGET_I386
>+ shutdown_requested = 0;
>+ }
>+#endif
> if (reset_requested) {
> reset_requested = 0;
> qemu_system_reset();
>@@ -2783,6 +2804,11 @@
> "-std-vga simulate a standard VGA card with VESA Bochs Extensions\n"
> " (default is CL-GD5446 PCI VGA)\n"
> #endif
>+#ifdef TARGET_I386
>+ "-on-quit [ignore-unless-halted|suspend-unless-halted]\n"
>+ " select the behaviour when the emulator window is asked to quit\n"
>+ " (default is none)\n"
>+#endif
> "-loadvm file start right away with a saved state (loadvm in monitor)\n"
> "\n"
> "During emulation, the following keys are useful:\n"
>@@ -2864,6 +2890,10 @@
> QEMU_OPTION_full_screen,
> QEMU_OPTION_pidfile,
> QEMU_OPTION_no_kqemu,
>+
>+#ifdef TARGET_I386
>+ QEMU_OPTION_on_quit
>+#endif
> };
>
> typedef struct QEMUOption {
>@@ -2932,6 +2962,9 @@
> { "loadvm", HAS_ARG, QEMU_OPTION_loadvm },
> { "full-screen", 0, QEMU_OPTION_full_screen },
> { "pidfile", HAS_ARG, QEMU_OPTION_pidfile },
>+#ifdef TARGET_I386
>+ { "on-quit", HAS_ARG, QEMU_OPTION_on_quit },
>+#endif
>
> /* temporary options */
> { "pci", 0, QEMU_OPTION_pci },
>@@ -3383,6 +3416,19 @@
> case QEMU_OPTION_pidfile:
> create_pidfile(optarg);
> break;
>+#ifdef TARGET_I386
>+ case QEMU_OPTION_on_quit:
>+ if(!strcmp(optarg, "ignore-unless-halted")) {
>+ fprintf(stderr, "%s enabled\n", optarg);
>+ on_quit = 1;
>+ }
>+ else if(!strcmp(optarg, "suspend-unless-halted")) {
>+ fprintf(stderr, "%s enabled\n", optarg);
>+ on_quit = 2;
>+ }
>+ else on_quit = 0;
>+ break;
>+#endif
> #ifdef USE_KQEMU
> case QEMU_OPTION_no_kqemu:
> kqemu_allowed = 0;
>@@ -3696,6 +3742,23 @@
> }
> }
> main_loop();
>+
>+#ifdef TARGET_I386
>+ if( on_quit == 2 ) {
>+ char *f = "suspended.qemu";
>+ if( ishalted() ) {
>+
>+ fprintf(stderr, "VM is halted: removing suspend file %s\n",f);
>+ unlink(f);
>+ /* qemu_savevm(f); */
>+ }
>+ else {
>+ fprintf(stderr, "Autosaving VM to file %s\n",f);
>+ qemu_savevm(f);
>+ }
>+ }
>+#endif
>+
> quit_timers();
> return 0;
> }
>
>
>------------------------------------------------------------------------
>
>_______________________________________________
>Qemu-devel mailing list
>Qemu-devel@nongnu.org
>http://lists.nongnu.org/mailman/listinfo/qemu-devel
>
>
[-- Attachment #1.2: Type: text/html, Size: 11313 bytes --]
[-- Attachment #2: on-quit-v0.21.patch --]
[-- Type: text/plain, Size: 6554 bytes --]
diff -r -U3 qemu-snapshot-2005-05-06_23/cocoa.m qemu-snapshot-2005-05-06_23-on-quit-v0.2/cocoa.m
--- qemu-snapshot-2005-05-06_23/cocoa.m Thu Apr 7 22:36:50 2005
+++ qemu-snapshot-2005-05-06_23-on-quit-v0.2/cocoa.m Sat May 7 15:41:23 2005
@@ -444,7 +444,7 @@
- (void)applicationWillTerminate:(NSNotification *)aNotification
{
printf("Application will terminate\n");
- qemu_system_shutdown_request();
+ qemu_system_shutdown_request(1);
/* In order to avoid a crash */
exit(0);
}
diff -r -U3 qemu-snapshot-2005-05-06_23/hw/cuda.c qemu-snapshot-2005-05-06_23-on-quit-v0.2/hw/cuda.c
--- qemu-snapshot-2005-05-06_23/hw/cuda.c Sat Apr 23 20:16:54 2005
+++ qemu-snapshot-2005-05-06_23-on-quit-v0.2/hw/cuda.c Sat May 7 15:41:06 2005
@@ -532,7 +532,7 @@
obuf[0] = CUDA_PACKET;
obuf[1] = 0;
cuda_send_packet_to_host(s, obuf, 2);
- qemu_system_shutdown_request();
+ qemu_system_shutdown_request(1);
break;
default:
break;
diff -r -U3 qemu-snapshot-2005-05-06_23/hw/pc.c qemu-snapshot-2005-05-06_23-on-quit-v0.2/hw/pc.c
--- qemu-snapshot-2005-05-06_23/hw/pc.c Sat Jan 15 13:02:56 2005
+++ qemu-snapshot-2005-05-06_23-on-quit-v0.2/hw/pc.c Sat May 7 16:20:42 2005
@@ -297,7 +297,7 @@
shutdown_index++;
if (shutdown_index == 8) {
shutdown_index = 0;
- qemu_system_shutdown_request();
+ qemu_system_shutdown_request(-1);
}
} else {
shutdown_index = 0;
diff -r -U3 qemu-snapshot-2005-05-06_23/sdl.c qemu-snapshot-2005-05-06_23-on-quit-v0.2/sdl.c
--- qemu-snapshot-2005-05-06_23/sdl.c Mon Jan 17 23:32:23 2005
+++ qemu-snapshot-2005-05-06_23-on-quit-v0.2/sdl.c Sat May 7 16:33:15 2005
@@ -414,7 +414,7 @@
sdl_process_key(&ev->key);
break;
case SDL_QUIT:
- qemu_system_shutdown_request();
+ qemu_system_shutdown_request(1);
break;
case SDL_MOUSEMOTION:
if (gui_grab) {
diff -r -U3 qemu-snapshot-2005-05-06_23/vl.c qemu-snapshot-2005-05-06_23-on-quit-v0.2/vl.c
--- qemu-snapshot-2005-05-06_23/vl.c Sat Apr 30 18:10:35 2005
+++ qemu-snapshot-2005-05-06_23-on-quit-v0.2/vl.c Sat May 7 18:25:11 2005
@@ -144,6 +144,11 @@
#endif
int graphic_depth = 15;
int full_screen = 0;
+
+#define ON_QUIT_ASK_FILENAME "on_quit_ask"
+int on_quit = 0;
+const char * on_quit_filepath = NULL;
+
TextConsole *vga_console;
CharDriverState *serial_hds[MAX_SERIAL_PORTS];
CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
@@ -2581,9 +2586,27 @@
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
}
-void qemu_system_shutdown_request(void)
+void qemu_system_shutdown_request(int s)
{
- shutdown_requested = 1;
+
+ if (s == 1 && on_quit == 3) { // User power-off request and Popup message setting
+ int r,c;
+
+ if( on_quit_filepath ) r = system(on_quit_filepath);
+ else {
+ char buf[1024];
+ snprintf(buf, sizeof(buf), "%s/%s", CONFIG_QEMU_SHAREDIR, ON_QUIT_ASK_FILENAME);
+ r = system(buf);
+ }
+ c = WEXITSTATUS(r);
+
+ if(c == 0) return;
+ if(c == 2) s = -1; // Simulate an APM power-off request
+ // else if r == -1, there was an error; if c == 1, then suspend;
+ // Either way, we suspend, for safety
+ }
+
+ shutdown_requested = s;
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
}
@@ -2701,8 +2724,11 @@
if (vm_running) {
ret = cpu_exec(env);
if (shutdown_requested) {
- ret = EXCP_INTERRUPT;
- break;
+ if (on_quit == 0 || on_quit == 2 || on_quit == 3 || (on_quit == 1 && shutdown_requested == -1)) {
+ ret = EXCP_INTERRUPT;
+ break;
+ }
+ shutdown_requested = 0;
}
if (reset_requested) {
reset_requested = 0;
@@ -2803,6 +2829,9 @@
"-std-vga simulate a standard VGA card with VESA Bochs Extensions\n"
" (default is CL-GD5446 PCI VGA)\n"
#endif
+ "-on-quit [ignore|suspend|ask|<script filepath>]\n"
+ " select the behaviour when the emulator window is asked to quit\n"
+ " (default is none)\n"
"-loadvm file start right away with a saved state (loadvm in monitor)\n"
"\n"
"During emulation, the following keys are useful:\n"
@@ -2885,6 +2914,8 @@
QEMU_OPTION_pidfile,
QEMU_OPTION_no_kqemu,
QEMU_OPTION_win2k_hack,
+ QEMU_OPTION_on_quit,
+
};
typedef struct QEMUOption {
@@ -2954,6 +2985,7 @@
{ "full-screen", 0, QEMU_OPTION_full_screen },
{ "pidfile", HAS_ARG, QEMU_OPTION_pidfile },
{ "win2k-hack", 0, QEMU_OPTION_win2k_hack },
+ { "on-quit", HAS_ARG, QEMU_OPTION_on_quit },
/* temporary options */
{ "pci", 0, QEMU_OPTION_pci },
@@ -3415,6 +3447,18 @@
kqemu_allowed = 0;
break;
#endif
+ case QEMU_OPTION_on_quit:
+ if(!strncmp(optarg, "ignore",6)) {
+ on_quit = 1;
+ }
+ else if(!strncmp(optarg, "suspend",7)) {
+ on_quit = 2;
+ }
+ else {
+ on_quit = 3;
+ if(strcmp(optarg, "ask")) on_quit_filepath = optarg;
+ }
+ break;
}
}
}
@@ -3723,6 +3767,20 @@
}
}
main_loop();
+
+ if (on_quit == 2 || on_quit == 3) {
+ char *f = "suspended.qemu";
+ if (shutdown_requested == -1) { // APM-request to shutdown
+
+ fprintf(stderr, "VM is halted: removing suspend file %s\n",f);
+ unlink(f);
+ }
+ else { // User-request to shutdown
+ fprintf(stderr, "Autosaving VM to file %s\n",f);
+ qemu_savevm(f);
+ }
+ }
+
quit_timers();
return 0;
}
diff -r -U3 qemu-snapshot-2005-05-06_23/vl.h qemu-snapshot-2005-05-06_23-on-quit-v0.2/vl.h
--- qemu-snapshot-2005-05-06_23/vl.h Sat Apr 30 18:10:35 2005
+++ qemu-snapshot-2005-05-06_23-on-quit-v0.2/vl.h Sat May 7 15:41:49 2005
@@ -109,7 +109,7 @@
void qemu_register_reset(QEMUResetHandler *func, void *opaque);
void qemu_system_reset_request(void);
-void qemu_system_shutdown_request(void);
+void qemu_system_shutdown_request(int);
void main_loop_wait(int timeout);
next prev parent reply other threads:[~2005-05-07 16:36 UTC|newest]
Thread overview: 49+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-03-27 3:49 [Qemu-devel] Suggestion - trap window-close of VM Ryan Rempel
2005-03-27 18:30 ` Struan Bartlett
2005-03-28 11:34 ` [patch] " Struan Bartlett
2005-03-28 12:51 ` Asko Kauppi
2005-03-28 13:04 ` Paul Brook
2005-03-29 22:37 ` [Qemu-devel] " Ryan Rempel
2005-03-29 22:52 ` Paul Brook
2005-03-30 1:17 ` Ryan Rempel
2005-03-30 12:20 ` Struan Bartlett
2005-03-30 12:48 ` Lennert Buytenhek
2005-03-30 13:26 ` Struan Bartlett
2005-03-30 18:22 ` Lennert Buytenhek
2005-03-30 20:16 ` Leonardo E. Reiter
2005-03-30 21:22 ` Lennert Buytenhek
2005-03-30 21:43 ` Struan Bartlett
2005-03-31 9:32 ` John R. Hogerhuis
2005-03-31 12:31 ` Lennert Buytenhek
2005-03-30 13:21 ` APM bug " Struan Bartlett
2005-03-31 10:38 ` Struan Bartlett
2005-03-31 17:56 ` Struan Bartlett
2005-04-03 22:00 ` A Fix " Struan Bartlett
2005-04-04 9:53 ` Struan Bartlett
2005-04-04 17:12 ` Struan Bartlett
2005-04-04 22:26 ` Iain McFarlane
2005-04-05 16:34 ` Volker Ruppert
2005-04-05 21:05 ` Iain McFarlane
2005-04-05 21:33 ` [Qemu-devel] Re: Windows 2000 SP4 (was Re: APM bug) Leonardo E. Reiter
2005-04-05 22:57 ` Hetz Ben Hamo
2005-04-05 23:03 ` Leonardo E. Reiter
2005-04-05 23:48 ` Hetz Ben Hamo
2005-04-06 0:28 ` Leonardo E. Reiter
2005-04-06 0:52 ` [Qemu-devel] Re: Windows 2000 SP4 Leonardo E. Reiter
2005-04-06 20:25 ` [Qemu-devel] Re: Windows 2000 SP4 (was Re: APM bug) Fabrice Bellard
2005-04-06 22:47 ` Hetz Ben Hamo
2005-04-07 7:17 ` Jonas Maebe
2005-04-07 11:56 ` Flavio Visentin
2005-04-05 23:40 ` Derek Fawcus
2005-04-07 16:42 ` A Fix Re: APM bug Re: [Qemu-devel] Re: Suggestion - trap window-closeof VM Andreas Bollhalder
2005-04-05 13:55 ` APM bug Re: [Qemu-devel] Re: Suggestion - trap window-close of VM Alex Beregszaszi
2005-03-31 16:38 ` Andreas Bollhalder
2005-03-31 17:32 ` Jason Gress
2005-05-07 16:30 ` Struan Bartlett [this message]
2005-05-09 15:43 ` [patch] on-quit-v0.21 with resume/suspend/power-off dialog Re: [patch] Re: [Qemu-devel] " Ryan Rempel
2005-05-09 22:25 ` Struan Bartlett
2005-05-09 23:19 ` Flavio Visentin
2005-05-10 8:40 ` Struan Bartlett
2005-07-29 0:07 ` [patch] " Struan Bartlett
2005-03-28 15:04 ` Mark Williamson
2005-03-28 19:13 ` Joshua Kugler
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=427CED18.4030607@praguespringpeople.org \
--to=struan@praguespringpeople.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).