atomic netreq removal from write_queue in upstream_write_cb

This commit is contained in:
Willem Toorop 2017-10-16 14:17:49 +02:00
parent 6afcc97b87
commit 968d94d2be
1 changed files with 36 additions and 18 deletions

View File

@ -462,6 +462,36 @@ stub_next_upstream(getdns_network_req *netreq)
dnsreq->upstreams->current_udp = 0; dnsreq->upstreams->current_udp = 0;
} }
static void
remove_from_write_queue(getdns_upstream *upstream, getdns_network_req * netreq)
{
getdns_network_req *r, *prev_r;
for ( r = upstream->write_queue, prev_r = NULL
; r
; prev_r = r, r = r->write_queue_tail) {
if (r != netreq)
continue;
if (prev_r)
prev_r->write_queue_tail = r->write_queue_tail;
else
upstream->write_queue = r->write_queue_tail;
if (r == upstream->write_queue_last) {
/* If r was the last netreq,
* its write_queue tail MUST be NULL
*/
assert(r->write_queue_tail == NULL);
upstream->write_queue_last = prev_r ? prev_r : NULL;
}
netreq->write_queue_tail = NULL;
break; /* netreq found and removed */
}
}
static void static void
stub_cleanup(getdns_network_req *netreq) stub_cleanup(getdns_network_req *netreq)
{ {
@ -481,22 +511,7 @@ stub_cleanup(getdns_network_req *netreq)
(void) _getdns_rbtree_delete(&upstream->netreq_by_query_id, (void) _getdns_rbtree_delete(&upstream->netreq_by_query_id,
(void *)(intptr_t)GLDNS_ID_WIRE(netreq->query)); (void *)(intptr_t)GLDNS_ID_WIRE(netreq->query));
/* Delete from upstream->write_queue (if present) */ remove_from_write_queue(upstream, netreq);
for (prev_r = NULL, r = upstream->write_queue; r;
prev_r = r, r = r->write_queue_tail)
if (r == netreq) {
if (prev_r)
prev_r->write_queue_tail = r->write_queue_tail;
else
upstream->write_queue = r->write_queue_tail;
if (r == upstream->write_queue_last)
upstream->write_queue_last =
prev_r ? prev_r : NULL;
netreq->write_queue_tail = NULL;
break;
}
upstream_reschedule_events(upstream, upstream->keepalive_timeout); upstream_reschedule_events(upstream, upstream->keepalive_timeout);
} }
@ -1706,8 +1721,11 @@ upstream_write_cb(void *userarg)
upstream->queries_sent++; upstream->queries_sent++;
/* Unqueue the netreq from the write_queue */ /* Unqueue the netreq from the write_queue */
if (!(upstream->write_queue = netreq->write_queue_tail)) { remove_from_write_queue(upstream, netreq);
upstream->write_queue_last = NULL;
/* Empty write_queue?, then deschedule upstream write_cb */
if (upstream->write_queue == NULL) {
assert(upstream->write_queue_last == NULL);
GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event);
upstream->event.write_cb = NULL; upstream->event.write_cb = NULL;
/* Reschedule (if already reading) to clear writable */ /* Reschedule (if already reading) to clear writable */