MEDIUM: threads/lb: Make LB algorithms (lb_*.c) thread-safe

A lock for LB parameters has been added inside the proxy structure and atomic
operations have been used to update server variables releated to lb.

The only significant change is about lb_map. Because the servers status are
updated in the sync-point, we can call recalc_server_map function synchronously
in map_set_server_status_up/down function.
diff --git a/src/lb_map.c b/src/lb_map.c
index fef16ac..028e85b 100644
--- a/src/lb_map.c
+++ b/src/lb_map.c
@@ -19,6 +19,7 @@
 #include <types/server.h>
 
 #include <proto/backend.h>
+#include <proto/lb_map.h>
 #include <proto/proto_http.h>
 #include <proto/proto_tcp.h>
 #include <proto/queue.h>
@@ -37,7 +38,7 @@
 	/* FIXME: could be optimized since we know what changed */
 	recount_servers(p);
 	update_backend_weight(p);
-	p->lbprm.map.state |= LB_MAP_RECALC;
+	recalc_server_map(p);
  out_update_state:
 	srv_lb_commit_status(srv);
 }
@@ -56,7 +57,7 @@
 	/* FIXME: could be optimized since we know what changed */
 	recount_servers(p);
 	update_backend_weight(p);
-	p->lbprm.map.state |= LB_MAP_RECALC;
+	recalc_server_map(p);
  out_update_state:
 	srv_lb_commit_status(srv);
 }
@@ -73,7 +74,6 @@
 
 	switch (px->lbprm.tot_used) {
 	case 0:	/* no server */
-		px->lbprm.map.state &= ~LB_MAP_RECALC;
 		return;
 	default:
 		tot = px->lbprm.tot_weight;
@@ -113,7 +113,7 @@
 					break;
 				}
 
-				cur->wscore += cur->next_eweight;
+				HA_ATOMIC_ADD(&cur->wscore, cur->next_eweight);
 				v = (cur->wscore + tot) / tot; /* result between 0 and 3 */
 				if (best == NULL || v > max) {
 					max = v;
@@ -122,9 +122,8 @@
 			}
 		}
 		px->lbprm.map.srv[o] = best;
-		best->wscore -= tot;
+		HA_ATOMIC_ADD(&best->wscore, tot);
 	}
-	px->lbprm.map.state &= ~LB_MAP_RECALC;
 }
 
 /* This function is responsible of building the server MAP for map-based LB
@@ -193,7 +192,6 @@
 
 	p->lbprm.map.srv = calloc(act, sizeof(struct server *));
 	/* recounts servers and their weights */
-	p->lbprm.map.state = LB_MAP_RECALC;
 	recount_servers(p);
 	update_backend_weight(p);
 	recalc_server_map(p);
@@ -210,11 +208,11 @@
 	int newidx, avoididx;
 	struct server *srv, *avoided;
 
-	if (px->lbprm.tot_weight == 0)
-		return NULL;
-
-	if (px->lbprm.map.state & LB_MAP_RECALC)
-		recalc_server_map(px);
+	SPIN_LOCK(LBPRM_LOCK, &px->lbprm.lock);
+	if (px->lbprm.tot_weight == 0) {
+		avoided = NULL;
+		goto out;
+	}
 
 	if (px->lbprm.map.rr_idx < 0 || px->lbprm.map.rr_idx >= px->lbprm.tot_weight)
 		px->lbprm.map.rr_idx = 0;
@@ -241,6 +239,8 @@
 	if (avoided)
 		px->lbprm.map.rr_idx = avoididx;
 
+  out:
+	SPIN_UNLOCK(LBPRM_LOCK, &px->lbprm.lock);
 	/* return NULL or srvtoavoid if found */
 	return avoided;
 }
@@ -255,10 +255,6 @@
 {
 	if (px->lbprm.tot_weight == 0)
 		return NULL;
-
-	if (px->lbprm.map.state & LB_MAP_RECALC)
-		recalc_server_map(px);
-
 	return px->lbprm.map.srv[hash % px->lbprm.tot_weight];
 }