[evolution-patches] camel, make name lookup behave cancellable



This isn't intended for a 1.4 release, just something i was playing with
tonight.  Its a manual diff too, something very odd is going on with my
internet at the moment.

I'm not sure if there's a bug out for this, but here's a preliminary
patch which makes hostname lookup behave as if its cancellable, even
when the underlying pthread implementation doesn't cancel the thread
immediately when you call pthread_cancel.

It basically leaves the child thread in a detatched state if we get a
problem/cancellation, rather than trying to join it, and lets it clean
itself up later, e.g. when the name lookup eventually times out or
whatever.  It should properly handle all the various cleanup issues that
can result from pre-emptive scheduling.

The same could/should be done for the gethostbyaddr stuff in the same
file.

This should go part of the way of addressing the problem of the 'cancel
button' not responding very well in some situations, e.g. when laptops
change network settings.  Although other delays will come down to e.g.
socket connect timeouts, which might need to be tweaked.

--- camel-service.c.~1.81.~	Wed May 14 11:55:39 2003
+++ camel-service.c	Tue May 20 22:03:50 2003
@@ -691,6 +691,7 @@
 #ifdef ENABLE_THREADS
 	EMsg msg;
 #endif
+	unsigned int cancelled:1;
 	const char *name;
 	int len;
 	int type;
@@ -718,7 +719,13 @@
 	d(printf("gethostbyname ok?\n"));
 
 #ifdef ENABLE_THREADS
-	e_msgport_reply((EMsg *)info);
+	/* If we got cancelled, dont reply, just free it */
+	if (info->cancelled) {
+		g_free(info->hostbufmem);
+		g_free(info);
+	} else {
+		e_msgport_reply((EMsg *)info);
+	}
 #endif
 	return NULL;
 }
@@ -766,27 +773,33 @@
 				FD_SET(cancel_fd, &rdset);
 				FD_SET(fd, &rdset);
 				fdmax = MAX(fd, cancel_fd) + 1;
-				status = select (fdmax, &rdset, NULL, 0, NULL);
+				status = select(fdmax, &rdset, NULL, 0, NULL);
 			} while (status == -1 && errno == EINTR);
-			
-			if (status == -1) {
-				camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
-						      _("Failure in name lookup: %s"),
-						      g_strerror (errno));
-				d(printf("Cancelling lookup thread\n"));
-				pthread_cancel(id);
-			} else if (FD_ISSET(cancel_fd, &rdset)) {
-				d(printf("Cancelling lookup thread\n"));
-				camel_exception_setv(ex, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled"));
+
+			if (status == -1 || FD_ISSET(cancel_fd, &rdset)) {
+				if (status == -1)
+					camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Failure in name lookup: %s"), g_strerror(errno));
+				else
+					camel_exception_setv(ex, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled"));
+
+				/* We cancel so if the thread impl is decent it causes immediate exit.
+				   We detach so we dont need to wait for it to exit if it isn't.
+				   We check the reply port incase we had a reply in the mean time, which we free later */
+				d(printf("Cancelling lookup thread and leaving it\n"));
+				msg->cancelled = 1;
+				pthread_detach(id);
 				pthread_cancel(id);
+				msg = (struct _lookup_msg *)e_msgport_get(reply_port);
 			} else {
 				struct _lookup_msg *reply = (struct _lookup_msg *)e_msgport_get(reply_port);
 
 				g_assert(reply == msg);
+				d(printf("waiting for child to exit\n"));
+				pthread_join(id, NULL);
+				d(printf("child done\n"));
 			}
-			d(printf("waiting for child to exit\n"));
-			pthread_join(id, NULL);
-			d(printf("child done\n"));
+		} else {
+			camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Host lookup failed: cannot create thread: %s"), g_strerror(errno));
 		}
 		e_msgport_destroy(reply_port);
 	}
@@ -794,23 +807,25 @@
 
 	camel_operation_end(NULL);
 
-	if (msg->result != 0) {
- 		if (!camel_exception_is_set(ex)) {
-			if (msg->herr == HOST_NOT_FOUND || msg->herr == NO_DATA)
-				camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
-						      _("Host lookup failed: %s: host not found"), name);
-			else
-				camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
-						      _("Host lookup failed: %s: unknown reason"), name);
-		}
+	if (!camel_exception_is_set(ex)) {
+		if (msg->result == 0)
+			return &msg->hostbuf;
+
+		if (msg->herr == HOST_NOT_FOUND || msg->herr == NO_DATA)
+			camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+					      _("Host lookup failed: %s: host not found"), name);
+		else
+			camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+					      _("Host lookup failed: %s: unknown reason"), name);
+	}
+
+	if (msg) {
 		g_free(msg->hostbufmem);
 		g_free(msg);
-		return NULL;
-	} else {
-		return &msg->hostbuf;
 	}
-}
 
+	return NULL;
+}
 
 static void *
 get_hostbyaddr (void *data)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]