espeakup release coming soon
Samuel Thibault
samuel.thibault at ens-lyon.org
Wed Jul 20 19:35:31 EDT 2016
Hello,
currently espeakup uses daemon() to do the daemonizing stuff.
Unfortunately, daemon() does things not very appropriately, and there
is notably a delay between the parent exit()ing and the child writing
the pid file. The attached patch reimplements it properly, espeakup then
notably plays much more nicely with systemd.
Samuel
-------------- next part --------------
--- a/espeakup.c
+++ b/espeakup.c
@@ -24,6 +24,8 @@
#include <string.h>
#include <unistd.h>
#include <pthread.h>
+#include <fcntl.h>
+#include <sys/file.h>
#include "espeakup.h"
@@ -42,21 +44,94 @@ const int defaultVolume = 5;
char *defaultVoice = NULL;
int debug = 0;
+int espeakup_start_daemon(void)
+{
+ int fds[2];
+ pid_t pid;
+ char c;
+
+ if (pipe(fds) < 0) {
+ perror("pipe");
+ exit(1);
+ }
+ pid = fork();
+
+ if (pid < 0) {
+ perror("fork");
+ exit(1);
+ }
+ if (pid) {
+ /* Parent, just wait for daemon */
+ if (read(fds[0], &c, 1) < 0) {
+ printf("Espeakup is already running!\n");
+ exit(1);
+ }
+ exit(c);
+ }
+
+
+ /* Child, create new session */
+ setsid();
+ pid = fork();
+ if (pid)
+ /* Intermediate child, just exit */
+ exit(0);
+
+ /* Child */
+ if (chdir("/") < 0) {
+ c = 1;
+ (void) write(fds[1], &c, 1);
+ exit(1);
+ }
+ return fds[1];
+}
+
int espeakup_is_running(void)
{
- int rc;
- FILE *pidFile;
+ int pidFile;
+ int n;
+ char s[16];
pid_t pid;
- rc = 0;
- pidFile = fopen(pidPath, "r");
- if (pidFile) {
- fscanf(pidFile, "%d", &pid);
- fclose(pidFile);
- if (!kill(pid, 0) || errno != ESRCH)
- rc = 1;
+ pidFile = open(pidPath, O_RDWR|O_CREAT, 0666);
+ if (pidFile < 0) {
+ printf("Can not work with the pid file %s: %s\n", pidPath, strerror(errno));
+ return -1;
+ }
+
+ if (flock(pidFile, LOCK_EX) < 0) {
+ printf("Can not lock the pid file %s: %s\n", pidPath, strerror(errno));
+ goto error;
+ }
+ n = read(pidFile, s, sizeof(s)-1);
+ if (n < 0) {
+ printf("Can not read the pid file %s: %s\n", pidPath, strerror(errno));
+ goto error;
+ }
+ s[n] = 0;
+ n = sscanf(s, "%d", &pid);
+ if (n == 1 && (!kill(pid, 0) || errno != ESRCH))
+ {
+ /* Already running */
+ close(pidFile);
+ return 1;
}
- return rc;
+ if (ftruncate(pidFile, 0) < 0) {
+ printf("Could not truncate the pid file %s: %s\n", pidPath, strerror(errno));
+ goto error;
+ }
+ lseek(pidFile, 0, SEEK_SET);
+ n = snprintf(s, sizeof(s), "%d", getpid());
+ if (write(pidFile, s, n) < 0) {
+ printf("Could not write to the pid file %s: %s\n", pidPath, strerror(errno));
+ goto error;
+ }
+ close(pidFile);
+ return 0;
+
+error:
+ close(pidFile);
+ return -1;
}
int create_pid_file(void)
@@ -91,6 +166,8 @@ void espeakup_sighandler(int sig)
int main(int argc, char **argv)
{
+ int fd, null;
+ char ret;
pthread_t queue_thread_id;
struct synth_t s = {
.voice = "",
@@ -99,27 +176,37 @@ int main(int argc, char **argv)
/* process command line options */
process_cli(argc, argv);
+ if (!debug)
+ fd = espeakup_start_daemon();
+
/* Is the espeakup daemon running? */
if (espeakup_is_running()) {
printf("Espeakup is already running!\n");
- return 1;
+ ret = 1;
+ goto out;
}
/* open the softsynth. */
if (! open_softsynth()) {
perror("Unable to open the softsynth device");
- return 3;
+ ret = 3;
+ goto out;
+ }
+
+ if (!debug) {
+ /* Shut down stdout/stderr */
+ null = open("/dev/null", O_RDWR);
+ dup2(null, STDIN_FILENO);
+ dup2(null, STDOUT_FILENO);
+ dup2(null, STDERR_FILENO);
+ if (null > 2)
+ close(null);
}
/* register signal handler */
signal(SIGINT, espeakup_sighandler);
signal(SIGTERM, espeakup_sighandler);
- if (!debug) {
- /* become a daemon */
- daemon(0, 1);
- }
-
/* initialize espeak */
espeak_Initialize(AUDIO_OUTPUT_PLAYBACK, 0, NULL, 0);
@@ -138,19 +225,23 @@ int main(int argc, char **argv)
/* Spawn our queue-processing thread. */
int err = pthread_create(&queue_thread_id, NULL, &queue_runner, &s);
if (err != 0) {
- return 4;
+ ret = 4;
+ goto out;
}
if (!debug) {
- /* We are now ready, write our pid file. */
- if (create_pid_file() < 0) {
- perror("Unable to create pid file");
- return 2;
- }
+ /* We are now ready, notify parent */
+ ret = 0;
+ (void) write(fd, &ret, 1);
+ close(fd);
}
/* run the main loop */
main_loop(&s);
-
return 0;
+
+out:
+ if (!debug)
+ (void) write(fd, &ret, 1);
+ return ret;
}
More information about the Speakup
mailing list