Change in osmo-mgw[master]: rework the counters and stats so they work with the threaded mgw

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

Hoernchen gerrit-no-reply at lists.osmocom.org
Tue Nov 9 21:20:22 UTC 2021


Hoernchen has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-mgw/+/26193 )


Change subject: rework the counters and stats so they work with the threaded mgw
......................................................................

rework the counters and stats so they work with the threaded mgw

Main thread has a one-second timer cb that aggregrates and updates the
rate counters, as well as the stats, by reading the actual atomic
counters that are being updated by the threads.

Change-Id: Iaab3fc262649cb5fb886f0297a60286bde1ffeb0

XXY

Change-Id: I5e3598f80cb062dbab376663ee51136b4508b78d
---
M include/osmocom/mgcp/mgcp_conn.h
M include/osmocom/mgcp/mgcp_network.h
M include/osmocom/mgcp/mgcp_ratectr.h
M include/osmocom/mgcp/mgcp_trunk.h
M src/libosmo-mgcp/mgcp_conn.c
M src/libosmo-mgcp/mgcp_e1.c
M src/libosmo-mgcp/mgcp_endp.c
M src/libosmo-mgcp/mgcp_network.c
M src/libosmo-mgcp/mgcp_protocol.c
M src/libosmo-mgcp/mgcp_ratectr.c
M src/libosmo-mgcp/mgcp_stat.c
M src/libosmo-mgcp/mgcp_threads.c
M src/libosmo-mgcp/mgcp_threads_vty.c
M src/libosmo-mgcp/mgcp_vty.c
M tests/mgcp/mgcp_test.c
15 files changed, 245 insertions(+), 215 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/osmo-mgw refs/changes/93/26193/1

diff --git a/include/osmocom/mgcp/mgcp_conn.h b/include/osmocom/mgcp/mgcp_conn.h
index 4f882e9..8ab61d1 100644
--- a/include/osmocom/mgcp/mgcp_conn.h
+++ b/include/osmocom/mgcp/mgcp_conn.h
@@ -29,6 +29,7 @@
 #include <osmocom/core/linuxlist.h>
 #include <osmocom/core/rate_ctr.h>
 #include <inttypes.h>
+#include <stdatomic.h>
 
 #define LOGPCONN(conn, cat, level, fmt, args...) \
 LOGPENDP((conn)->endp, cat, level, "CI:%s " fmt, \
@@ -93,7 +94,7 @@
 		} stats;
 	} osmux;
 
-	struct rate_ctr_group *rate_ctr_group;
+	atomic_uint_least64_t atomic_counters[_MAX_RTP_CTR_NUM];
 };
 
 /*! MGCP connection (untyped) */
@@ -131,17 +132,6 @@
 	void *priv;
 };
 
-/* RTP connection related counters */
-enum {
-	IN_STREAM_ERR_TSTMP_CTR,
-	OUT_STREAM_ERR_TSTMP_CTR,
-        RTP_PACKETS_RX_CTR,
-        RTP_OCTETS_RX_CTR,
-        RTP_PACKETS_TX_CTR,
-        RTP_OCTETS_TX_CTR,
-        RTP_DROPPED_PACKETS_CTR,
-        RTP_NUM_CONNECTIONS,
-};
 
 /* RTP per-connection statistics. Instances of the corresponding rate counter group
  * exist for the lifetime of an RTP connection.
diff --git a/include/osmocom/mgcp/mgcp_network.h b/include/osmocom/mgcp/mgcp_network.h
index b9cf5e3..75e6ae6 100644
--- a/include/osmocom/mgcp/mgcp_network.h
+++ b/include/osmocom/mgcp/mgcp_network.h
@@ -1,6 +1,7 @@
 #pragma once
 
 #include <inttypes.h>
+#include <stdatomic.h>
 #include <stdbool.h>
 
 #include <osmocom/core/socket.h>
@@ -23,7 +24,7 @@
 	uint32_t ssrc;
 	uint16_t last_seq;
 	uint32_t last_timestamp;
-	struct rate_ctr *err_ts_ctr;
+	atomic_uint_least64_t err_ts_ctr;
 	int32_t last_tsdelta;
 	uint32_t last_arrival_time;
 };
diff --git a/include/osmocom/mgcp/mgcp_ratectr.h b/include/osmocom/mgcp/mgcp_ratectr.h
index c03c4e1..8c0cb8e 100644
--- a/include/osmocom/mgcp/mgcp_ratectr.h
+++ b/include/osmocom/mgcp/mgcp_ratectr.h
@@ -1,4 +1,18 @@
 #pragma once
+#include <stdatomic.h>
+
+/* RTP connection related counters */
+enum {
+	IN_STREAM_ERR_TSTMP_CTR,
+	OUT_STREAM_ERR_TSTMP_CTR,
+	RTP_PACKETS_RX_CTR,
+	RTP_OCTETS_RX_CTR,
+	RTP_PACKETS_TX_CTR,
+	RTP_OCTETS_TX_CTR,
+	RTP_DROPPED_PACKETS_CTR,
+	RTP_NUM_CONNECTIONS,
+	_MAX_RTP_CTR_NUM
+};
 
 /* Global MCGP general rate counters */
 enum {
@@ -8,6 +22,7 @@
 	MGCP_GENERAL_RX_MSGS_UNHANDLED,
 	MGCP_GENERAL_RX_FAIL_MSG_PARSE,
 	MGCP_GENERAL_RX_FAIL_NO_ENDPOINT,
+	_MGCP_GENERAL_NUM_ENUMS,
 };
 
 /* Trunk-global MCGP CRCX related rate counters */
@@ -28,6 +43,7 @@
 	MGCP_CRCX_FAIL_BIND_PORT,
 	MGCP_CRCX_FAIL_AVAIL,
 	MGCP_CRCX_FAIL_CLAIM,
+	_MGCP_CRCX_NUM_ENUMS,
 };
 
 /* Trunk-global MCGP MDCX related rate counters */
@@ -45,6 +61,7 @@
 	MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC,
 	MGCP_MDCX_FAIL_START_RTP,
 	MGCP_MDCX_FAIL_AVAIL,
+	_MGCP_MDCX_NUM_ENUMS,
 };
 
 /* Trunk-global MCGP DLCX related rate counters */
@@ -55,13 +72,15 @@
 	MGCP_DLCX_FAIL_INVALID_CONNID,
 	MGCP_DLCX_FAIL_UNHANDLED_PARAM,
 	MGCP_DLCX_FAIL_AVAIL,
+	_MGCP_DLCX_NUM_ENUMS,
 };
 
 /* Trunk-global E1 related counters */
 enum {
-        E1_I460_TRAU_RX_FAIL_CTR,
-        E1_I460_TRAU_TX_FAIL_CTR,
-        E1_I460_TRAU_MUX_EMPTY_CTR,
+	E1_I460_TRAU_RX_FAIL_CTR,
+	E1_I460_TRAU_TX_FAIL_CTR,
+	E1_I460_TRAU_MUX_EMPTY_CTR,
+	_E1_I460_TRAU_NUM_ENUMS,
 };
 
 /* NOTE: When adding counters, also the dump_ratectr_* routines in vty.c must be updated. */
@@ -69,6 +88,7 @@
 struct mgcp_ratectr_global {
 	/* Rate counter group which contains stats for generic MGCP events. */
 	struct rate_ctr_group *mgcp_general_ctr_group;
+	atomic_uint_least64_t mgcp_general_ctr_atomic[_MGCP_GENERAL_NUM_ENUMS];
 };
 
 struct mgcp_ratectr_trunk {
@@ -79,9 +99,18 @@
 	/* Rate counter group which contains stats for processed DLCX commands. */
 	struct rate_ctr_group *mgcp_dlcx_ctr_group;
 	/* Rate counter group which aggregates stats of individual RTP connections. */
-	struct rate_ctr_group *all_rtp_conn_stats;
+	struct rate_ctr_group *all_rtp_conn_stats_group;
 	/* Rate counter group which contains stats for E1 events (only valid for E1 trunks) */
-	struct rate_ctr_group *e1_stats;
+	struct rate_ctr_group *e1_stats_group;
+};
+
+/* as above, but just counters updated by the trunkthreads, then aggregated by the main thread */
+struct mgcp_per_thread_ctr_trunk {
+	atomic_uint_least64_t mgcp_crcx_ctr_atomic[_MGCP_CRCX_NUM_ENUMS];
+	atomic_uint_least64_t mgcp_mdcx_ctr_atomic[_MGCP_MDCX_NUM_ENUMS];
+	atomic_uint_least64_t mgcp_dlcx_ctr_atomic[_MGCP_DLCX_NUM_ENUMS];
+	atomic_uint_least64_t all_rtp_conn_stats_atomic[_MAX_RTP_CTR_NUM];
+	atomic_uint_least64_t e1_stats_atomic[_E1_I460_TRAU_NUM_ENUMS];
 };
 
 struct mgcp_config;
