Skip to content

Commit

Permalink
use sigtimedwait instead of pthread_cond_timedwait
Browse files Browse the repository at this point in the history
pthread mutexes should not be used inside signal handlers
  • Loading branch information
arichardson committed Mar 31, 2013
1 parent 12b30bf commit f2e7888
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 45 deletions.
3 changes: 0 additions & 3 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@ AC_CONFIG_HEADERS([config.h])
AC_PROG_CC
AC_PROG_INSTALL

# FIXME: Replace `main' with a function in `-lpthread':
AC_CHECK_LIB([pthread], [main], ,
AC_MSG_ERROR([libpthread is required but was not found]))
# FIXME: Replace `main' with a function in `-lrt':
AC_CHECK_LIB([rt], [main], ,
AC_MSG_ERROR([librt is required but was not found]))
Expand Down
97 changes: 55 additions & 42 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <pthread.h>
#include <string.h>
#include <time.h>
#include <assert.h>
#include <linux/limits.h>
#include <linux/vt.h>
#include <linux/kd.h>
Expand All @@ -33,69 +34,81 @@
#include <systemd/sd-daemon.h>


static pthread_mutex_t notify_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t notify_condition = PTHREAD_COND_INITIALIZER;

static int xpid;

static void usr1handler(int foo)
{
/* Got the signal from the X server that it's ready */
if (foo++) foo--;

sd_notify(0, "READY=1");

pthread_mutex_lock(&notify_mutex);
pthread_cond_signal(&notify_condition);
pthread_mutex_unlock(&notify_mutex);
}

static void termhandler(int foo)
{
if (foo++) foo--;

kill(xpid, SIGTERM);
}


int main(int argc, char **argv)
{
struct sigaction usr1;
struct sigaction term;
char *xserver = NULL;
char *ptrs[32];
int count = 0;
pid_t pid;
char all[PATH_MAX] = "";
int i;

/* Step 1: arm the signal */
memset(&usr1, 0, sizeof(struct sigaction));
usr1.sa_handler = usr1handler;
sigaction(SIGUSR1, &usr1, NULL);
sigset_t mask;
sigset_t oldmask;
/* Step 1: block sigusr1 until we wait for it */
sigemptyset(&mask);
sigaddset(&mask, SIGUSR1);
sigprocmask(SIG_BLOCK, &mask, &oldmask);

/* Step 2: fork */
pid = fork();
if (pid) {
struct timespec tv;
int err;
struct timespec starttime;
struct timespec timeout;
int status;

xpid = pid;

/* setup sighandler for main thread */
clock_gettime(CLOCK_REALTIME, &tv);
tv.tv_sec += 10;

pthread_mutex_lock(&notify_mutex);
err = pthread_cond_timedwait(&notify_condition, &notify_mutex, &tv);
pthread_mutex_unlock(&notify_mutex);

if (err == ETIMEDOUT) {
fprintf(stderr, "X server startup timed out (10secs). This indicates an"
"an issue in the server configuration or drivers.\n");
exit(EXIT_FAILURE);
}
/* wait up to 10 seconds for X server to start */
clock_gettime(CLOCK_REALTIME, &starttime);
timeout.tv_sec = 10;
timeout.tv_nsec = 0;
do {
int ret = sigtimedwait(&mask, NULL, &timeout);
if (ret > 0) {
assert(ret == SIGUSR1);
/* got SIGUSR1, X server has started */
sd_notify(0, "READY=1");
break;
}
else if (errno == EINTR) {
struct timespec currenttime;
/* interrupted by other signal, update timeout and retry */
clock_gettime(CLOCK_REALTIME, &currenttime);
timeout.tv_sec = (starttime.tv_sec + 10) - currenttime.tv_sec;
if (currenttime.tv_nsec > starttime.tv_nsec) {
timeout.tv_nsec = starttime.tv_nsec + 1000000000L - currenttime.tv_nsec;
timeout.tv_sec--;
}
else {
timeout.tv_nsec = currenttime.tv_nsec - starttime.tv_nsec ;
}
/* printf("New timeout: %d s, %d ns\n",
(int)timeout.tv_sec, (int)timeout.tv_nsec); */
if (timeout.tv_sec < 0 || timeout.tv_nsec < 0) {
timeout.tv_sec = 0;
timeout.tv_nsec = 0;
}
}
else if (errno == EAGAIN) {
fprintf(stderr, "X server startup timed out (10secs). This "
"indicates an issue in the server configuration or drivers.\n");
exit(EXIT_FAILURE);
}
else {
perror("sigtimedwait");
exit(EXIT_FAILURE);
}
} while (1);

/* handle TERM gracefully and pass it on to xpid */
memset(&term, 0, sizeof(struct sigaction));
Expand All @@ -112,9 +125,10 @@ int main(int argc, char **argv)
/* if we get here we're the child */

/*
* set the X server sigchld to SIG_IGN, that's the
* magic to make X send the parent the signal.
* reset signal mask and set the X server sigchld to SIG_IGN, that's the
* magic to make X send the parent the signal.
*/
sigprocmask(SIG_SETMASK, &oldmask, NULL);
signal(SIGUSR1, SIG_IGN);

/* Step 3: find the X server */
Expand Down Expand Up @@ -143,9 +157,8 @@ int main(int argc, char **argv)
strncat(all, " ", PATH_MAX - strlen(all) - 1);
}

fprintf(stderr, "Starting Xorg server with: \"%s\"", all);
fprintf(stderr, "Starting Xorg server with: \"%s\"\n", all);
execv(ptrs[0], ptrs);
fprintf(stderr, "Failed to execv() the X server.\n");

exit(EXIT_FAILURE);
}

0 comments on commit f2e7888

Please sign in to comment.