Browse code

- high connection number deadlock fix (tested with 50k open tcp connections) - experimental queue send fd ops code WARNING: lightly tested

Andrei Pelinescu-Onciul authored on 30/01/2006 19:24:30
Showing 1 changed files
... ...
@@ -59,7 +59,10 @@
59 59
  *  2005-07-08  tcp_max_connections, tcp_connection_lifetime, don't accept
60 60
  *               more connections if tcp_max_connections is exceeded (andrei)
61 61
  *  2005-10-21  cleanup all the open connections on exit
62
- *              decrement the no. of open connections on timeout too    (andrei)
62
+ *              decrement the no. of open connections on timeout too    (andrei) *  2006-01-30  queue send_fd request and execute them at the end of the
63
+ *              poll loop  (#ifdef) (andrei)
64
+ *              process all children requests, before attempting to send
65
+ *              them new stuff (fixes some deadlocks) (andrei)
63 66
  */
64 67
 
65 68
 
... ...
@@ -119,6 +122,13 @@
119 119
 
120 120
 #define MAX_TCP_CHILDREN 100
121 121
 
122
+/* #define SEND_FD_QUEUE */ /* queue send fd request, instead of sending 
123
+							   them immediately */
124
+#ifdef SEND_FD_QUEUE
125
+#define MAX_SEND_FD_QUEUE_SIZE	tcp_max_fd_no
126
+#define SEND_FD_QUEUE_SIZE		128  /* initial size */
127
+#define MAX_SEND_FD_RETRIES		3	 /* FIXME: increase */
128
+#endif
122 129
 
123 130
 
124 131
 enum fd_types { F_NONE, F_SOCKINFO /* a tcp_listen fd */,
... ...
@@ -911,7 +921,7 @@ int tcp_init(struct socket_info* sock_info)
911 911
 				strerror(errno));
912 912
 		goto error;
913 913
 	}