diff --git a/include/osmocom/mgcp/mgcp_trunk.h b/include/osmocom/mgcp/mgcp_trunk.h
index 36032b9..9058b51 100644
--- a/include/osmocom/mgcp/mgcp_trunk.h
+++ b/include/osmocom/mgcp/mgcp_trunk.h
@@ -27,8 +27,14 @@
 	struct per_thread_info *thread_info;
 	int num_threads; /* number of threads for this parent trunk, related to thread_info */
 	bool use_threads; /* enables thread usage, set at cfg parsing time, ALWAYS false for e1/osmux */
-	unsigned int number_endpoints_offset; /* offset for proper ep counting, since only the first thread starts at ep0 */
+	unsigned int number_endpoints_offset; /* offset for proper ep counting, only first thread starts at ep0 */
 	struct mgcp_config *cfg; /* global cfg, points at private cfg copy in thread_info for child trunks */
+	struct mgcp_per_thread_ctr_trunk thread_ctr; /* counters used by the threads, used by main thread */
+
+	/*	rate counters and stat items to measure the trunks overall performance and health
+		updated by the main thread by aggregating the per-thread raw counters */
+	struct mgcp_ratectr_trunk ratectr; /* NULL for the threads! */
+	struct mgcp_stat_trunk stats; /* NULL for the threads! */
 
 	/* !!! no thread specific handling below this comment !!! */
 
@@ -62,10 +68,6 @@
 	unsigned int number_endpoints;
 	struct mgcp_endpoint **endpoints;
 
-	/* rate counters and stat items to measure the trunks overall performance and health */
-	struct mgcp_ratectr_trunk ratectr;
-	struct mgcp_stat_trunk stats;
-
 	union {
 		/* Virtual trunk specific */
 		struct {
diff --git a/src/libosmo-mgcp/mgcp_conn.c b/src/libosmo-mgcp/mgcp_conn.c
index 1d169f4..19b56bf 100644
--- a/src/libosmo-mgcp/mgcp_conn.c
+++ b/src/libosmo-mgcp/mgcp_conn.c
@@ -35,15 +35,6 @@
 #include <osmocom/core/timer.h>
 #include <ctype.h>
 
-const static struct rate_ctr_group_desc rate_ctr_group_desc = {
-	.group_name_prefix = "conn_rtp",
-	.group_description = "rtp connection statistics",
-	.class_id = 1,
-	.num_ctr = ARRAY_SIZE(mgcp_conn_rate_ctr_desc),
-	.ctr_desc = mgcp_conn_rate_ctr_desc
-};
-
-
 /* Allocate a new connection identifier. According to RFC3435, they must
  * be unique only within the scope of the endpoint. (Caller must provide
  * memory for id) */
@@ -87,10 +78,6 @@
 static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *conn)
 {
 	struct mgcp_rtp_end *end = &conn_rtp->end;
-	/* FIXME: Each new rate counter group requires an unique index. At the
-	 * moment we generate this index using this counter, but perhaps there
-	 * is a more concious way to assign the indexes. */
-	static atomic_uint rate_ctr_index = 0;
 
 	conn_rtp->type = MGCP_RTP_DEFAULT;
 	conn_rtp->osmux.cid_allocated = false;
@@ -111,12 +98,8 @@
 	end->output_enabled = 0;
 	end->maximum_packet_time = -1;
 
-	conn_rtp->rate_ctr_group = rate_ctr_group_alloc(conn, &rate_ctr_group_desc, rate_ctr_index++);
-	if (!conn_rtp->rate_ctr_group)
-		return -1;
-
-	conn_rtp->state.in_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->rate_ctr_group, IN_STREAM_ERR_TSTMP_CTR);
-	conn_rtp->state.out_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->rate_ctr_group, OUT_STREAM_ERR_TSTMP_CTR);
+	memset(&conn_rtp->state, 0, sizeof(conn_rtp->state));
+	memset(&conn_rtp->atomic_counters, 0, sizeof(conn_rtp->atomic_counters));
 
 	/* Make sure codec table is reset */
 	mgcp_codec_reset_all(conn_rtp);
@@ -130,7 +113,6 @@
 	if (mgcp_conn_rtp_is_osmux(conn_rtp))
 		conn_osmux_disable(conn_rtp);
 	mgcp_free_rtp_port(&conn_rtp->end);
-	rate_ctr_group_free(conn_rtp->rate_ctr_group);
 	mgcp_codec_reset_all(conn_rtp);
 }
 
@@ -258,24 +240,12 @@
 
 static void aggregate_rtp_conn_stats(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn_rtp)
 {
-	struct rate_ctr_group *all_stats = endp->trunk->ratectr.all_rtp_conn_stats;
-	struct rate_ctr_group *conn_stats = conn_rtp->rate_ctr_group;
+	atomic_uint_least64_t *per_trunk_stats = endp->trunk->thread_ctr.all_rtp_conn_stats_atomic;
+	atomic_uint_least64_t *per_conn_stats = conn_rtp->atomic_counters;
 
-	if (all_stats == NULL || conn_stats == NULL)
-		return;
-
-	/* Compared to per-connection RTP statistics, aggregated RTP statistics
-	 * contain one additional rate couter item (RTP_NUM_CONNECTIONS).
-	 * All other counters in both counter groups correspond to each other. */
-	OSMO_ASSERT(conn_stats->desc->num_ctr + 1 == all_stats->desc->num_ctr);
-
-	/* all other counters are [now] updated in real-time */
-	rate_ctr_add(rate_ctr_group_get_ctr(all_stats, IN_STREAM_ERR_TSTMP_CTR),
-		     rate_ctr_group_get_ctr(conn_stats, IN_STREAM_ERR_TSTMP_CTR)->current);
-	rate_ctr_add(rate_ctr_group_get_ctr(all_stats, OUT_STREAM_ERR_TSTMP_CTR),
-		     rate_ctr_group_get_ctr(conn_stats, OUT_STREAM_ERR_TSTMP_CTR)->current);
-
-	rate_ctr_inc(rate_ctr_group_get_ctr(all_stats, RTP_NUM_CONNECTIONS));
+	per_trunk_stats[IN_STREAM_ERR_TSTMP_CTR] += per_conn_stats[IN_STREAM_ERR_TSTMP_CTR];
+	per_trunk_stats[OUT_STREAM_ERR_TSTMP_CTR] += per_conn_stats[OUT_STREAM_ERR_TSTMP_CTR];
+	per_trunk_stats[RTP_NUM_CONNECTIONS]++;
 }
 
 /*! free a connection by its ID.
diff --git a/src/libosmo-mgcp/mgcp_e1.c b/src/libosmo-mgcp/mgcp_e1.c
index 807904f..2de0baf 100644
--- a/src/libosmo-mgcp/mgcp_e1.c
+++ b/src/libosmo-mgcp/mgcp_e1.c
@@ -41,6 +41,7 @@
 #include <osmocom/mgcp/mgcp_e1.h>
 #include <osmocom/mgcp/mgcp_threads.h>
 #include <osmocom/codec/codec.h>
+#include <stdatomic.h>
 
 #define DEBUG_BITS_MAX 80
 #define DEBUG_BYTES_MAX 40
@@ -192,13 +193,13 @@
 static void e1_i460_mux_empty_cb(struct osmo_i460_subchan *schan, void *user_data)
 {
 	struct mgcp_endpoint *endp = user_data;
-	struct rate_ctr_group *rate_ctrs = endp->trunk->ratectr.e1_stats;
+	atomic_uint_least64_t *rate_ctrs = endp->trunk->thread_ctr.e1_stats_atomic;
 	struct msgb *msg = msgb_alloc_c(endp->trunk, E1_TRAU_BITS_MSGB, "E1-I.460-IDLE-TX-TRAU-frame");
 	uint8_t *ptr;
 	const uint8_t *ptr_ft;
 	enum osmo_trau_frame_type ft;
 
-	rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, E1_I460_TRAU_MUX_EMPTY_CTR));
+	rate_ctrs[E1_I460_TRAU_MUX_EMPTY_CTR]++;
 
 	/* Choose an appropiate idle frame type */
 	ft = endp->e1.trau_rtp_st->type;
@@ -242,7 +243,7 @@
 	unsigned int rtp_hdr_len = sizeof(struct rtp_hdr);
 	struct mgcp_endpoint *endp = user_data;
 	struct msgb *msg = msgb_alloc_c(endp->trunk, RTP_BUF_SIZE, "RTP-rx-from-E1");
-	struct rate_ctr_group *rate_ctrs = endp->trunk->ratectr.e1_stats;
+	atomic_uint_least64_t *rate_ctrs = endp->trunk->thread_ctr.e1_stats_atomic;
 	struct mgcp_conn *conn_dst;
 	struct osmo_trau_frame fr;
 	int rc;
