sync code with last improvements from OpenBSD
This commit is contained in:
commit
88965415ff
26235 changed files with 29195616 additions and 0 deletions
152
xserver/os/busfault.c
Normal file
152
xserver/os/busfault.c
Normal file
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* 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 *iter, *busfault = NULL;
|
||||
void *new_addr;
|
||||
|
||||
/* Locate the faulting address in our list of shared segments
|
||||
*/
|
||||
xorg_list_for_each_entry(iter, &busfaults, list) {
|
||||
if ((char *) iter->addr <= (char *) fault && (char *) fault < (char *) iter->addr + iter->size) {
|
||||
busfault = iter;
|
||||
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_ANON|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\n");
|
||||
}
|
||||
|
||||
Bool
|
||||
busfault_init(void)
|
||||
{
|
||||
struct sigaction act, old_act;
|
||||
|
||||
act.sa_sigaction = busfault_sigaction;
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
sigemptyset(&act.sa_mask);
|
||||
if (sigaction(SIGBUS, &act, &old_act) < 0)
|
||||
return FALSE;
|
||||
previous_busfault_sigaction = old_act.sa_sigaction;
|
||||
xorg_list_init(&busfaults);
|
||||
return TRUE;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue