commit ad78c8e8c299f71aacb4d4e9d8cbf2b49c1276fe
parent 64e616f54d5ad9edb6881154318856fd0e784330
Author: Jacob R. Edwards <jacobouno@protonmail.com>
Date:   Fri, 16 Jul 2021 00:45:25 -0700
Improve player management
Add a completed state which tells if the player exited successfully
and interrupt poll when the player state updates due to SIGCHLD.
Diffstat:
5 files changed, 29 insertions(+), 16 deletions(-)
diff --git a/aps/command.c b/aps/command.c
@@ -229,6 +229,9 @@ aps_status(struct aps *aps, int s, int argc, char **argv)
 	case FAILURE:
 		status = "failure";
 		break;
+	case COMPLETE:
+		status = "complete";
+		break;
 	default:
 		BUG("impossible player state");
 	}
diff --git a/aps/main.c b/aps/main.c
@@ -57,17 +57,28 @@ sigchld(int sig)
 
 	while ((pid =
 	    waitpid(-1, &status, WCONTINUED | WNOHANG | WUNTRACED)) > 0) {
-		if (pid == aps->player->pid)
+		if (pid == aps->player->pid) {
 			pupdate(aps->player, status);
+			kill(getpid(), SIGINT);
+		}
 	}
 }
 
+void
+sigint(int sig)
+{
+}
+
 int
 run(struct aps *aps)
 {
 	while (!aps->close) {
-		if (!aps->player->state && aps->queue)
-			aps_next(aps, -1, 0, NULL);
+		if (aps->queue) {
+			if (aps->player->state == COMPLETE)
+				aps_next(aps, -1, 0, NULL);
+			if (aps->player->state == OFF)
+				pplay(aps->player, aps->queue->path);
+		}
 		if ((aps_accept(aps) || aps_update(aps)) && errno != EINTR)
 			return 1;
 	}
@@ -96,7 +107,8 @@ main(int argc, char *argv[])
 	aps->logmask = INFO | WARN | ERROR | FATAL;
 
 	signal(SIGCHLD, sigchld);
-	signal(SIGINT, sigclose);
+	signal(SIGINT, sigint);
+	signal(SIGQUIT, sigclose);
 	signal(SIGTERM, sigclose);
 
 	error = run(aps);
diff --git a/aps/player.c b/aps/player.c
@@ -61,8 +61,8 @@ pstop(struct player *p)
 		errno = EALREADY;
 		return 1;
 	}
-	if (p->state & (RUNNING | SUSPENDED) && kill(p->pid, SIGTERM) == -1)
-		return 1;
+	if (p->state & (RUNNING | SUSPENDED))
+		kill(p->pid, SIGTERM);	/* errors unconsequential */
 	p->state = STOPPED;
 	return 0;
 }
@@ -132,13 +132,10 @@ ptoggle(struct player *p)
 void
 pupdate(struct player *p, int status)
 {
-	if (WIFEXITED(status) || WIFSIGNALED(status)) {
-		if (p->state != STOPPED) {
-			if (WIFEXITED(status) && WEXITSTATUS(status))
-				p->state = FAILURE;
-			else
-				p->state = 0;
-		}
+	if (WIFEXITED(status)) {
+		p->state = (WEXITSTATUS(status) ? FAILURE : COMPLETE);
+	} else if (WIFSIGNALED(status)) {
+		p->state = STOPPED;
 	} else if (WIFCONTINUED(status)) {
 		p->state = RUNNING;
 	} else if (WIFSTOPPED(status)) {
diff --git a/aps/player.h b/aps/player.h
@@ -3,7 +3,8 @@ enum pstate {
 	RUNNING = 1,
 	STOPPED = 2,
 	SUSPENDED = 4,
-	FAILURE = 8
+	FAILURE = 8,
+	COMPLETE = 16
 };
 
 struct player {
diff --git a/aps/queue.c b/aps/queue.c
@@ -28,10 +28,10 @@ int
 queue_set(struct aps *aps, struct item *item)
 {
 	aps->queue = item;
-	if (aps->player->state && aps->player->state != STOPPED) {
+	if (aps->player->state != OFF && aps->player->state != STOPPED) {
 		if (pstop(aps->player))
 			return 1;
-		aps->player->state = 0;
+		aps->player->state = OFF;
 	}
 	return 0;
 }