@@ -305,7 +306,7 @@
 	msgb_free(msg);
 	return;
 skip:
-	rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, E1_I460_TRAU_RX_FAIL_CTR));
+	rate_ctrs[E1_I460_TRAU_RX_FAIL_CTR]++;
 	msgb_free(msg);
 	return;
 }
@@ -627,7 +628,7 @@
 int mgcp_e1_send_rtp(struct mgcp_endpoint *endp, struct mgcp_rtp_codec *codec, struct msgb *msg)
 {
 	struct msgb *msg_tf = msgb_alloc_c(endp->trunk, E1_TRAU_BITS_MSGB, "E1-I.460-TX-TRAU-frame");
-	struct rate_ctr_group *rate_ctrs = endp->trunk->ratectr.e1_stats;
+	atomic_uint_least64_t *rate_ctrs = endp->trunk->thread_ctr.e1_stats_atomic;
 	unsigned int rtp_hdr_len = sizeof(struct rtp_hdr);
 	struct osmo_trau_frame tf;
 	uint8_t amr_ft;
@@ -683,7 +684,7 @@
 
 	return 0;
 skip:
-	rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, E1_I460_TRAU_TX_FAIL_CTR));
+	rate_ctrs[E1_I460_TRAU_TX_FAIL_CTR]++;
 	msgb_free(msg_tf);
 	return -1;
 }
diff --git a/src/libosmo-mgcp/mgcp_endp.c b/src/libosmo-mgcp/mgcp_endp.c
index 11ef9e0..72d5fdb 100644
--- a/src/libosmo-mgcp/mgcp_endp.c
+++ b/src/libosmo-mgcp/mgcp_endp.c
@@ -126,8 +126,6 @@
 	/* We must only decrement the stat item when the endpoint as actually
 	 * claimed. An endpoint is claimed when a call-id is set */
 	if (endp->callid) {
-		osmo_stat_item_dec(osmo_stat_item_group_get_item(endp->trunk->stats.common,
-								 TRUNK_STAT_ENDPOINTS_USED), 1);
 		endp->trunk->thread_info->eps_free++;
 	}
 
@@ -613,8 +611,6 @@
 	 * connection ids) */
 	endp->callid = talloc_strdup(endp, callid);
 	OSMO_ASSERT(endp->callid);
-	osmo_stat_item_inc(osmo_stat_item_group_get_item(endp->trunk->stats.common,
-							 TRUNK_STAT_ENDPOINTS_USED), 1);
 	endp->trunk->thread_info->eps_free--;
 
 	/* Allocate resources */
diff --git a/src/libosmo-mgcp/mgcp_network.c b/src/libosmo-mgcp/mgcp_network.c
index 2d275ec..32ac930 100644
--- a/src/libosmo-mgcp/mgcp_network.c
+++ b/src/libosmo-mgcp/mgcp_network.c
@@ -21,6 +21,7 @@
  *
  */
 
+#include <stdatomic.h>
 #include <string.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -62,12 +63,11 @@
 static void rtpconn_rate_ctr_add(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp,
 				 int id, int inc)
 {
-	struct rate_ctr_group *conn_stats = conn_rtp->rate_ctr_group;
-	struct rate_ctr_group *mgw_stats = endp->trunk->ratectr.all_rtp_conn_stats;
+	atomic_uint_least64_t *mgw_stats = endp->trunk->thread_ctr.all_rtp_conn_stats_atomic;
 
 	/* add to both the per-connection and the global stats */
-	rate_ctr_add(rate_ctr_group_get_ctr(conn_stats, id), inc);
-	rate_ctr_add(rate_ctr_group_get_ctr(mgw_stats, id), inc);
+	conn_rtp->atomic_counters[id] += inc;
+	mgw_stats[id] += inc;
 }
 
 static void rtpconn_rate_ctr_inc(struct mgcp_conn_rtp *conn_rtp, struct mgcp_endpoint *endp, int id)
@@ -192,13 +192,10 @@
 }
 
 /* Check timestamp and sequence number for plausibility */
-static int check_rtp_timestamp(const struct mgcp_endpoint *endp,
-			       const struct mgcp_rtp_state *state,
-			       const struct mgcp_rtp_stream_state *sstate,
-			       const struct mgcp_rtp_end *rtp_end,
-			       const struct osmo_sockaddr *addr,
-			       uint16_t seq, uint32_t timestamp,
-			       const char *text, int32_t * tsdelta_out)
+static int check_rtp_timestamp(const struct mgcp_endpoint *endp, const struct mgcp_rtp_state *state,
+			       struct mgcp_rtp_stream_state *sstate, const struct mgcp_rtp_end *rtp_end,
+			       const struct osmo_sockaddr *addr, uint16_t seq, uint32_t timestamp, const char *text,
+			       int32_t *tsdelta_out)
 {
 	int32_t tsdelta;
 	int32_t timestamp_error;
@@ -210,7 +207,7 @@
 
 	if (seq == sstate->last_seq) {
 		if (timestamp != sstate->last_timestamp) {
-			rate_ctr_inc(sstate->err_ts_ctr);
+			sstate->err_ts_ctr++;
 			LOGPENDP(endp, DRTP, LOGL_ERROR,
 				 "The %s timestamp delta is != 0 but the sequence "
 				 "number %d is the same, "
@@ -262,7 +259,7 @@
 	    ts_alignment_error(sstate, state->packet_duration, timestamp);
 
 	if (timestamp_error) {
-		rate_ctr_inc(sstate->err_ts_ctr);
+		sstate->err_ts_ctr++;
 		LOGPENDP(endp, DRTP, LOGL_NOTICE,
 			 "The %s timestamp has an alignment error of %d "
 			 "on SSRC: %u "
@@ -1501,8 +1498,8 @@
 					sizeof(struct sockaddr_in)));
 
 	/* Increment RX statistics */
-	rate_ctr_inc(rate_ctr_group_get_ctr(conn_src->rate_ctr_group, RTP_PACKETS_RX_CTR));
-	rate_ctr_add(rate_ctr_group_get_ctr(conn_src->rate_ctr_group, RTP_OCTETS_RX_CTR), msgb_length(msg));
+	conn_src->atomic_counters[RTP_PACKETS_RX_CTR]++;
+	conn_src->atomic_counters[RTP_OCTETS_RX_CTR]++;
 	/* FIXME: count RTP and RTCP separately, also count IuUP payload-less separately */
 
 	/* Forward a copy of the RTP data to a debug ip/port */
diff --git a/src/libosmo-mgcp/mgcp_protocol.c b/src/libosmo-mgcp/mgcp_protocol.c
index 99f1257..d889238 100644
--- a/src/libosmo-mgcp/mgcp_protocol.c
+++ b/src/libosmo-mgcp/mgcp_protocol.c
@@ -22,6 +22,7 @@
  */
 
 #include <ctype.h>
+#include <stdatomic.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -314,18 +315,18 @@
  * !! only public for testing !! */
 struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct to_trunkthread_mgcp_msg *w)
 {
-	struct rate_ctr_group *rate_ctrs = cfg->ratectr.mgcp_general_ctr_group;
+	atomic_uint_least64_t *rate_ctrs = cfg->ratectr.mgcp_general_ctr_atomic;
 	int code;
 	ssize_t rc = w->x.msglen;
 	struct mgcp_parse_data *pdata = &w->x.pdata;
 	struct mgcp_request_data *rq = &w->x.rq;
 
 	/* Count all messages, even incorect ones */
-	rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_GENERAL_RX_MSGS_TOTAL));
+	rate_ctrs[MGCP_GENERAL_RX_MSGS_TOTAL]++;
 
 	if (rc < sizeof(rq->name) - 1) {
 		LOGP(DLMGCP, LOGL_ERROR, "msg too short: %zd\n", rc);
-		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_GENERAL_RX_FAIL_MSG_PARSE));
+		rate_ctrs[MGCP_GENERAL_RX_FAIL_MSG_PARSE]++;
 		return 0;
 	}
 	memcpy(rq->name, (const char *)&w->msg[0], sizeof(rq->name) - 1);
@@ -335,7 +336,7 @@
 	/* attempt to treat it as a response */
 	if (sscanf((const char *)&w->msg[0], "%3d %*s", &code) == 1) {
 		LOGP(DLMGCP, LOGL_DEBUG, "Response: Code: %d\n", code);
-		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_GENERAL_RX_FAIL_MSG_PARSE));
+		rate_ctrs[MGCP_GENERAL_RX_FAIL_MSG_PARSE]++;
 		return 0;
 	}
 
@@ -343,7 +344,7 @@
 	rc = mgcp_parse_header(pdata, mgcp_strline((char *)&w->msg[4], &pdata->save));
 	if (rc < 0) {
 		LOGP(DLMGCP, LOGL_ERROR, "%s: failed to parse MCGP message\n", rq->name);
-		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_GENERAL_RX_FAIL_MSG_PARSE));
+		rate_ctrs[MGCP_GENERAL_RX_FAIL_MSG_PARSE]++;
 		return create_err_response(cfg, NULL, -rc, rq->name, "000000");
 	}
 
@@ -418,7 +419,7 @@
 {
 	int rc = -500, handled = 0;
 	struct msgb *resp = NULL;
-	struct rate_ctr_group *rate_ctrs = w->x.rq.trunk->cfg->ratectr.mgcp_general_ctr_group;
+	atomic_uint_least64_t *rate_ctrs = w->x.rq.trunk->cfg->ratectr.mgcp_general_ctr_atomic;
 	struct mgcp_parse_data *pdata = &w->x.pdata;
 	struct mgcp_request_data *rq = &w->x.rq;
 
@@ -437,7 +438,7 @@
 		if (rq->wildcarded) {
 			/* we know this is the trunk that handles this wildcarded message */
 		} else {
-			rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_GENERAL_RX_FAIL_NO_ENDPOINT));
+			rate_ctrs[MGCP_GENERAL_RX_FAIL_NO_ENDPOINT]++;
 			/* If the endpoint name suggests that the request refers to a specific endpoint, then the
 				* request cannot be handled and we must stop early. */
 			LOGP(DLMGCP, LOGL_NOTICE, "%s: cannot find endpoint \"%s\", cause=%d -- abort\n", rq->name,
@@ -449,7 +450,7 @@
 
 		/* Check if we have to retransmit a response from a previous transaction */
 		if (pdata->trans && rq->endp->last_trans && strcmp(rq->endp->last_trans, pdata->trans) == 0) {
-			rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_GENERAL_RX_MSGS_RETRANSMITTED));
+			rate_ctrs[MGCP_GENERAL_RX_MSGS_RETRANSMITTED]++;
 			return create_retransmission_response(rq->endp);
 		}
 	}
@@ -482,9 +483,9 @@
 	/* Check if the MGCP request was handled and increment rate counters accordingly - but don't count this multiple times */
 	if (!rq->wildcarded || (rq->wildcarded && !strcmp(rq->name, "CRCX"))) {
 		if (handled) {
-			rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_GENERAL_RX_MSGS_HANDLED));
+			rate_ctrs[MGCP_GENERAL_RX_MSGS_HANDLED]++;
 		} else {
-			rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_GENERAL_RX_MSGS_UNHANDLED));
+			rate_ctrs[MGCP_GENERAL_RX_MSGS_UNHANDLED]++;
 			LOGP(DLMGCP, LOGL_ERROR, "MSG with type: '%.4s' not handled\n", rq->name);
 		}
 	}
@@ -881,7 +882,7 @@
 	struct mgcp_parse_data *pdata = rq->pdatap;
 	struct mgcp_trunk *trunk = rq->trunk;
 	struct mgcp_endpoint *endp = rq->endp;
-	struct rate_ctr_group *rate_ctrs = trunk->ratectr.mgcp_crcx_ctr_group;
+	atomic_uint_least64_t *rate_ctrs = trunk->thread_ctr.mgcp_crcx_ctr_atomic;
 	int error_code = 400;
 	const char *local_options = NULL;
 	const char *callid = NULL;
@@ -897,13 +898,13 @@
 
 	/* we must have a free ep */
 	if (!endp) {
-		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_AVAIL));
+		rate_ctrs[MGCP_CRCX_FAIL_AVAIL]++;
 		LOGPENDP(endp, DLMGCP, LOGL_ERROR, "CRCX: no free endpoints available!\n");
 		return create_err_response(rq->trunk, NULL, 403, "CRCX", pdata->trans);
 	}
 
 	if (!mgcp_endp_avail(endp)) {
-		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_AVAIL));
+		rate_ctrs[MGCP_CRCX_FAIL_AVAIL]++;
 		LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 			 "CRCX: selected endpoint not available!\n");
 		return create_err_response(rq->trunk, NULL, 501, "CRCX", pdata->trans);
@@ -925,7 +926,7 @@
 			/* It is illegal to send a connection identifier
 			 * together with a CRCX, the MGW will assign the
 			 * connection identifier by itself on CRCX */
-			rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_BAD_ACTION));
+			rate_ctrs[MGCP_CRCX_FAIL_BAD_ACTION]++;
 			return create_err_response(rq->trunk, NULL, 523, "CRCX", pdata->trans);
 			break;
 		case 'M':
@@ -951,7 +952,7 @@
 		default:
 			LOGPENDP(endp, DLMGCP, LOGL_NOTICE,
 				 "CRCX: unhandled option: '%c'/%d\n", *line, *line);
-			rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_UNHANDLED_PARAM));
+			rate_ctrs[MGCP_CRCX_FAIL_UNHANDLED_PARAM]++;
 			return create_err_response(rq->trunk, NULL, 539, "CRCX", pdata->trans);
 			break;
 		}
@@ -962,14 +963,14 @@
 	if (!callid) {
 		LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 			 "CRCX: insufficient parameters, missing callid\n");
-		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_MISSING_CALLID));
+		rate_ctrs[MGCP_CRCX_FAIL_MISSING_CALLID]++;
 		return create_err_response(endp, endp, 516, "CRCX", pdata->trans);
 	}
 
 	if (!mode) {
 		LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 			 "CRCX: insufficient parameters, missing mode\n");
-		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_INVALID_MODE));
+		rate_ctrs[MGCP_CRCX_FAIL_INVALID_MODE]++;
 		return create_err_response(endp, endp, 517, "CRCX", pdata->trans);
 	}
 
@@ -986,7 +987,7 @@
 		} else {
 			/* There is no more room for a connection, leave
 			 * everything as it is and return with an error */
-			rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_LIMIT_EXCEEDED));
+			rate_ctrs[MGCP_CRCX_FAIL_LIMIT_EXCEEDED]++;
 			return create_err_response(endp, endp, 540, "CRCX", pdata->trans);
 		}
 	}
@@ -1004,7 +1005,7 @@
 		else {
 			/* This is not our call, leave everything as it is and
 			 * return with an error. */
-			rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_UNKNOWN_CALLID));
+			rate_ctrs[MGCP_CRCX_FAIL_UNKNOWN_CALLID]++;
 			return create_err_response(endp, endp, 400, "CRCX", pdata->trans);
 		}
 	}
@@ -1015,7 +1016,7 @@
 		 * the callid matches up (see above). */
 		rc = mgcp_endp_claim(endp, callid);
 		if (rc != 0) {
-			rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_CLAIM));
+			rate_ctrs[MGCP_CRCX_FAIL_CLAIM]++;
 			return create_err_response(endp, endp, 502, "CRCX", pdata->trans);
 		}
 	}
@@ -1025,7 +1026,7 @@
 	if (!_conn) {
 		LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 			 "CRCX: unable to allocate RTP connection\n");
-		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_ALLOC_CONN));
+		rate_ctrs[MGCP_CRCX_FAIL_ALLOC_CONN]++;
 		goto error2;
 
 	}
@@ -1035,7 +1036,7 @@
 
 	if (mgcp_parse_conn_mode(mode, endp, conn->conn) != 0) {
 		error_code = 517;
-		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_INVALID_MODE));
+		rate_ctrs[MGCP_CRCX_FAIL_INVALID_MODE]++;
 		goto error2;
 	}
 
@@ -1045,13 +1046,13 @@
 	if (osmux_cid >= -1) { /* -1 is wilcard, alloc next avail CID */
 		conn->osmux.state = OSMUX_STATE_ACTIVATING;
 		if (conn_osmux_allocate_cid(conn, osmux_cid) == -1) {
-			rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_NO_OSMUX));
+			rate_ctrs[MGCP_CRCX_FAIL_NO_OSMUX]++;
 			goto error2;
 		}
 	} else if (endp->trunk->cfg->osmux == OSMUX_USAGE_ONLY) {
 		LOGPCONN(_conn, DLMGCP, LOGL_ERROR,
 			 "CRCX: osmux only and no osmux offered\n");
-		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_NO_OSMUX));
+		rate_ctrs[MGCP_CRCX_FAIL_NO_OSMUX]++;
 		goto error2;
 	}
 
@@ -1063,7 +1064,7 @@
 			LOGPCONN(_conn, DLMGCP, LOGL_ERROR,
 				 "CRCX: inavlid local connection options!\n");
 			error_code = rc;
-			rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_INVALID_CONN_OPTIONS));
+			rate_ctrs[MGCP_CRCX_FAIL_INVALID_CONN_OPTIONS]++;
 			goto error2;
 		}
 	}
@@ -1073,7 +1074,7 @@
 	mgcp_codec_summary(conn);
 	if (rc) {
 		error_code = rc;
-		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_CODEC_NEGOTIATION));
+		rate_ctrs[MGCP_CRCX_FAIL_CODEC_NEGOTIATION]++;
 		goto error2;
 	}
 
