summaryrefslogtreecommitdiff
path: root/os
diff options
context:
space:
mode:
Diffstat (limited to 'os')
-rw-r--r--os/Makefile.am5
-rw-r--r--os/WaitFor.c5
-rw-r--r--os/busfault.c149
-rw-r--r--os/osinit.c5
4 files changed, 164 insertions, 0 deletions
diff --git a/os/Makefile.am b/os/Makefile.am
index 364b6da2d..a1bbb4d1e 100644
--- a/os/Makefile.am
+++ b/os/Makefile.am
@@ -5,6 +5,7 @@ AM_CFLAGS = $(DIX_CFLAGS) $(SHA1_CFLAGS)
SECURERPC_SRCS = rpcauth.c
XDMCP_SRCS = xdmcp.c
XORG_SRCS = log.c
+BUSFAULT_SRCS = busfault.c
libos_la_SOURCES = \
WaitFor.c \
@@ -39,6 +40,10 @@ AM_CFLAGS += $(LIBUNWIND_CFLAGS)
libos_la_LIBADD += $(LIBUNWIND_LIBS)
endif
+if BUSFAULT
+libos_la_SOURCES += $(BUSFAULT_SRCS)
+endif
+
EXTRA_DIST = $(SECURERPC_SRCS) $(XDMCP_SRCS)
if SPECIAL_DTRACE_OBJECTS
diff --git a/os/WaitFor.c b/os/WaitFor.c
index c5f4cd78b..39fedd9a2 100644
--- a/os/WaitFor.c
+++ b/os/WaitFor.c
@@ -72,6 +72,7 @@ SOFTWARE.
#ifdef DPMSExtension
#include "dpmsproc.h"
#endif
+#include "busfault.h"
#ifdef WIN32
/* Error codes from windows sockets differ from fileio error codes */
@@ -162,6 +163,10 @@ WaitForSomething(int *pClientsReady)
SmartScheduleStopTimer();
nready = 0;
+#ifdef BUSFAULT
+ busfault_check();
+#endif
+
/* We need a while loop here to handle
crashed connections and the screen saver timeout */
while (1) {
diff --git a/os/busfault.c b/os/busfault.c
new file mode 100644
index 000000000..78e7693e3
--- /dev/null
+++ b/os/busfault.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright © 2013 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <X11/Xos.h>
+#include <X11/Xdefs.h>
+#include "misc.h"
+#include <busfault.h>
+#include <list.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <signal.h>
+
+struct busfault {
+ struct xorg_list list;
+
+ void *addr;
+ size_t size;
+
+ Bool valid;
+
+ busfault_notify_ptr notify;
+ void *context;
+};
+
+static Bool busfaulted;
+static struct xorg_list busfaults;
+
+struct busfault *
+busfault_register_mmap(void *addr, size_t size, busfault_notify_ptr notify, void *context)
+{
+ struct busfault *busfault;
+
+ busfault = calloc(1, sizeof (struct busfault));
+ if (!busfault)
+ return NULL;
+
+ busfault->addr = addr;
+ busfault->size = size;
+ busfault->notify = notify;
+ busfault->context = context;
+ busfault->valid = TRUE;
+
+ xorg_list_add(&busfault->list, &busfaults);
+ return busfault;
+}
+
+void
+busfault_unregister(struct busfault *busfault)
+{
+ xorg_list_del(&busfault->list);
+ free(busfault);
+}
+
+void
+busfault_check(void)
+{
+ struct busfault *busfault, *tmp;
+
+ if (!busfaulted)
+ return;
+
+ busfaulted = FALSE;
+
+ xorg_list_for_each_entry_safe(busfault, tmp, &busfaults, list) {
+ if (!busfault->valid)
+ (*busfault->notify)(busfault->context);
+ }
+}
+
+static void (*previous_busfault_sigaction)(int sig, siginfo_t *info, void *param);
+
+static void
+busfault_sigaction(int sig, siginfo_t *info, void *param)
+{
+ void *fault = info->si_addr;
+ struct busfault *busfault = NULL;
+ void *new_addr;
+
+ /* Locate the faulting address in our list of shared segments
+ */
+ xorg_list_for_each_entry(busfault, &busfaults, list) {
+ if ((char *) busfault->addr <= (char *) fault && (char *) fault < (char *) busfault->addr + busfault->size) {
+ break;
+ }
+ }
+ if (!busfault)
+ goto panic;
+
+ if (!busfault->valid)
+ goto panic;
+
+ busfault->valid = FALSE;
+ busfaulted = TRUE;
+
+ /* The client truncated the file; unmap the shared file, map
+ * /dev/zero over that area and keep going
+ */
+
+ new_addr = mmap(busfault->addr, busfault->size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED, -1, 0);
+
+ if (new_addr == MAP_FAILED)
+ goto panic;
+
+ return;
+panic:
+ if (previous_busfault_sigaction)
+ (*previous_busfault_sigaction)(sig, info, param);
+ else
+ FatalError("bus error");
+}
+
+Bool
+busfault_init(void)
+{
+ struct sigaction act, old_act;
+
+ act.sa_sigaction = busfault_sigaction;
+ act.sa_flags = SA_SIGINFO;
+ if (sigaction(SIGBUS, &act, &old_act) < 0)
+ return FALSE;
+ previous_busfault_sigaction = old_act.sa_sigaction;
+ xorg_list_init(&busfaults);
+ return TRUE;
+}
diff --git a/os/osinit.c b/os/osinit.c
index 6c66f9c12..60d10694b 100644
--- a/os/osinit.c
+++ b/os/osinit.c
@@ -149,6 +149,8 @@ OsSigHandler(int signo)
}
#endif /* !WIN32 || __CYGWIN__ */
+#include "busfault.h"
+
void
OsInit(void)
{
@@ -185,6 +187,9 @@ OsInit(void)
}
}
#endif /* !WIN32 || __CYGWIN__ */
+#ifdef BUSFAULT
+ busfault_init();
+#endif
#ifdef HAVE_BACKTRACE
/*