conn: remove the boolean 'inuse' field

... as the usage needs to be counted.
This commit is contained in:
Daniel Stenberg 2018-07-04 00:55:48 +02:00
parent d6417f6c2d
commit 1b76c38904
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
7 changed files with 73 additions and 83 deletions

View File

@ -63,10 +63,9 @@
static void conn_llist_dtor(void *user, void *element) static void conn_llist_dtor(void *user, void *element)
{ {
struct connectdata *data = element; struct connectdata *conn = element;
(void)user; (void)user;
conn->bundle = NULL;
data->bundle = NULL;
} }
static CURLcode bundle_create(struct Curl_easy *data, static CURLcode bundle_create(struct Curl_easy *data,
@ -313,19 +312,20 @@ void Curl_conncache_remove_conn(struct connectdata *conn, bool lock)
due to a failed connection attempt, before being added to a bundle */ due to a failed connection attempt, before being added to a bundle */
if(bundle) { if(bundle) {
if(lock) { if(lock) {
CONN_LOCK(conn->data); CONN_LOCK(data);
} }
conn->data = NULL; /* detach */
bundle_remove_conn(bundle, conn); bundle_remove_conn(bundle, conn);
if(bundle->num_connections == 0) if(bundle->num_connections == 0)
conncache_remove_bundle(connc, bundle); conncache_remove_bundle(connc, bundle);
conn->bundle = NULL; /* removed from it */ conn->bundle = NULL; /* removed from it */
if(connc) { if(connc) {
connc->num_conn--; connc->num_conn--;
DEBUGF(infof(conn->data, "The cache now contains %zu members\n", DEBUGF(infof(data, "The cache now contains %zu members\n",
connc->num_conn)); connc->num_conn));
} }
if(lock) { if(lock) {
CONN_UNLOCK(conn->data); CONN_UNLOCK(data);
} }
} }
} }
@ -433,19 +433,11 @@ bool Curl_conncache_return_conn(struct connectdata *conn)
infof(data, "Connection cache is full, closing the oldest one.\n"); infof(data, "Connection cache is full, closing the oldest one.\n");
conn_candidate = Curl_conncache_extract_oldest(data); conn_candidate = Curl_conncache_extract_oldest(data);
if(conn_candidate) { if(conn_candidate) {
/* Set the connection's owner correctly */
conn_candidate->data = data;
/* the winner gets the honour of being disconnected */ /* the winner gets the honour of being disconnected */
(void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE); (void)Curl_disconnect(data, conn_candidate, /* dead_connection */ FALSE);
} }
} }
CONN_LOCK(data);
conn->inuse = FALSE; /* Mark the connection unused */
conn->data = NULL; /* no owner */
CONN_UNLOCK(data);
return (conn_candidate == conn) ? FALSE : TRUE; return (conn_candidate == conn) ? FALSE : TRUE;
@ -479,7 +471,7 @@ Curl_conncache_extract_bundle(struct Curl_easy *data,
while(curr) { while(curr) {
conn = curr->ptr; conn = curr->ptr;
if(!conn->inuse) { if(!CONN_INUSE(conn)) {
/* Set higher score for the age passed since the connection was used */ /* Set higher score for the age passed since the connection was used */
score = Curl_timediff(now, conn->now); score = Curl_timediff(now, conn->now);
@ -496,6 +488,7 @@ Curl_conncache_extract_bundle(struct Curl_easy *data,
data->state.conn_cache->num_conn--; data->state.conn_cache->num_conn--;
DEBUGF(infof(data, "The cache now contains %zu members\n", DEBUGF(infof(data, "The cache now contains %zu members\n",
data->state.conn_cache->num_conn)); data->state.conn_cache->num_conn));
conn_candidate->data = data; /* associate! */
} }
return conn_candidate; return conn_candidate;
@ -536,7 +529,7 @@ Curl_conncache_extract_oldest(struct Curl_easy *data)
while(curr) { while(curr) {
conn = curr->ptr; conn = curr->ptr;
if(!conn->inuse) { if(!CONN_INUSE(conn)) {
/* Set higher score for the age passed since the connection was used */ /* Set higher score for the age passed since the connection was used */
score = Curl_timediff(now, conn->now); score = Curl_timediff(now, conn->now);
@ -557,6 +550,7 @@ Curl_conncache_extract_oldest(struct Curl_easy *data)
connc->num_conn--; connc->num_conn--;
DEBUGF(infof(data, "The cache now contains %zu members\n", DEBUGF(infof(data, "The cache now contains %zu members\n",
connc->num_conn)); connc->num_conn));
conn_candidate->data = data; /* associate! */
} }
CONN_UNLOCK(data); CONN_UNLOCK(data);
@ -577,7 +571,7 @@ void Curl_conncache_close_all_connections(struct conncache *connc)
pointer */ pointer */
/* This will remove the connection from the cache */ /* This will remove the connection from the cache */
connclose(conn, "kill all"); connclose(conn, "kill all");
(void)Curl_disconnect(conn, FALSE); (void)Curl_disconnect(connc->closure_handle, conn, FALSE);
sigpipe_restore(&pipe_st); sigpipe_restore(&pipe_st);
conn = Curl_conncache_find_first_connection(connc); conn = Curl_conncache_find_first_connection(connc);

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____| * \___|\___/|_| \_\_____|
* *
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
* *
* This software is licensed as described in the file COPYING, which * This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms * you should have received as part of this distribution. The terms
@ -131,7 +131,7 @@ CURLcode Curl_async_resolved(struct connectdata *conn,
if(result) if(result)
/* We're not allowed to return failure with memory left allocated /* We're not allowed to return failure with memory left allocated
in the connectdata struct, free those here */ in the connectdata struct, free those here */
Curl_disconnect(conn, FALSE); /* close the connection */ Curl_disconnect(conn->data, conn, FALSE); /* close the connection */
return result; return result;
} }

View File

@ -604,7 +604,7 @@ static CURLcode multi_done(struct connectdata **connp,
#endif #endif
) || conn->bits.close ) || conn->bits.close
|| (premature && !(conn->handler->flags & PROTOPT_STREAM))) { || (premature && !(conn->handler->flags & PROTOPT_STREAM))) {
CURLcode res2 = Curl_disconnect(conn, premature); /* close connection */ CURLcode res2 = Curl_disconnect(data, conn, premature);
/* If we had an error already, make sure we return that one. But /* If we had an error already, make sure we return that one. But
if we got a new error, return that. */ if we got a new error, return that. */
@ -622,7 +622,7 @@ static CURLcode multi_done(struct connectdata **connp,
conn->bits.conn_to_host ? conn->conn_to_host.dispname : conn->bits.conn_to_host ? conn->conn_to_host.dispname :
conn->host.dispname); conn->host.dispname);
/* the connection is no longer in use */ /* the connection is no longer in use by this transfer */
if(Curl_conncache_return_conn(conn)) { if(Curl_conncache_return_conn(conn)) {
/* remember the most recently used connection */ /* remember the most recently used connection */
data->state.lastconnect = conn; data->state.lastconnect = conn;
@ -2109,7 +2109,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* Don't attempt to send data over a connection that timed out */ /* Don't attempt to send data over a connection that timed out */
bool dead_connection = result == CURLE_OPERATION_TIMEDOUT; bool dead_connection = result == CURLE_OPERATION_TIMEDOUT;
/* disconnect properly */ /* disconnect properly */
Curl_disconnect(data->easy_conn, dead_connection); Curl_disconnect(data, data->easy_conn, dead_connection);
/* This is where we make sure that the easy_conn pointer is reset. /* This is where we make sure that the easy_conn pointer is reset.
We don't have to do this in every case block above where a We don't have to do this in every case block above where a
@ -2471,20 +2471,23 @@ void Curl_updatesocket(struct Curl_easy *data)
void Curl_multi_closed(struct connectdata *conn, curl_socket_t s) void Curl_multi_closed(struct connectdata *conn, curl_socket_t s)
{ {
struct Curl_multi *multi = conn->data->multi; if(conn->data) {
if(multi) { /* if there's still an easy handle associated with this connection */
/* this is set if this connection is part of a handle that is added to struct Curl_multi *multi = conn->data->multi;
a multi handle, and only then this is necessary */ if(multi) {
struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s); /* this is set if this connection is part of a handle that is added to
a multi handle, and only then this is necessary */
struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
if(entry) { if(entry) {
if(multi->socket_cb) if(multi->socket_cb)
multi->socket_cb(conn->data, s, CURL_POLL_REMOVE, multi->socket_cb(conn->data, s, CURL_POLL_REMOVE,
multi->socket_userp, multi->socket_userp,
entry->socketp); entry->socketp);
/* now remove it from the socket hash */ /* now remove it from the socket hash */
sh_delentry(&multi->sockhash, s); sh_delentry(&multi->sockhash, s);
}
} }
} }
} }
@ -3135,12 +3138,15 @@ static void process_pending_handles(struct Curl_multi *multi)
} }
} }
void Curl_set_in_callback(struct Curl_easy *easy, bool value) void Curl_set_in_callback(struct Curl_easy *data, bool value)
{ {
if(easy->multi_easy) /* might get called when there is no data pointer! */
easy->multi_easy->in_callback = value; if(data) {
else if(easy->multi) if(data->multi_easy)
easy->multi->in_callback = value; data->multi_easy->in_callback = value;
else if(data->multi)
data->multi->in_callback = value;
}
} }
bool Curl_is_in_callback(struct Curl_easy *easy) bool Curl_is_in_callback(struct Curl_easy *easy)