@@ -1094,7 +1095,7 @@
 		LOGPCONN(_conn, DLMGCP, LOGL_ERROR,
 			 "CRCX: selected connection mode type requires an opposite end!\n");
 		error_code = 527;
-		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_NO_REMOTE_CONN_DESC));
+		rate_ctrs[MGCP_CRCX_FAIL_NO_REMOTE_CONN_DESC]++;
 		goto error2;
 	}
 
@@ -1102,14 +1103,14 @@
 	   information, then find a free port for it */
 	mgcp_get_local_addr(conn->end.local_addr, conn);
 	if (allocate_port(endp, conn) != 0) {
-		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_BIND_PORT));
+		rate_ctrs[MGCP_CRCX_FAIL_BIND_PORT]++;
 		goto error2;
 	}
 
 	if (setup_rtp_processing(endp, conn) != 0) {
 		LOGPCONN(_conn, DLMGCP, LOGL_ERROR,
 			 "CRCX: could not start RTP processing!\n");
-		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_START_RTP));
+		rate_ctrs[MGCP_CRCX_FAIL_START_RTP]++;
 		goto error2;
 	}
 
@@ -1125,7 +1126,7 @@
 
 	LOGPCONN(_conn, DLMGCP, LOGL_NOTICE,
 		 "CRCX: connection successfully created\n");
-	rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_SUCCESS));
+	rate_ctrs[MGCP_CRCX_SUCCESS]++;
 	mgcp_endp_update(endp);
 
 	/* NOTE: Only in the virtual trunk we allow dynamic endpoint names */
@@ -1144,7 +1145,7 @@
 	struct mgcp_parse_data *pdata = rq->pdatap;
 	struct mgcp_trunk *trunk = rq->trunk;
 	struct mgcp_endpoint *endp = rq->endp;
-	struct rate_ctr_group *rate_ctrs = trunk->ratectr.mgcp_mdcx_ctr_group;
+	atomic_uint_least64_t *rate_ctrs = trunk->thread_ctr.mgcp_mdcx_ctr_atomic;
 	char new_local_addr[INET6_ADDRSTRLEN];
 	int error_code = 500;
 	int silent = 0;
@@ -1163,19 +1164,19 @@
 	if (rq->wildcarded) {
 		LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 			 "MDCX: wildcarded endpoint names not supported.\n");
-		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_WILDCARD));
+		rate_ctrs[MGCP_MDCX_FAIL_WILDCARD]++;
 		return create_err_response(rq->trunk, endp, 507, "MDCX", pdata->trans);
 	}
 
 	if (!endp || !mgcp_endp_avail(endp)) {
-		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_AVAIL));
+		rate_ctrs[MGCP_MDCX_FAIL_AVAIL]++;
 		LOGPENDP(endp, DLMGCP, LOGL_ERROR, "MDCX: selected endpoint not available!\n");
 		return create_err_response(rq->trunk, NULL, 501, "MDCX", pdata->trans);
 	}
 	if (llist_count(&endp->conns) <= 0) {
 		LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 			 "MDCX: endpoint is not holding a connection.\n");
-		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_NO_CONN));
+		rate_ctrs[MGCP_MDCX_FAIL_NO_CONN]++;
 		return create_err_response(endp, endp, 400, "MDCX", pdata->trans);
 	}
 
@@ -1186,7 +1187,7 @@
 		switch (toupper(line[0])) {
 		case 'C':
 			if (mgcp_verify_call_id(endp, line + 3) != 0) {
-				rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_INVALID_CALLID));
+				rate_ctrs[MGCP_MDCX_FAIL_INVALID_CALLID]++;
 				error_code = 516;
 				goto error3;
 			}
@@ -1194,7 +1195,7 @@
 		case 'I':
 			conn_id = (const char *)line + 3;
 			if ((error_code = mgcp_verify_ci(endp, conn_id))) {
-				rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_INVALID_CONNID));
+				rate_ctrs[MGCP_MDCX_FAIL_INVALID_CONNID]++;
 				goto error3;
 			}
 			break;
@@ -1225,7 +1226,7 @@
 			LOGPENDP(endp, DLMGCP, LOGL_NOTICE,
 				 "MDCX: Unhandled MGCP option: '%c'/%d\n",
 				 line[0], line[0]);
-			rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_UNHANDLED_PARAM));
+			rate_ctrs[MGCP_MDCX_FAIL_UNHANDLED_PARAM]++;
 			return create_err_response(rq->trunk, NULL, 539, "MDCX", pdata->trans);
 			break;
 		}
@@ -1235,13 +1236,13 @@
 	if (!conn_id) {
 		LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 			 "MDCX: insufficient parameters, missing ci (connectionIdentifier)\n");
-		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_NO_CONNID));
+		rate_ctrs[MGCP_MDCX_FAIL_NO_CONNID]++;
 		return create_err_response(endp, endp, 515, "MDCX", pdata->trans);
 	}
 
 	conn = mgcp_conn_get_rtp(endp, conn_id);
 	if (!conn) {
-		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_CONN_NOT_FOUND));
+		rate_ctrs[MGCP_MDCX_FAIL_CONN_NOT_FOUND]++;
 		return create_err_response(endp, endp, 400, "MDCX", pdata->trans);
 	}
 
@@ -1249,7 +1250,7 @@
 
 	if (mode) {
 		if (mgcp_parse_conn_mode(mode, endp, conn->conn) != 0) {
-			rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_INVALID_MODE));
+			rate_ctrs[MGCP_MDCX_FAIL_INVALID_MODE]++;
 			error_code = 517;
 			goto error3;
 		}
@@ -1264,7 +1265,7 @@
 			LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 				 "MDCX: invalid local connection options!\n");
 			error_code = rc;
-			rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_INVALID_CONN_OPTIONS));
+			rate_ctrs[MGCP_MDCX_FAIL_INVALID_CONN_OPTIONS]++;
 			goto error3;
 		}
 	}
@@ -1284,7 +1285,7 @@
 		LOGPCONN(conn->conn, DLMGCP, LOGL_ERROR,
 			 "MDCX: selected connection mode type requires an opposite end!\n");
 		error_code = 527;
-		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC));
+		rate_ctrs[MGCP_MDCX_FAIL_NO_REMOTE_CONN_DESC]++;
 		goto error3;
 	}
 
@@ -1317,13 +1318,13 @@
 		osmo_strlcpy(conn->end.local_addr, new_local_addr, sizeof(conn->end.local_addr));
 		mgcp_free_rtp_port(&conn->end);
 		if (allocate_port(endp, conn) != 0) {
-			rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_CRCX_FAIL_BIND_PORT));
+			rate_ctrs[MGCP_CRCX_FAIL_BIND_PORT]++;
 			goto error3;
 		}
 	}
 
 	if (setup_rtp_processing(endp, conn) != 0) {
-		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_FAIL_START_RTP));
+		rate_ctrs[MGCP_MDCX_FAIL_START_RTP]++;
 		goto error3;
 	}
 
@@ -1340,7 +1341,7 @@
 	    trunk->keepalive_interval != MGCP_KEEPALIVE_NEVER)
 		send_dummy(endp, conn);
 
-	rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_MDCX_SUCCESS));
+	rate_ctrs[MGCP_MDCX_SUCCESS]++;
 	if (silent)
 		goto out_silent;
 
@@ -1362,7 +1363,7 @@
 	struct mgcp_parse_data *pdata = rq->pdatap;
 	struct mgcp_trunk *trunk = rq->trunk;
 	struct mgcp_endpoint *endp = rq->endp;
-	struct rate_ctr_group *rate_ctrs = trunk->ratectr.mgcp_dlcx_ctr_group;
+	atomic_uint_least64_t *rate_ctrs = trunk->thread_ctr.mgcp_dlcx_ctr_atomic;
 	int error_code = 400;
 	int silent = 0;
 	char *line;
@@ -1377,7 +1378,7 @@
 	LOGPEPTR(endp, trunk, DLMGCP, LOGL_NOTICE, "DLCX: deleting connection(s) ...\n");
 
 	if (endp && !mgcp_endp_avail(endp)) {
-		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_AVAIL));
+		rate_ctrs[MGCP_DLCX_FAIL_AVAIL]++;
 		LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 			 "DLCX: selected endpoint not available!\n");
 		return create_err_response(rq->trunk, NULL, 501, "DLCX", pdata->trans);
@@ -1386,7 +1387,7 @@
 	if (endp && !rq->wildcarded && llist_empty(&endp->conns)) {
 		LOGPENDP(endp, DLMGCP, LOGL_ERROR,
 			 "DLCX: endpoint is not holding a connection.\n");
-		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_NO_CONN));
+		rate_ctrs[MGCP_DLCX_FAIL_NO_CONN]++;
 		return create_err_response(endp, endp, 515, "DLCX", pdata->trans);
 	}
 
