]> git.alsa-project.org Git - alsa-utils.git/commitdiff
alsactl: add locking for per-card initialization
authorJaroslav Kysela <perex@perex.cz>
Wed, 2 Feb 2022 14:31:33 +0000 (15:31 +0100)
committerJaroslav Kysela <perex@perex.cz>
Wed, 2 Feb 2022 14:34:40 +0000 (15:34 +0100)
Introduce the -K,--lock-dir parameter to specify the locking
directory. If the locking is active, files card<NUM>.lock
are used to serialize the multiple initialization requests
(udev, service).

Allow the relative -O,--lock-file argument (it's default now).

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
alsactl/Makefile.am
alsactl/alsactl.c
alsactl/alsactl.h
alsactl/lock.c
alsactl/state.c
alsactl/utils.c

index deff2cd1e8b7f68dae1f037f65c7cbfaf6ce2cca..3d2f6e82b9e261eb41268bb5ca75694043fcada3 100644 (file)
@@ -14,7 +14,8 @@ alsactl_SOURCES=alsactl.c state.c lock.c utils.c init_parse.c init_ucm.c \
 
 alsactl_CFLAGS=$(AM_CFLAGS) -D__USE_GNU \
                -DSYS_ASOUNDRC=\"$(ASOUND_STATE_DIR)/asound.state\" \
-               -DSYS_LOCKFILE=\"$(ASOUND_LOCK_DIR)/asound.state.lock\" \
+               -DSYS_LOCKPATH=\"$(ASOUND_LOCK_DIR)\" \
+               -DSYS_LOCKFILE=\"asound.state.lock\" \
                -DSYS_PIDFILE=\"$(ALSACTL_PIDFILE_DIR)/alsactl.pid\"
 
 noinst_HEADERS=alsactl.h list.h init_sysdeps.c init_utils_string.c \
index ecc5d28624446b8477441f970ad4bb2b065a775b..9719b83845f139aedac6522e138796988c64255a 100644 (file)
@@ -51,6 +51,7 @@ int do_lock = 0;
 int use_syslog = 0;
 char *command;
 char *statefile = NULL;
+char *lockpath = SYS_LOCKPATH;
 char *lockfile = SYS_LOCKFILE;
 
 #define TITLE  0x0100
@@ -79,6 +80,7 @@ static struct arg args[] = {
 { FILEARG | 'a', "config-dir", "boot / hotplug configuration directory (default " SYS_ASOUND_DIR ")" },
 { 'l', "lock", "use file locking to serialize concurrent access" },
 { 'L', "no-lock", "do not use file locking to serialize concurrent access" },
+{ FILEARG | 'K', "lock-dir", "lock path (default " SYS_LOCKPATH ")" },
 { FILEARG | 'O', "lock-state-file", "state lock file path (default " SYS_LOCKFILE ")" },
 { 'F', "force", "try to restore the matching controls as much as possible" },
 { 0, NULL, "  (default mode)" },
@@ -306,6 +308,9 @@ int main(int argc, char *argv[])
                case 'L':
                        do_lock = -1;
                        break;
+               case 'K':
+                       lockpath = optarg;
+                       break;
                case 'O':
                        lockfile = optarg;
                        break;
index d0dd7ebc883636e7cde05fa4680e611d9096a3c9..2f925700baacf6dfda00cdcf1a63e09bc4b74f4b 100644 (file)
@@ -1,6 +1,8 @@
 #include <stdbool.h>
 #include <alsa/asoundlib.h>
 
+#define LOCK_TIMEOUT 10
+
 extern int debugflag;
 extern int force_restore;
 extern int ignore_nocards;
@@ -8,6 +10,7 @@ extern int do_lock;
 extern int use_syslog;
 extern char *command;
 extern char *statefile;
+extern char *lockpath;
 extern char *lockfile;
 
 struct snd_card_iterator {
@@ -50,7 +53,9 @@ int load_configuration(const char *file, snd_config_t **top, int *open_failed);
 int init(const char *cfgdir, const char *file, int flags, const char *cardname);
 int init_ucm(int flags, int cardno);
 int state_lock(const char *file, int timeout);
-int state_unlock(int fd, const char *file);
+int state_unlock(int lock_fd, const char *file);
+int card_lock(int card_number, int timeout);
+int card_unlock(int lock_fd, int card_number);
 int save_state(const char *file, const char *cardname);
 int load_state(const char *cfgdir, const char *file,
               const char *initfile, int initflags,
index 0238e95b7174d5aff836d5581e7a63dfa6e619e9..64bdaff85f9988e57f1723606e1d9aabed81a351 100644 (file)
@@ -32,6 +32,8 @@
 #include <sys/stat.h>
 #include "alsactl.h"
 
+#define PATH_SIZE 512
+
 static int alarm_flag;
 
 static void signal_handler_alarm(int sig)
@@ -39,7 +41,7 @@ static void signal_handler_alarm(int sig)
        alarm_flag = 1;
 }
 
-static int state_lock_(int lock, int timeout, int _fd)
+static int state_lock_(const char *lock_file, int lock, int timeout, int _fd)
 {
        int fd = -1, err = 0;
        struct flock lck;
@@ -47,7 +49,6 @@ static int state_lock_(int lock, int timeout, int _fd)
        char lcktxt[14];
        struct sigaction sig_alarm, sig_alarm_orig;
        struct itimerval itv;
-       char *nfile = lockfile;
 
        if (do_lock <= 0)
                return 0;
@@ -64,20 +65,20 @@ static int state_lock_(int lock, int timeout, int _fd)
                fd = _fd;
        }
        while (fd < 0 && timeout-- > 0) {
-               fd = open(nfile, O_RDWR);
+               fd = open(lock_file, O_RDWR);
                if (!lock && fd < 0) {
                        err = -EIO;
                        goto out;
                }
                if (fd < 0) {
-                       fd = open(nfile, O_RDWR|O_CREAT|O_EXCL, 0644);
+                       fd = open(lock_file, O_RDWR|O_CREAT|O_EXCL, 0644);
                        if (fd < 0) {
                                if (errno == EBUSY || errno == EAGAIN) {
                                        sleep(1);
                                        continue;
                                }
                                if (errno == EEXIST) {
-                                       fd = open(nfile, O_RDWR);
+                                       fd = open(lock_file, O_RDWR);
                                        if (fd >= 0)
                                                break;
                                }
@@ -147,11 +148,21 @@ out:
        return err;
 }
 
+static void state_lock_file(char *buf, size_t buflen)
+{
+       if (lockfile[0] == '/')
+               snprintf(buf, buflen, "%s", lockfile);
+       else
+               snprintf(buf, buflen, "%s/%s", lockpath, lockfile);
+}
+
 int state_lock(const char *file, int timeout)
 {
+       char fn[PATH_SIZE];
        int err;
 
-       err = state_lock_(1, timeout, -1);
+       state_lock_file(fn, sizeof(fn));
+       err = state_lock_(fn, 1, timeout, -1);
        if (err < 0)
                error("file %s lock error: %s", file, strerror(-err));
        return err;
@@ -159,10 +170,41 @@ int state_lock(const char *file, int timeout)
 
 int state_unlock(int _fd, const char *file)
 {
+       char fn[PATH_SIZE];
        int err;
 
-       err = state_lock_(0, 10, _fd);
+       state_lock_file(fn, sizeof(fn));
+       err = state_lock_(fn, 0, 10, _fd);
        if (err < 0)
                error("file %s unlock error: %s", file, strerror(-err));
        return err;
 }
+
+static void card_lock_file(char *buf, size_t buflen, int card_number)
+{
+       snprintf(buf, buflen, "%s/card%i.lock", lockpath, card_number);
+}
+
+int card_lock(int card_number, int timeout)
+{
+       char fn[PATH_SIZE];
+       int err;
+
+       card_lock_file(fn, sizeof(fn), card_number);
+       err = state_lock_(fn, 1, timeout, -1);
+       if (err < 0)
+               error("card %d lock error: %s", card_number, strerror(-err));
+       return err;
+}
+
+int card_unlock(int _fd, int card_number)
+{
+       char fn[PATH_SIZE];
+       int err;
+
+       card_lock_file(fn, sizeof(fn), card_number);
+       err = state_lock_(fn, 0, 10, _fd);
+       if (err < 0)
+               error("card %d unlock error: %s", card_number, strerror(-err));
+       return err;
+}
index d943df43c199c0c096b19e062f64f123b0a66f06..93f38883f80f81faa5c5ad42f5a05279ccb84a8f 100644 (file)
@@ -1614,7 +1614,7 @@ int save_state(const char *file, const char *cardname)
                }
                strcpy(nfile, file);
                strcat(nfile, ".new");
-               lock_fd = state_lock(file, 10);
+               lock_fd = state_lock(file, LOCK_TIMEOUT);
                if (lock_fd < 0) {
                        err = lock_fd;
                        goto out;
@@ -1675,7 +1675,7 @@ int load_state(const char *cfgdir, const char *file,
               const char *initfile, int initflags,
               const char *cardname, int do_init)
 {
-       int err, finalerr = 0, open_failed;
+       int err, finalerr = 0, open_failed, lock_fd;
        struct snd_card_iterator iter;
        snd_config_t *config;
        const char *cardname1;
@@ -1695,7 +1695,14 @@ int load_state(const char *cfgdir, const char *file,
                while ((cardname1 = snd_card_iterator_next(&iter)) != NULL) {
                        if (!do_init)
                                break;
+                       lock_fd = card_lock(iter.card, LOCK_TIMEOUT);
+                       if (lock_fd < 0) {
+                               finalerr = lock_fd;
+                               initfailed(iter.card, "lock", err);
+                               continue;
+                       }
                        err = init(cfgdir, initfile, initflags | FLAG_UCM_FBOOT | FLAG_UCM_BOOT, cardname1);
+                       card_unlock(lock_fd, iter.card);
                        if (err < 0) {
                                finalerr = err;
                                initfailed(iter.card, "init", err);
@@ -1712,6 +1719,12 @@ int load_state(const char *cfgdir, const char *file,
        if (err < 0)
                goto out;
        while ((cardname1 = snd_card_iterator_next(&iter)) != NULL) {
+               lock_fd = card_lock(iter.card, LOCK_TIMEOUT);
+               if (lock_fd < 0) {
+                       initfailed(iter.card, "lock", lock_fd);
+                       finalerr = lock_fd;
+                       continue;
+               }
                /* error is ignored */
                init_ucm(initflags | FLAG_UCM_FBOOT, iter.card);
                /* do a check if controls matches state file */
@@ -1727,6 +1740,7 @@ int load_state(const char *cfgdir, const char *file,
                                finalerr = err;
                        initfailed(iter.card, "restore", err);
                }
+               card_unlock(lock_fd, iter.card);
        }
        err = finalerr ? finalerr : snd_card_iterator_error(&iter);
 out:
index a50797259f21ab208a64ef209cfec101dc989e28..d8cbf535598401b1ddbdc4e80b20c410aba3f7cb 100644 (file)
@@ -211,7 +211,7 @@ int load_configuration(const char *file, snd_config_t **top, int *open_failed)
        if (stdio_flag) {
                err = snd_input_stdio_attach(&in, stdin, 0);
        } else {
-               lock_fd = state_lock(file, 10);
+               lock_fd = state_lock(file, LOCK_TIMEOUT);
                err = lock_fd >= 0 ? snd_input_stdio_open(&in, file, "r") : lock_fd;
        }
        if (err < 0) {