Procházet zdrojové kódy

- more tcp stuff (uses locking.h, hashtables, mostly untested)
- main exit cleanups (created cleanup(show_status() function that should prepare ser for exiting: dellocate everything, free sems a.s.o).

Andrei Pelinescu-Onciul před 22 roky
rodič
revize
8aeb47e2ed
11 změnil soubory, kde provedl 235 přidání a 79 odebrání
  1. 2 2
      Makefile.defs
  2. 3 1
      TODO
  3. 1 0
      ip_addr.h
  4. 7 6
      locking.h
  5. 40 14
      main.c
  6. 1 0
      sr_module.c
  7. 23 4
      tcp_conn.h
  8. 1 0
      tcp_init.h
  9. 143 51
      tcp_main.c
  10. 13 1
      timer.c
  11. 1 0
      timer.h

+ 2 - 2
Makefile.defs

@@ -8,7 +8,7 @@
 VERSION = 0
 PATCHLEVEL = 8
 SUBLEVEL =   11
-EXTRAVERSION = pre4-tcp0-locking
+EXTRAVERSION = pre4-tcp1-locking
 
 RELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 OS = $(shell uname -s | sed -e s/SunOS/solaris/ | tr "[A-Z]" "[a-z]")
@@ -150,7 +150,7 @@ DEFS+= -DNAME='"$(NAME)"' -DVERSION='"$(RELEASE)"' -DARCH='"$(ARCH)"' \
 	 -DDNS_IP_HACK \
 	 -DUSE_IPV6 \
 	 -DDBG_QM_MALLOC \
-	 # -DUSE_TCP \
+	 -DUSE_TCP \
 	 #-DF_MALLOC \
 	 #-DNO_DEBUG \
 	 #-DNO_LOG

+ 3 - 1
TODO

@@ -16,7 +16,7 @@ x (different way) add request header bitmap field for the modules
 
 
 High priority:
-- parse_uri should not copy anymore the uri members (and it should not 0
+x- parse_uri should not copy anymore the uri members (and it should not 0
  terminate them anylonger).
 x fix/replace T_REF/T_UNREF
 x review all the tm locking
@@ -66,3 +66,5 @@ x freopen stdin, stdout, stderr to /dev/null
 - add a section on building ser & configuring it for maximum performance
  (-DF_MALLOC, -DNO_DBG, ... sip_warning=0, a.s.o)
 - add src_port, dst_port, proto to cfg.{y,lex}
+x generic locking lib
+- convert tm to use new locking lib

+ 1 - 0
ip_addr.h

@@ -49,6 +49,7 @@ struct ip_addr{
 	
 	/* 64 bits alligned address */
 	union {
+		unsigned long  addrl[16/sizeof(long)]; /* long format*/
 		unsigned int   addr32[4];
 		unsigned short addr16[8];
 		unsigned char  addr[16];

+ 7 - 6
locking.h

@@ -44,12 +44,6 @@ Implements:
 #ifndef _locking_h
 #define _locking_h
 
-#include "mem/mem.h"
-#ifdef SHM_MEM
-#include "mem/shm_mem.h"
-#else
-#error "locking requires shared memroy support"
-#endif
 
 #ifdef FAST_LOCK
 #include "fastlock.h"
@@ -179,5 +173,12 @@ inline static void lock_release(lock_t* lock)
 #endif
 
 
+/*shm_{malloc, free}*/
+#include "mem/mem.h"
+#ifdef SHM_MEM
+#include "mem/shm_mem.h"
+#else
+#error "locking requires shared memroy support"
+#endif
 
 #endif

+ 40 - 14
main.c

@@ -326,6 +326,38 @@ int is_main=0; /* flag = is this the  "main" process? */
 
 char* pid_file = 0; /* filename as asked by use */
 
+
+
+/* callit before exiting; if show_status==1, mem status is displayed */
+void cleanup(show_status)
+{
+	/*clean-up*/
+	destroy_modules();
+#ifdef USE_TCP
+	destroy_tcp();
+#endif
+	destroy_timer();
+#ifdef PKG_MALLOC
+	if (show_status){
+		LOG(memlog, "Memory status (pkg):\n");
+		pkg_status();
+	}
+#endif
+#ifdef SHM_MEM
+	shm_free(pt);
+	pt=0;
+	if (show_status){
+			LOG(memlog, "Memory status (shm):\n");
+			shm_status();
+	}
+	/* zero all shmem alloc vars that we still use */
+	shm_mem_destroy();
+#endif
+	if (pid_file) unlink(pid_file);
+}
+
+
+
 /* daemon init, return 0 on success, -1 on error */
 int daemonize(char*  name)
 {
@@ -472,20 +504,8 @@ void handle_sigs()
 
 			     /* Wait for all the children to die */
 			while(wait(0) > 0);
-
-			destroy_modules();
-#ifdef PKG_MALLOC
-			LOG(memlog, "Memory status (pkg):\n");
-			pkg_status();
-#endif
-#ifdef SHM_MEM
-			LOG(memlog, "Memory status (shm):\n");
-			shm_status();
-			/* zero all shmem alloc vars that we still use */
-			pt=0;
-			shm_mem_destroy();
-#endif
-			if (pid_file) unlink(pid_file);
+			
+			cleanup(1); /* cleanup & show status*/
 			dprint("Thank you for flying " NAME "\n");
 			exit(0);
 			break;
@@ -531,6 +551,8 @@ void handle_sigs()
 #endif
 			/* exit */
 			kill(0, SIGTERM);
+			while(wait(0) > 0); /* wait for all the children to terminate*/
+			cleanup(1); /* cleanup & show status*/
 			DBG("terminating due to SIGCHLD\n");
 			exit(0);
 			break;
@@ -1558,11 +1580,15 @@ try_again:
 	ret=main_loop();
 	/*kill everything*/
 	kill(0, SIGTERM);
+	/*clean-up*/
+	cleanup(0);
 	return ret;
 
 error:
 	/*kill everything*/
 	kill(0, SIGTERM);
+	/*clean-up*/
+	cleanup(0);
 	return -1;
 
 }

+ 1 - 0
sr_module.c

@@ -256,6 +256,7 @@ void destroy_modules()
 
 	for(t=modules;t;t=t->next)
 		if  ((t->exports)&&(t->exports->destroy_f)) t->exports->destroy_f();
+	modules=0;
 }
 
 #ifdef NO_REVERSE_INIT

+ 23 - 4
tcp_conn.h

@@ -89,8 +89,12 @@ struct tcp_connection{
 	struct tcp_req req; /* request data */
 	int refcnt;
 	int timeout; /* connection timeout, after this it will be removed*/
+	unsigned addr_hash; /* hash indexes in thge 2 tables */
+	unsigned id_hash;
 	struct tcp_connection* next; /* next, prev in hash table, used by "main" */
 	struct tcp_connection* prev;
+	struct tcp_connection* id_next; /* next, prev in id hash table */
+	struct tcp_connection* id_prev;
 	struct tcp_connection* c_next; /* child next prev (use locally) */
 	struct tcp_connection* c_prev;
 };
@@ -128,11 +132,26 @@ struct tcp_connection{
 	}while(0)
 
 
-#define TCPCONN_LOCK LOG(L_CRIT, "LOCK not implemented yet: %s : %d: %s\n", \
-							__FILE__, __LINE__, __FUNCTION__);
-#define TCPCONN_UNLOCK LOG(L_CRIT, "UNLOCK not implemented yet: %s: %d: %s\n",\
-							__FILE__, __LINE__, __FUNCTION__);
+#define TCPCONN_LOCK lock_get(tcpconn_lock);
+#define TCPCONN_UNLOCK lock_release(tcpconn_lock);
 
+#define TCP_ADDR_HASH_SIZE 1024
+#define TCP_ID_HASH_SIZE 1024
+
+static inline unsigned tcp_addr_hash(struct ip_addr* ip, unsigned short port)
+{
+	if(ip->len==4) return (ip->u.addr32[0]^port)&(TCP_ADDR_HASH_SIZE-1);
+	else if (ip->len==16) 
+			return (ip->u.addr32[0]^ip->u.addr32[1]^ip->u.addr32[2]^
+					ip->u.addr32[3]^port) & (TCP_ADDR_HASH_SIZE-1);
+	else{
+		LOG(L_CRIT, "tcp_addr_hash: BUG: bad len %d for an ip address\n",
+				ip->len);
+		return 0;
+	}
+}
+
+#define tcp_id_hash(id) (id&(TCP_ID_HASH_SIZE-1))
 
 
 #endif

+ 1 - 0
tcp_init.h

@@ -30,6 +30,7 @@
 #include "ip_addr.h"
 
 int init_tcp();
+void destroy_tcp();
 int tcp_init(struct socket_info* sock_info);
 int tcp_init_children();
 void tcp_main_loop();

+ 143 - 51
tcp_main.c

@@ -51,6 +51,7 @@
 #include "tcp_conn.h"
 #include "globals.h"
 #include "pt.h"
+#include "locking.h"
 #include "mem/mem.h"
 #include "mem/shm_mem.h"
 #include "timer.h"
@@ -59,6 +60,7 @@
 
 
 
+
 #define local_malloc pkg_malloc
 #define local_free   pkg_free
 
@@ -73,7 +75,12 @@ struct tcp_child{
 
 
 
-struct tcp_connection** conn_list=0;
+/* connection hash table (after ip&port) */
+struct tcp_connection** tcpconn_addr_hash=0;
+/* connection hash table (after connection id) */
+struct tcp_connection** tcpconn_id_hash=0;
+lock_t* tcpconn_lock=0;
+
 struct tcp_child tcp_children[MAX_TCP_CHILDREN];
 static int connection_id=1; /*  unique for each connection, used for 
 								quickly finding the corresponding connection
@@ -143,11 +150,24 @@ error:
 
 struct tcp_connection*  tcpconn_add(struct tcp_connection *c)
 {
-	TCPCONN_LOCK;
-	/* add it at the begining of the list*/
-	if (c) tcpconn_listadd(*conn_list, c, next, prev);
-	TCPCONN_UNLOCK;
-	return c;
+	unsigned hash;
+
+	if (c){
+		TCPCONN_LOCK;
+		/* add it at the begining of the list*/
+		hash=tcp_addr_hash(&c->rcv.src_ip, c->rcv.src_port);
+		c->addr_hash=hash;
+		tcpconn_listadd(tcpconn_addr_hash[hash], c, next, prev);
+		hash=tcp_id_hash(c->id);
+		c->id_hash=hash;
+		tcpconn_listadd(tcpconn_id_hash[hash], c, id_next, id_prev);
+		TCPCONN_UNLOCK;
+		DBG("tcpconn_add: hashes: %d, %d\n", c->addr_hash, c->id_hash);
+		return c;
+	}else{
+		LOG(L_CRIT, "tcpconn_add: BUG: null connection pointer\n");
+		return 0;
+	}
 }
 
 
@@ -155,39 +175,52 @@ struct tcp_connection*  tcpconn_add(struct tcp_connection *c)
 void tcpconn_rm(struct tcp_connection* c)
 {
 	TCPCONN_LOCK;
-	tcpconn_listrm(*conn_list, c, next, prev);
+	tcpconn_listrm(tcpconn_addr_hash[c->addr_hash], c, next, prev);
+	tcpconn_listrm(tcpconn_id_hash[c->id_hash], c, id_next, id_prev);
 	TCPCONN_UNLOCK;
 	shm_free(c);
 }
 
 
-/* finds a connection, if id=0 uses the ip addr & port */
-struct tcp_connection* tcpconn_find(int id, struct ip_addr* ip, int port)
+/* finds a connection, if id=0 uses the ip addr & port
+ * WARNING: unprotected (locks) use tcpconn_get unless you really
+ * know what you are doing */
+struct tcp_connection* _tcpconn_find(int id, struct ip_addr* ip, int port)
 {
 
 	struct tcp_connection *c;
+	unsigned hash;
 	
 	DBG("tcpconn_find: %d ",id ); print_ip(ip); DBG(" %d\n", ntohs(port));
-	for (c=*conn_list; c; c=c->next){
-		DBG("c=%p, c->id=%d, ip=",c, c->id);
-		print_ip(&c->rcv.src_ip);
-		DBG(" port=%d\n", ntohs(c->rcv.src_port));
-		if (id){
+	if (id){
+		hash=tcp_id_hash(id);
+		for (c=tcpconn_id_hash[hash]; c; c=c->id_next){
+			DBG("c=%p, c->id=%d, ip=",c, c->id);
+			print_ip(&c->rcv.src_ip);
+			DBG(" port=%d\n", ntohs(c->rcv.src_port));
 			if (id==c->id) return c;
-		}else if (ip &&	(port==c->rcv.src_port)&&
-					(ip_addr_cmp(ip, &c->rcv.src_ip)))
-			return c;
+		}
+	}else if (ip){
+		hash=tcp_addr_hash(ip, port);
+		for (c=tcpconn_addr_hash[hash]; c; c=c->next){
+			DBG("c=%p, c->id=%d, ip=",c, c->id);
+			print_ip(&c->rcv.src_ip);
+			DBG(" port=%d\n", ntohs(c->rcv.src_port));
+			if ( (port==c->rcv.src_port) && (ip_addr_cmp(ip, &c->rcv.src_ip)) )
+				return c;
+		}
 	}
 	return 0;
 }
 
 
 
+/* _tcpconn_find with locks */
 struct tcp_connection* tcpconn_get(int id, struct ip_addr* ip, int port)
 {
 	struct tcp_connection* c;
 	TCPCONN_LOCK;
-	c=tcpconn_find(id, ip, port);
+	c=_tcpconn_find(id, ip, port);
 	if (c) c->refcnt++;
 	TCPCONN_UNLOCK;
 	return c;
@@ -275,27 +308,30 @@ send_it:
 
 
 
-/* very ineficient for now, use hashtable some day - FIXME*/
+/* very ineficient for now - FIXME*/
 void tcpconn_timeout(fd_set* set)
 {
 	struct tcp_connection *c, *next;
-	int ticks;;
+	int ticks;
+	unsigned h;;
 	
 	
 	ticks=get_ticks();
-	c=*conn_list;
-	while(c){
-		next=c->next;
-		if ((c->refcnt==0) && (ticks>c->timeout)) {
-			DBG("tcpconn_timeout: timeout for %p (%d > %d)\n",
-					c, ticks, c->timeout);
-			if (c->s>0) {
-				FD_CLR(c->s, set);
-				close(c->s);
+	for(h=0; h<TCP_ADDR_HASH_SIZE; h++){
+		c=tcpconn_addr_hash[h];
+		while(c){
+			next=c->next;
+			if ((c->refcnt==0) && (ticks>c->timeout)) {
+				DBG("tcpconn_timeout: timeout for hash=%d - %p (%d > %d)\n",
+						h, c, ticks, c->timeout);
+				if (c->s>0) {
+					FD_CLR(c->s, set);
+					close(c->s);
+				}
+				tcpconn_rm(c);
 			}
-			tcpconn_rm(c);
+			c=next;
 		}
-		c=next;
 	}
 }
 
@@ -390,6 +426,7 @@ void tcp_main_loop()
 	int new_sock;
 	union sockaddr_union su;
 	struct tcp_connection* tcpconn;
+	unsigned h;
 	long response[2];
 	int cmd;
 	int bytes;
@@ -459,24 +496,26 @@ void tcp_main_loop()
 			}
 		}
 		
-		/* check all the read fds (from the tcpconn list) */
-		
-		for(tcpconn=*conn_list; tcpconn && n; tcpconn=tcpconn->next){
-			if ((tcpconn->refcnt==0)&&(FD_ISSET(tcpconn->s, &sel_set))){
-				/* new data available */
-				n--;
-				/* pass it to child, so remove it from select list */
-				DBG("tcp_main_loop: data available on %p %d\n",
-						tcpconn, tcpconn->s);
-				FD_CLR(tcpconn->s, &master_set);
-				if (send2child(tcpconn)<0){
-					LOG(L_ERR,"ERROR: tcp_main_loop: no children available\n");
-					close(tcpconn->s);
-					tcpconn_rm(tcpconn);
+		/* check all the read fds (from the tcpconn_addr_hash ) */
+		for (h=0; h<TCP_ADDR_HASH_SIZE; h++){
+			for(tcpconn=tcpconn_addr_hash[h]; tcpconn && n; 
+					tcpconn=tcpconn->next){
+				if ((tcpconn->refcnt==0)&&(FD_ISSET(tcpconn->s, &sel_set))){
+					/* new data available */
+					n--;
+					/* pass it to child, so remove it from select list */
+					DBG("tcp_main_loop: data available on %p [h:%d] %d\n",
+							tcpconn, h, tcpconn->s);
+					FD_CLR(tcpconn->s, &master_set);
+					if (send2child(tcpconn)<0){
+						LOG(L_ERR,"ERROR: tcp_main_loop: no "
+									"children available\n");
+						close(tcpconn->s);
+						tcpconn_rm(tcpconn);
+					}
 				}
 			}
 		}
-		
 		/* check unix sockets & listen | destroy connections */
 		/* start from 1, the "main" process does not transmit anything*/
 		for (r=1; r<process_no && n; r++){
@@ -589,13 +628,46 @@ read_again:
 
 int init_tcp()
 {
-	/* allocate list head*/
-	conn_list=shm_malloc(sizeof(struct tcp_connection*));
-	if (conn_list==0){
-		LOG(L_CRIT, "ERROR: init_tcp: memory allocation failure\n");
+	/* init lock */
+	tcpconn_lock=lock_alloc();
+	if (tcpconn_lock==0){
+		LOG(L_CRIT, "ERROR: init_tcp: could not alloc lock\n");
+		goto error;
+	}
+	if (lock_init(tcpconn_lock)==0){
+		LOG(L_CRIT, "ERROR: init_tcp: could not init lock\n");
+		lock_dealloc((void*)tcpconn_lock);
+		tcpconn_lock=0;
+		goto error;
+	}
+	/* alloc hashtables*/
+	tcpconn_addr_hash=(struct tcp_connection**)shm_malloc(TCP_ADDR_HASH_SIZE*
+								sizeof(struct tcp_connection*));
+
+	if (tcpconn_addr_hash==0){
+		LOG(L_CRIT, "ERROR: init_tcp: could not alloc address hashtable\n");
+		lock_destroy(tcpconn_lock);
+		lock_dealloc((void*)tcpconn_lock);
+		tcpconn_lock=0;
+		goto error;
+	}
+	
+	tcpconn_id_hash=(struct tcp_connection**)shm_malloc(TCP_ID_HASH_SIZE*
+								sizeof(struct tcp_connection*));
+	if (tcpconn_id_hash==0){
+		LOG(L_CRIT, "ERROR: init_tcp: could not alloc id hashtable\n");
+		shm_free(tcpconn_addr_hash);
+		tcpconn_addr_hash=0;
+		lock_destroy(tcpconn_lock);
+		lock_dealloc((void*)tcpconn_lock);
+		tcpconn_lock=0;
 		goto error;
 	}
-	*conn_list=0;
+	/* init hashtables*/
+	memset((void*)tcpconn_addr_hash, 0, 
+			TCP_ADDR_HASH_SIZE * sizeof(struct tcp_connection*));
+	memset((void*)tcpconn_id_hash, 0, 
+			TCP_ID_HASH_SIZE * sizeof(struct tcp_connection*));
 	return 0;
 error:
 		return -1;
@@ -603,6 +675,26 @@ error:
 
 
 
+/* cleanup before exit */
+void destroy_tcp()
+{
+	if (tcpconn_lock){
+		lock_destroy(tcpconn_lock);
+		lock_dealloc((void*)tcpconn_lock);
+		tcpconn_lock=0;
+	}
+	if(tcpconn_addr_hash){
+		shm_free(tcpconn_addr_hash);
+		tcpconn_addr_hash=0;
+	}
+	if(tcpconn_id_hash){
+		shm_free(tcpconn_id_hash);
+		tcpconn_id_hash=0;
+	}
+}
+
+
+
 /* starts the tcp processes */
 int tcp_init_children()
 {

+ 13 - 1
timer.c

@@ -66,7 +66,19 @@ int init_timer()
 
 
 
-	
+void destroy_timer()
+{
+	if (jiffies){
+#ifdef SHM_MEM
+		shm_free(jiffies); jiffies=0;
+#else
+		free(jiffies); jiffies=0;
+#endif
+	}
+}
+
+
+
 /*register a periodic timer;
  * ret: <0 on error*/
 int register_timer(timer_function f, void* param, unsigned int interval)

+ 1 - 0
timer.h

@@ -54,6 +54,7 @@ extern struct sr_timer* timer_list;
 
 
 int init_timer();
+void destroy_timer();
 /*register a periodic timer;
  * ret: <0 on errror*/
 int register_timer(timer_function f, void* param, unsigned int interval);