Index | Thread | Search

From:
Alexandre Ratchov <alex@caoua.org>
Subject:
sndiod: Fix SIGHUP to reopen the devices in priority order
To:
tech@openbsd.org
Date:
Mon, 22 Apr 2024 14:05:00 +0200

Download raw body.

Thread
  • Alexandre Ratchov:

    sndiod: Fix SIGHUP to reopen the devices in priority order

With this diff, SIGHUP makes sndiod discover new devices and if there is a
new device with higher priority (greater -F option number) than the current
one, sndiod switches to it.  If the current device is already the one with
the highest priority (i.e. last -F), then SIGHUP does nothing.

Now that we've the server.device knob exposed by sndioctl(1), I don't
recommend using SIGHUP to toggle between two devices anymore.

If you're still using SIGHUP, please test this diff.

OK?

Index: midi.c
===================================================================
RCS file: /cvs/src/usr.bin/sndiod/midi.c,v
diff -u -p -r1.29 midi.c
--- midi.c	1 Nov 2021 14:43:25 -0000	1.29
+++ midi.c	22 Apr 2024 11:11:09 -0000
@@ -155,6 +155,23 @@ midi_link(struct midi *ep, struct midi *
 }
 
 /*
+ * return the list of endpoints the given one receives from
+ */
+unsigned int
+midi_rxmask(struct midi *ep)
+{
+	int i, rxmask;
+
+	for (rxmask = 0, i = 0; i < MIDI_NEP; i++) {
+		if ((midi_ep[i].txmask & ep->self) == 0)
+			continue;
+		rxmask |= midi_ep[i].self;
+	}
+
+	return rxmask;
+}
+
+/*
  * add the midi endpoint in the ``tag'' midi thru box
  */
 void
Index: midi.h
===================================================================
RCS file: /cvs/src/usr.bin/sndiod/midi.h,v
diff -u -p -r1.15 midi.h
--- midi.h	1 Nov 2021 14:43:25 -0000	1.15
+++ midi.h	22 Apr 2024 11:11:09 -0000
@@ -112,6 +112,7 @@ void midi_send(struct midi *, unsigned c
 void midi_fill(struct midi *);
 void midi_tag(struct midi *, unsigned int);
 unsigned int midi_tags(struct midi *);
+unsigned int midi_rxmask(struct midi *);
 void midi_link(struct midi *, struct midi *);
 void midi_abort(struct midi *);
 void midi_migrate(struct midi *, struct midi *);
Index: sndiod.c
===================================================================
RCS file: /cvs/src/usr.bin/sndiod/sndiod.c,v
diff -u -p -r1.48 sndiod.c
--- sndiod.c	7 Mar 2022 08:58:33 -0000	1.48
+++ sndiod.c	22 Apr 2024 11:11:09 -0000
@@ -254,6 +254,89 @@ opt_mode(void)
 	return mode;
 }
 
+/*
+ * Open all devices. Possibly switch to the new devices if they have higher
+ * priorities than the current ones.
+ */
+static void
+reopen_devs(void)
+{
+	struct opt *o;
+	struct dev *d, *a;
+
+	for (o = opt_list; o != NULL; o = o->next) {
+
+		/* skip unused logical devices and ones with fixed hardware */
+		if (o->refcnt == 0 || strcmp(o->name, o->dev->name) == 0)
+			continue;
+
+		/* circulate to the device with the highest prio */
+		a = o->alt_first;
+		for (d = a; d->alt_next != a; d = d->alt_next) {
+			if (d->num > o->alt_first->num)
+				o->alt_first = d;
+		}
+
+		/* switch to the first working one, in pririty order */
+		d = o->alt_first;
+		while (d != o->dev) {
+			if (opt_setdev(o, d))
+				break;
+			d = d->alt_next;
+		}
+	}
+
+	/*
+	 * retry to open the remaining devices that are not used but need
+	 * to stay open (ex. '-a on')
+	 */
+	for (d = dev_list; d != NULL; d = d->next) {
+		if (d->refcnt > 0 && d->pstate == DEV_CFG)
+			dev_open(d);
+	}
+}
+
+/*
+ * For each port, open the alt with the highest priority and switch to it
+ */
+static void
+reopen_ports(void)
+{
+	struct port *p, *a, *apri;
+	int inuse;
+
+	for (p = port_list; p != NULL; p = a->next) {
+
+		/* skip unused ports */
+		inuse = 0;
+		a = p;
+		while (1) {
+			if (midi_rxmask(a->midi) || a->midi->txmask)
+				inuse = 1;
+			if (a->alt_next == p)
+				break;
+			a = a->alt_next;
+		}
+		if (!inuse)
+			continue;
+
+		/* open the alt with the highest prio */
+		apri = port_alt_ref(p->num);
+
+		/* switch to it */
+		a = p;
+		while (1) {
+			if (a != apri) {
+				midi_migrate(a->midi, apri->midi);
+				port_unref(a);
+			}
+			if (a->alt_next == p)
+				break;
+			a = a->alt_next;
+		}
+	}
+}
+
 void
 setsig(void)
 {
@@ -461,7 +544,6 @@ main(int argc, char **argv)
 	char base[SOCKPATH_MAX], path[SOCKPATH_MAX];
 	unsigned int mode, dup, mmc, vol;
 	unsigned int hold, autovol, bufsz, round, rate;
-	unsigned int reopen_list;
 	const char *str;
 	struct aparams par;
 	struct opt *o;
@@ -712,33 +794,14 @@ main(int argc, char **argv)
 		if (pledge("stdio audio recvfd unix", NULL) == -1)
 			err(1, "pledge");
 	}
+
 	for (;;) {
 		if (quit_flag)
 			break;
 		if (reopen_flag) {
 			reopen_flag = 0;
-
-			reopen_list = 0;
-			for (d = dev_list; d != NULL; d = d->next) {
-				if (d->pstate != DEV_CFG)
-					reopen_list |= (1 << d->num);
-			}
-			for (d = dev_list; d != NULL; d = d->next) {
-				if (reopen_list & (1 << d->num))
-					dev_migrate(d);
-			}
-
-			reopen_list = 0;
-			for (p = port_list; p != NULL; p = p->next) {
-				if (p->state != PORT_CFG)
-					reopen_list |= (1 << p->num);
-			}
-			for (p = port_list; p != NULL; p = p->next) {
-				if (reopen_list & (1 << p->num)) {
-					if (port_migrate(p) != p)
-						port_close(p);
-				}
-			}
+			reopen_devs();
+			reopen_ports();
 		}
 		if (!fdpass_peer)
 			break;