From 09b9fc9009bfe6b7b6fd5ba82e81b4ca76539d8d Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 2 Aug 2013 00:09:59 +0200 Subject: [PATCH] multi: remove 'Curl_one_easy' struct, phase 1 The motivation for having a separate struct that keep track of an easy handle when using the multi handle was removed when we switched to always using the multi interface internally. Now they were just two separate struct that was always allocated for each easy handle. This first step just moves the Curl_one_easy struct members into the SessionHandle struct and hides this somehow (== keeps the source code changes to a minimum) by defining Curl_one_easy to SessionHandle The biggest changes in this commit are: 1 - the linked list of easy handles had to be changed somewhat due to the new struct layout. This made the main linked list pointer get renamed to 'easyp' and there's also a new pointer to the last node, called easylp. It is no longer circular but ends with ->next pointing to NULL. New nodes are still added last. 2 - easy->state is now called easy->mstate to avoid name collision --- lib/multi.c | 143 ++++++++++++++++++++++------------------------ lib/multihandle.h | 24 +------- lib/urldata.h | 20 +++++++ 3 files changed, 92 insertions(+), 95 deletions(-) diff --git a/lib/multi.c b/lib/multi.c index 3318e0d4c..e5565ef10 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -114,23 +114,23 @@ static void mstate(struct Curl_one_easy *easy, CURLMstate state #ifdef DEBUGBUILD long connection_id = -5000; #endif - CURLMstate oldstate = easy->state; + CURLMstate oldstate = easy->mstate; if(oldstate == state) /* don't bother when the new state is the same as the old state */ return; - easy->state = state; + easy->mstate = state; #ifdef DEBUGBUILD - if(easy->state >= CURLM_STATE_CONNECT_PEND && - easy->state < CURLM_STATE_COMPLETED) { + if(easy->mstate >= CURLM_STATE_CONNECT_PEND && + easy->mstate < CURLM_STATE_COMPLETED) { if(easy->easy_conn) connection_id = easy->easy_conn->connection_id; infof(easy->easy_handle, "STATE: %s => %s handle %p; line %d (connection #%ld) \n", - statename[oldstate], statename[easy->state], + statename[oldstate], statename[easy->mstate], (void *)easy, lineno, connection_id); } #endif @@ -307,12 +307,6 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ if(!multi->msglist) goto error; - /* Let's make the doubly-linked list a circular list. This makes - the linked list code simpler and allows inserting at the end - with less work (we didn't keep a tail pointer before). */ - multi->easy.next = &multi->easy; - multi->easy.prev = &multi->easy; - multi->max_pipeline_length = 5; return (CURLM *) multi; @@ -365,13 +359,7 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle, if(!timeoutlist) return CURLM_OUT_OF_MEMORY; - /* Allocate new node for the doubly-linked circular list of - Curl_one_easy structs that holds pointers to easy handles */ - easy = calloc(1, sizeof(struct Curl_one_easy)); - if(!easy) { - Curl_llist_destroy(timeoutlist, NULL); - return CURLM_OUT_OF_MEMORY; - } + easy = data; /* In case multi handle has no hostcache yet, allocate one */ if(!multi->hostcache) { @@ -441,17 +429,21 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle, list of Curl_one_easy structs to try and maintain a FIFO queue so the pipelined requests are in order. */ - /* We add this new entry last in the list. We make our 'next' point to the - 'first' struct and our 'prev' point to the previous 'prev' */ - easy->next = &multi->easy; - easy->prev = multi->easy.prev; + /* We add this new entry last in the list. */ - /* make 'easy' the last node in the chain */ - multi->easy.prev = easy; - - /* if there was a prev node, make sure its 'next' pointer links to - the new node */ - easy->prev->next = easy; + easy->next = NULL; /* end of the line */ + if(multi->easyp) { + struct Curl_one_easy *last = multi->easylp; + last->next = easy; + easy->prev = last; + multi->easylp = easy; /* the new last node */ + } + else { + /* first node, make both prev and next be NULL! */ + easy->next = NULL; + easy->prev = NULL; + multi->easylp = multi->easyp = easy; /* both first and last */ + } /* make the SessionHandle refer back to this multi handle */ Curl_easy_addmulti(easy_handle, multi_handle); @@ -524,7 +516,7 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle, easy = data->multi_pos; if(easy) { - bool premature = (easy->state < CURLM_STATE_COMPLETED) ? TRUE : FALSE; + bool premature = (easy->mstate < CURLM_STATE_COMPLETED) ? TRUE : FALSE; bool easy_owns_conn = (easy->easy_conn && (easy->easy_conn->data == easy->easy_handle)) ? TRUE : FALSE; @@ -539,8 +531,8 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle, if(easy->easy_conn && (easy->easy_conn->send_pipe->size + easy->easy_conn->recv_pipe->size > 1) && - easy->state > CURLM_STATE_WAITDO && - easy->state < CURLM_STATE_COMPLETED) { + easy->mstate > CURLM_STATE_WAITDO && + easy->mstate < CURLM_STATE_COMPLETED) { /* If the handle is in a pipeline and has started sending off its request but not received its response yet, we need to close connection. */ @@ -591,7 +583,7 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle, /* change state without using multistate(), only to make singlesocket() do what we want */ - easy->state = CURLM_STATE_COMPLETED; + easy->mstate = CURLM_STATE_COMPLETED; singlesocket(multi, easy); /* to let the application know what sockets that vanish with this handle */ @@ -623,9 +615,14 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle, /* make the previous node point to our next */ if(easy->prev) easy->prev->next = easy->next; + else + multi->easyp = easy->next; /* point to first node */ + /* make our next point to our previous node */ if(easy->next) easy->next->prev = easy->prev; + else + multi->easylp = easy->prev; /* point to last node */ easy->easy_handle->set.one_easy = NULL; /* detached */ @@ -634,7 +631,6 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle, /* NOTE NOTE NOTE We do not touch the easy handle here! */ - free(easy); multi->num_easy--; /* one less to care about now */ @@ -698,13 +694,13 @@ static int multi_getsock(struct Curl_one_easy *easy, if(easy->easy_handle->state.pipe_broke || !easy->easy_conn) return 0; - if(easy->state > CURLM_STATE_CONNECT && - easy->state < CURLM_STATE_COMPLETED) { + if(easy->mstate > CURLM_STATE_CONNECT && + easy->mstate < CURLM_STATE_COMPLETED) { /* Set up ownership correctly */ easy->easy_conn->data = easy->easy_handle; } - switch(easy->state) { + switch(easy->mstate) { default: #if 0 /* switch back on these cases to get the compiler to check for all enums to be present */ @@ -766,8 +762,8 @@ CURLMcode curl_multi_fdset(CURLM *multi_handle, if(!GOOD_MULTI_HANDLE(multi)) return CURLM_BAD_HANDLE; - easy=multi->easy.next; - while(easy != &multi->easy) { + easy=multi->easyp; + while(easy) { bitmap = multi_getsock(easy, sockbunch, MAX_SOCKSPEREASYHANDLE); for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) { @@ -825,8 +821,8 @@ CURLMcode curl_multi_wait(CURLM *multi_handle, timeout_ms = (int)timeout_internal; /* Count up how many fds we have from the multi handle */ - easy=multi->easy.next; - while(easy != &multi->easy) { + easy=multi->easyp; + while(easy) { bitmap = multi_getsock(easy, sockbunch, MAX_SOCKSPEREASYHANDLE); for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) { @@ -863,8 +859,8 @@ CURLMcode curl_multi_wait(CURLM *multi_handle, if(curlfds) { /* Add the curl handles to our pollfds first */ - easy=multi->easy.next; - while(easy != &multi->easy) { + easy=multi->easyp; + while(easy) { bitmap = multi_getsock(easy, sockbunch, MAX_SOCKSPEREASYHANDLE); for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) { @@ -968,7 +964,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, infof(data, "Pipe broke: handle 0x%p, url = %s\n", (void *)easy, data->state.path); - if(easy->state < CURLM_STATE_COMPLETED) { + if(easy->mstate < CURLM_STATE_COMPLETED) { /* Head back to the CONNECT state */ multistate(easy, CURLM_STATE_CONNECT); result = CURLM_CALL_MULTI_PERFORM; @@ -981,36 +977,36 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, } if(!easy->easy_conn && - easy->state > CURLM_STATE_CONNECT && - easy->state < CURLM_STATE_DONE) { + easy->mstate > CURLM_STATE_CONNECT && + easy->mstate < CURLM_STATE_DONE) { /* In all these states, the code will blindly access 'easy->easy_conn' so this is precaution that it isn't NULL. And it silences static analyzers. */ - failf(data, "In state %d with no easy_conn, bail out!\n", easy->state); + failf(data, "In state %d with no easy_conn, bail out!\n", easy->mstate); return CURLM_INTERNAL_ERROR; } - if(easy->easy_conn && easy->state > CURLM_STATE_CONNECT && - easy->state < CURLM_STATE_COMPLETED) + if(easy->easy_conn && easy->mstate > CURLM_STATE_CONNECT && + easy->mstate < CURLM_STATE_COMPLETED) /* Make sure we set the connection's current owner */ easy->easy_conn->data = data; if(easy->easy_conn && - (easy->state >= CURLM_STATE_CONNECT) && - (easy->state < CURLM_STATE_COMPLETED)) { + (easy->mstate >= CURLM_STATE_CONNECT) && + (easy->mstate < CURLM_STATE_COMPLETED)) { /* we need to wait for the connect state as only then is the start time stored, but we must not check already completed handles */ timeout_ms = Curl_timeleft(data, &now, - (easy->state <= CURLM_STATE_WAITDO)? + (easy->mstate <= CURLM_STATE_WAITDO)? TRUE:FALSE); if(timeout_ms < 0) { /* Handle timed out */ - if(easy->state == CURLM_STATE_WAITRESOLVE) + if(easy->mstate == CURLM_STATE_WAITRESOLVE) failf(data, "Resolving timed out after %ld milliseconds", Curl_tvdiff(now, data->progress.t_startsingle)); - else if(easy->state == CURLM_STATE_WAITCONNECT) + else if(easy->mstate == CURLM_STATE_WAITCONNECT) failf(data, "Connection timed out after %ld milliseconds", Curl_tvdiff(now, data->progress.t_startsingle)); else { @@ -1031,7 +1027,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, } } - switch(easy->state) { + switch(easy->mstate) { case CURLM_STATE_INIT: /* init this transfer. */ easy->result=Curl_pretransfer(data); @@ -1662,7 +1658,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, return CURLM_INTERNAL_ERROR; } - if(easy->state < CURLM_STATE_COMPLETED) { + if(easy->mstate < CURLM_STATE_COMPLETED) { if(CURLE_OK != easy->result) { /* * If an error was returned, and we aren't in completed state now, @@ -1695,7 +1691,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, easy->easy_conn = NULL; } } - else if(easy->state == CURLM_STATE_CONNECT) { + else if(easy->mstate == CURLM_STATE_CONNECT) { /* Curl_connect() failed */ (void)Curl_posttransfer(data); } @@ -1709,14 +1705,14 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, easy->easy_conn->bits.close = TRUE; /* if not yet in DONE state, go there, otherwise COMPLETED */ - multistate(easy, (easy->state < CURLM_STATE_DONE)? + multistate(easy, (easy->mstate < CURLM_STATE_DONE)? CURLM_STATE_DONE: CURLM_STATE_COMPLETED); result = CURLM_CALL_MULTI_PERFORM; } } } WHILE_FALSE; /* just to break out from! */ - if(CURLM_STATE_COMPLETED == easy->state) { + if(CURLM_STATE_COMPLETED == easy->mstate) { /* now fill in the Curl_message with this info */ msg = &easy->msg; @@ -1744,8 +1740,8 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles) if(!GOOD_MULTI_HANDLE(multi)) return CURLM_BAD_HANDLE; - easy=multi->easy.next; - while(easy != &multi->easy) { + easy=multi->easyp; + while(easy) { CURLMcode result; struct WildcardData *wc = &easy->easy_handle->wildcard; @@ -1845,8 +1841,8 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle) multi->msglist = NULL; /* remove all easy handles */ - easy = multi->easy.next; - while(easy != &multi->easy) { + easy = multi->easyp; + while(easy) { nexteasy=easy->next; if(easy->easy_handle->dns.hostcachetype == HCACHE_MULTI) { /* clear out the usage of the shared DNS cache */ @@ -1860,7 +1856,6 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle) Curl_easy_addmulti(easy->easy_handle, NULL); /* clear the association */ - free(easy); easy = nexteasy; } @@ -2178,16 +2173,16 @@ static CURLMcode multi_socket(struct Curl_multi *multi, struct timeval now = Curl_tvnow(); if(checkall) { - struct Curl_one_easy *easyp; + struct Curl_one_easy *easy; /* *perform() deals with running_handles on its own */ result = curl_multi_perform(multi, running_handles); /* walk through each easy handle and do the socket state change magic and callbacks */ - easyp=multi->easy.next; - while(easyp != &multi->easy) { - singlesocket(multi, easyp); - easyp = easyp->next; + easy=multi->easyp; + while(easy) { + singlesocket(multi, easy); + easy = easy->next; } /* or should we fall-through and do the timer-based stuff? */ @@ -2714,9 +2709,9 @@ void Curl_multi_process_pending_handles(struct Curl_multi *multi) { struct Curl_one_easy *easy; - easy=multi->easy.next; - while(easy != &multi->easy) { - if(easy->state == CURLM_STATE_CONNECT_PEND) { + easy=multi->easyp; + while(easy) { + if(easy->mstate == CURLM_STATE_CONNECT_PEND) { multistate(easy, CURLM_STATE_CONNECT); /* Make sure that the handle will be processed soonish. */ Curl_expire(easy->easy_handle, 1); @@ -2733,12 +2728,12 @@ void Curl_multi_dump(const struct Curl_multi *multi_handle) int i; fprintf(stderr, "* Multi status: %d handles, %d alive\n", multi->num_easy, multi->num_alive); - for(easy=multi->easy.next; easy != &multi->easy; easy = easy->next) { - if(easy->state < CURLM_STATE_COMPLETED) { + for(easy=multi->easyp; easy; easy = easy->next) { + if(easy->mstate < CURLM_STATE_COMPLETED) { /* only display handles that are not completed */ fprintf(stderr, "handle %p, state %s, %d sockets\n", (void *)easy->easy_handle, - statename[easy->state], easy->numsocks); + statename[easy->mstate], easy->numsocks); for(i=0; i < easy->numsocks; i++) { curl_socket_t s = easy->sockets[i]; struct Curl_sh_entry *entry = diff --git a/lib/multihandle.h b/lib/multihandle.h index 3fcd9c0e6..714abf6b7 100644 --- a/lib/multihandle.h +++ b/lib/multihandle.h @@ -59,26 +59,7 @@ typedef enum { #define GETSOCK_READABLE (0x00ff) #define GETSOCK_WRITABLE (0xff00) -struct Curl_one_easy { - /* first, two fields for the linked list of these */ - struct Curl_one_easy *next; - struct Curl_one_easy *prev; - - struct SessionHandle *easy_handle; /* the easy handle for this unit */ - struct connectdata *easy_conn; /* the "unit's" connection */ - - CURLMstate state; /* the handle's state */ - CURLcode result; /* previous result */ - - struct Curl_message msg; /* A single posted message. */ - - /* Array with the plain socket numbers this handle takes care of, in no - particular order. Note that all sockets are added to the sockhash, where - the state etc are also kept. This array is mostly used to detect when a - socket is to be removed from the hash. See singlesocket(). */ - curl_socket_t sockets[MAX_SOCKSPEREASYHANDLE]; - int numsocks; -}; +#define Curl_one_easy SessionHandle /* This is the struct known as CURLM on the outside */ struct Curl_multi { @@ -87,7 +68,8 @@ struct Curl_multi { long type; /* We have a doubly-linked circular list with easy handles */ - struct Curl_one_easy easy; + struct Curl_one_easy *easyp; + struct Curl_one_easy *easylp; /* last node */ int num_easy; /* amount of entries in the linked list above. */ int num_alive; /* amount of easy handles that are added but have not yet diff --git a/lib/urldata.h b/lib/urldata.h index e245bfb4f..520fe2ca6 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -188,6 +188,7 @@ #include "http.h" #include "rtsp.h" #include "wildcard.h" +#include "multihandle.h" #ifdef HAVE_GSSAPI # ifdef HAVE_GSSGNU @@ -1619,6 +1620,25 @@ struct Names { */ struct SessionHandle { + /* first, two fields for the linked list of these */ + struct Curl_one_easy *next; + struct Curl_one_easy *prev; + + struct SessionHandle *easy_handle; /* the easy handle for this unit */ + struct connectdata *easy_conn; /* the "unit's" connection */ + + CURLMstate mstate; /* the handle's state */ + CURLcode result; /* previous result */ + + struct Curl_message msg; /* A single posted message. */ + + /* Array with the plain socket numbers this handle takes care of, in no + particular order. Note that all sockets are added to the sockhash, where + the state etc are also kept. This array is mostly used to detect when a + socket is to be removed from the hash. See singlesocket(). */ + curl_socket_t sockets[MAX_SOCKSPEREASYHANDLE]; + int numsocks; + struct Names dns; struct Curl_multi *multi; /* if non-NULL, points to the multi handle struct to which this "belongs" when used by