From 945c4ce971b6ac483278cfeabea6f4de4fd4420d Mon Sep 17 00:00:00 2001
From: Olivier Dion <olivier.dion@savoirfairelinux.com>
Date: Fri, 28 Jan 2022 16:24:01 -0500
Subject: [PATCH] test/agent/jami/signal: Add syntax rules for signal handlers

Small helpers for signal handling.

`with-signal-handler` is useful for scoping signal handler and
`with-signal-handler-sync` for signal synchronization.

Change-Id: Idc7696fb273003d526f3a4658e7fb5623c2c5827
---
 test/agent/Makefile.am               |  1 +
 test/agent/jami/signal.scm           | 58 ++++++++++++++++++++++++++++
 test/agent/src/bindings/bindings.cpp |  2 +-
 3 files changed, 60 insertions(+), 1 deletion(-)
 create mode 100644 test/agent/jami/signal.scm

diff --git a/test/agent/Makefile.am b/test/agent/Makefile.am
index b031ff6e33..8e0df4771b 100644
--- a/test/agent/Makefile.am
+++ b/test/agent/Makefile.am
@@ -23,6 +23,7 @@ MODULES =                                       \
 	examples/active-agent.scm               \
 	examples/passive-agent.scm              \
 	jami/logger.scm                         \
+	jami/signal.scm                         \
 	scenarios/peer-monitor/scenario.scm
 
 GOBJECTS = $(MODULES:%=%.go)
diff --git a/test/agent/jami/signal.scm b/test/agent/jami/signal.scm
new file mode 100644
index 0000000000..ba33c3c593
--- /dev/null
+++ b/test/agent/jami/signal.scm
@@ -0,0 +1,58 @@
+(define-module (jami signal)
+  #:use-module (ice-9 atomic)
+  #:use-module (ice-9 format)
+  #:use-module (ice-9 threads)
+  #:use-module (jami logger)
+  #:use-module (jami signal bindings)
+  #:re-export (on-signal)
+  #:export-syntax (with-signal
+                   with-signal-sync)
+  #:export (log-signal))
+
+;;; Install for signal SIG an HANDLER and execute bodies.  HANDLER is removed
+;;; for SIG at the exit of the dynamic extent.
+(define-syntax-rule (with-signal sig handler body body* ...)
+  (let ([continue? (make-atomic-box #t)])
+    (dynamic-wind
+      (const #f)
+      (lambda ()
+        (on-signal
+         sig
+         (lambda args
+           (let ([continue? (atomic-box-ref continue?)])
+             (when continue? (apply handler args))
+             continue?)))
+        body
+        body* ...)
+      (lambda () (atomic-box-set! continue? #f)))))
+
+(define* (wait-cnd cnd mtx #:optional timeout)
+  (if timeout
+      (wait-condition-variable cnd mtx (+ (current-time) timeout))
+      (wait-condition-variable cnd mtx)))
+
+;;; Synchronize with Jami's signal.  Install signal handler for SIG and wait for
+;;; either PRED to return #t or that TIMEOUT seconds has expired, after TRIGGERS
+;;; are been executed.
+(define-syntax with-signal-sync
+  (syntax-rules ()
+    [(_ sig pred) (with-signal-sync sig pred #f #f)]
+    [(_ sig pred timeout) (with-signal-sync sig pred timeout #f)]
+    [(_ sig pred timeout triggers ...)
+     (let ([mtx (make-recursive-mutex)]
+           [cnd (make-condition-variable)])
+       (with-mutex mtx
+         (on-signal sig (lambda args
+                          (let ([sync? (apply pred args)])
+                            (when sync?
+                              (with-mutex mtx
+                                (signal-condition-variable cnd)))
+                            (not sync?))))
+         (begin triggers ...)
+         (wait-cnd cnd mtx timeout)))]))
+
+;;; Install signal handler for SIG that print the arguments of the signal.
+(define (log-signal sig)
+  (on-signal sig (lambda args
+                   (info "Signal ~a:~{ ~a~}" sig args)
+                   #t)))
diff --git a/test/agent/src/bindings/bindings.cpp b/test/agent/src/bindings/bindings.cpp
index ca076fdcaf..6fc36ee44e 100644
--- a/test/agent/src/bindings/bindings.cpp
+++ b/test/agent/src/bindings/bindings.cpp
@@ -40,7 +40,7 @@ install_scheme_primitives()
     load_module("jami call", install_call_primitives);
     load_module("jami conversation", install_conversation_primitives);
     load_module("jami logger bindings", install_logger_primitives);
-    load_module("jami signal", install_signal_primitives);
+    load_module("jami signal bindings", install_signal_primitives);
 }
 
 /*
-- 
GitLab