diff --git a/alsactl/lock.c b/alsactl/lock.c index aa77254..0238e95 100644 --- a/alsactl/lock.c +++ b/alsactl/lock.c @@ -27,15 +27,26 @@ #include #include #include +#include +#include #include #include "alsactl.h" +static int alarm_flag; + +static void signal_handler_alarm(int sig) +{ + alarm_flag = 1; +} + static int state_lock_(int lock, int timeout, int _fd) { int fd = -1, err = 0; struct flock lck; struct stat st; char lcktxt[14]; + struct sigaction sig_alarm, sig_alarm_orig; + struct itimerval itv; char *nfile = lockfile; if (do_lock <= 0) @@ -93,15 +104,31 @@ static int state_lock_(int lock, int timeout, int _fd) goto out; } } - while (timeout > 0) { - if (fcntl(fd, F_SETLK, &lck) < 0) { - sleep(1); - timeout--; - } else { - break; - } + alarm_flag = 0; + memset(&sig_alarm, 0, sizeof(sig_alarm)); + sigemptyset(&sig_alarm.sa_mask); + sig_alarm.sa_handler = signal_handler_alarm; + if (sigaction(SIGALRM, &sig_alarm, &sig_alarm_orig) < 0) { + err = -ENXIO; + goto out; } - if (timeout <= 0) { + memset(&itv, 0, sizeof(itv)); + itv.it_value.tv_sec = timeout; + if (setitimer(ITIMER_REAL, &itv, NULL) < 0) { + err = -ENXIO; + sigaction(SIGALRM, &sig_alarm_orig, NULL); + goto out; + } + while (alarm_flag == 0) { + if (fcntl(fd, F_SETLKW, &lck) == 0) + break; + if (errno == EAGAIN || errno == ERESTART) + continue; + } + memset(&itv, 0, sizeof(itv)); + setitimer(ITIMER_REAL, &itv, NULL); + sigaction(SIGALRM, &sig_alarm_orig, NULL); + if (alarm_flag) { err = -EBUSY; goto out; }