<p>Vadim Yanitskiy has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/12698">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">libmsc/osmo_msc.c: move connection ref-counting code to 'ran_conn.c'<br><br>Change-Id: I593675d9bf56eaef12afdaf596ee1337b9a44259<br>---<br>M src/libmsc/osmo_msc.c<br>M src/libmsc/ran_conn.c<br>2 files changed, 111 insertions(+), 111 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-msc refs/changes/98/12698/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/libmsc/osmo_msc.c b/src/libmsc/osmo_msc.c</span><br><span>index 1a1ba3c..9828da1 100644</span><br><span>--- a/src/libmsc/osmo_msc.c</span><br><span>+++ b/src/libmsc/osmo_msc.c</span><br><span>@@ -219,117 +219,6 @@</span><br><span> return 1;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static const char *used_ref_counts_str(struct ran_conn *conn)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- static char buf[256];</span><br><span style="color: hsl(0, 100%, 40%);">- int bit_nr;</span><br><span style="color: hsl(0, 100%, 40%);">- char *pos = buf;</span><br><span style="color: hsl(0, 100%, 40%);">- *pos = '\0';</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (conn->use_tokens < 0)</span><br><span style="color: hsl(0, 100%, 40%);">- return "invalid";</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#define APPEND_STR(fmt, args...) do { \</span><br><span style="color: hsl(0, 100%, 40%);">- int remain = sizeof(buf) - (pos - buf) - 1; \</span><br><span style="color: hsl(0, 100%, 40%);">- int l = -1; \</span><br><span style="color: hsl(0, 100%, 40%);">- if (remain > 0) \</span><br><span style="color: hsl(0, 100%, 40%);">- l = snprintf(pos, remain, "%s" fmt, (pos == buf? "" : ","), ##args); \</span><br><span style="color: hsl(0, 100%, 40%);">- if (l < 0 || l > remain) { \</span><br><span style="color: hsl(0, 100%, 40%);">- buf[sizeof(buf) - 1] = '\0'; \</span><br><span style="color: hsl(0, 100%, 40%);">- return buf; \</span><br><span style="color: hsl(0, 100%, 40%);">- } \</span><br><span style="color: hsl(0, 100%, 40%);">- pos += l; \</span><br><span style="color: hsl(0, 100%, 40%);">- } while(0)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- for (bit_nr = 0; (1 << bit_nr) <= conn->use_tokens; bit_nr++) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (conn->use_tokens & (1 << bit_nr)) {</span><br><span style="color: hsl(0, 100%, 40%);">- APPEND_STR("%s", get_value_string(ran_conn_use_names, bit_nr));</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%);">- return buf;</span><br><span style="color: hsl(0, 100%, 40%);">-#undef APPEND_STR</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%);">-/* increment the ref-count. Needs to be called by every user */</span><br><span style="color: hsl(0, 100%, 40%);">-struct ran_conn *_ran_conn_get(struct ran_conn *conn, enum ran_conn_use balance_token,</span><br><span style="color: hsl(0, 100%, 40%);">- const char *file, int line)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(conn);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (balance_token != RAN_CONN_USE_UNTRACKED) {</span><br><span style="color: hsl(0, 100%, 40%);">- uint32_t flag = 1 << balance_token;</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(balance_token < 32);</span><br><span style="color: hsl(0, 100%, 40%);">- if (conn->use_tokens & flag)</span><br><span style="color: hsl(0, 100%, 40%);">- LOGPSRC(DREF, LOGL_ERROR, file, line,</span><br><span style="color: hsl(0, 100%, 40%);">- "%s: MSC conn use error: using an already used token: %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">- vlr_subscr_name(conn->vsub),</span><br><span style="color: hsl(0, 100%, 40%);">- ran_conn_use_name(balance_token));</span><br><span style="color: hsl(0, 100%, 40%);">- conn->use_tokens |= flag;</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%);">- conn->use_count++;</span><br><span style="color: hsl(0, 100%, 40%);">- LOGPSRC(DREF, LOGL_DEBUG, file, line,</span><br><span style="color: hsl(0, 100%, 40%);">- "%s: MSC conn use + %s == %u (0x%x: %s)\n",</span><br><span style="color: hsl(0, 100%, 40%);">- vlr_subscr_name(conn->vsub), ran_conn_use_name(balance_token),</span><br><span style="color: hsl(0, 100%, 40%);">- conn->use_count, conn->use_tokens, used_ref_counts_str(conn));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- return conn;</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%);">-/* decrement the ref-count. Once it reaches zero, we release */</span><br><span style="color: hsl(0, 100%, 40%);">-void _ran_conn_put(struct ran_conn *conn, enum ran_conn_use balance_token,</span><br><span style="color: hsl(0, 100%, 40%);">- const char *file, int line)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(conn);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (balance_token != RAN_CONN_USE_UNTRACKED) {</span><br><span style="color: hsl(0, 100%, 40%);">- uint32_t flag = 1 << balance_token;</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(balance_token < 32);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!(conn->use_tokens & flag))</span><br><span style="color: hsl(0, 100%, 40%);">- LOGPSRC(DREF, LOGL_ERROR, file, line,</span><br><span style="color: hsl(0, 100%, 40%);">- "%s: MSC conn use error: freeing an unused token: %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">- vlr_subscr_name(conn->vsub),</span><br><span style="color: hsl(0, 100%, 40%);">- ran_conn_use_name(balance_token));</span><br><span style="color: hsl(0, 100%, 40%);">- conn->use_tokens &= ~flag;</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%);">- if (conn->use_count == 0) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGPSRC(DREF, LOGL_ERROR, file, line,</span><br><span style="color: hsl(0, 100%, 40%);">- "%s: MSC conn use - %s failed: is already 0\n",</span><br><span style="color: hsl(0, 100%, 40%);">- vlr_subscr_name(conn->vsub),</span><br><span style="color: hsl(0, 100%, 40%);">- ran_conn_use_name(balance_token));</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%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- conn->use_count--;</span><br><span style="color: hsl(0, 100%, 40%);">- LOGPSRC(DREF, LOGL_DEBUG, file, line,</span><br><span style="color: hsl(0, 100%, 40%);">- "%s: MSC conn use - %s == %u (0x%x: %s)\n",</span><br><span style="color: hsl(0, 100%, 40%);">- vlr_subscr_name(conn->vsub), ran_conn_use_name(balance_token),</span><br><span style="color: hsl(0, 100%, 40%);">- conn->use_count, conn->use_tokens, used_ref_counts_str(conn));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (conn->use_count == 0)</span><br><span style="color: hsl(0, 100%, 40%);">- osmo_fsm_inst_dispatch(conn->fi, RAN_CONN_E_UNUSED, NULL);</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%);">-bool ran_conn_used_by(struct ran_conn *conn, enum ran_conn_use token)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- return conn && (conn->use_tokens & (1 << token));</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%);">-const struct value_string ran_conn_use_names[] = {</span><br><span style="color: hsl(0, 100%, 40%);">- {RAN_CONN_USE_UNTRACKED, "UNTRACKED"},</span><br><span style="color: hsl(0, 100%, 40%);">- {RAN_CONN_USE_COMPL_L3, "compl_l3"},</span><br><span style="color: hsl(0, 100%, 40%);">- {RAN_CONN_USE_DTAP, "dtap"},</span><br><span style="color: hsl(0, 100%, 40%);">- {RAN_CONN_USE_AUTH_CIPH, "auth+ciph"},</span><br><span style="color: hsl(0, 100%, 40%);">- {RAN_CONN_USE_CM_SERVICE, "cm_service"},</span><br><span style="color: hsl(0, 100%, 40%);">- {RAN_CONN_USE_TRANS_CC, "trans_cc"},</span><br><span style="color: hsl(0, 100%, 40%);">- {RAN_CONN_USE_TRANS_SMS, "trans_sms"},</span><br><span style="color: hsl(0, 100%, 40%);">- {RAN_CONN_USE_TRANS_NC_SS, "trans_nc_ss"},</span><br><span style="color: hsl(0, 100%, 40%);">- {RAN_CONN_USE_SILENT_CALL, "silent_call"},</span><br><span style="color: hsl(0, 100%, 40%);">- {RAN_CONN_USE_RELEASE, "release"},</span><br><span style="color: hsl(0, 100%, 40%);">- {0, NULL},</span><br><span style="color: hsl(0, 100%, 40%);">-};</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> void msc_stop_paging(struct vlr_subscr *vsub)</span><br><span> {</span><br><span> DEBUGP(DPAG, "Paging can stop for %s\n", vlr_subscr_name(vsub));</span><br><span>diff --git a/src/libmsc/ran_conn.c b/src/libmsc/ran_conn.c</span><br><span>index 4eefa6d..eea9936 100644</span><br><span>--- a/src/libmsc/ran_conn.c</span><br><span>+++ b/src/libmsc/ran_conn.c</span><br><span>@@ -772,3 +772,114 @@</span><br><span> {</span><br><span> rx_close_complete(conn, "Iu Release Complete", &conn->iu.waiting_for_release_complete);</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const struct value_string ran_conn_use_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ { RAN_CONN_USE_UNTRACKED, "UNTRACKED" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { RAN_CONN_USE_COMPL_L3, "compl_l3" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { RAN_CONN_USE_DTAP, "dtap" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { RAN_CONN_USE_AUTH_CIPH, "auth+ciph" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { RAN_CONN_USE_CM_SERVICE, "cm_service" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { RAN_CONN_USE_TRANS_CC, "trans_cc" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { RAN_CONN_USE_TRANS_SMS, "trans_sms" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { RAN_CONN_USE_TRANS_NC_SS, "trans_nc_ss" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { RAN_CONN_USE_SILENT_CALL, "silent_call" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { RAN_CONN_USE_RELEASE, "release" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { 0, NULL }</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 const char *used_ref_counts_str(struct ran_conn *conn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ static char buf[256];</span><br><span style="color: hsl(120, 100%, 40%);">+ int bit_nr;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *pos = buf;</span><br><span style="color: hsl(120, 100%, 40%);">+ *pos = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (conn->use_tokens < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ return "invalid";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define APPEND_STR(fmt, args...) do { \</span><br><span style="color: hsl(120, 100%, 40%);">+ int remain = sizeof(buf) - (pos - buf) - 1; \</span><br><span style="color: hsl(120, 100%, 40%);">+ int l = -1; \</span><br><span style="color: hsl(120, 100%, 40%);">+ if (remain > 0) \</span><br><span style="color: hsl(120, 100%, 40%);">+ l = snprintf(pos, remain, "%s" fmt, (pos == buf? "" : ","), ##args); \</span><br><span style="color: hsl(120, 100%, 40%);">+ if (l < 0 || l > remain) { \</span><br><span style="color: hsl(120, 100%, 40%);">+ buf[sizeof(buf) - 1] = '\0'; \</span><br><span style="color: hsl(120, 100%, 40%);">+ return buf; \</span><br><span style="color: hsl(120, 100%, 40%);">+ } \</span><br><span style="color: hsl(120, 100%, 40%);">+ pos += l; \</span><br><span style="color: hsl(120, 100%, 40%);">+ } while(0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ for (bit_nr = 0; (1 << bit_nr) <= conn->use_tokens; bit_nr++) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (conn->use_tokens & (1 << bit_nr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ APPEND_STR("%s", get_value_string(ran_conn_use_names, bit_nr));</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%);">+ return buf;</span><br><span style="color: hsl(120, 100%, 40%);">+#undef APPEND_STR</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%);">+/* increment the ref-count. Needs to be called by every user */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ran_conn *_ran_conn_get(struct ran_conn *conn, enum ran_conn_use balance_token,</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *file, int line)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(conn);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (balance_token != RAN_CONN_USE_UNTRACKED) {</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t flag = 1 << balance_token;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(balance_token < 32);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (conn->use_tokens & flag)</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPSRC(DREF, LOGL_ERROR, file, line,</span><br><span style="color: hsl(120, 100%, 40%);">+ "%s: MSC conn use error: using an already used token: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ vlr_subscr_name(conn->vsub),</span><br><span style="color: hsl(120, 100%, 40%);">+ ran_conn_use_name(balance_token));</span><br><span style="color: hsl(120, 100%, 40%);">+ conn->use_tokens |= flag;</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%);">+ conn->use_count++;</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPSRC(DREF, LOGL_DEBUG, file, line,</span><br><span style="color: hsl(120, 100%, 40%);">+ "%s: MSC conn use + %s == %u (0x%x: %s)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ vlr_subscr_name(conn->vsub), ran_conn_use_name(balance_token),</span><br><span style="color: hsl(120, 100%, 40%);">+ conn->use_count, conn->use_tokens, used_ref_counts_str(conn));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return conn;</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%);">+/* decrement the ref-count. Once it reaches zero, we release */</span><br><span style="color: hsl(120, 100%, 40%);">+void _ran_conn_put(struct ran_conn *conn, enum ran_conn_use balance_token,</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *file, int line)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(conn);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (balance_token != RAN_CONN_USE_UNTRACKED) {</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t flag = 1 << balance_token;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(balance_token < 32);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!(conn->use_tokens & flag))</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPSRC(DREF, LOGL_ERROR, file, line,</span><br><span style="color: hsl(120, 100%, 40%);">+ "%s: MSC conn use error: freeing an unused token: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ vlr_subscr_name(conn->vsub),</span><br><span style="color: hsl(120, 100%, 40%);">+ ran_conn_use_name(balance_token));</span><br><span style="color: hsl(120, 100%, 40%);">+ conn->use_tokens &= ~flag;</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%);">+ if (conn->use_count == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPSRC(DREF, LOGL_ERROR, file, line,</span><br><span style="color: hsl(120, 100%, 40%);">+ "%s: MSC conn use - %s failed: is already 0\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ vlr_subscr_name(conn->vsub),</span><br><span style="color: hsl(120, 100%, 40%);">+ ran_conn_use_name(balance_token));</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</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%);">+ conn->use_count--;</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPSRC(DREF, LOGL_DEBUG, file, line,</span><br><span style="color: hsl(120, 100%, 40%);">+ "%s: MSC conn use - %s == %u (0x%x: %s)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ vlr_subscr_name(conn->vsub), ran_conn_use_name(balance_token),</span><br><span style="color: hsl(120, 100%, 40%);">+ conn->use_count, conn->use_tokens, used_ref_counts_str(conn));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (conn->use_count == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_dispatch(conn->fi, RAN_CONN_E_UNUSED, NULL);</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%);">+bool ran_conn_used_by(struct ran_conn *conn, enum ran_conn_use token)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return conn && (conn->use_tokens & (1 << token));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/12698">change 12698</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/12698"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: osmo-msc </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: I593675d9bf56eaef12afdaf596ee1337b9a44259 </div>
<div style="display:none"> Gerrit-Change-Number: 12698 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Vadim Yanitskiy <axilirator@gmail.com> </div>