914
-	if (listen(sock_info->socket, 10)==-1){
914
+	if (listen(sock_info->socket, 1024)==-1){
915 915
 		LOG(L_ERR, "ERROR: tcp_init: listen(%x, %p, %d) on %s: %s\n",
916 916
 				sock_info->socket, &addr->s, 
917 917
 				(unsigned)sockaddru_len(*addr),
... ...
@@ -931,109 +941,134 @@ error:
931 931
 
932 932
 
933 933
 
934
-static int send2child(struct tcp_connection* tcpconn)
934
+#ifdef SEND_FD_QUEUE
935
+struct send_fd_info{
936
+	struct tcp_connection* tcp_conn;
937
+	int unix_sock;
938
+	int retries;
939
+};
940
+
941
+struct tcp_send_fd_q{
942
+	struct send_fd_info* data; /* buffer */
943
+	struct send_fd_info* crt;  /* pointer inside the buffer */
944
+	struct send_fd_info* end;  /* points after the last valid position */
945
+};
946
+
947
+
948
+static struct tcp_send_fd_q send2child_q;
949
+
950
+
951
+
952
+static int send_fd_queue_init(struct tcp_send_fd_q *q, unsigned int size)
935 953
 {
936
-	int i;
937
-	int min_busy;
938
-	int idx;
939
-	
940
-	min_busy=tcp_children[0].busy;
941
-	idx=0;
942
-	for (i=0; i<tcp_children_no; i++){
943
-		if (!tcp_children[i].busy){
944
-			idx=i;
945
-			min_busy=0;
946
-			break;
947
-		}else if (min_busy>tcp_children[i].busy){
948
-			min_busy=tcp_children[i].busy;
949
-			idx=i;
950
-		}
951
-	}
952
-	
953
-	tcp_children[idx].busy++;
954
-	tcp_children[idx].n_reqs++;
955
-	if (min_busy){
956
-		DBG("WARNING: send2child: no free tcp receiver, "
957
-				" connection passed to the least busy one (%d)\n",
958
-				min_busy);
959
-	}
960
-	DBG("send2child: to tcp child %d %d(%d), %p\n", idx, 
961
-					tcp_children[idx].proc_no,
962
-					tcp_children[idx].pid, tcpconn);
963
-	if (send_fd(tcp_children[idx].unix_sock, &tcpconn, sizeof(tcpconn),
964
-			tcpconn->s)<=0){
965
-		LOG(L_ERR, "ERROR: send2child: send_fd failed\n");
954
+	q->data=pkg_malloc(size*sizeof(struct send_fd_info));
955
+	if (q->data==0){
956
+		LOG(L_ERR, "ERROR: send_fd_queue_init: out of memory\n");
966 957
 		return -1;
967 958
 	}
968
-	
959
+	q->crt=&q->data[0];
960
+	q->end=&q->data[size];
969 961
 	return 0;
970 962
 }
971 963
 
964
+static void send_fd_queue_destroy(struct tcp_send_fd_q *q)
965
+{
966
+	if (q->data){
967
+		pkg_free(q->data);
968
+		q->data=0;
969
+		q->crt=q->end=0;
970
+	}
971
+}
972 972
 
973
-/* handles a new connection, called internally by tcp_main_loop/handle_io.
974
- * params: si - pointer to one of the tcp socket_info structures on which
975
- *              an io event was detected (connection attempt)
976
- * returns:  handle_* return convention: -1 on error, 0 on EAGAIN (no more
977
- *           io events queued), >0 on success. success/error refer only to
978
- *           the accept.
979
- */
980
-static inline int handle_new_connect(struct socket_info* si)
973
+
974
+
975
+static int init_send_fd_queues()
981 976
 {
982
-	union sockaddr_union su;
983
-	struct tcp_connection* tcpconn;
984
-	socklen_t su_len;
985
-	int new_sock;
977
+	if (send_fd_queue_init(&get_fd_q, SEND_FD_QUEUE_SIZE)!=0)
978
+		goto error;
979
+	if (send_fd_queue_init(&send2child_q, SEND_FD_QUEUE_SIZE)!=0)
980
+		goto error;
981
+	return 0;
982
+error:
983
+	LOG(L_ERR, "ERROR: init_send_fd_queues: init failed\n");
984
+	return -1;
985
+}
986
+
987
+
988
+
989
+static void destroy_send_fd_queues()
990
+{
991
+	send_fd_queue_destroy(&get_fd_q);
992
+	send_fd_queue_destroy(&send2child_q);
993
+}
994
+
995
+
996
+
997
+
998
+inline static int send_fd_queue_add(	struct tcp_send_fd_q* q, 
999
+										int unix_sock,
1000
+										struct tcp_connection *t)
1001
+{
1002
+	struct send_fd_info* tmp;
1003
+	unsigned long new_size;
986 1004
 	
987
-	/* got a connection on r */
988
-	su_len=sizeof(su);
989
-	new_sock=accept(si->socket, &(su.s), &su_len);
990
-	if (new_sock==-1){
991
-		if ((errno==EAGAIN)||(errno==EWOULDBLOCK))
992
-			return 0;
993
-		LOG(L_ERR,  "WARNING: handle_new_connect: error while accepting"
994
-				" connection(%d): %s\n", errno, strerror(errno));
995
-		return -1;
996
-	}
997
-	if (tcp_connections_no>=tcp_max_connections){
998
-		LOG(L_ERR, "ERROR: maximum number of connections exceeded: %d/%d\n",
999
-					tcp_connections_no, tcp_max_connections);
1000
-		close(new_sock);
1001
-		return 1; /* success, because the accept was succesfull */
1002
-	}
1003
-	if (init_sock_opt(new_sock)<0){
1004
-		LOG(L_ERR, "ERROR: handle_new_connect: init_sock_opt failed\n");
1005
-		close(new_sock);
1006
-		return 1; /* success, because the accept was succesfull */
1007
-	}
1005
+	if (q->crt>=q->end){
1006
+		new_size=q->end-&q->data[0];
1007
+		if (new_size< MAX_SEND_FD_QUEUE_SIZE/2){
1008
+			new_size*=2;
1009
+		}else new_size=MAX_SEND_FD_QUEUE_SIZE;
1010
+		if (q->crt>=&q->data[new_size]){
1011
+			LOG(L_ERR, "ERROR: send_fd_queue_add: queue full: %ld/%ld\n",
1012
+					q->crt-&q->data[0]-1, new_size);
1013
+			goto error;
1014
+		}
1015
+		LOG(L_CRIT, "INFO: send_fd_queue: queue full: %ld, extending to %ld\n",
1016
+				q->end-&q->data[0], new_size);
1017
+		tmp=pkg_realloc(q->data, new_size*sizeof(struct send_fd_info));
1018
+		if (tmp==0){
1019
+			LOG(L_ERR, "ERROR: send_fd_queue_add: out of memory\n");
1020
+			goto error;
1021
+		}
1022
+		q->crt=(q->crt-&q->data[0])+tmp;
1023
+		q->data=tmp;
1024
+		q->end=&q->data[new_size];
1025
+	}
1026
+	q->crt->tcp_conn=t;
1027
+	q->crt->unix_sock=unix_sock;
1028
+	q->crt->retries=0;
1029
+	q->crt++;
1030
+	return 0;
1031
+error:
1032
+	return -1;
1033
+}
1034
+
1035
+
1036
+
1037
+inline static void send_fd_queue_run(struct tcp_send_fd_q* q)
1038
+{
1039
+	struct send_fd_info* p;
1040
+	struct send_fd_info* t;
1008 1041
 	
1009
-	/* add socket to list */
1010
-	tcpconn=tcpconn_new(new_sock, &su, si, si->proto, S_CONN_ACCEPT);
1011
-	if (tcpconn){
1012
-		tcpconn->refcnt++; /* safe, not yet available to the
1013
-							  outside world */
1014
-		tcpconn_add(tcpconn);
1015
-		DBG("handle_new_connect: new connection: %p %d flags: %04x\n",
1016
-			tcpconn, tcpconn->s, tcpconn->flags);
1017
-		/* pass it to a child */
1018
-		if(send2child(tcpconn)<0){
1019
-			LOG(L_ERR,"ERROR: handle_new_connect: no children "
1020
-					"available\n");
1021
-			TCPCONN_LOCK;
1022
-			tcpconn->refcnt--;
1023
-			if (tcpconn->refcnt==0){
1024
-				close(tcpconn->s);
1025
-				_tcpconn_rm(tcpconn);
1026
-			}else tcpconn->timeout=0; /* force expire */
1027
-			TCPCONN_UNLOCK;
1042
+	for (p=t=&q->data[0]; p<q->crt; p++){
1043
+		if (send_fd(p->unix_sock, &(p->tcp_conn),
1044
+					sizeof(struct tcp_connection*), p->tcp_conn->s)<=0){
1045
+			if (/*FIXME: E_WOULD_BLOCK && */(p->retries<MAX_SEND_FD_RETRIES)){
1046
+				/* leave in queue for a future try */
1047
+				*t=*p;
1048
+				t->retries++;
1049
+				t++;
1050
+			}else{
1051
+				LOG(L_ERR, "ERROR: rund_send_fd_queue: send_fd failed"
1052
+						   "on %d socket, %ld queue entry, retries %d \n",
1053
+						   p->unix_sock, p-&q->data[0], p->retries);
1054
+			}
1028 1055
 		}
1029
-	}else{ /*tcpconn==0 */
1030
-		LOG(L_ERR, "ERROR: handle_new_connect: tcpconn_new failed, "
1031
-				"closing socket\n");
1032
-		close(new_sock);
1033
-		
1034 1056
 	}
1035
-	return 1; /* accept() was succesfull */
1057
+	q->crt=t;
1036 1058
 }
1059
+#else
1060
+#define send_fd_queue_run(q)
1061
+#endif
1037 1062
 
1038 1063
 
1039 1064
 
... ...
@@ -1069,61 +1104,6 @@ static void tcpconn_destroy(struct tcp_connection* tcpconn)
1069 1069
 
1070 1070
 
1071 1071
 
1072
-/* handles an io event on one of the watched tcp connections
1073
- * 
1074
- * params: tcpconn - pointer to the tcp_connection for which we have an io ev.
1075
- *         fd_i    - index in the fd_array table (needed for delete)
1076
- * returns:  handle_* return convention, but on success it always returns 0
1077
- *           (because it's one-shot, after a succesfull execution the fd is
1078
- *            removed from tcp_main's watch fd list and passed to a child =>
1079
- *            tcp_main is not interested in further io events that might be
1080
- *            queued for this fd)
1081
- */
1082
-inline static int handle_tcpconn_ev(struct tcp_connection* tcpconn, int fd_i)
1083
-{
1084
-	int fd;
1085
-	
1086
-	/*  is refcnt!=0 really necessary? 
1087
-	 *  No, in fact it's a bug: I can have the following situation: a send only
1088
-	 *   tcp connection used by n processes simultaneously => refcnt = n. In 
1089
-	 *   the same time I can have a read event and this situation is perfectly
1090
-	 *   valid. -- andrei
1091
-	 */
1092
-#if 0
1093
-	if ((tcpconn->refcnt!=0)){
1094
-		/* FIXME: might be valid for sigio_rt iff fd flags are not cleared
1095
-		 *        (there is a short window in which it could generate a sig
1096
-		 *         that would be catched by tcp_main) */
1097
-		LOG(L_CRIT, "BUG: handle_tcpconn_ev: io event on referenced"
1098
-					" tcpconn (%p), refcnt=%d, fd=%d\n",
1099
-					tcpconn, tcpconn->refcnt, tcpconn->s);
1100
-		return -1;
1101
-	}
1102
-#endif
1103
-	/* pass it to child, so remove it from the io watch list */
1104
-	DBG("handle_tcpconn_ev: data available on %p %d\n", tcpconn, tcpconn->s);
1105
-	if (io_watch_del(&io_h, tcpconn->s, fd_i, 0)==-1) goto error;
1106
-	tcpconn->flags|=F_CONN_REMOVED;
1107
-	tcpconn_ref(tcpconn); /* refcnt ++ */
1108
-	if (send2child(tcpconn)<0){
1109
-		LOG(L_ERR,"ERROR: handle_tcpconn_ev: no children available\n");
1110
-		TCPCONN_LOCK;
1111
-		tcpconn->refcnt--;
1112
-		if (tcpconn->refcnt==0){
1113
-			fd=tcpconn->s;
1114
-			_tcpconn_rm(tcpconn);
1115
-			close(fd);
1116
-		}else tcpconn->timeout=0; /* force expire*/
1117
-		TCPCONN_UNLOCK;
1118
-	}
1119
-	return 0; /* we are not interested in possibly queued io events, 
1120
-				 the fd was either passed to a child, or closed */
1121
-error:
1122
-	return -1;
1123
-}
1124
-
1125
-
1126
-
1127 1072
 /* handles io from a tcp child process
1128 1073
  * params: tcp_c - pointer in the tcp_children array, to the entry for
1129 1074
  *                 which an io event was detected 
... ...
@@ -1357,6 +1337,186 @@ error:
1357 1357
 
1358 1358
 
1359 1359
 
1360
+/* sends a tcpconn + fd to a choosen child */
1361
+inline static int send2child(struct tcp_connection* tcpconn)
1362
+{
1363
+	int i;
1364
+	int min_busy;
1365
+	int idx;
1366
+	
1367
+	min_busy=tcp_children[0].busy;
1368
+	idx=0;
1369
+	for (i=0; i<tcp_children_no; i++){
1370
+		if (!tcp_children[i].busy){
1371
+			idx=i;
1372
+			min_busy=0;
1373
+			break;
1374
+		}else if (min_busy>tcp_children[i].busy){
1375
+			min_busy=tcp_children[i].busy;
1376
+			idx=i;
1377
+		}
1378
+	}
1379
+	
1380
+	tcp_children[idx].busy++;
1381
+	tcp_children[idx].n_reqs++;
1382
+	if (min_busy){
1383
+		DBG("WARNING: send2child: no free tcp receiver, "
1384
+				" connection passed to the least busy one (%d)\n",
1385
+				min_busy);
1386
+	}
1387
+	DBG("send2child: to tcp child %d %d(%d), %p\n", idx, 
1388
+					tcp_children[idx].proc_no,
1389
+					tcp_children[idx].pid, tcpconn);
1390
+	/* first make sure this child doesn't have pending request for
1391
+	 * tcp_main (to avoid a possible deadlock: e.g. child wants to
1392
+	 * send a release command, but the master fills its socket buffer
1393
+	 * with new connection commands => deadlock) */
1394
+	/* answer tcp_send requests first */
1395
+	while(handle_ser_child(&pt[tcp_children[idx].proc_no], -1)>0);
1396
+	/* process tcp readers requests */
1397
+	while(handle_tcp_child(&tcp_children[idx], -1)>0);
1398
+		
1399
+#ifdef SEND_FD_QUEUE
1400
+	if (send_fd_queue_add(&send2child_q, tcp_children[idx].unix_sock, 
1401
+						tcpconn)!=0){
1402
+		LOG(L_ERR, "ERROR: send2child: queue send op. failed\n");
1403
+		return -1;
1404
+	}
1405
+#else
1406
+	if (send_fd(tcp_children[idx].unix_sock, &tcpconn, sizeof(tcpconn),
1407
+			tcpconn->s)<=0){
1408
+		LOG(L_ERR, "ERROR: send2child: send_fd failed\n");
1409
+		return -1;
1410
+	}
1411
+#endif
1412
+	
1413
+	return 0;
1414
+}
1415
+
1416
+
1417
+
1418
+/* handles a new connection, called internally by tcp_main_loop/handle_io.
1419
+ * params: si - pointer to one of the tcp socket_info structures on which
1420
+ *              an io event was detected (connection attempt)
1421
+ * returns:  handle_* return convention: -1 on error, 0 on EAGAIN (no more
1422
+ *           io events queued), >0 on success. success/error refer only to
1423
+ *           the accept.
1424
+ */
1425
+static inline int handle_new_connect(struct socket_info* si)
1426
+{
1427
+	union sockaddr_union su;
1428
+	struct tcp_connection* tcpconn;
1429
+	socklen_t su_len;
1430
+	int new_sock;
1431
+	
1432
+	/* got a connection on r */
1433
+	su_len=sizeof(su);
1434
+	new_sock=accept(si->socket, &(su.s), &su_len);
1435
+	if (new_sock==-1){
1436
+		if ((errno==EAGAIN)||(errno==EWOULDBLOCK))
1437
+			return 0;
1438
+		LOG(L_ERR,  "WARNING: handle_new_connect: error while accepting"
1439
+				" connection(%d): %s\n", errno, strerror(errno));
1440
+		return -1;
1441
+	}
1442
+	if (tcp_connections_no>=tcp_max_connections){
1443
+		LOG(L_ERR, "ERROR: maximum number of connections exceeded: %d/%d\n",
1444
+					tcp_connections_no, tcp_max_connections);
1445
+		close(new_sock);
1446
+		return 1; /* success, because the accept was succesfull */
1447
+	}
1448
+	if (init_sock_opt(new_sock)<0){
1449
+		LOG(L_ERR, "ERROR: handle_new_connect: init_sock_opt failed\n");
1450
+		close(new_sock);
1451
+		return 1; /* success, because the accept was succesfull */
1452
+	}
1453
+	
1454
+	/* add socket to list */
1455
+	tcpconn=tcpconn_new(new_sock, &su, si, si->proto, S_CONN_ACCEPT);
1456
+	if (tcpconn){
1457
+		tcpconn->refcnt++; /* safe, not yet available to the
1458
+							  outside world */
1459
+		tcpconn_add(tcpconn);
1460
+		DBG("handle_new_connect: new connection: %p %d flags: %04x\n",
1461
+			tcpconn, tcpconn->s, tcpconn->flags);
1462
+		/* pass it to a child */
1463
+		if(send2child(tcpconn)<0){
1464
+			LOG(L_ERR,"ERROR: handle_new_connect: no children "
1465
+					"available\n");
1466
+			TCPCONN_LOCK;
1467
+			tcpconn->refcnt--;
1468
+			if (tcpconn->refcnt==0){
1469
+				close(tcpconn->s);
1470
+				_tcpconn_rm(tcpconn);
1471
+			}else tcpconn->timeout=0; /* force expire */
1472
+			TCPCONN_UNLOCK;
1473
+		}
1474
+	}else{ /*tcpconn==0 */
1475
+		LOG(L_ERR, "ERROR: handle_new_connect: tcpconn_new failed, "
1476
+				"closing socket\n");
1477
+		close(new_sock);
1478
+		
1479
+	}
1480
+	return 1; /* accept() was succesfull */
1481
+}
1482
+
1483
+
1484
+
1485
+/* handles an io event on one of the watched tcp connections
1486
+ * 
1487
+ * params: tcpconn - pointer to the tcp_connection for which we have an io ev.
1488
+ *         fd_i    - index in the fd_array table (needed for delete)
1489
+ * returns:  handle_* return convention, but on success it always returns 0
1490
+ *           (because it's one-shot, after a succesfull execution the fd is
1491
+ *            removed from tcp_main's watch fd list and passed to a child =>
1492
+ *            tcp_main is not interested in further io events that might be
1493
+ *            queued for this fd)
1494
+ */
1495
+inline static int handle_tcpconn_ev(struct tcp_connection* tcpconn, int fd_i)
1496
+{
1497
+	int fd;
1498
+	
1499
+	/*  is refcnt!=0 really necessary? 
1500
+	 *  No, in fact it's a bug: I can have the following situation: a send only
1501
+	 *   tcp connection used by n processes simultaneously => refcnt = n. In 
1502
+	 *   the same time I can have a read event and this situation is perfectly
1503
+	 *   valid. -- andrei
1504
+	 */
1505
+#if 0
1506
+	if ((tcpconn->refcnt!=0)){
1507
+		/* FIXME: might be valid for sigio_rt iff fd flags are not cleared
1508
+		 *        (there is a short window in which it could generate a sig
1509
+		 *         that would be catched by tcp_main) */
1510
+		LOG(L_CRIT, "BUG: handle_tcpconn_ev: io event on referenced"
1511
+					" tcpconn (%p), refcnt=%d, fd=%d\n",
1512
+					tcpconn, tcpconn->refcnt, tcpconn->s);
1513
+		return -1;
1514
+	}
1515
+#endif
1516
+	/* pass it to child, so remove it from the io watch list */
1517
+	DBG("handle_tcpconn_ev: data available on %p %d\n", tcpconn, tcpconn->s);
1518
+	if (io_watch_del(&io_h, tcpconn->s, fd_i, 0)==-1) goto error;
1519
+	tcpconn->flags|=F_CONN_REMOVED;
1520
+	tcpconn_ref(tcpconn); /* refcnt ++ */
1521
+	if (send2child(tcpconn)<0){
1522
+		LOG(L_ERR,"ERROR: handle_tcpconn_ev: no children available\n");
1523
+		TCPCONN_LOCK;
1524
+		tcpconn->refcnt--;
1525
+		if (tcpconn->refcnt==0){
1526
+			fd=tcpconn->s;
1527
+			_tcpconn_rm(tcpconn);
1528
+			close(fd);
1529
+		}else tcpconn->timeout=0; /* force expire*/
1530
+		TCPCONN_UNLOCK;
1531
+	}
1532
+	return 0; /* we are not interested in possibly queued io events, 
1533
+				 the fd was either passed to a child, or closed */
1534
+error:
1535
+	return -1;
1536
+}
1537
+
1538
+
1539
+
1360 1540
 /* generic handle io routine, it will call the appropiate
1361 1541
  *  handle_xxx() based on the fd_map type
1362 1542
  *
... ...
@@ -1515,6 +1675,7 @@ void tcp_main_loop()
1515 1515
 			while(1){
1516 1516
 				/* wait and process IO */
1517 1517
 				io_wait_loop_poll(&io_h, TCP_MAIN_SELECT_TIMEOUT, 0); 
1518
+				send_fd_queue_run(&send2child_q); /* then new io */
1518 1519
 				/* remove old connections */
1519 1520
 				tcpconn_timeout(0);
1520 1521
 			}
... ...
@@ -1523,6 +1684,7 @@ void tcp_main_loop()
1523 1523
 		case POLL_SELECT:
1524 1524
 			while(1){
1525 1525
 				io_wait_loop_select(&io_h, TCP_MAIN_SELECT_TIMEOUT, 0);
1526
+				send_fd_queue_run(&send2child_q); /* then new io */
1526 1527
 				tcpconn_timeout(0);
1527 1528
 			}
1528 1529
 			break;
... ...
@@ -1531,6 +1693,7 @@ void tcp_main_loop()
1531 1531
 		case POLL_SIGIO_RT:
1532 1532
 			while(1){
1533 1533
 				io_wait_loop_sigio_rt(&io_h, TCP_MAIN_SELECT_TIMEOUT);
1534
+				send_fd_queue_run(&send2child_q); /* then new io */
1534 1535
 				tcpconn_timeout(0);
1535 1536
 			}
1536 1537
 			break;
... ...
@@ -1539,12 +1702,14 @@ void tcp_main_loop()
1539 1539
 		case POLL_EPOLL_LT:
1540 1540
 			while(1){
1541 1541
 				io_wait_loop_epoll(&io_h, TCP_MAIN_SELECT_TIMEOUT, 0);
1542
+				send_fd_queue_run(&send2child_q); /* then new io */
1542 1543
 				tcpconn_timeout(0);
1543 1544
 			}
1544 1545
 			break;
1545 1546
 		case POLL_EPOLL_ET:
1546 1547
 			while(1){
1547 1548
 				io_wait_loop_epoll(&io_h, TCP_MAIN_SELECT_TIMEOUT, 1);
1549
+				send_fd_queue_run(&send2child_q); /* then new io */
1548 1550
 				tcpconn_timeout(0);
1549 1551
 			}
1550 1552
 			break;
... ...
@@ -1553,6 +1718,7 @@ void tcp_main_loop()
1553 1553
 		case POLL_KQUEUE:
1554 1554
 			while(1){
1555 1555
 				io_wait_loop_kqueue(&io_h, TCP_MAIN_SELECT_TIMEOUT, 0);
1556
+				send_fd_queue_run(&send2child_q); /* then new io */
1556 1557
 				tcpconn_timeout(0);
1557 1558
 			}
1558 1559
 			break;
... ...
@@ -1561,6 +1727,7 @@ void tcp_main_loop()
1561 1561
 		case POLL_DEVPOLL:
1562 1562
 			while(1){
1563 1563
 				io_wait_loop_devpoll(&io_h, TCP_MAIN_SELECT_TIMEOUT, 0);
1564
+				send_fd_queue_run(&send2child_q); /* then new io */
1564 1565
 				tcpconn_timeout(0);
1565 1566
 			}
1566 1567
 			break;
... ...
@@ -1600,6 +1767,9 @@ void destroy_tcp()
1600 1600
 			lock_dealloc((void*)tcpconn_lock);
1601 1601
 			tcpconn_lock=0;
1602 1602
 		}
1603
+#ifdef SEND_FD_QUEUE
1604
+		destroy_send_fd_queues();
1605
+#endif
1603 1606
 }
1604 1607
 
1605 1608
 
... ...
@@ -1645,7 +1815,14 @@ int init_tcp()
1645 1645
 			TCP_ALIAS_HASH_SIZE * sizeof(struct tcp_conn_alias*));
1646 1646
 	memset((void*)tcpconn_id_hash, 0, 
1647 1647
 			TCP_ID_HASH_SIZE * sizeof(struct tcp_connection*));
1648
+	/* init send fd queues */
1648 1649
 	
1650
+#ifdef SEND_FD_QUEUE
1651
+	if (init_send_fd_queues()<0){
1652
+		LOG(L_CRIT, "ERROR: init_tcp: could not init send fd queues\n");
1653
+		goto error;
1654
+	}
1655
+#endif
1649 1656
 	/* fix config variables */
1650 1657
 	/* they can have only positive values due the config parser so we can
1651 1658
 	 * ignore most of them */