@@ -1399,7 +1400,7 @@
 			num_conns += llist_count(&trunk->endpoints[i]->conns);
 			mgcp_endp_release(trunk->endpoints[i]);
 		}
-		rate_ctr_add(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_SUCCESS), num_conns);
+		rate_ctrs[MGCP_DLCX_SUCCESS] += num_conns;
 		return create_ok_response(trunk, NULL, 200, "DLCX", pdata->trans);
 	}
 
@@ -1414,13 +1415,13 @@
 			if (!endp) {
 				LOGPTRUNK(trunk, DLMGCP, LOGL_NOTICE,
 					  "cannot handle requests with call-id (C) without endpoint -- abort!");
-				rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_UNHANDLED_PARAM));
+				rate_ctrs[MGCP_DLCX_FAIL_UNHANDLED_PARAM]++;
 				return create_err_response(rq->trunk, NULL, 539, "DLCX", pdata->trans);
 			}
 
 			if (mgcp_verify_call_id(endp, line + 3) != 0) {
 				error_code = 516;
-				rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_INVALID_CALLID));
+				rate_ctrs[MGCP_DLCX_FAIL_INVALID_CALLID]++;
 				goto error3;
 			}
 			break;
@@ -1430,13 +1431,13 @@
 			if (!endp) {
 				LOGPTRUNK(trunk, DLMGCP, LOGL_NOTICE,
 					  "cannot handle requests with conn-id (I) without endpoint -- abort!");
-				rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_UNHANDLED_PARAM));
+				rate_ctrs[MGCP_DLCX_FAIL_UNHANDLED_PARAM]++;
 				return create_err_response(rq->trunk, NULL, 539, "DLCX", pdata->trans);
 			}
 
 			conn_id = (const char *)line + 3;
 			if ((error_code = mgcp_verify_ci(endp, conn_id))) {
-				rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_INVALID_CONNID));
+				rate_ctrs[MGCP_DLCX_FAIL_INVALID_CONNID]++;
 				goto error3;
 			}
 			break;
@@ -1446,7 +1447,7 @@
 		default:
 			LOGPEPTR(endp, trunk, DLMGCP, LOGL_NOTICE, "DLCX: Unhandled MGCP option: '%c'/%d\n",
 				 line[0], line[0]);
-			rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_UNHANDLED_PARAM));
+			rate_ctrs[MGCP_DLCX_FAIL_UNHANDLED_PARAM]++;
 			return create_err_response(rq->trunk, NULL, 539, "DLCX", pdata->trans);
 			break;
 		}
@@ -1467,7 +1468,7 @@
 			 num_conns);
 
 		if (num_conns > 0)
-			rate_ctr_add(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_SUCCESS), num_conns);
+			rate_ctrs[MGCP_DLCX_SUCCESS] += num_conns;
 
 		mgcp_endp_release(endp);
 
@@ -1480,7 +1481,7 @@
 	/* Find the connection */
 	conn = mgcp_conn_get_rtp(endp, conn_id);
 	if (!conn) {
-		rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_FAIL_INVALID_CONNID));
+		rate_ctrs[MGCP_DLCX_FAIL_INVALID_CONNID]++;
 		goto error3;
 	}
 	/* save the statistics of the current connection */
@@ -1500,7 +1501,7 @@
 		LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "DLCX: endpoint released\n");
 	}
 
-	rate_ctr_inc(rate_ctr_group_get_ctr(rate_ctrs, MGCP_DLCX_SUCCESS));
+	rate_ctrs[MGCP_DLCX_SUCCESS]++;
 	if (silent)
 		goto out_silent;
 	return create_ok_resp_with_param(endp, endp, 250, "DLCX", pdata->trans, stats);
diff --git a/src/libosmo-mgcp/mgcp_ratectr.c b/src/libosmo-mgcp/mgcp_ratectr.c
index 6030ce2..e2b7f59 100644
--- a/src/libosmo-mgcp/mgcp_ratectr.c
+++ b/src/libosmo-mgcp/mgcp_ratectr.c
@@ -220,24 +220,24 @@
 			 trunk->trunk_nr);
 		rate_ctr_group_set_name(ratectr->mgcp_dlcx_ctr_group, ctr_name);
 	}
-	if (ratectr->all_rtp_conn_stats == NULL) {
-		ratectr->all_rtp_conn_stats = rate_ctr_group_alloc(trunk, &all_rtp_conn_rate_ctr_group_desc,
-								   all_rtp_conn_rate_ctr_index++);
-		if (!ratectr->all_rtp_conn_stats)
+	if (ratectr->all_rtp_conn_stats_group == NULL) {
+		ratectr->all_rtp_conn_stats_group =
+			rate_ctr_group_alloc(trunk, &all_rtp_conn_rate_ctr_group_desc, all_rtp_conn_rate_ctr_index++);
+		if (!ratectr->all_rtp_conn_stats_group)
 			return -EINVAL;
 		snprintf(ctr_name, sizeof(ctr_name), "%s-%u:rtp_conn", mgcp_trunk_type_strs_str(trunk->trunk_type),
 			 trunk->trunk_nr);
-		rate_ctr_group_set_name(ratectr->all_rtp_conn_stats, ctr_name);
+		rate_ctr_group_set_name(ratectr->all_rtp_conn_stats_group, ctr_name);
 	}
 
 	/* E1 specific */
-	if (trunk->trunk_type == MGCP_TRUNK_E1 && ratectr->e1_stats == NULL) {
-		ratectr->e1_stats = rate_ctr_group_alloc(trunk, &e1_rate_ctr_group_desc, mdcx_rate_ctr_index++);
-		if (!ratectr->e1_stats)
+	if (trunk->trunk_type == MGCP_TRUNK_E1 && ratectr->e1_stats_group == NULL) {
+		ratectr->e1_stats_group = rate_ctr_group_alloc(trunk, &e1_rate_ctr_group_desc, mdcx_rate_ctr_index++);
+		if (!ratectr->e1_stats_group)
 			return -EINVAL;
 		snprintf(ctr_name, sizeof(ctr_name), "%s-%u:e1", mgcp_trunk_type_strs_str(trunk->trunk_type),
 			 trunk->trunk_nr);
-		rate_ctr_group_set_name(ratectr->e1_stats, ctr_name);
+		rate_ctr_group_set_name(ratectr->e1_stats_group, ctr_name);
 	}
 	return 0;
 }
@@ -261,15 +261,15 @@
 		rate_ctr_group_free(ratectr->mgcp_dlcx_ctr_group);
 		ratectr->mgcp_dlcx_ctr_group = NULL;
 	}
-	if (ratectr->all_rtp_conn_stats) {
-		rate_ctr_group_free(ratectr->all_rtp_conn_stats);
-		ratectr->all_rtp_conn_stats = NULL;
+	if (ratectr->all_rtp_conn_stats_group) {
+		rate_ctr_group_free(ratectr->all_rtp_conn_stats_group);
+		ratectr->all_rtp_conn_stats_group = NULL;
 	}
 
 	/* E1 specific */
-	if (ratectr->e1_stats) {
-		rate_ctr_group_free(ratectr->e1_stats);
-		ratectr->e1_stats = NULL;
+	if (ratectr->e1_stats_group) {
+		rate_ctr_group_free(ratectr->e1_stats_group);
+		ratectr->e1_stats_group = NULL;
 	}
 }
 
diff --git a/src/libosmo-mgcp/mgcp_stat.c b/src/libosmo-mgcp/mgcp_stat.c
index e679882..512d141 100644
--- a/src/libosmo-mgcp/mgcp_stat.c
+++ b/src/libosmo-mgcp/mgcp_stat.c
@@ -29,6 +29,7 @@
 #include <osmocom/mgcp/mgcp_stat.h>
 #include <osmocom/mgcp/mgcp_endp.h>
 #include <osmocom/mgcp/mgcp_trunk.h>
+#include <stdatomic.h>
 
 /* Helper function for mgcp_format_stats_rtp() to calculate packet loss */
 #if defined(__has_attribute)
@@ -39,7 +40,7 @@
 void calc_loss(struct mgcp_conn_rtp *conn, uint32_t *expected, int *loss)
 {
 	struct mgcp_rtp_state *state = &conn->state;
-	struct rate_ctr *packets_rx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_RX_CTR);
+	atomic_uint_least64_t packets_rx = conn->atomic_counters[RTP_PACKETS_RX_CTR];
 
 	*expected = state->stats.cycles + state->stats.max_seq;
 	*expected = *expected - state->stats.base_seq + 1;
@@ -54,8 +55,8 @@
 	 * Make sure the sign is correct and use the biggest
 	 * positive/negative number that fits.
 	 */
-	*loss = *expected - packets_rx->current;
-	if (*expected < packets_rx->current) {
+	*loss = *expected - packets_rx;
+	if (*expected < packets_rx) {
 		if (*loss > 0)
 			*loss = INT_MIN;
 	} else {
@@ -80,19 +81,17 @@
 	int ploss;
 	int nchars;
 
-	struct rate_ctr *packets_rx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_RX_CTR);
-	struct rate_ctr *octets_rx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_OCTETS_RX_CTR);
-	struct rate_ctr *packets_tx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_TX_CTR);
-	struct rate_ctr *octets_tx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_OCTETS_TX_CTR);
+	atomic_uint_least64_t packets_rx = conn->atomic_counters[RTP_PACKETS_RX_CTR];
+	atomic_uint_least64_t octets_rx = conn->atomic_counters[RTP_OCTETS_RX_CTR];
+	atomic_uint_least64_t packets_tx = conn->atomic_counters[RTP_PACKETS_TX_CTR];
+	atomic_uint_least64_t octets_tx = conn->atomic_counters[RTP_OCTETS_TX_CTR];
 
 	calc_loss(conn, &expected, &ploss);
 	jitter = calc_jitter(&conn->state);
 
 	nchars = snprintf(str, str_len,
 			  "\r\nP: PS=%" PRIu64 ", OS=%" PRIu64 ", PR=%" PRIu64 ", OR=%" PRIu64 ", PL=%d, JI=%u",
-			  packets_tx->current, octets_tx->current,
-			  packets_rx->current, octets_rx->current,
-			  ploss, jitter);
+			  packets_tx, octets_tx, packets_rx, octets_rx, ploss, jitter);
 	if (nchars < 0 || nchars >= str_len)
 		goto truncate;
 
