From 142ba992065dd9c37a9d06dc6e96cfc9adfb6be0 Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Tue, 5 Jul 2011 06:56:43 +0200 Subject: [PATCH] OS/acpi: Reconnect to acpid when it gets restarted. Patch-mainline: To be upstreamed On Linux the Xserver connects to the ACPI daemon to receive power management events. If this daemon isn't started when the server starts or goes down the connection is lost. When this happens we add a timer which periodically tries to reconnect. Signed-off-by: Egbert Eich --- hw/xfree86/os-support/linux/lnx_acpi.c | 68 ++++++++++++++++++++++++++----- hw/xfree86/os-support/linux/lnx_apm.c | 9 ++++ 2 files changed, 66 insertions(+), 11 deletions(-) diff --git a/hw/xfree86/os-support/linux/lnx_acpi.c b/hw/xfree86/os-support/linux/lnx_acpi.c index 5fad194..8dd6881 100644 --- a/hw/xfree86/os-support/linux/lnx_acpi.c +++ b/hw/xfree86/os-support/linux/lnx_acpi.c @@ -32,9 +32,12 @@ #define ACPI_VIDEO_HEAD_INVALID (~0u - 1) #define ACPI_VIDEO_HEAD_END (~0u) +static PMClose doLnxACPIOpen(void); static void lnxCloseACPI(void); static pointer ACPIihPtr = NULL; +static OsTimerPtr acpiTimer = NULL; PMClose lnxACPIOpen(void); +PMClose lnxACPIPoll(void); /* in milliseconds */ #define ACPI_REOPEN_DELAY 1000 @@ -52,6 +55,22 @@ lnxACPIReopen(OsTimerPtr timer, CARD32 time, pointer arg) #define LINE_LENGTH 80 +static CARD32 +lnxACPICheckTimer(OsTimerPtr timer, CARD32 now, pointer arg) +{ +#if DEBUG + ErrorF("ACPI: trying to reopen\n"); +#endif + if (doLnxACPIOpen()) { +#if DEBUG + ErrorF("ACPI: successfully reopened\n"); +#endif + acpiTimer = NULL; + return 0; + } + return 10000; +} + static int lnxACPIGetEventFromOs(int fd, pmEvent *events, int num) { @@ -127,33 +146,35 @@ lnxACPIConfirmEventToOs(int fd, pmEvent event) } } -PMClose -lnxACPIOpen(void) +static PMClose +doLnxACPIOpen(void) { - int fd; + int fd = -1; struct sockaddr_un addr; int r = -1; static int warned = 0; - DebugF("ACPI: OSPMOpen called\n"); if (ACPIihPtr || !xf86Info.pmFlag) return NULL; DebugF("ACPI: Opening device\n"); - if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) > -1) { + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd > -1) { memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strcpy(addr.sun_path, ACPI_SOCKET); - if ((r = connect(fd, (struct sockaddr*)&addr, sizeof(addr))) == -1) { - if (!warned) + r = connect(fd, (struct sockaddr*)&addr, sizeof(addr)); + if (r == -1) { + if (errno != warned) xf86MsgVerb(X_WARNING,3,"Open ACPI failed (%s) (%s)\n", ACPI_SOCKET, strerror(errno)); - warned = 1; - shutdown(fd, 2); + warned = errno; + shutdown(fd, SHUT_RDWR); close(fd); return NULL; } - } + } else + return NULL; xf86PMGetEventFromOs = lnxACPIGetEventFromOs; xf86PMConfirmEventToOs = lnxACPIConfirmEventToOs; @@ -164,6 +185,25 @@ lnxACPIOpen(void) return lnxCloseACPI; } +PMClose +lnxACPIPoll(void) +{ + TimerSet(NULL, 0, 10000, lnxACPICheckTimer, NULL); + return lnxCloseACPI; +} + +PMClose +lnxACPIOpen(void) +{ + PMClose ret; +#ifdef DEBUG + ErrorF("ACPI: OSPMOpen called\n"); +#endif + ret = doLnxACPIOpen(); + + return ret; +} + static void lnxCloseACPI(void) { @@ -172,8 +212,14 @@ lnxCloseACPI(void) DebugF("ACPI: Closing device\n"); if (ACPIihPtr) { fd = xf86RemoveGeneralHandler(ACPIihPtr); - shutdown(fd, 2); + shutdown(fd, SHUT_RDWR); close(fd); ACPIihPtr = NULL; + xf86PMGetEventFromOs = NULL; + xf86PMConfirmEventToOs = NULL; + if (acpiTimer) { + TimerCancel(acpiTimer); + acpiTimer = NULL; + } } } diff --git a/hw/xfree86/os-support/linux/lnx_apm.c b/hw/xfree86/os-support/linux/lnx_apm.c index 54c6989..c8b254f 100644 --- a/hw/xfree86/os-support/linux/lnx_apm.c +++ b/hw/xfree86/os-support/linux/lnx_apm.c @@ -12,6 +12,7 @@ #ifdef HAVE_ACPI extern PMClose lnxACPIOpen(void); +extern PMClose lnxACPIPoll(void); #endif #ifdef HAVE_APM @@ -149,6 +150,14 @@ xf86OSPMOpen(void) ret = lnxAPMOpen(); #endif +#ifdef HAVE_ACPI + /* if we can neither open ACPI nor APM poll for an ACPI service to + become available */ + + if (!ret && !xf86acpiDisableFlag) + ret = lnxACPIPoll(); +#endif + return ret; } -- 1.6.0.2 From 3f35d15f7c7eb202de36e2d1040f27ef7b38c1d2 Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Thu, 7 Jul 2011 09:01:35 +0200 Subject: [PATCH] OS/ACPI: Make socket to read from acpid non-blocking. If acpid for some reason does not service a connect() this function may hang forever stalling the Xserver. To prevent this make the socket non-blocking. If connect returns EINPROGRESS use select() and getsockopt() to check for completion of the connect request. select() gets a different timeout depending if it is called during startup or to do a reconnect. Signed-off-by: Egbert Eich --- hw/xfree86/os-support/linux/lnx_acpi.c | 34 +++++++++++++++++++++++++++---- 1 files changed, 29 insertions(+), 5 deletions(-) diff --git a/hw/xfree86/os-support/linux/lnx_acpi.c b/hw/xfree86/os-support/linux/lnx_acpi.c index 8dd6881..f0e6eb4 100644 --- a/hw/xfree86/os-support/linux/lnx_acpi.c +++ b/hw/xfree86/os-support/linux/lnx_acpi.c @@ -32,7 +32,7 @@ #define ACPI_VIDEO_HEAD_INVALID (~0u - 1) #define ACPI_VIDEO_HEAD_END (~0u) -static PMClose doLnxACPIOpen(void); +static PMClose doLnxACPIOpen(struct timeval *); static void lnxCloseACPI(void); static pointer ACPIihPtr = NULL; static OsTimerPtr acpiTimer = NULL; @@ -58,10 +58,11 @@ lnxACPIReopen(OsTimerPtr timer, CARD32 time, pointer arg) static CARD32 lnxACPICheckTimer(OsTimerPtr timer, CARD32 now, pointer arg) { + struct timeval timeval = { 0, 0 }; #if DEBUG ErrorF("ACPI: trying to reopen\n"); #endif - if (doLnxACPIOpen()) { + if (doLnxACPIOpen(&timeval)) { #if DEBUG ErrorF("ACPI: successfully reopened\n"); #endif @@ -147,7 +148,7 @@ lnxACPIConfirmEventToOs(int fd, pmEvent event) } static PMClose -doLnxACPIOpen(void) +doLnxACPIOpen(struct timeval *tv_p) { int fd = -1; struct sockaddr_un addr; @@ -158,13 +159,34 @@ doLnxACPIOpen(void) return NULL; DebugF("ACPI: Opening device\n"); - fd = socket(AF_UNIX, SOCK_STREAM, 0); + fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0); if (fd > -1) { memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strcpy(addr.sun_path, ACPI_SOCKET); r = connect(fd, (struct sockaddr*)&addr, sizeof(addr)); if (r == -1) { + int sock_errno = errno; + if (sock_errno == EINPROGRESS) { + fd_set fds; + int result; + do { + FD_ZERO(&fds); + FD_SET(fd, &fds); + result = select(fd + 1, NULL, &fds, NULL, tv_p); + } while (result < 0 && errno == EINTR); + if (result < 0) + sock_errno = errno; + else if (result > 0) { + int sock_errno; + socklen_t size = sizeof(sock_errno); + if (0 > getsockopt(fd, SOL_SOCKET, SO_ERROR, &sock_errno, + &size)) + sock_errno = errno; + if (!sock_errno) + goto success; + } + } if (errno != warned) xf86MsgVerb(X_WARNING,3,"Open ACPI failed (%s) (%s)\n", ACPI_SOCKET, strerror(errno)); @@ -176,6 +198,7 @@ doLnxACPIOpen(void) } else return NULL; + success: xf86PMGetEventFromOs = lnxACPIGetEventFromOs; xf86PMConfirmEventToOs = lnxACPIConfirmEventToOs; ACPIihPtr = xf86AddGeneralHandler(fd,xf86HandlePMEvents,NULL); @@ -196,10 +219,11 @@ PMClose lnxACPIOpen(void) { PMClose ret; + struct timeval timeval = { 0, 30000 }; #ifdef DEBUG ErrorF("ACPI: OSPMOpen called\n"); #endif - ret = doLnxACPIOpen(); + ret = doLnxACPIOpen(&timeval); return ret; } -- 1.7.3.4