[evolution-patches] 1.4 patch for 45504, gethostbyname thread issues
- From: Not Zed <notzed ximian com>
- To: evolution-patches ximian com
- Subject: [evolution-patches] 1.4 patch for 45504, gethostbyname thread issues
- Date: Thu, 16 Oct 2003 12:06:36 +0930
The other patch wouldn't apply to 1.4 in any way shape or form, so here's a new one. So we can test in the snapshots.
Z
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution/camel/ChangeLog,v
retrieving revision 1.1836.2.16
diff -u -3 -r1.1836.2.16 ChangeLog
--- ChangeLog 9 Oct 2003 16:41:20 -0000 1.1836.2.16
+++ ChangeLog 16 Oct 2003 02:26:16 -0000
@@ -1,3 +1,15 @@
+2003-10-08 Not Zed <NotZed Ximian com>
+
+ ** See Bug #45504
+
+ * camel-service.c (run_gethostbyx): new thread dispatcher which
+ just consumes tasks on the lookup port.
+ (get_hostbyx): generic lookup handler that handles cancellation.
+ (camel_gethostbyname, camel_gethostbyaddr): Changed to use stuff
+ above, sets up a request message and lets gethostbyx run it.
+ (init_gethostbyx): setup threads for dns lookups,
+ CAMEL_DNS_THREADS allows the number to be altered.
+
2003-10-08 Jeffrey Stedfast <fejj ximian com>
* camel-mime-utils.c (header_decode_date): Allow timezone offsets
Index: camel-service.c
===================================================================
RCS file: /cvs/gnome/evolution/camel/camel-service.c,v
retrieving revision 1.83.2.2
diff -u -3 -r1.83.2.2 camel-service.c
--- camel-service.c 8 Sep 2003 21:33:36 -0000 1.83.2.2
+++ camel-service.c 16 Oct 2003 02:26:23 -0000
@@ -689,11 +689,16 @@
#define STRUCT_OFFSET(type, field) ((gint) ((gchar*) &((type *) 0)->field))
#endif
+enum {
+ LOOKUP_QUIT,
+ LOOKUP_HOSTBYNAME,
+ LOOKUP_HOSTBYADDR,
+};
+
struct _lookup_msg {
-#ifdef ENABLE_THREADS
EMsg msg;
-#endif
unsigned int cancelled:1;
+ unsigned int op:2;
const char *name;
int len;
int type;
@@ -704,75 +709,112 @@
char *hostbufmem;
};
+static pthread_once_t gethostbyx_once = PTHREAD_ONCE_INIT;
+static EMsgPort *gethostbyx_port;
+static int gethostbyx_threaded = FALSE;
+
+static void
+run_gethostbyx_lookup(struct _lookup_msg *info)
+{
+ do {
+ if (info->op == LOOKUP_HOSTBYNAME)
+ info->result = e_gethostbyname_r(info->name, &info->hostbuf, info->hostbufmem, info->hostbuflen, &info->herr);
+ else
+ info->result = e_gethostbyaddr_r(info->name, info->len, info->type, &info->hostbuf, info->hostbufmem, info->hostbuflen, &info->herr);
+
+ if (info->result == ERANGE) {
+ info->hostbuflen *= 2;
+ info->hostbufmem = g_realloc(info->hostbufmem, info->hostbuflen);
+ }
+ } while (info->result == ERANGE && !info->cancelled);
+}
+
static void *
-get_hostbyname(void *data)
+run_gethostbyx(void *data)
{
- struct _lookup_msg *info = data;
+ int more = TRUE;
- while ((info->result = e_gethostbyname_r(info->name, &info->hostbuf, info->hostbufmem, info->hostbuflen, &info->herr)) == ERANGE) {
- d(printf("gethostbyname fialed?\n"));
-#ifdef ENABLE_THREADS
- pthread_testcancel();
-#endif
- info->hostbuflen *= 2;
- info->hostbufmem = g_realloc(info->hostbufmem, info->hostbuflen);
- }
+ /* This never quits actually ... */
+ do {
+ struct _lookup_msg *msg;
+
+ e_msgport_wait(gethostbyx_port);
+ msg = (struct _lookup_msg *)e_msgport_get(gethostbyx_port);
+ if (msg == NULL)
+ continue;
+
+ if (!msg->cancelled)
+ run_gethostbyx_lookup(msg);
+
+ if (msg->cancelled) {
+ g_free(msg->hostbufmem);
+ g_free(msg);
+ } else {
+ e_msgport_reply((EMsg *)msg);
+ }
+ } while (more);
- d(printf("gethostbyname ok?\n"));
+ return NULL;
+}
-#ifdef ENABLE_THREADS
- /* 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);
+static void
+init_gethostbyx(void)
+{
+ pthread_t id;
+ int count = 3, i;
+ char *tmp;
+
+ gethostbyx_port = e_msgport_new();
+
+ tmp = getenv("CAMEL_DNS_THREADS");
+ if (tmp && tmp[0]) {
+ count = MAX(atoi(tmp), 1);
+ g_warning("Overriding CAMEL_DNS_THREADS: %d threads for dns lookups", count);
+ }
+
+ /* We could create as many threads as we want here, they're auto-setup as consumers by e_msgport */
+ for (i=0;i<count;i++) {
+ if (pthread_create(&id, NULL, run_gethostbyx, NULL) != 0 && i == 0) {
+ g_warning("Could not create async dns thread, host lookups will block");
+ return;
+ }
}
-#endif
- return NULL;
+
+ gethostbyx_threaded = TRUE;
}
-struct hostent *
-camel_gethostbyname (const char *name, CamelException *exout)
+static struct hostent *
+get_hostbyx(struct _lookup_msg *msg, CamelException *exout)
{
-#ifdef ENABLE_THREADS
- int fdmax, status, fd, cancel_fd;
-#endif
- struct _lookup_msg *msg;
CamelException ex;
- g_return_val_if_fail(name != NULL, NULL);
-
- if (camel_operation_cancel_check(NULL)) {
- camel_exception_set (exout, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled"));
- return NULL;
- }
+ /* This routine is used to serialise name lookups, and make them 'cancellable', in practice,
+ we can't cancel, but we just throw away the result. The problem is that if one name lookup
+ is taking an inordinate amount of time, any new lookups will have to wait till that
+ one times out. A sort of workaround is to setup more than one lookup thread ... */
+ pthread_once(&gethostbyx_once, init_gethostbyx);
+
camel_exception_init(&ex);
- camel_operation_start_transient(NULL, _("Resolving: %s"), name);
- msg = g_malloc0(sizeof(*msg));
- msg->hostbuflen = 1024;
- msg->hostbufmem = g_malloc(msg->hostbuflen);
- msg->name = name;
- msg->result = -1;
+ if (msg->op == LOOKUP_HOSTBYNAME)
+ camel_operation_start_transient(NULL, _("Resolving: %s"), msg->name);
+ else
+ camel_operation_start_transient(NULL, _("Resolving address"));
-#ifdef ENABLE_THREADS
- cancel_fd = camel_operation_cancel_fd(NULL);
- if (cancel_fd == -1) {
-#endif
- get_hostbyname(msg);
-#ifdef ENABLE_THREADS
- } else {
+ if (gethostbyx_threaded) {
+ int fdmax, status, fd, cancel_fd;
EMsgPort *reply_port;
- pthread_t id;
fd_set rdset;
- int err;
reply_port = msg->msg.reply_port = e_msgport_new();
- fd = e_msgport_fd(msg->msg.reply_port);
- if ((err = pthread_create(&id, NULL, get_hostbyname, msg)) == 0) {
- d(printf("waiting for name return/cancellation in main process\n"));
+ cancel_fd = camel_operation_cancel_fd(NULL);
+ if (cancel_fd != -1)
+ fd = e_msgport_fd(msg->msg.reply_port);
+
+ e_msgport_put(gethostbyx_port, (EMsg *)msg);
+
+ if (cancel_fd != -1) {
do {
FD_ZERO(&rdset);
FD_SET(cancel_fd, &rdset);
@@ -787,28 +829,25 @@
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);
+ /* we could leak the message here, but its not very likely, and only small and harmless */
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"));
}
} else {
- camel_exception_setv(&ex, CAMEL_EXCEPTION_SYSTEM, _("Host lookup failed: cannot create thread: %s"), g_strerror(err));
+ struct _lookup_msg *reply;
+
+ e_msgport_wait(reply_port);
+ reply = (struct _lookup_msg *)e_msgport_get(reply_port);
+ g_assert(reply == msg);
}
e_msgport_destroy(reply_port);
+ } else {
+ run_gethostbyx_lookup(msg);
}
-#endif
camel_operation_end(NULL);
@@ -818,10 +857,10 @@
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);
+ _("Host lookup failed: host not found"));
else
camel_exception_setv (&ex, CAMEL_EXCEPTION_SYSTEM,
- _("Host lookup failed: %s: unknown reason"), name);
+ _("Host lookup failed: unknown reason"));
}
if (msg) {
@@ -834,139 +873,50 @@
return NULL;
}
-static void *
-get_hostbyaddr (void *data)
+struct hostent *
+camel_gethostbyname (const char *name, CamelException *exout)
{
- struct _lookup_msg *info = data;
-
- while ((info->result = e_gethostbyaddr_r (info->name, info->len, info->type, &info->hostbuf,
- info->hostbufmem, info->hostbuflen, &info->herr)) == ERANGE) {
- d(printf ("gethostbyaddr fialed?\n"));
-#ifdef ENABLE_THREADS
- pthread_testcancel ();
-#endif
- info->hostbuflen *= 2;
- info->hostbufmem = g_realloc (info->hostbufmem, info->hostbuflen);
- }
+ struct _lookup_msg *msg;
- d(printf ("gethostbyaddr ok?\n"));
+ g_return_val_if_fail(name != NULL, NULL);
-#ifdef ENABLE_THREADS
- if (info->cancelled) {
- g_free(info->hostbufmem);
- g_free(info);
- } else {
- e_msgport_reply((EMsg *)info);
+ if (camel_operation_cancel_check(NULL)) {
+ camel_exception_set(exout, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled"));
+ return NULL;
}
-#endif
- return NULL;
-}
+ msg = g_malloc0(sizeof(*msg));
+ msg->hostbuflen = 1024;
+ msg->hostbufmem = g_malloc(msg->hostbuflen);
+ msg->name = name;
+ msg->result = -1;
+ msg->op = LOOKUP_HOSTBYNAME;
+
+ return get_hostbyx(msg, exout);
+}
struct hostent *
camel_gethostbyaddr (const char *addr, int len, int type, CamelException *exout)
{
-#ifdef ENABLE_THREADS
- int fdmax, status, fd, cancel_fd;
-#endif
struct _lookup_msg *msg;
- CamelException ex;
g_return_val_if_fail (addr != NULL, NULL);
- if (camel_operation_cancel_check (NULL)) {
- camel_exception_set (exout, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled"));
+ if (camel_operation_cancel_check(NULL)) {
+ camel_exception_set(exout, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled"));
return NULL;
}
- camel_exception_init(&ex);
- camel_operation_start_transient (NULL, _("Resolving address"));
-
- msg = g_malloc0 (sizeof (struct _lookup_msg));
+ msg = g_malloc0(sizeof(struct _lookup_msg));
msg->hostbuflen = 1024;
- msg->hostbufmem = g_malloc (msg->hostbuflen);
+ msg->hostbufmem = g_malloc(msg->hostbuflen);
msg->name = addr;
msg->len = len;
msg->type = type;
msg->result = -1;
+ msg->op = LOOKUP_HOSTBYADDR;
-#ifdef ENABLE_THREADS
- cancel_fd = camel_operation_cancel_fd (NULL);
- if (cancel_fd == -1) {
-#endif
- get_hostbyaddr (msg);
-#ifdef ENABLE_THREADS
- } else {
- EMsgPort *reply_port;
- pthread_t id;
- fd_set rdset;
- int err;
-
- reply_port = msg->msg.reply_port = e_msgport_new ();
- fd = e_msgport_fd (msg->msg.reply_port);
- if ((err = pthread_create (&id, NULL, get_hostbyaddr, msg)) == 0) {
- d(printf("waiting for name return/cancellation in main process\n"));
- do {
- FD_ZERO(&rdset);
- FD_SET(cancel_fd, &rdset);
- FD_SET(fd, &rdset);
- fdmax = MAX(fd, cancel_fd) + 1;
- status = select (fdmax, &rdset, NULL, 0, NULL);
- } while (status == -1 && errno == EINTR);
-
- 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"));
- }
- } else {
- camel_exception_setv(&ex, CAMEL_EXCEPTION_SYSTEM, _("Host lookup failed: cannot create thread: %s"), g_strerror(err));
- }
-
-
- e_msgport_destroy (reply_port);
- }
-#endif
-
- camel_operation_end (NULL);
-
- 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: host not found"));
- else
- camel_exception_setv (&ex, CAMEL_EXCEPTION_SYSTEM,
- _("Host lookup failed: unknown reason"));
- }
-
- if (msg) {
- g_free(msg->hostbufmem);
- g_free(msg);
- }
-
- camel_exception_xfer(exout, &ex);
-
- return NULL;
+ return get_hostbyx(msg, exout);
}
void camel_free_host(struct hostent *h)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]