@@ -101,10 +100,8 @@
 
 	if (conn->conn->endp->trunk->cfg->osmux != OSMUX_USAGE_OFF) {
 		/* Error Counter */
-		nchars = snprintf(str, str_len,
-				  "\r\nX-Osmo-CP: EC TI=%" PRIu64 ", TO=%" PRIu64,
-				  conn->state.in_stream.err_ts_ctr->current,
-				  conn->state.out_stream.err_ts_ctr->current);
+		nchars = snprintf(str, str_len, "\r\nX-Osmo-CP: EC TI=%" PRIu64 ", TO=%" PRIu64,
+				  conn->state.in_stream.err_ts_ctr, conn->state.out_stream.err_ts_ctr);
 		if (nchars < 0 || nchars >= str_len)
 			goto truncate;
 
diff --git a/src/libosmo-mgcp/mgcp_threads.c b/src/libosmo-mgcp/mgcp_threads.c
index 6d47f24..afd744a 100644
--- a/src/libosmo-mgcp/mgcp_threads.c
+++ b/src/libosmo-mgcp/mgcp_threads.c
@@ -20,6 +20,7 @@
  */
 
 #include <pthread.h>
+#include <stdatomic.h>
 #include <stdio.h>
 #include <talloc.h>
 #include <assert.h>
@@ -234,6 +235,7 @@
 	temp_trunk.number_endpoints_offset = own_trunk_data->number_endpoints_offset;
 	temp_trunk.endpoints = own_trunk_data->endpoints;
 	temp_trunk.stats = own_trunk_data->stats;
+	temp_trunk.thread_ctr = own_trunk_data->thread_ctr;
 	temp_trunk.num_threads = own_trunk_data->num_threads;
 
 	if (own_trunk_data->trunk_type == MGCP_TRUNK_VIRTUAL)
@@ -413,6 +415,50 @@
 	//FIXME: shutdown
 }
 
+#define UPD_RATE_CTR_ATOMIC(ctrname, tid, enumname)                                                                    \
+	for (int i = 0; i < enumname; i++) {                                                                           \
+		atomic_uint_least64_t *c = &trunk->thread_info[tid].this_trunk->thread_ctr.ctrname##_atomic[i];        \
+		struct rate_ctr *ctr = &trunk->ratectr.ctrname##_group->ctr[i];                                        \
+		rate_ctr_add(ctr, *c - ctr->current);                                                                  \
+	}
+
+static struct osmo_timer_list rate_ctr_timer;
+
+/* updates rate counters by collecting the atomic per-thread counters, also updates ep used stats */
+static void rate_ctr_timer_cb(void *data)
+{
+	struct mgcp_trunk *trunk;
+	struct mgcp_config *cfg = data;
+
+	for (int i = 0; i < _MGCP_GENERAL_NUM_ENUMS; i++) {
+		struct rate_ctr *ctr = &cfg->ratectr.mgcp_general_ctr_group->ctr[i];
+		rate_ctr_add(ctr, cfg->ratectr.mgcp_general_ctr_atomic[i] - ctr->current);
+	}
+
+	atomic_uint_least64_t endpoints_used = 0;
+	llist_for_each_entry(trunk, &cfg->trunks, entry) {
+		int thread_num = 0;
+		/* at least once: 0-thread trunks still need updating! */
+		do {
+			UPD_RATE_CTR_ATOMIC(mgcp_crcx_ctr, thread_num, _MGCP_CRCX_NUM_ENUMS)
+			UPD_RATE_CTR_ATOMIC(mgcp_mdcx_ctr, thread_num, _MGCP_MDCX_NUM_ENUMS)
+			UPD_RATE_CTR_ATOMIC(mgcp_dlcx_ctr, thread_num, _MGCP_DLCX_NUM_ENUMS)
+			UPD_RATE_CTR_ATOMIC(all_rtp_conn_stats, thread_num, _MAX_RTP_CTR_NUM)
+			if (trunk->trunk_type == MGCP_TRUNK_E1)
+				UPD_RATE_CTR_ATOMIC(e1_stats, thread_num, _E1_I460_TRAU_NUM_ENUMS)
+
+			endpoints_used += trunk->thread_info[thread_num].this_trunk->number_endpoints -
+					  trunk->thread_info[thread_num].eps_free;
+		} while (++thread_num < trunk->num_threads);
+
+		/* cheat by using the rate ctr one second callback to also update the ep usage stats */
+		osmo_stat_item_set(osmo_stat_item_group_get_item(trunk->stats.common, TRUNK_STAT_ENDPOINTS_USED),
+				   endpoints_used);
+	}
+
+	osmo_timer_schedule(&rate_ctr_timer, 1, 0);
+}
+
 void split_trunks_into_threads(struct mgcp_config *cfg)
 {
 	struct mgcp_trunk *trunk;
@@ -447,4 +493,9 @@
 				split_per_thead(&trunk->thread_info[i]);
 		}
 	}
+
+	/* wait for the threads to be done with init, so main thread can safely read atomics*/
+	usleep(1000 * 100);
+	osmo_timer_setup(&rate_ctr_timer, rate_ctr_timer_cb, cfg);
+	osmo_timer_schedule(&rate_ctr_timer, 1, 0);
 }
diff --git a/src/libosmo-mgcp/mgcp_threads_vty.c b/src/libosmo-mgcp/mgcp_threads_vty.c
index 3259c8d..0cd6daa 100644
--- a/src/libosmo-mgcp/mgcp_threads_vty.c
+++ b/src/libosmo-mgcp/mgcp_threads_vty.c
@@ -31,15 +31,15 @@
 	struct mgcp_rtp_state *state = &conn->state;
 	struct mgcp_rtp_end *end = &conn->end;
 	struct mgcp_rtp_codec *codec = end->codec;
-	struct rate_ctr *tx_packets, *tx_bytes;
-	struct rate_ctr *rx_packets, *rx_bytes;
-	struct rate_ctr *dropped_packets;
+	atomic_uint_least64_t tx_packets, tx_bytes;
+	atomic_uint_least64_t rx_packets, rx_bytes;
+	atomic_uint_least64_t dropped_packets;
 
