aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVladimir Chtchetkine <vchtchetkine@google.com>2011-12-07 10:24:33 -0800
committerVladimir Chtchetkine <vchtchetkine@google.com>2011-12-07 11:10:37 -0800
commit5f7d7a2e06acc8a40838e73644abb8d43820d381 (patch)
treecd47c2e0a604162483a3e012f08d88ac35e9c7a6
parent4e61742d4f26cefb1baf8d2dc5e7dc8b85a78549 (diff)
downloadqemu-tools_r16.tar.gz
Cherry-picked from ef71cb8b3 on master. Do not merge.android-sdk-adt_r16.0.1tools_r16
Fixes emulator crash due to premature pipe client destruction. The pipe client should really be closed (and destructed) only when the guest closes its handle to the pipe. When pipe client is closed from within the emulator, it should only notify the guest about disconnection, and wait for the guest to explicitly close the pipe handle. Change-Id: I6bde3ae1e05ff5dc40e9903282c3fc46df0b9b57
-rw-r--r--android/hw-qemud.c35
1 files changed, 26 insertions, 9 deletions
diff --git a/android/hw-qemud.c b/android/hw-qemud.c
index df9ab21ec5..e80abed8ab 100644
--- a/android/hw-qemud.c
+++ b/android/hw-qemud.c
@@ -824,30 +824,47 @@ _qemud_client_free(QemudClient* c)
/* disconnect a client. this automatically frees the QemudClient.
* note that this also removes the client from the global list
* and from its service's list, if any.
+ * Param:
+ * opaque - QemuClient instance
+ * guest_close - For pipe clients control whether or not the disconnect is
+ * caused by guest closing the pipe handle (in which case 1 is passed in
+ * this parameter). For serial clients this parameter is ignored.
*/
static void
-qemud_client_disconnect( void* opaque )
+qemud_client_disconnect( void* opaque, int guest_close )
{
QemudClient* c = opaque;
if (c->closing) { /* recursive call, exit immediately */
return;
}
+
+ if (_is_pipe_client(c) && !guest_close) {
+ /* This is emulator component (rather than the guest) closing a pipe
+ * client. Since pipe clients are controlled strictly by the guest, we
+ * don't actually close the client here, but notify the guest about the
+ * client being disconnected. Then we will do the real client close when
+ * the guest explicitly closes the pipe, in which case this routine will
+ * be called from the _qemudPipe_closeFromGuest callback with guest_close
+ * set to 1. */
+ char tmp[128], *p=tmp, *end=p+sizeof(tmp);
+ p = bufprint(tmp, end, "disconnect:00");
+ _qemud_pipe_send(c, (uint8_t*)tmp, p-tmp);
+ return;
+ }
+
c->closing = 1;
/* remove from current list */
qemud_client_remove(c);
- /* send a disconnect command to the daemon */
if (_is_pipe_client(c)) {
- char tmp[128], *p=tmp, *end=p+sizeof(tmp);
- p = bufprint(tmp, end, "disconnect:00");
- _qemud_pipe_send(c, (uint8_t*)tmp, p-tmp);
/* We must NULL the client reference in the QemuPipe for this connection,
* so if a sudden receive request comes after client has been closed, we
* don't blow up. */
c->ProtocolSelector.Pipe.qemud_pipe->client = NULL;
} else if (c->ProtocolSelector.Serial.channel > 0) {
+ /* send a disconnect command to the daemon */
char tmp[128], *p=tmp, *end=p+sizeof(tmp);
p = bufprint(tmp, end, "disconnect:%02x",
c->ProtocolSelector.Serial.channel);
@@ -1348,7 +1365,7 @@ qemud_multiplexer_disconnect( QemudMultiplexer* m,
* m->clients automatically.
*/
c->ProtocolSelector.Serial.channel = -1; /* no need to send disconnect:<id> */
- qemud_client_disconnect(c);
+ qemud_client_disconnect(c, 0);
return;
}
}
@@ -1378,7 +1395,7 @@ qemud_multiplexer_disconnect_noncontrol( QemudMultiplexer* m )
D("%s: disconnecting client %d\n",
__FUNCTION__, c->ProtocolSelector.Serial.channel);
c->ProtocolSelector.Serial.channel = -1; /* do not send disconnect:<id> */
- qemud_client_disconnect(c);
+ qemud_client_disconnect(c, 0);
}
}
}
@@ -1695,7 +1712,7 @@ qemud_client_set_framing( QemudClient* client, int framing )
void
qemud_client_close( QemudClient* client )
{
- qemud_client_disconnect(client);
+ qemud_client_disconnect(client, 0);
}
@@ -1945,7 +1962,7 @@ _qemudPipe_closeFromGuest( void* opaque )
QemudClient* client = pipe->client;
D("%s", __FUNCTION__);
if (client != NULL) {
- qemud_client_disconnect(client);
+ qemud_client_disconnect(client, 1);
} else {
D("%s: Unexpected NULL client", __FUNCTION__);
}