View File

@ -734,17 +734,20 @@ static void conn_free(struct connectdata *conn)
* primary connection, like when freeing room in the connection cache or * primary connection, like when freeing room in the connection cache or
* killing of a dead old connection. * killing of a dead old connection.
* *
* A connection needs an easy handle when closing down. We support this passed
* in separately since the connection to get closed here is often already
* disconnected from an easy handle.
*
* This function MUST NOT reset state in the Curl_easy struct if that * This function MUST NOT reset state in the Curl_easy struct if that
* isn't strictly bound to the life-time of *this* particular connection. * isn't strictly bound to the life-time of *this* particular connection.
* *
*/ */
CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection) CURLcode Curl_disconnect(struct Curl_easy *data,
struct connectdata *conn, bool dead_connection)
{ {
struct Curl_easy *data;
if(!conn) if(!conn)
return CURLE_OK; /* this is closed and fine already */ return CURLE_OK; /* this is closed and fine already */
data = conn->data;
if(!data) { if(!data) {
DEBUGF(fprintf(stderr, "DISCONNECT without easy handle, ignoring\n")); DEBUGF(fprintf(stderr, "DISCONNECT without easy handle, ignoring\n"));
@ -755,13 +758,13 @@ CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection)
* If this connection isn't marked to force-close, leave it open if there * If this connection isn't marked to force-close, leave it open if there
* are other users of it * are other users of it
*/ */
if(!conn->bits.close && if(!conn->bits.close && CONN_INUSE(conn)) {
(conn->send_pipe.size + conn->recv_pipe.size)) { DEBUGF(fprintf(stderr, "Curl_disconnect when inuse: %d\n",
DEBUGF(infof(data, "Curl_disconnect, usecounter: %zu\n", CONN_INUSE(conn)));
conn->send_pipe.size + conn->recv_pipe.size));
return CURLE_OK; return CURLE_OK;
} }
conn->data = data;
if(conn->dns_entry != NULL) { if(conn->dns_entry != NULL) {
Curl_resolv_unlock(data, conn->dns_entry); Curl_resolv_unlock(data, conn->dns_entry);
conn->dns_entry = NULL; conn->dns_entry = NULL;
@ -959,7 +962,7 @@ static bool extract_if_dead(struct connectdata *conn,
struct Curl_easy *data) struct Curl_easy *data)
{ {
size_t pipeLen = conn->send_pipe.size + conn->recv_pipe.size; size_t pipeLen = conn->send_pipe.size + conn->recv_pipe.size;
if(!pipeLen && !conn->inuse) { if(!pipeLen && !CONN_INUSE(conn)) {
/* The check for a dead socket makes sense only if there are no /* The check for a dead socket makes sense only if there are no
handles in pipeline and the connection isn't already marked in handles in pipeline and the connection isn't already marked in
use */ use */
@ -1025,7 +1028,7 @@ static void prune_dead_connections(struct Curl_easy *data)
while(Curl_conncache_foreach(data, data->state.conn_cache, &prune, while(Curl_conncache_foreach(data, data->state.conn_cache, &prune,
call_extract_if_dead)) { call_extract_if_dead)) {
/* disconnect it */ /* disconnect it */
(void)Curl_disconnect(prune.extracted, /* dead_connection */TRUE); (void)Curl_disconnect(data, prune.extracted, /* dead_connection */TRUE);
} }
data->state.conn_cache->last_cleanup = now; data->state.conn_cache->last_cleanup = now;
} }
@ -1139,7 +1142,7 @@ ConnectionExists(struct Curl_easy *data,
if(extract_if_dead(check, data)) { if(extract_if_dead(check, data)) {
/* disconnect it */ /* disconnect it */
(void)Curl_disconnect(check, /* dead_connection */TRUE); (void)Curl_disconnect(data, check, /* dead_connection */TRUE);
continue; continue;
} }
@ -1267,12 +1270,12 @@ ConnectionExists(struct Curl_easy *data,
} }
} }
if(!canpipe && check->inuse) if(!canpipe && CONN_INUSE(check))
/* this request can't be pipelined but the checked connection is /* this request can't be pipelined but the checked connection is
already in use so we skip it */ already in use so we skip it */
continue; continue;
if((check->inuse) && (check->data->multi != needle->data->multi)) if(CONN_INUSE(check) && (check->data->multi != needle->data->multi))
/* this could be subject for pipeline/multiplex use, but only /* this could be subject for pipeline/multiplex use, but only
if they belong to the same multi handle */ if they belong to the same multi handle */
continue; continue;
@ -1464,7 +1467,6 @@ ConnectionExists(struct Curl_easy *data,
if(chosen) { if(chosen) {
/* mark it as used before releasing the lock */ /* mark it as used before releasing the lock */
chosen->inuse = TRUE;
chosen->data = data; /* own it! */ chosen->data = data; /* own it! */
Curl_conncache_unlock(needle); Curl_conncache_unlock(needle);
*usethis = chosen; *usethis = chosen;
@ -4481,11 +4483,9 @@ static CURLcode create_conn(struct Curl_easy *data,
conn_candidate = Curl_conncache_extract_bundle(data, bundle); conn_candidate = Curl_conncache_extract_bundle(data, bundle);
Curl_conncache_unlock(conn); Curl_conncache_unlock(conn);
if(conn_candidate) { if(conn_candidate)
/* Set the connection's owner correctly, then kill it */ (void)Curl_disconnect(data, conn_candidate,
conn_candidate->data = data; /* dead_connection */ FALSE);
(void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE);
}
else { else {
infof(data, "No more connections allowed to host: %zu\n", infof(data, "No more connections allowed to host: %zu\n",
max_host_connections); max_host_connections);
@ -4504,12 +4504,9 @@ static CURLcode create_conn(struct Curl_easy *data,
/* The cache is full. Let's see if we can kill a connection. */ /* The cache is full. Let's see if we can kill a connection. */
conn_candidate = Curl_conncache_extract_oldest(data); conn_candidate = Curl_conncache_extract_oldest(data);
if(conn_candidate)
if(conn_candidate) { (void)Curl_disconnect(data, conn_candidate,
/* Set the connection's owner correctly, then kill it */ /* dead_connection */ FALSE);
conn_candidate->data = data;
(void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE);
}
else { else {
infof(data, "No connections available in cache\n"); infof(data, "No connections available in cache\n");
connections_available = FALSE; connections_available = FALSE;
@ -4526,9 +4523,6 @@ static CURLcode create_conn(struct Curl_easy *data,
goto out; goto out;
} }
else { else {
/* Mark the connection as used, before we add it */
conn->inuse = TRUE;
/* /*
* This is a brand new connection, so let's store it in the connection * This is a brand new connection, so let's store it in the connection
* cache of ours! * cache of ours!
@ -4693,10 +4687,10 @@ CURLcode Curl_connect(struct Curl_easy *data,
} }
if(result && *in_connect) { if(result && *in_connect) {
/* We're not allowed to return failure with memory left allocated /* We're not allowed to return failure with memory left allocated in the
in the connectdata struct, free those here */ connectdata struct, free those here */
Curl_disconnect(*in_connect, FALSE); /* close the connection */ Curl_disconnect(data, *in_connect, FALSE);
*in_connect = NULL; /* return a NULL */ *in_connect = NULL; /* return a NULL */
} }
return result; return result;

View File

@ -39,7 +39,8 @@ void Curl_freeset(struct Curl_easy * data);
CURLcode Curl_close(struct Curl_easy *data); /* opposite of curl_open() */ CURLcode Curl_close(struct Curl_easy *data); /* opposite of curl_open() */
CURLcode Curl_connect(struct Curl_easy *, struct connectdata **, CURLcode Curl_connect(struct Curl_easy *, struct connectdata **,
bool *async, bool *protocol_connect); bool *async, bool *protocol_connect);
CURLcode Curl_disconnect(struct connectdata *, bool dead_connection); CURLcode Curl_disconnect(struct Curl_easy *data,
struct connectdata *, bool dead_connection);
CURLcode Curl_protocol_connect(struct connectdata *conn, bool *done); CURLcode Curl_protocol_connect(struct connectdata *conn, bool *done);
CURLcode Curl_protocol_connecting(struct connectdata *conn, bool *done); CURLcode Curl_protocol_connecting(struct connectdata *conn, bool *done);
CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done); CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done);

View File

@ -781,11 +781,12 @@ struct connectdata {
curl_closesocket_callback fclosesocket; /* function closing the socket(s) */ curl_closesocket_callback fclosesocket; /* function closing the socket(s) */
void *closesocket_client; void *closesocket_client;
bool inuse; /* This is a marker for the connection cache logic. If this is /* This is used by the connection cache logic. If this returns TRUE, this
TRUE this handle is being used by one or more easy handles handle is being used by one or more easy handles and can only used by any
and can only used by any other easy handle without careful other easy handle without careful consideration (== only for
consideration (== only for pipelining/multiplexing) and it pipelining/multiplexing) and it cannot be used by another multi
cannot be used by another multi handle! */ handle! */
#define CONN_INUSE(c) ((c)->send_pipe.size || (c)->recv_pipe.size)
/**** Fields set when inited and not modified again */ /**** Fields set when inited and not modified again */
long connection_id; /* Contains a unique number to make it easier to long connection_id; /* Contains a unique number to make it easier to

View File

@ -38,8 +38,6 @@ run 1: foobar and so on fun!
<- Mutex unlock <- Mutex unlock
-> Mutex lock -> Mutex lock
<- Mutex unlock <- Mutex unlock
-> Mutex lock
<- Mutex unlock
run 1: foobar and so on fun! run 1: foobar and so on fun!
-> Mutex lock -> Mutex lock
<- Mutex unlock <- Mutex unlock
@ -49,8 +47,6 @@ run 1: foobar and so on fun!
<- Mutex unlock <- Mutex unlock
-> Mutex lock -> Mutex lock
<- Mutex unlock <- Mutex unlock
-> Mutex lock
<- Mutex unlock
run 1: foobar and so on fun! run 1: foobar and so on fun!
-> Mutex lock -> Mutex lock
<- Mutex unlock <- Mutex unlock
@ -58,8 +54,6 @@ run 1: foobar and so on fun!
<- Mutex unlock <- Mutex unlock
-> Mutex lock -> Mutex lock
<- Mutex unlock <- Mutex unlock
-> Mutex lock
<- Mutex unlock
</datacheck> </datacheck>
</reply> </reply>