I was getting random SEGVs when disconnecting from the VNC server. I
tracked it down to the fact that if you remove a IOHandler from another
IOHandler, all sorts of badness may result as you're removing entries
from a linked list while transversing it.
My solution is to simply add a deleted flag to each entry and walk the
list a second time. During the second transversal, we'll remove nodes
that need removing.
Haven't seen the SEGV since I started using this patch.
Regards,
Anthony Liguori
diff -r 5f92961f382b vl.c
--- a/vl.c Thu Feb 22 01:48:01 2007 +
+++ b/vl.c Sat Feb 24 11:51:00 2007 -0600
@@ -4462,6 +4462,7 @@ typedef struct IOHandlerRecord {
IOCanRWHandler *fd_read_poll;
IOHandler *fd_read;
IOHandler *fd_write;
+int deleted;
void *opaque;
/* temporary data */
struct pollfd *ufd;
@@ -4487,8 +4488,7 @@ int qemu_set_fd_handler2(int fd,
if (ioh == NULL)
break;
if (ioh-fd == fd) {
-*pioh = ioh-next;
-qemu_free(ioh);
+ ioh-deleted = 1;
break;
}
pioh = ioh-next;
@@ -6157,7 +6157,7 @@ void qemu_system_powerdown_request(void)
void main_loop_wait(int timeout)
{
-IOHandlerRecord *ioh, *ioh_next;
+IOHandlerRecord *ioh;
fd_set rfds, wfds, xfds;
int ret, nfds;
struct timeval tv;
@@ -6192,6 +6192,8 @@ void main_loop_wait(int timeout)
FD_ZERO(wfds);
FD_ZERO(xfds);
for(ioh = first_io_handler; ioh != NULL; ioh = ioh-next) {
+ if (ioh-deleted)
+ continue;
if (ioh-fd_read
(!ioh-fd_read_poll ||
ioh-fd_read_poll(ioh-opaque) != 0)) {
@@ -6219,9 +6221,11 @@ void main_loop_wait(int timeout)
#endif
ret = select(nfds + 1, rfds, wfds, xfds, tv);
if (ret 0) {
-/* XXX: better handling of removal */
-for(ioh = first_io_handler; ioh != NULL; ioh = ioh_next) {
-ioh_next = ioh-next;
+ IOHandlerRecord **pioh;
+
+for(ioh = first_io_handler; ioh != NULL; ioh = ioh-next) {
+ if (ioh-deleted)
+ continue;
if (FD_ISSET(ioh-fd, rfds)) {
ioh-fd_read(ioh-opaque);
}
@@ -6229,6 +6233,17 @@ void main_loop_wait(int timeout)
ioh-fd_write(ioh-opaque);
}
}
+
+ /* remove deleted IO handlers */
+ pioh = first_io_handler;
+ while (*pioh) {
+ ioh = *pioh;
+ if (ioh-deleted) {
+ *pioh = ioh-next;
+ qemu_free(ioh);
+ } else
+ pioh = ioh-next;
+ }
}
#if defined(CONFIG_SLIRP)
if (slirp_inited) {
___
Qemu-devel mailing list
Qemu-devel@nongnu.org
http://lists.nongnu.org/mailman/listinfo/qemu-devel