... | ... |
@@ -40,6 +40,7 @@ |
40 | 40 |
|
41 | 41 |
#include "ip_addr.h" |
42 | 42 |
#include "locking.h" |
43 |
+#include "atomic_ops.h" |
|
43 | 44 |
|
44 | 45 |
|
45 | 46 |
#define TCP_CON_MAX_ALIASES 4 /* maximum number of port aliases */ |
... | ... |
@@ -123,7 +124,7 @@ struct tcp_connection{ |
123 | 124 |
reply-ing*/ |
124 | 125 |
struct receive_info rcv; /* src & dst ip, ports, proto a.s.o*/ |
125 | 126 |
struct tcp_req req; /* request data */ |
126 |
- volatile int refcnt; |
|
127 |
+ atomic_t refcnt; |
|
127 | 128 |
enum sip_protos type; /* PROTO_TCP or a protocol over it, e.g. TLS */ |
128 | 129 |
int flags; /* connection related flags */ |
129 | 130 |
enum tcp_conn_states state; /* connection state */ |
... | ... |
@@ -142,6 +143,9 @@ struct tcp_connection{ |
142 | 143 |
|
143 | 144 |
|
144 | 145 |
|
146 |
+#define tcpconn_ref(c) atomic_inc(&((c)->refcnt)) |
|
147 |
+#define tcpconn_put(c) atomic_dec(&((c)->refcnt)) |
|
148 |
+ |
|
145 | 149 |
|
146 | 150 |
#define init_tcp_req( r) \ |
147 | 151 |
do{ \ |
... | ... |
@@ -69,6 +69,8 @@ |
69 | 69 |
* 2006-02-06 better tcp_max_connections checks, tcp_connections_no moved to |
70 | 70 |
* shm (andrei) |
71 | 71 |
* 2006-04-12 tcp_send() changed to use struct dest_info (andrei) |
72 |
+ * 2006-11-02 switched to atomic ops for refcnt, locking improvements |
|
73 |
+ * (andrei) |
|
72 | 74 |
*/ |
73 | 75 |
|
74 | 76 |
|
... | ... |
@@ -415,7 +417,7 @@ struct tcp_connection* tcpconn_new(int sock, union sockaddr_union* su, |
415 | 417 |
|
416 | 418 |
c->rcv.src_su=*su; |
417 | 419 |
|
418 |
- c->refcnt=0; |
|
420 |
+ atomic_set(&c->refcnt, 0); |
|
419 | 421 |
su2ip_addr(&c->rcv.src_ip, su); |
420 | 422 |
c->rcv.src_port=su_getport(su); |
421 | 423 |
c->rcv.bind_address=ba; |
... | ... |
@@ -522,25 +524,22 @@ error: |
522 | 524 |
|
523 | 525 |
struct tcp_connection* tcpconn_add(struct tcp_connection *c) |
524 | 526 |
{ |
525 |
- unsigned hash; |
|
526 | 527 |
|
527 | 528 |
if (c){ |
529 |
+ c->id_hash=tcp_id_hash(c->id); |
|
530 |
+ c->con_aliases[0].hash=tcp_addr_hash(&c->rcv.src_ip, c->rcv.src_port); |
|
528 | 531 |
TCPCONN_LOCK; |
529 | 532 |
/* add it at the begining of the list*/ |
530 |
- hash=tcp_id_hash(c->id); |
|
531 |
- c->id_hash=hash; |
|
532 |
- tcpconn_listadd(tcpconn_id_hash[hash], c, id_next, id_prev); |
|
533 |
- |
|
534 |
- hash=tcp_addr_hash(&c->rcv.src_ip, c->rcv.src_port); |
|
533 |
+ tcpconn_listadd(tcpconn_id_hash[c->id_hash], c, id_next, id_prev); |
|
535 | 534 |
/* set the first alias */ |
536 | 535 |
c->con_aliases[0].port=c->rcv.src_port; |
537 |
- c->con_aliases[0].hash=hash; |
|
538 | 536 |
c->con_aliases[0].parent=c; |
539 |
- tcpconn_listadd(tcpconn_aliases_hash[hash], &c->con_aliases[0], |
|
540 |
- next, prev); |
|
537 |
+ tcpconn_listadd(tcpconn_aliases_hash[c->con_aliases[0].hash], |
|
538 |
+ &c->con_aliases[0], next, prev); |
|
541 | 539 |
c->aliases++; |
542 | 540 |
TCPCONN_UNLOCK; |
543 |
- DBG("tcpconn_add: hashes: %d, %d\n", hash, c->id_hash); |
|
541 |
+ DBG("tcpconn_add: hashes: %d, %d\n", c->con_aliases[0].hash, |
|
542 |
+ c->id_hash); |
|
544 | 543 |
return c; |
545 | 544 |
}else{ |
546 | 545 |
LOG(L_CRIT, "tcpconn_add: BUG: null connection pointer\n"); |
... | ... |
@@ -634,7 +633,7 @@ struct tcp_connection* tcpconn_get(int id, struct ip_addr* ip, int port, |
634 | 633 |
TCPCONN_LOCK; |
635 | 634 |
c=_tcpconn_find(id, ip, port); |
636 | 635 |
if (c){ |
637 |
- c->refcnt++; |
|
636 |
+ atomic_inc(&c->refcnt); |
|
638 | 637 |
c->timeout=get_ticks()+timeout; |
639 | 638 |
} |
640 | 639 |
TCPCONN_UNLOCK; |
... | ... |
@@ -704,24 +703,6 @@ error_sec: |
704 | 703 |
|
705 | 704 |
|
706 | 705 |
|
707 |
-void tcpconn_ref(struct tcp_connection* c) |
|
708 |
-{ |
|
709 |
- TCPCONN_LOCK; |
|
710 |
- c->refcnt++; /* FIXME: atomic_dec */ |
|
711 |
- TCPCONN_UNLOCK; |
|
712 |
-} |
|
713 |
- |
|
714 |
- |
|
715 |
- |
|
716 |
-void tcpconn_put(struct tcp_connection* c) |
|
717 |
-{ |
|
718 |
- TCPCONN_LOCK; |
|
719 |
- c->refcnt--; /* FIXME: atomic_dec */ |
|
720 |
- TCPCONN_UNLOCK; |
|
721 |
-} |
|
722 |
- |
|
723 |
- |
|
724 |
- |
|
725 | 706 |
/* finds a tcpconn & sends on it |
726 | 707 |
* uses the dst members to, proto (TCP|TLS) and id |
727 | 708 |
* returns: number of bytes written (>=0) on success |
... | ... |
@@ -768,8 +749,7 @@ no_id: |
768 | 749 |
LOG(L_ERR, "ERROR: tcp_send: connect failed\n"); |
769 | 750 |
return -1; |
770 | 751 |
} |
771 |
- c->refcnt++; /* safe to do it w/o locking, it's not yet |
|
772 |
- available to the rest of the world */ |
|
752 |
+ atomic_set(&c->refcnt, 1); /* ref. only from here for now */ |
|
773 | 753 |
fd=c->s; |
774 | 754 |
|
775 | 755 |
/* send the new tcpconn to "tcp main" */ |
... | ... |
@@ -811,8 +791,8 @@ get_fd: |
811 | 791 |
LOG(L_CRIT, "BUG: tcp_send: get_fd: got different connection:" |
812 | 792 |
" %p (id= %d, refcnt=%d state=%d != " |
813 | 793 |
" %p (id= %d, refcnt=%d state=%d (n=%d)\n", |
814 |
- c, c->id, c->refcnt, c->state, |
|
815 |
- tmp, tmp->id, tmp->refcnt, tmp->state, n |
|
794 |
+ c, c->id, atomic_get(&c->refcnt), c->state, |
|
795 |
+ tmp, tmp->id, atomic_get(&tmp->refcnt), tmp->state, n |
|
816 | 796 |
); |
817 | 797 |
n=-1; /* fail */ |
818 | 798 |
goto end; |
... | ... |
@@ -963,8 +943,7 @@ static void tcpconn_destroy(struct tcp_connection* tcpconn) |
963 | 943 |
int fd; |
964 | 944 |
|
965 | 945 |
TCPCONN_LOCK; /*avoid races w/ tcp_send*/ |
966 |
- tcpconn->refcnt--; |
|
967 |
- if (tcpconn->refcnt==0){ |
|
946 |
+ if (atomic_dec_and_test(&tcpconn->refcnt)){ |
|
968 | 947 |
DBG("tcpconn_destroy: destroying connection %p, flags %04x\n", |
969 | 948 |
tcpconn, tcpconn->flags); |
970 | 949 |
fd=tcpconn->s; |
... | ... |
@@ -1209,7 +1188,7 @@ inline static int handle_tcp_child(struct tcp_child* tcp_c, int fd_i) |
1209 | 1188 |
io_watch_add(&io_h, tcpconn->s, F_TCPCONN, tcpconn); |
1210 | 1189 |
tcpconn->flags&=~F_CONN_REMOVED; |
1211 | 1190 |
DBG("handle_tcp_child: CONN_RELEASE %p refcnt= %d\n", |
1212 |
- tcpconn, tcpconn->refcnt); |
|
1191 |
+ tcpconn, atomic_get(&tcpconn->refcnt)); |
|
1213 | 1192 |
break; |
1214 | 1193 |
case CONN_ERROR: |
1215 | 1194 |
case CONN_DESTROY: |
... | ... |
@@ -1480,8 +1459,8 @@ static inline int handle_new_connect(struct socket_info* si) |
1480 | 1459 |
tcpconn->flags&=~F_CONN_REMOVED; |
1481 | 1460 |
tcpconn_add(tcpconn); |
1482 | 1461 |
#else |
1483 |
- tcpconn->refcnt++; /* safe, not yet available to the |
|
1484 |
- outside world */ |
|
1462 |
+ atomic_set(&tcpconn->refcnt, 1); /* safe, not yet available to the |
|
1463 |
+ outside world */ |
|
1485 | 1464 |
tcpconn_add(tcpconn); |
1486 | 1465 |
DBG("handle_new_connect: new connection: %p %d flags: %04x\n", |
1487 | 1466 |
tcpconn, tcpconn->s, tcpconn->flags); |
... | ... |
@@ -1623,7 +1602,8 @@ static inline void tcpconn_timeout(int force) |
1623 | 1602 |
c=tcpconn_id_hash[h]; |
1624 | 1603 |
while(c){ |
1625 | 1604 |
next=c->id_next; |
1626 |
- if (force ||((c->refcnt==0) && ((int)(ticks-c->timeout)>=0))){ |
|
1605 |
+ if (force ||((atomic_get(&c->refcnt)==0) && |
|
1606 |
+ ((int)(ticks-c->timeout)>=0))){ |
|
1627 | 1607 |
if (!force) |
1628 | 1608 |
DBG("tcpconn_timeout: timeout for hash=%d - %p" |
1629 | 1609 |
" (%d > %d)\n", h, c, ticks, c->timeout); |
... | ... |
@@ -1633,7 +1613,7 @@ static inline void tcpconn_timeout(int force) |
1633 | 1613 |
tls_close(c, fd); |
1634 | 1614 |
#endif |
1635 | 1615 |
_tcpconn_rm(c); |
1636 |
- if ((fd>0)&&(c->refcnt==0)) { |
|
1616 |
+ if ((fd>0)&&(atomic_get(&c->refcnt)==0)) { |
|
1637 | 1617 |
if (!(c->flags & F_CONN_REMOVED)){ |
1638 | 1618 |
io_watch_del(&io_h, fd, -1, IO_FD_CLOSING); |
1639 | 1619 |
c->flags|=F_CONN_REMOVED; |
... | ... |
@@ -754,7 +754,7 @@ void tcp_receive_loop(int unix_sock) |
754 | 754 |
LOG(L_CRIT, "BUG: tcp_receive_loop: duplicate" |
755 | 755 |
" connection received: %p, id %d, fd %d, refcnt %d" |
756 | 756 |
" state %d (n=%d)\n", con, con->id, con->fd, |
757 |
- con->refcnt, con->state, n); |
|
757 |
+ atomic_get(&con->refcnt), con->state, n); |
|
758 | 758 |
resp=CONN_ERROR; |
759 | 759 |
release_tcpconn(con, resp, unix_sock); |
760 | 760 |
goto skip; /* try to recover */ |
... | ... |
@@ -767,7 +767,8 @@ skip: |
767 | 767 |
c_next=con->c_next; /* safe for removing*/ |
768 | 768 |
#ifdef EXTRA_DEBUG |
769 | 769 |
DBG("tcp receive: list fd=%d, id=%d, timeout=%d, refcnt=%d\n", |
770 |
- con->fd, con->id, con->timeout, con->refcnt); |
|
770 |
+ con->fd, con->id, con->timeout, |
|
771 |
+ atomic_get(&con->refcnt)); |
|
771 | 772 |
#endif |
772 | 773 |
if (con->state<0){ |
773 | 774 |
/* S_CONN_BAD or S_CONN_ERROR, remove it */ |
... | ... |
@@ -869,7 +870,7 @@ again: |
869 | 870 |
LOG(L_CRIT, "BUG: tcp_receive: handle_io: duplicate" |
870 | 871 |
" connection received: %p, id %d, fd %d, refcnt %d" |
871 | 872 |
" state %d (n=%d)\n", con, con->id, con->fd, |
872 |
- con->refcnt, con->state, n); |
|
873 |
+ atomic_get(&con->refcnt), con->state, n); |
|
873 | 874 |
release_tcpconn(con, CONN_ERROR, tcpmain_sock); |
874 | 875 |
break; /* try to recover */ |
875 | 876 |
} |
... | ... |
@@ -34,9 +34,6 @@ |
34 | 34 |
|
35 | 35 |
/* "public" functions*/ |
36 | 36 |
|
37 |
-struct tcp_connection* tcpconn_get(int id, struct ip_addr* ip, int port, |
|
38 |
- int timeout); |
|
39 |
-void tcpconn_put(struct tcp_connection* c); |
|
40 | 37 |
int tcp_send(struct dest_info* dst, char* buf, unsigned len); |
41 | 38 |
|
42 | 39 |
int tcpconn_add_alias(int id, int port, int proto); |