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

<div style="display:none"> Gerrit-Project: osmo-mgw </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Iaab3fc262649cb5fb886f0297a60286bde1ffeb0 </div>
<div style="display:none"> Gerrit-Change-Number: 26190 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Hoernchen <ewild@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>