mirror of
https://github.com/alsa-project/alsa-utils
synced 2024-11-09 17:25:42 +01:00
alsactl: add locking for per-card initialization
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>
This commit is contained in:
parent
64fa37f09b
commit
8403967669
6 changed files with 79 additions and 12 deletions
|
@ -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 \
|
alsactl_CFLAGS=$(AM_CFLAGS) -D__USE_GNU \
|
||||||
-DSYS_ASOUNDRC=\"$(ASOUND_STATE_DIR)/asound.state\" \
|
-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\"
|
-DSYS_PIDFILE=\"$(ALSACTL_PIDFILE_DIR)/alsactl.pid\"
|
||||||
|
|
||||||
noinst_HEADERS=alsactl.h list.h init_sysdeps.c init_utils_string.c \
|
noinst_HEADERS=alsactl.h list.h init_sysdeps.c init_utils_string.c \
|
||||||
|
|
|
@ -51,6 +51,7 @@ int do_lock = 0;
|
||||||
int use_syslog = 0;
|
int use_syslog = 0;
|
||||||
char *command;
|
char *command;
|
||||||
char *statefile = NULL;
|
char *statefile = NULL;
|
||||||
|
char *lockpath = SYS_LOCKPATH;
|
||||||
char *lockfile = SYS_LOCKFILE;
|
char *lockfile = SYS_LOCKFILE;
|
||||||
|
|
||||||
#define TITLE 0x0100
|
#define TITLE 0x0100
|
||||||
|
@ -79,6 +80,7 @@ static struct arg args[] = {
|
||||||
{ FILEARG | 'a', "config-dir", "boot / hotplug configuration directory (default " SYS_ASOUND_DIR ")" },
|
{ FILEARG | 'a', "config-dir", "boot / hotplug configuration directory (default " SYS_ASOUND_DIR ")" },
|
||||||
{ 'l', "lock", "use file locking to serialize concurrent access" },
|
{ 'l', "lock", "use file locking to serialize concurrent access" },
|
||||||
{ 'L', "no-lock", "do not 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 ")" },
|
{ FILEARG | 'O', "lock-state-file", "state lock file path (default " SYS_LOCKFILE ")" },
|
||||||
{ 'F', "force", "try to restore the matching controls as much as possible" },
|
{ 'F', "force", "try to restore the matching controls as much as possible" },
|
||||||
{ 0, NULL, " (default mode)" },
|
{ 0, NULL, " (default mode)" },
|
||||||
|
@ -306,6 +308,9 @@ int main(int argc, char *argv[])
|
||||||
case 'L':
|
case 'L':
|
||||||
do_lock = -1;
|
do_lock = -1;
|
||||||
break;
|
break;
|
||||||
|
case 'K':
|
||||||
|
lockpath = optarg;
|
||||||
|
break;
|
||||||
case 'O':
|
case 'O':
|
||||||
lockfile = optarg;
|
lockfile = optarg;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <alsa/asoundlib.h>
|
#include <alsa/asoundlib.h>
|
||||||
|
|
||||||
|
#define LOCK_TIMEOUT 10
|
||||||
|
|
||||||
extern int debugflag;
|
extern int debugflag;
|
||||||
extern int force_restore;
|
extern int force_restore;
|
||||||
extern int ignore_nocards;
|
extern int ignore_nocards;
|
||||||
|
@ -8,6 +10,7 @@ extern int do_lock;
|
||||||
extern int use_syslog;
|
extern int use_syslog;
|
||||||
extern char *command;
|
extern char *command;
|
||||||
extern char *statefile;
|
extern char *statefile;
|
||||||
|
extern char *lockpath;
|
||||||
extern char *lockfile;
|
extern char *lockfile;
|
||||||
|
|
||||||
struct snd_card_iterator {
|
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(const char *cfgdir, const char *file, int flags, const char *cardname);
|
||||||
int init_ucm(int flags, int cardno);
|
int init_ucm(int flags, int cardno);
|
||||||
int state_lock(const char *file, int timeout);
|
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 save_state(const char *file, const char *cardname);
|
||||||
int load_state(const char *cfgdir, const char *file,
|
int load_state(const char *cfgdir, const char *file,
|
||||||
const char *initfile, int initflags,
|
const char *initfile, int initflags,
|
||||||
|
|
|
@ -32,6 +32,8 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include "alsactl.h"
|
#include "alsactl.h"
|
||||||
|
|
||||||
|
#define PATH_SIZE 512
|
||||||
|
|
||||||
static int alarm_flag;
|
static int alarm_flag;
|
||||||
|
|
||||||
static void signal_handler_alarm(int sig)
|
static void signal_handler_alarm(int sig)
|
||||||
|
@ -39,7 +41,7 @@ static void signal_handler_alarm(int sig)
|
||||||
alarm_flag = 1;
|
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;
|
int fd = -1, err = 0;
|
||||||
struct flock lck;
|
struct flock lck;
|
||||||
|
@ -47,7 +49,6 @@ static int state_lock_(int lock, int timeout, int _fd)
|
||||||
char lcktxt[14];
|
char lcktxt[14];
|
||||||
struct sigaction sig_alarm, sig_alarm_orig;
|
struct sigaction sig_alarm, sig_alarm_orig;
|
||||||
struct itimerval itv;
|
struct itimerval itv;
|
||||||
char *nfile = lockfile;
|
|
||||||
|
|
||||||
if (do_lock <= 0)
|
if (do_lock <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -64,20 +65,20 @@ static int state_lock_(int lock, int timeout, int _fd)
|
||||||
fd = _fd;
|
fd = _fd;
|
||||||
}
|
}
|
||||||
while (fd < 0 && timeout-- > 0) {
|
while (fd < 0 && timeout-- > 0) {
|
||||||
fd = open(nfile, O_RDWR);
|
fd = open(lock_file, O_RDWR);
|
||||||
if (!lock && fd < 0) {
|
if (!lock && fd < 0) {
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (fd < 0) {
|
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 (fd < 0) {
|
||||||
if (errno == EBUSY || errno == EAGAIN) {
|
if (errno == EBUSY || errno == EAGAIN) {
|
||||||
sleep(1);
|
sleep(1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (errno == EEXIST) {
|
if (errno == EEXIST) {
|
||||||
fd = open(nfile, O_RDWR);
|
fd = open(lock_file, O_RDWR);
|
||||||
if (fd >= 0)
|
if (fd >= 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -147,11 +148,21 @@ out:
|
||||||
return err;
|
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)
|
int state_lock(const char *file, int timeout)
|
||||||
{
|
{
|
||||||
|
char fn[PATH_SIZE];
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = state_lock_(1, timeout, -1);
|
state_lock_file(fn, sizeof(fn));
|
||||||
|
err = state_lock_(fn, 1, timeout, -1);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
error("file %s lock error: %s", file, strerror(-err));
|
error("file %s lock error: %s", file, strerror(-err));
|
||||||
return err;
|
return err;
|
||||||
|
@ -159,10 +170,41 @@ int state_lock(const char *file, int timeout)
|
||||||
|
|
||||||
int state_unlock(int _fd, const char *file)
|
int state_unlock(int _fd, const char *file)
|
||||||
{
|
{
|
||||||
|
char fn[PATH_SIZE];
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = state_lock_(0, 10, _fd);
|
state_lock_file(fn, sizeof(fn));
|
||||||
|
err = state_lock_(fn, 0, 10, _fd);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
error("file %s unlock error: %s", file, strerror(-err));
|
error("file %s unlock error: %s", file, strerror(-err));
|
||||||
return 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;
|
||||||
|
}
|
||||||
|
|
|
@ -1614,7 +1614,7 @@ int save_state(const char *file, const char *cardname)
|
||||||
}
|
}
|
||||||
strcpy(nfile, file);
|
strcpy(nfile, file);
|
||||||
strcat(nfile, ".new");
|
strcat(nfile, ".new");
|
||||||
lock_fd = state_lock(file, 10);
|
lock_fd = state_lock(file, LOCK_TIMEOUT);
|
||||||
if (lock_fd < 0) {
|
if (lock_fd < 0) {
|
||||||
err = lock_fd;
|
err = lock_fd;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -1675,7 +1675,7 @@ int load_state(const char *cfgdir, const char *file,
|
||||||
const char *initfile, int initflags,
|
const char *initfile, int initflags,
|
||||||
const char *cardname, int do_init)
|
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;
|
struct snd_card_iterator iter;
|
||||||
snd_config_t *config;
|
snd_config_t *config;
|
||||||
const char *cardname1;
|
const char *cardname1;
|
||||||
|
@ -1695,7 +1695,14 @@ int load_state(const char *cfgdir, const char *file,
|
||||||
while ((cardname1 = snd_card_iterator_next(&iter)) != NULL) {
|
while ((cardname1 = snd_card_iterator_next(&iter)) != NULL) {
|
||||||
if (!do_init)
|
if (!do_init)
|
||||||
break;
|
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);
|
err = init(cfgdir, initfile, initflags | FLAG_UCM_FBOOT | FLAG_UCM_BOOT, cardname1);
|
||||||
|
card_unlock(lock_fd, iter.card);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
finalerr = err;
|
finalerr = err;
|
||||||
initfailed(iter.card, "init", err);
|
initfailed(iter.card, "init", err);
|
||||||
|
@ -1712,6 +1719,12 @@ int load_state(const char *cfgdir, const char *file,
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto out;
|
goto out;
|
||||||
while ((cardname1 = snd_card_iterator_next(&iter)) != NULL) {
|
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 */
|
/* error is ignored */
|
||||||
init_ucm(initflags | FLAG_UCM_FBOOT, iter.card);
|
init_ucm(initflags | FLAG_UCM_FBOOT, iter.card);
|
||||||
/* do a check if controls matches state file */
|
/* do a check if controls matches state file */
|
||||||
|
@ -1727,6 +1740,7 @@ int load_state(const char *cfgdir, const char *file,
|
||||||
finalerr = err;
|
finalerr = err;
|
||||||
initfailed(iter.card, "restore", err);
|
initfailed(iter.card, "restore", err);
|
||||||
}
|
}
|
||||||
|
card_unlock(lock_fd, iter.card);
|
||||||
}
|
}
|
||||||
err = finalerr ? finalerr : snd_card_iterator_error(&iter);
|
err = finalerr ? finalerr : snd_card_iterator_error(&iter);
|
||||||
out:
|
out:
|
||||||
|
|
|
@ -211,7 +211,7 @@ int load_configuration(const char *file, snd_config_t **top, int *open_failed)
|
||||||
if (stdio_flag) {
|
if (stdio_flag) {
|
||||||
err = snd_input_stdio_attach(&in, stdin, 0);
|
err = snd_input_stdio_attach(&in, stdin, 0);
|
||||||
} else {
|
} 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;
|
err = lock_fd >= 0 ? snd_input_stdio_open(&in, file, "r") : lock_fd;
|
||||||
}
|
}
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
|
|
Loading…
Reference in a new issue