summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2012-10-24 09:08:19 +1000
committerPeter Hutterer <peter.hutterer@who-t.net>2012-10-29 08:53:42 +1000
commit55eaaec2383fa67eb42e06cf094327481b77a8d9 (patch)
treef413998a19b73f64c9f7b4b97c24e37925b6192a
parentd710ae9f3a58fe3543ebf94f9e4f9ca325abc9a2 (diff)
xserver: use new fork handling for signal masks
The child must have SIGUSR1 set to SIG_IGN so the XServer will notify us when it is ready to accept connection. The parent must block SIGUSR1 until ready to receive them, but the server must _not_ have that mask blocked. Otherwise, it won't react to VT switches. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Chase Douglas <chase.douglas@ubuntu.com>
-rw-r--r--src/xserver.cpp74
1 files changed, 46 insertions, 28 deletions
diff --git a/src/xserver.cpp b/src/xserver.cpp
index 156c820..114f610 100644
--- a/src/xserver.cpp
+++ b/src/xserver.cpp
@@ -430,42 +430,60 @@ void xorg::testing::XServer::Start(const std::string &program) {
err_msg.append(std::strerror(errno));
throw std::runtime_error(err_msg);
}
- /* set SIGUSR1 handler to SIG_IGN, XServer tests for this and will
- * send SIGUSR1 when ready */
- if (SIG_ERR == signal(SIGUSR1, SIG_IGN)) {
- err_msg.append("Failed to set signal handler: ");
- err_msg.append(std::strerror(errno));
- throw std::runtime_error(err_msg);
- }
- args.push_back(std::string(GetDisplayString()));
+ pid_t pid = Fork();
+ if (pid == 0) {
+ /* set SIGUSR1 handler to SIG_IGN, XServer tests for this and will
+ * send SIGUSR1 when ready */
+ sighandler_t old_handler;
+ old_handler = signal(SIGUSR1, SIG_IGN);
+ if (old_handler == SIG_ERR) {
+ err_msg.append("Failed to set signal handler: ");
+ err_msg.append(std::strerror(errno));
+ throw std::runtime_error(err_msg);
+ }
- for (it = d_->options.begin(); it != d_->options.end(); it++) {
- args.push_back(it->first);
- if (!it->second.empty())
- args.push_back(it->second);
- }
+ /* unblock for the child process so the server receives SIGUSR1, needed
+ for VT switching */
+ sigemptyset(&sig_mask);
+ sigaddset(&sig_mask, SIGUSR1);
+ if (sigprocmask(SIG_UNBLOCK, &sig_mask, NULL)) {
+ err_msg.append("Failed to unblock signal mask: ");
+ err_msg.append(std::strerror(errno));
+ throw std::runtime_error(err_msg);
+ }
+
+ args.push_back(std::string(GetDisplayString()));
- Process::Start(program.empty() ? d_->path_to_server : program, args);
-
- if (Pid() > 0) {
- char *sleepwait = getenv("XORG_GTEST_XSERVER_SIGSTOP");
- if (sleepwait)
- raise(SIGSTOP);
-
- /* wait for SIGUSR1 from XServer */
- int recv_sig = sigtimedwait(&sig_mask, NULL, &sig_timeout);
- if (recv_sig == SIGCHLD) {
- GetState();
- } else if (recv_sig != SIGUSR1 && errno != EAGAIN) {
- err_msg.append("Error while waiting for XServer startup: ");
- err_msg.append(std::strerror(errno));
- throw std::runtime_error(err_msg);
+ for (it = d_->options.begin(); it != d_->options.end(); it++) {
+ args.push_back(it->first);
+ if (!it->second.empty())
+ args.push_back(it->second);
}
+
+ Process::Start(program.empty() ? d_->path_to_server : program, args);
+ /* noreturn */
+
+ }
+
+ /* parent */
+ char *sleepwait = getenv("XORG_GTEST_XSERVER_SIGSTOP");
+ if (sleepwait)
+ raise(SIGSTOP);
+
+ /* wait for SIGUSR1 from XServer */
+ int recv_sig = sigtimedwait(&sig_mask, NULL, &sig_timeout);
+ if (recv_sig == SIGCHLD) {
+ GetState();
+ } else if (recv_sig != SIGUSR1 && errno != EAGAIN) {
+ err_msg.append("Error while waiting for XServer startup: ");
+ err_msg.append(std::strerror(errno));
+ throw std::runtime_error(err_msg);
}
sigemptyset(&sig_mask);
sigaddset(&sig_mask, SIGCHLD);
+ sigaddset(&sig_mask, SIGUSR1);
sigprocmask(SIG_UNBLOCK, &sig_mask, NULL);
RegisterXIOErrorHandler();