[Libevent-users] thread-safety (and performance)

Tani Hosokawa tani at tanihosokawa.org
Mon Jan 21 19:14:08 EST 2008


When initiating HTTP requests in a multi-threaded process, under any 
significant load you will start finding horrible memory corruption 
problems, sometimes resulting in bad requests and sometimes resulting in 
core dumps.  Also, under any significant load, you'll probably find that 
you are dropping a large number of connections due to the listen queue 
overflowing while your code is performing some other task.  This is a 
patch that I think largely deals with these.  Also, http_hostportfile() 
is not thread-safe, so I've attached a thread-safe version that can be 
used in its place (unfortunately I can't think of any clean way to make 
the current interface thread-safe without introducing a memory leak).

/* TH: remember to free() opaque after you're done with this */
int
http_hostportfile_r(const char *url, char **phost, u_short *pport, char 
**pfile,void **opaque)
{
        struct http_hostportfile_threadsafe_opaque {
           char shost[1024];
           char sfile[1024];
        } *opaquedata;
        opaquedata = malloc(sizeof(*opaquedata));
        *opaque = opaquedata;
        char *p, *p2;
        int len;
        u_short port;

        len = strlen(HTTP_PREFIX);
        if (strncasecmp(url, HTTP_PREFIX, len))
                return (-1);

        url += len;

        /* We might overrun */
        if (strlcpy(opaquedata->shost, url, sizeof(opaquedata->shost)) 
 >= sizeof(opaquedata->shost))
                return (-1);

        p = strchr(opaquedata->shost, '/');
        if (p != NULL) {
                *p = '\0';
                p2 = p + 1;
        } else
                p2 = NULL;

        if (pfile != NULL) {
                /* Generate request file */
                if (p2 == NULL)
                        p2 = "";
                snprintf(opaquedata->sfile, sizeof(opaquedata->sfile), 
"/%s", p2);
        }

        p = strchr(opaquedata->shost, ':');
        if (p != NULL) {
                *p = '\0';
                port = atoi(p + 1);

                if (port == 0)
                        return (-1);
        } else
                port = HTTP_DEFAULTPORT;

        if (phost != NULL)
                *phost = opaquedata->shost;
        if (pport != NULL)
                *pport = port;
        if (pfile != NULL)
                *pfile = opaquedata->sfile;

        return (0);
}


Index: http.c
===================================================================
--- http.c      (revision 1)
+++ http.c      (working copy)
@@ -308,7 +308,7 @@
 evhttp_make_header_request(struct evhttp_connection *evcon,
     struct evhttp_request *req)
 {
-       static char line[1024];
+       char line[1024];
        const char *method;

        evhttp_remove_header(req->output_headers, "Accept-Encoding");
@@ -378,9 +378,9 @@
 evhttp_maybe_add_content_length_header(struct evkeyvalq *headers,
     long content_length)
 {
+   char len[12]; /* XXX: not thread-safe */
        if (evhttp_find_header(headers, "Transfer-Encoding") == NULL &&
            evhttp_find_header(headers, "Content-Length") == NULL) {
-               static char len[12]; /* XXX: not thread-safe */
                snprintf(len, sizeof(len), "%ld", content_length);
                evhttp_add_header(headers, "Content-Length", len);
        }
@@ -394,7 +394,7 @@
 evhttp_make_header_response(struct evhttp_connection *evcon,
     struct evhttp_request *req)
 {
-       static char line[1024];
+       char line[1024];
        snprintf(line, sizeof(line), "HTTP/%d.%d %d %s\r\n",
            req->major, req->minor, req->response_code,
            req->response_code_line);
@@ -433,7 +433,7 @@
 void
 evhttp_make_header(struct evhttp_connection *evcon, struct 
evhttp_request *req)
 {
-       static char line[1024];
+       char line[1024];
        struct evkeyval *header;

        /*
@@ -1999,7 +1999,7 @@
        if ((fd = bind_socket(address, port)) == -1)
                return (-1);

-       if (listen(fd, 10) == -1) {
+       if (listen(fd, 8192) == -1) {
                event_warn("%s: listen", __func__);
                EVUTIL_CLOSESOCKET(fd);
                return (-1);



More information about the Libevent-users mailing list