-	tx_packets = conn->rate_ctr_group[RTP_PACKETS_TX_CTR].ctr;
-	tx_bytes = conn->rate_ctr_group[RTP_OCTETS_TX_CTR].ctr;
-	rx_packets = conn->rate_ctr_group[RTP_PACKETS_RX_CTR].ctr;
-	rx_bytes = conn->rate_ctr_group[RTP_OCTETS_RX_CTR].ctr;
-	dropped_packets = conn->rate_ctr_group[RTP_DROPPED_PACKETS_CTR].ctr;
+	tx_packets = conn->atomic_counters[RTP_PACKETS_TX_CTR];
+	tx_bytes = conn->atomic_counters[RTP_OCTETS_TX_CTR];
+	rx_packets = conn->atomic_counters[RTP_PACKETS_RX_CTR];
+	rx_bytes = conn->atomic_counters[RTP_OCTETS_RX_CTR];
+	dropped_packets = conn->atomic_counters[RTP_DROPPED_PACKETS_CTR];
 
 	vty_out(vty,
 		"   Packets Sent: %" PRIu64 " (%" PRIu64 " bytes total)%s"
@@ -51,12 +51,12 @@
 		"   FPP: %d Packet Duration: %u%s"
 		"   FMTP-Extra: %s Audio-Name: %s Sub-Type: %s%s"
 		"   Output-Enabled: %d Force-PTIME: %d%s",
-		tx_packets->current, tx_bytes->current, VTY_NEWLINE, rx_packets->current, rx_bytes->current,
-		VTY_NEWLINE, state->in_stream.err_ts_ctr->current, state->out_stream.err_ts_ctr->current, VTY_NEWLINE,
-		dropped_packets->current, VTY_NEWLINE, codec->payload_type, codec->rate, codec->channels, VTY_NEWLINE,
-		codec->frame_duration_num, codec->frame_duration_den, VTY_NEWLINE, end->frames_per_packet,
-		end->packet_duration_ms, VTY_NEWLINE, end->fmtp_extra, codec->audio_name, codec->subtype_name,
-		VTY_NEWLINE, end->output_enabled, end->force_output_ptime, VTY_NEWLINE);
+		tx_packets, tx_bytes, VTY_NEWLINE, rx_packets, rx_bytes, VTY_NEWLINE, state->in_stream.err_ts_ctr,
+		state->out_stream.err_ts_ctr, VTY_NEWLINE, dropped_packets, VTY_NEWLINE, codec->payload_type,
+		codec->rate, codec->channels, VTY_NEWLINE, codec->frame_duration_num, codec->frame_duration_den,
+		VTY_NEWLINE, end->frames_per_packet, end->packet_duration_ms, VTY_NEWLINE, end->fmtp_extra,
+		codec->audio_name, codec->subtype_name, VTY_NEWLINE, end->output_enabled, end->force_output_ptime,
+		VTY_NEWLINE);
 }
 
 void dump_endpoint(struct vty *vty, struct mgcp_endpoint *endp, unsigned int trunk_nr, enum mgcp_trunk_type trunk_type,
diff --git a/src/libosmo-mgcp/mgcp_vty.c b/src/libosmo-mgcp/mgcp_vty.c
index 62a2bbf..8635fe0 100644
--- a/src/libosmo-mgcp/mgcp_vty.c
+++ b/src/libosmo-mgcp/mgcp_vty.c
@@ -209,22 +209,15 @@
 					   "   %25n: %10c (%S/s %M/m %H/h %D/d) %d",
 					   ratectr->mgcp_mdcx_ctr_group);
 	}
-	if (ratectr->all_rtp_conn_stats) {
-		vty_out(vty, "   %s:%s",
-			ratectr->all_rtp_conn_stats->desc->group_description,
-			VTY_NEWLINE);
-		vty_out_rate_ctr_group_fmt(vty,
-					   "   %25n: %10c (%S/s %M/m %H/h %D/d) %d",
-					   ratectr->all_rtp_conn_stats);
+	if (ratectr->all_rtp_conn_stats_group) {
+		vty_out(vty, "   %s:%s", ratectr->all_rtp_conn_stats_group->desc->group_description, VTY_NEWLINE);
+		vty_out_rate_ctr_group_fmt(vty, "   %25n: %10c (%S/s %M/m %H/h %D/d) %d",
+					   ratectr->all_rtp_conn_stats_group);
 	}
 
-	if (ratectr->e1_stats && trunk->trunk_type == MGCP_TRUNK_E1) {
-		vty_out(vty, "   %s:%s",
-			ratectr->e1_stats->desc->group_description,
-			VTY_NEWLINE);
-		vty_out_rate_ctr_group_fmt(vty,
-					   "   %25n: %10c (%S/s %M/m %H/h %D/d) %d",
-					   ratectr->e1_stats);
+	if (ratectr->e1_stats_group && trunk->trunk_type == MGCP_TRUNK_E1) {
+		vty_out(vty, "   %s:%s", ratectr->e1_stats_group->desc->group_description, VTY_NEWLINE);
+		vty_out_rate_ctr_group_fmt(vty, "   %25n: %10c (%S/s %M/m %H/h %D/d) %d", ratectr->e1_stats_group);
 	}
 }
 
diff --git a/tests/mgcp/mgcp_test.c b/tests/mgcp/mgcp_test.c
index 9deee85..c74a2c4 100644
--- a/tests/mgcp/mgcp_test.c
+++ b/tests/mgcp/mgcp_test.c
@@ -16,9 +16,8 @@
  * You should have received a copy of the GNU Affero General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
-#undef _GNU_SOURCE
-#define _GNU_SOURCE
 
+#include <stdatomic.h>
 #include <osmocom/mgcp/mgcp.h>
 #include <osmocom/mgcp/vty.h>
 #include <osmocom/mgcp/mgcp_common.h>
@@ -39,11 +38,17 @@
 #include <osmocom/core/socket.h>
 #include <string.h>
 #include <limits.h>
-#include <dlfcn.h>
+
 #include <time.h>
 #include <math.h>
 #include <ctype.h>
 
+#undef _GNU_SOURCE
+#define _GNU_SOURCE
+#undef __USE_GNU
+#define __USE_GNU
+#include <dlfcn.h>
+
 char *strline_r(char *str, char **saveptr);
 
 const char *strline_test_data =
@@ -1084,21 +1089,19 @@
 		struct mgcp_conn_rtp *conn = NULL;
 		struct mgcp_conn *_conn = NULL;
 		struct mgcp_rtp_state *state;
-		struct rate_ctr *packets_rx;
 
 		_conn =
 		    mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
 				    "test-connection");
 		conn = mgcp_conn_get_rtp(&endp, _conn->id);
 		state = &conn->state;
-		packets_rx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_RX_CTR);
 
 		state->stats.initialized = 1;
 		state->stats.base_seq = pl_test_dat[i].base_seq;
 		state->stats.max_seq = pl_test_dat[i].max_seq;
 		state->stats.cycles = pl_test_dat[i].cycles;
 
-		packets_rx->current = pl_test_dat[i].packets;
+		conn->atomic_counters[RTP_PACKETS_RX_CTR] = pl_test_dat[i].packets;
 		calc_loss(conn, &expected, &loss);
 
 		if (loss != pl_test_dat[i].loss
@@ -1309,8 +1312,8 @@
 	uint64_t last_out_ts_err_cnt = 0;
 	struct mgcp_conn_rtp *conn = NULL;
 	struct mgcp_conn *_conn = NULL;
-	struct rate_ctr test_ctr_in;
-	struct rate_ctr test_ctr_out;
+	atomic_uint_least64_t test_ctr_in;
+	atomic_uint_least64_t test_ctr_out;
 
 	printf("Testing packet error detection%s%s.\n",
 	       patch_ssrc ? ", patch SSRC" : "",
@@ -1323,8 +1326,8 @@
 
 	memset(&test_ctr_in, 0, sizeof(test_ctr_in));
 	memset(&test_ctr_out, 0, sizeof(test_ctr_out));
-	state.in_stream.err_ts_ctr = &test_ctr_in;
-	state.out_stream.err_ts_ctr = &test_ctr_out;
+	state.in_stream.err_ts_ctr = test_ctr_in;
+	state.out_stream.err_ts_ctr = test_ctr_out;
 
 	endp.type = &ep_typeset.rtp;
 
@@ -1374,17 +1377,16 @@
 
 		printf("Out TS change: %d, dTS: %d, Seq change: %d, "
 		       "TS Err change: in +%u, out +%u\n",
-		       state.out_stream.last_timestamp - last_timestamp,
-		       state.out_stream.last_tsdelta,
+		       state.out_stream.last_timestamp - last_timestamp, state.out_stream.last_tsdelta,
 		       state.out_stream.last_seq - last_seqno,
-		       (unsigned int) (state.in_stream.err_ts_ctr->current - last_in_ts_err_cnt),
-		       (unsigned int) (state.out_stream.err_ts_ctr->current - last_out_ts_err_cnt));
+		       (unsigned int)(state.in_stream.err_ts_ctr - last_in_ts_err_cnt),
+		       (unsigned int)(state.out_stream.err_ts_ctr - last_out_ts_err_cnt));
 
 		printf("Stats: Jitter = %u, Transit = %d\n",
 		       calc_jitter(&state), state.stats.transit);
 
-		last_in_ts_err_cnt = state.in_stream.err_ts_ctr->current;
-		last_out_ts_err_cnt = state.out_stream.err_ts_ctr->current;
+		last_in_ts_err_cnt = state.in_stream.err_ts_ctr;
+		last_out_ts_err_cnt = state.out_stream.err_ts_ctr;
 		last_timestamp = state.out_stream.last_timestamp;
 		last_seqno = state.out_stream.last_seq;
 

-- 
To view, visit https://gerrit.osmocom.org/c/osmo-mgw/+/26193
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-mgw
Gerrit-Branch: master
Gerrit-Change-Id: I5e3598f80cb062dbab376663ee51136b4508b78d
Gerrit-Change-Number: 26193
Gerrit-PatchSet: 1
Gerrit-Owner: Hoernchen <ewild at sysmocom.de>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20211109/4c921d50/attachment.htm>


More information about the gerrit-log mailing list