laforge has submitted this change. (
https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/38206?usp=email )
Change subject: library: add generic Mutex API for parallel components
......................................................................
library: add generic Mutex API for parallel components
In certain scenarios, it's required to ensure that only one of multiple
parallel components executes a specific code block at any given time.
This, for example, is the case for the S1GW testsuite, where we want to
simulate multiple eNBs establishing E-RABs. Each new E-RAB triggers the
IUT (osmo-s1gw) to send a PFCP Session Establishment Request, and there
is no way for the PFCPEM to correlate which session belongs to which eNB.
This problem can be solved by ensuring that only one eNB is triggering
the PFCP Session Establishment Request(s) at a time.
This patch implements a generic Mutex API, which can also be used
by other testsuites that orchestrate multiple parallel components.
Change-Id: Id71f43bd5fc78d4bb4417d6c01fcff8112ea6032
---
A library/Mutex.ttcn
1 file changed, 135 insertions(+), 0 deletions(-)
Approvals:
laforge: Looks good to me, approved
Jenkins Builder: Verified
diff --git a/library/Mutex.ttcn b/library/Mutex.ttcn
new file mode 100644
index 0000000..625090b
--- /dev/null
+++ b/library/Mutex.ttcn
@@ -0,0 +1,135 @@
+/* Generic Mutex API for parallel components.
+ *
+ * (C) 2024 by sysmocom - s.f.m.c. GmbH <info(a)sysmocom.de>
+ * Author: Vadim Yanitskiy <vyanitskiy(a)sysmocom.de>
+ *
+ * All rights reserved.
+ *
+ * Released under the terms of GNU General Public License, Version 2 or
+ * (at your option) any later version.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+module Mutex {
+
+import from Misc_Helpers all;
+
+type component MutexCT {
+ port MutexPT LOCK; /* port for LOCKing the mutex */
+ port MutexPT UNLOCK; /* port for UNLOCKing the mutex */
+ var integer g_mutex_ref;
+};
+
+type port MutexPT procedure {
+ inout MUTEX_LOCK;
+ inout MUTEX_UNLOCK;
+} with { extension "internal" };
+
+private signature MUTEX_LOCK(out integer ref);
+private signature MUTEX_UNLOCK(in integer ref) noblock;
+
+type component MutexDispCT extends MutexCT { };
+
+private function f_MutexDisp_main()
+runs on MutexDispCT {
+ var boolean locked := false;
+ var MutexCT vc_conn;
+
+ g_mutex_ref := 0;
+
+ alt {
+ [not locked] LOCK.getcall(MUTEX_LOCK:{?}) -> sender vc_conn {
+ LOCK.reply(MUTEX_LOCK:{g_mutex_ref}) to vc_conn;
+ locked := true;
+ repeat;
+ }
+ [locked] UNLOCK.getcall(MUTEX_UNLOCK:{g_mutex_ref}) {
+ g_mutex_ref := g_mutex_ref + 1;
+ locked := false;
+ repeat;
+ }
+ [not locked] UNLOCK.getcall -> sender vc_conn {
+ setverdict(fail, __SCOPE__, "(): ",
+ "mutex unlock without prior lock from ", vc_conn);
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
+ }
+ [locked] UNLOCK.getcall(MUTEX_UNLOCK:{?}) -> sender vc_conn {
+ setverdict(fail, __SCOPE__, "(): ",
+ "mutex unlock was not unexpected from ", vc_conn);
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
+ }
+ }
+}
+
+/* used by the MTC to start the mutex dispatcher */
+function f_MutexDisp_start()
+return MutexDispCT {
+ var MutexDispCT vc_disp;
+
+ vc_disp := MutexDispCT.create("MutexDispCT-" & testcasename());
+ vc_disp.start(f_MutexDisp_main());
+
+ return vc_disp;
+}
+
+/* used by the MTC to connect a parallel component to the mutex dispatcher */
+function f_MutexDisp_connect(MutexDispCT vc_disp, MutexCT vc_conn)
+{
+ connect(vc_disp:LOCK, vc_conn:LOCK);
+ connect(vc_disp:UNLOCK, vc_conn:UNLOCK);
+}
+
+/* used by parallel components to lock the mutex (blocking) */
+function f_Mutex_lock(charstring file, integer line,
+ float Tval := 10.0)
+runs on MutexCT {
+ LOCK.call(MUTEX_LOCK:{-}, Tval) {
+ [] LOCK.getreply(MUTEX_LOCK:{?}) -> param(g_mutex_ref) {
+ log(__SCOPE__, "(): mutex acquired @ ", file, ":", line);
+ }
+ [] LOCK.catch(timeout) {
+ setverdict(fail, __SCOPE__, "(): timeout @ ", file, ":", line);
+ Misc_Helpers.f_shutdown(file, line);
+ }
+ }
+}
+
+/* used by parallel components to unlock the mutex (non-blocking) */
+function f_Mutex_unlock(charstring file, integer line)
+runs on MutexCT {
+ UNLOCK.call(MUTEX_UNLOCK:{g_mutex_ref});
+ log(__SCOPE__, "(): mutex released @ ", file, ":", line);
+}
+
+
+/* self-test for this module */
+private type component TestCT { };
+private type component TestChildCT extends MutexCT { };
+
+private function f_TC_selftest()
+runs on TestChildCT {
+ f_Mutex_lock(__BFILE__, __LINE__);
+ /* yay, we're the only one ruling this parallel world! */
+ f_Mutex_unlock(__BFILE__, __LINE__);
+ setverdict(pass);
+}
+
+testcase TC_selftest() runs on TestCT {
+ var TestChildCT vc_conns[42];
+ var MutexDispCT vc_disp;
+
+ vc_disp := f_MutexDisp_start();
+
+ for (var integer i := 0; i < sizeof(vc_conns); i := i + 1) {
+ vc_conns[i] := TestChildCT.create("TestChildCT-" & int2str(i));
+ f_MutexDisp_connect(vc_disp, vc_conns[i]);
+ vc_conns[i].start(f_TC_selftest());
+ }
+
+ for (var integer i := 0; i < sizeof(vc_conns); i := i + 1) {
+ vc_conns[i].done;
+ }
+}
+
+}
--
To view, visit
https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/38206?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: osmo-ttcn3-hacks
Gerrit-Branch: master
Gerrit-Change-Id: Id71f43bd5fc78d4bb4417d6c01fcff8112ea6032
Gerrit-Change-Number: 38206
Gerrit-PatchSet: 5
Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-CC: pespin <pespin(a)sysmocom.de>