diff options
-rw-r--r-- | android/hw-qemud.c | 35 | ||||
-rw-r--r-- | android/utils/list.h | 112 |
2 files changed, 138 insertions, 9 deletions
diff --git a/android/hw-qemud.c b/android/hw-qemud.c index df9ab21..e80abed 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__); } diff --git a/android/utils/list.h b/android/utils/list.h new file mode 100644 index 0000000..a4171ae --- /dev/null +++ b/android/utils/list.h @@ -0,0 +1,112 @@ +/* Copyright (C) 2011 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ +#ifndef _ANDROID_UTILS_LIST_H +#define _ANDROID_UTILS_LIST_H + +#include <inttypes.h> + +/* Encapsulates a double-linked, circular list. + * The list is organized in the following way: + * - List entries contain references to the next, and the previous entry in the + * list. + * - The list is circular, i.e. the "last" list entry references the "list head" + * in its 'next' reference, and the "list head" references the "last" entry in + * its 'previous' reference. + * - The list is empty if its 'next' and 'previous' references are addressing the + * head of the list. + */ +typedef struct ACList ACList; +struct ACList { + /* Next entry in the list */ + ACList* next; + /* Previous entry in the list */ + ACList* prev; +}; + +/* Initializes the list. */ +AINLINED void +alist_init(ACList* list) +{ + list->next = list->prev = list; +} + +/* Checks if the list is empty. */ +AINLINED int +alist_is_empty(const ACList* list) +{ + return list->next == list; +} + +/* Inserts an entry to the head of the list */ +AINLINED void +alist_insert_head(ACList* list, ACList* entry) +{ + ACList* const next = list->next; + entry->next = next; + entry->prev = list; + next->prev = entry; + list->next = entry; +} +/* Inserts an entry to the tail of the list */ +AINLINED void +alist_insert_tail(ACList* list, ACList* entry) +{ + ACList* const prev = list->prev; + entry->next = list; + entry->prev = prev; + prev->next = entry; + list->prev = entry; +} + +/* Removes an entry from the list. NOTE: Entry must be in the list when this + * routine is called. */ +AINLINED void +alist_remove(ACList* entry) +{ + ACList* const next = entry->next; + ACList* const prev = entry->prev; + prev->next = next; + next->prev = prev; + entry->next = entry->prev = entry; +} + +/* Returns an entry removed from the head of the list. If the list was empty, + * this routine returns NULL. */ +AINLINED ACList* +alist_remove_head(ACList* list) +{ + ACList* entry = NULL; + if (!alist_is_empty(list)) { + entry = list->next; + list->next = entry->next; + entry->next->prev = list; + entry->next = entry->prev = entry; + } + return entry; +} + +/* Returns an entry removed from the tail of the list. If the list was empty, + * this routine returns NULL. */ +AINLINED ACList* +alist_remove_tail(ACList* list) +{ + ACList* entry = NULL; + if (!alist_is_empty(list)) { + entry = list->prev; + list->prev = entry->prev; + entry->prev->next = list; + entry->next = entry->prev = entry; + } + return entry; +} + +#endif /* _ANDROID_UTILS_LIST_H */ |