forked from 12to11/12to11

* Imakefile (EXTRA_DEFINES, DEPEND_DEFINES, ANALYZE, OPTIMIZE): Make port and compiler specific. * compositor.h: Update compiler-specific defines. * fns.c (PortPopcount): New function. * seat.c (MaskPopCount): Use Popcount macro.
917 lines
17 KiB
C
917 lines
17 KiB
C
/* Wayland compositor running on top of an X server.
|
||
|
||
Copyright (C) 2022 to various contributors.
|
||
|
||
This file is part of 12to11.
|
||
|
||
12to11 is free software: you can redistribute it and/or modify it
|
||
under the terms of the GNU General Public License as published by the
|
||
Free Software Foundation, either version 3 of the License, or (at your
|
||
option) any later version.
|
||
|
||
12to11 is distributed in the hope that it will be useful, but WITHOUT
|
||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||
for more details.
|
||
|
||
You should have received a copy of the GNU General Public License
|
||
along with 12to11. If not, see <https://www.gnu.org/licenses/>. */
|
||
|
||
#include <sys/mman.h>
|
||
#include <sys/fcntl.h>
|
||
#include <sys/stat.h>
|
||
#include <sys/errno.h>
|
||
|
||
#include <signal.h>
|
||
#include <stdlib.h>
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
|
||
#include <math.h>
|
||
|
||
#include "compositor.h"
|
||
|
||
typedef struct _Busfault Busfault;
|
||
|
||
struct _RootWindowSelection
|
||
{
|
||
/* The next and last event selection records in this chain. */
|
||
RootWindowSelection *next, *last;
|
||
|
||
/* The event mask one piece of code has selected for. */
|
||
unsigned long event_mask;
|
||
};
|
||
|
||
struct _Busfault
|
||
{
|
||
/* Nodes to the left and right. */
|
||
Busfault *left, *right;
|
||
|
||
/* Start of the ignored area. */
|
||
char *data;
|
||
|
||
/* Size of the ignored area. */
|
||
size_t ignored_area;
|
||
|
||
/* Height of this node. */
|
||
int height;
|
||
};
|
||
|
||
/* Events that are being selected for on the root window. */
|
||
static RootWindowSelection root_window_events;
|
||
|
||
/* All busfaults. */
|
||
static Busfault *busfault_tree;
|
||
|
||
/* Whether or not the SIGBUS handler has been installed. */
|
||
static Bool bus_handler_installed;
|
||
|
||
void
|
||
XLListFree (XLList *list, void (*item_func) (void *))
|
||
{
|
||
XLList *tem, *last;
|
||
|
||
tem = list;
|
||
|
||
while (tem)
|
||
{
|
||
last = tem;
|
||
tem = tem->next;
|
||
|
||
if (item_func)
|
||
item_func (last->data);
|
||
XLFree (last);
|
||
}
|
||
}
|
||
|
||
XLList *
|
||
XLListRemove (XLList *list, void *data)
|
||
{
|
||
XLList *tem, **last;
|
||
|
||
last = &list;
|
||
|
||
while (*last)
|
||
{
|
||
tem = *last;
|
||
|
||
if (tem->data == data)
|
||
{
|
||
*last = tem->next;
|
||
XLFree (tem);
|
||
}
|
||
else
|
||
last = &tem->next;
|
||
}
|
||
|
||
return list;
|
||
}
|
||
|
||
XLList *
|
||
XLListPrepend (XLList *list, void *data)
|
||
{
|
||
XLList *tem;
|
||
|
||
tem = XLMalloc (sizeof *tem);
|
||
tem->data = data;
|
||
tem->next = list;
|
||
|
||
return tem;
|
||
}
|
||
|
||
|
||
/* List of XIDs (not pointers). */
|
||
|
||
void
|
||
XIDListFree (XIDList *list, void (*item_func) (XID))
|
||
{
|
||
XIDList *tem, *last;
|
||
|
||
tem = list;
|
||
|
||
while (tem)
|
||
{
|
||
last = tem;
|
||
tem = tem->next;
|
||
|
||
if (item_func)
|
||
item_func (last->data);
|
||
XLFree (last);
|
||
}
|
||
}
|
||
|
||
XIDList *
|
||
XIDListRemove (XIDList *list, XID resource)
|
||
{
|
||
XIDList *tem, **last;
|
||
|
||
last = &list;
|
||
|
||
while (*last)
|
||
{
|
||
tem = *last;
|
||
|
||
if (tem->data == resource)
|
||
{
|
||
*last = tem->next;
|
||
XLFree (tem);
|
||
}
|
||
else
|
||
last = &tem->next;
|
||
}
|
||
|
||
return list;
|
||
}
|
||
|
||
XIDList *
|
||
XIDListPrepend (XIDList *list, XID resource)
|
||
{
|
||
XIDList *tem;
|
||
|
||
tem = XLMalloc (sizeof *tem);
|
||
tem->data = resource;
|
||
tem->next = list;
|
||
|
||
return tem;
|
||
}
|
||
|
||
|
||
/* Hash tables between XIDs and arbitrary data. */
|
||
|
||
XLAssocTable *
|
||
XLCreateAssocTable (int size)
|
||
{
|
||
XLAssocTable *table;
|
||
XLAssoc *buckets;
|
||
|
||
table = XLMalloc (sizeof *table);
|
||
buckets = XLCalloc (size, sizeof *buckets);
|
||
|
||
table->buckets = buckets;
|
||
table->size = size;
|
||
|
||
while (--size >= 0)
|
||
{
|
||
/* Initialize each bucket with the sentinel node. */
|
||
buckets->prev = buckets;
|
||
buckets->next = buckets;
|
||
buckets++;
|
||
}
|
||
|
||
return table;
|
||
}
|
||
|
||
static void
|
||
Insque (XLAssoc *velem, XLAssoc *vprev)
|
||
{
|
||
XLAssoc *elem, *prev, *next;
|
||
|
||
elem = velem;
|
||
prev = vprev;
|
||
next = prev->next;
|
||
|
||
prev->next = elem;
|
||
if (next)
|
||
next->prev = elem;
|
||
elem->next = next;
|
||
elem->prev = prev;
|
||
}
|
||
|
||
static void
|
||
Remque (XLAssoc *velem)
|
||
{
|
||
XLAssoc *elem, *prev, *next;
|
||
|
||
elem = velem;
|
||
next = elem->next;
|
||
prev = elem->prev;
|
||
|
||
if (next)
|
||
next->prev = prev;
|
||
|
||
if (prev)
|
||
prev->next = next;
|
||
}
|
||
|
||
void
|
||
XLMakeAssoc (XLAssocTable *table, XID x_id, void *data)
|
||
{
|
||
int hash;
|
||
XLAssoc *bucket, *entry, *new_entry;
|
||
|
||
hash = x_id % table->size;
|
||
bucket = &table->buckets[hash];
|
||
entry = bucket->next;
|
||
|
||
if (entry != bucket)
|
||
{
|
||
/* Bucket isn't empty, start searching. */
|
||
|
||
for (; entry != bucket; entry = entry->next)
|
||
{
|
||
if (entry->x_id == x_id)
|
||
{
|
||
entry->data = data;
|
||
return;
|
||
}
|
||
|
||
if (entry->x_id > x_id)
|
||
break;
|
||
}
|
||
}
|
||
|
||
/* Insert new_entry immediately before entry. */
|
||
|
||
new_entry = XLMalloc (sizeof *new_entry);
|
||
new_entry->x_id = x_id;
|
||
new_entry->data = data;
|
||
|
||
Insque (new_entry, entry->prev);
|
||
}
|
||
|
||
void *
|
||
XLLookUpAssoc (XLAssocTable *table, XID x_id)
|
||
{
|
||
int hash;
|
||
XLAssoc *bucket, *entry;
|
||
|
||
hash = x_id % table->size;
|
||
bucket = &table->buckets[hash];
|
||
entry = bucket->next;
|
||
|
||
for (; entry != bucket; entry = entry->next)
|
||
{
|
||
if (entry->x_id == x_id)
|
||
return entry->data;
|
||
|
||
if (entry->x_id > x_id)
|
||
return NULL;
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
void
|
||
XLDeleteAssoc (XLAssocTable *table, XID x_id)
|
||
{
|
||
int hash;
|
||
XLAssoc *bucket, *entry;
|
||
|
||
hash = x_id % table->size;
|
||
bucket = &table->buckets[hash];
|
||
entry = bucket->next;
|
||
|
||
for (; entry != bucket; entry = entry->next)
|
||
{
|
||
if (entry->x_id == x_id)
|
||
{
|
||
Remque (entry);
|
||
XLFree (entry);
|
||
return;
|
||
}
|
||
|
||
if (entry->x_id > x_id)
|
||
return;
|
||
}
|
||
}
|
||
|
||
void
|
||
XLDestroyAssocTable (XLAssocTable *table)
|
||
{
|
||
int i;
|
||
XLAssoc *bucket, *entry, *entry_next;
|
||
|
||
for (i = 0; i < table->size; i++)
|
||
{
|
||
bucket = &table->buckets[i];
|
||
|
||
for (entry = bucket->next; entry != bucket;
|
||
entry = entry_next)
|
||
{
|
||
entry_next = entry->next;
|
||
XLFree (entry);
|
||
}
|
||
}
|
||
|
||
XLFree (table->buckets);
|
||
XLFree (table);
|
||
}
|
||
|
||
void
|
||
XLScaleRegion (pixman_region32_t *dst, pixman_region32_t *src,
|
||
float scale_x, float scale_y)
|
||
{
|
||
int nrects, i;
|
||
pixman_box32_t *src_rects;
|
||
pixman_box32_t *dst_rects;
|
||
|
||
if (scale_x == 1.0f && scale_y == 1.0f)
|
||
{
|
||
pixman_region32_copy (dst, src);
|
||
return;
|
||
}
|
||
|
||
src_rects = pixman_region32_rectangles (src, &nrects);
|
||
|
||
if (nrects < 128)
|
||
dst_rects = alloca (nrects * sizeof *dst_rects);
|
||
else
|
||
dst_rects = XLMalloc (nrects * sizeof *dst_rects);
|
||
|
||
for (i = 0; i < nrects; ++i)
|
||
{
|
||
dst_rects[i].x1 = floor (src_rects[i].x1 * scale_x);
|
||
dst_rects[i].x2 = ceil (src_rects[i].x2 * scale_x);
|
||
dst_rects[i].y1 = floor (src_rects[i].y1 * scale_y);
|
||
dst_rects[i].y2 = ceil (src_rects[i].y2 * scale_y);
|
||
}
|
||
|
||
pixman_region32_fini (dst);
|
||
pixman_region32_init_rects (dst, dst_rects, nrects);
|
||
|
||
if (nrects >= 128)
|
||
XLFree (dst_rects);
|
||
}
|
||
|
||
void
|
||
XLExtendRegion (pixman_region32_t *dst, pixman_region32_t *src,
|
||
int extend_x, int extend_y)
|
||
{
|
||
int nrects, i;
|
||
pixman_box32_t *src_rects;
|
||
pixman_box32_t *dst_rects;
|
||
|
||
src_rects = pixman_region32_rectangles (src, &nrects);
|
||
|
||
if (nrects < 128)
|
||
dst_rects = alloca (nrects * sizeof *dst_rects);
|
||
else
|
||
dst_rects = XLMalloc (nrects * sizeof *dst_rects);
|
||
|
||
for (i = 0; i < nrects; ++i)
|
||
{
|
||
dst_rects[i].x1 = src_rects[i].x1;
|
||
dst_rects[i].x2 = src_rects[i].x2 + extend_x;
|
||
dst_rects[i].y1 = src_rects[i].y1;
|
||
dst_rects[i].y2 = src_rects[i].y2 + extend_y;
|
||
}
|
||
|
||
pixman_region32_fini (dst);
|
||
pixman_region32_init_rects (dst, dst_rects, nrects);
|
||
|
||
if (nrects >= 128)
|
||
XLFree (dst_rects);
|
||
}
|
||
|
||
void
|
||
XLTransformRegion (pixman_region32_t *dst, pixman_region32_t *src,
|
||
BufferTransform transform, int width, int height)
|
||
{
|
||
int nrects, i;
|
||
pixman_box32_t *src_rects;
|
||
pixman_box32_t *dst_rects;
|
||
|
||
src_rects = pixman_region32_rectangles (src, &nrects);
|
||
|
||
if (nrects < 128)
|
||
dst_rects = alloca (nrects * sizeof *dst_rects);
|
||
else
|
||
dst_rects = XLMalloc (nrects * sizeof *dst_rects);
|
||
|
||
for (i = 0; i < nrects; ++i)
|
||
{
|
||
dst_rects[i] = src_rects[i];
|
||
|
||
/* width and height should be in the transformed space! */
|
||
TransformBox (&dst_rects[i], transform, width, height);
|
||
}
|
||
|
||
pixman_region32_fini (dst);
|
||
pixman_region32_init_rects (dst, dst_rects, nrects);
|
||
|
||
if (nrects >= 128)
|
||
XLFree (dst_rects);
|
||
}
|
||
|
||
int
|
||
XLOpenShm (void)
|
||
{
|
||
char name[sizeof "SharedBufferXXXXXXXX"];
|
||
int fd;
|
||
unsigned int i;
|
||
|
||
i = 0;
|
||
|
||
while (i <= 0xffffffff)
|
||
{
|
||
sprintf (name, "SharedBuffer%x", i);
|
||
fd = shm_open (name, O_RDWR | O_CREAT | O_EXCL, 0600);
|
||
|
||
if (fd >= 0)
|
||
{
|
||
shm_unlink (name);
|
||
return fd;
|
||
}
|
||
|
||
if (errno == EEXIST)
|
||
++i;
|
||
else
|
||
{
|
||
perror ("shm_open");
|
||
exit (1);
|
||
}
|
||
}
|
||
|
||
return -1;
|
||
}
|
||
|
||
static Bool
|
||
ServerTimePredicate (Display *display, XEvent *event, XPointer arg)
|
||
{
|
||
return (event->type == PropertyNotify
|
||
&& event->xproperty.window == selection_transfer_window
|
||
&& event->xproperty.atom == _XL_SERVER_TIME_ATOM);
|
||
}
|
||
|
||
Time
|
||
XLGetServerTimeRoundtrip (void)
|
||
{
|
||
XEvent event;
|
||
|
||
XChangeProperty (compositor.display, selection_transfer_window,
|
||
_XL_SERVER_TIME_ATOM, XA_ATOM, 32, PropModeReplace,
|
||
(unsigned char *) &_XL_SERVER_TIME_ATOM, 1);
|
||
XIfEvent (compositor.display, &event, ServerTimePredicate, NULL);
|
||
|
||
return event.xproperty.time;
|
||
}
|
||
|
||
static void
|
||
ReselectRootWindowInput (void)
|
||
{
|
||
unsigned long effective;
|
||
RootWindowSelection *record;
|
||
|
||
effective = NoEventMask;
|
||
record = root_window_events.next;
|
||
|
||
if (!record)
|
||
return;
|
||
|
||
while (record != &root_window_events)
|
||
{
|
||
effective |= record->event_mask;
|
||
record = record->next;
|
||
}
|
||
|
||
XSelectInput (compositor.display,
|
||
DefaultRootWindow (compositor.display),
|
||
effective);
|
||
}
|
||
|
||
RootWindowSelection *
|
||
XLSelectInputFromRootWindow (unsigned long event_mask)
|
||
{
|
||
RootWindowSelection *selection;
|
||
|
||
/* This lets different pieces of code select for input from the root
|
||
window without clobbering eachothers event masks. */
|
||
|
||
selection = XLMalloc (sizeof *selection);
|
||
|
||
/* If the global chain has not yet been initialized, initialize it
|
||
now. */
|
||
if (!root_window_events.next)
|
||
{
|
||
root_window_events.next = &root_window_events;
|
||
root_window_events.last = &root_window_events;
|
||
}
|
||
|
||
/* Link this onto the chain of events being selected for on the root
|
||
window. */
|
||
selection->next = root_window_events.next;
|
||
selection->last = &root_window_events;
|
||
root_window_events.next->last = selection;
|
||
root_window_events.next = selection;
|
||
|
||
/* Set the event mask. */
|
||
selection->event_mask = event_mask;
|
||
|
||
/* Actually select for events. */
|
||
ReselectRootWindowInput ();
|
||
return selection;
|
||
}
|
||
|
||
void
|
||
XLDeselectInputFromRootWindow (RootWindowSelection *key)
|
||
{
|
||
key->last->next = key->next;
|
||
key->next->last = key->last;
|
||
|
||
XLFree (key);
|
||
ReselectRootWindowInput ();
|
||
}
|
||
|
||
static int
|
||
GetHeight (Busfault *busfault)
|
||
{
|
||
if (!busfault)
|
||
return 0;
|
||
|
||
return busfault->height;
|
||
}
|
||
|
||
static void
|
||
FixHeights (Busfault *busfault)
|
||
{
|
||
XLAssert (busfault != NULL);
|
||
|
||
busfault->height = 1 + MAX (GetHeight (busfault->left),
|
||
GetHeight (busfault->right));
|
||
}
|
||
|
||
static void
|
||
RotateLeft (Busfault **root)
|
||
{
|
||
Busfault *old_root, *new_root, *old_middle;
|
||
|
||
/* Rotate *root->left to *root. */
|
||
old_root = *root;
|
||
new_root = old_root->left;
|
||
old_middle = new_root->right;
|
||
old_root->left = old_middle;
|
||
new_root->right = old_root;
|
||
*root = new_root;
|
||
|
||
/* Update heights. */
|
||
FixHeights ((*root)->right);
|
||
FixHeights (*root);
|
||
}
|
||
|
||
static void
|
||
RotateRight (Busfault **root)
|
||
{
|
||
Busfault *old_root, *new_root, *old_middle;
|
||
|
||
/* Rotate *root->right to *root. */
|
||
old_root = *root;
|
||
new_root = old_root->right;
|
||
old_middle = new_root->left;
|
||
old_root->right = old_middle;
|
||
new_root->left = old_root;
|
||
*root = new_root;
|
||
|
||
/* Update heights. */
|
||
FixHeights ((*root)->left);
|
||
FixHeights (*root);
|
||
}
|
||
|
||
static void
|
||
RebalanceBusfault (Busfault **tree)
|
||
{
|
||
if (*tree)
|
||
{
|
||
/* Check the left. It could be too tall. */
|
||
if (GetHeight ((*tree)->left)
|
||
> GetHeight ((*tree)->right) + 1)
|
||
{
|
||
/* The left side is unbalanced. Look for a taller
|
||
grandchild of tree->left. */
|
||
|
||
if (GetHeight ((*tree)->left->left)
|
||
> GetHeight ((*tree)->left->right))
|
||
RotateLeft (tree);
|
||
else
|
||
{
|
||
XLAssert ((*tree)->left->right != NULL);
|
||
|
||
RotateRight (&(*tree)->left);
|
||
RotateLeft (tree);
|
||
}
|
||
|
||
return;
|
||
}
|
||
/* Then, check the right. */
|
||
else if (GetHeight ((*tree)->right)
|
||
> GetHeight ((*tree)->left) + 1)
|
||
{
|
||
/* The right side is unbalanced. Look for a taller
|
||
grandchild of tree->right. */
|
||
|
||
if (GetHeight ((*tree)->right->right)
|
||
> GetHeight ((*tree)->right->left))
|
||
RotateRight (tree);
|
||
else
|
||
{
|
||
XLAssert ((*tree)->right->left != NULL);
|
||
|
||
RotateLeft (&(*tree)->right);
|
||
RotateRight (tree);
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
/* Nothing was called, so fix heights. */
|
||
FixHeights (*tree);
|
||
}
|
||
}
|
||
|
||
static void
|
||
RecordBusfault (Busfault **tree, Busfault *node)
|
||
{
|
||
if (!*tree)
|
||
{
|
||
/* Tree is empty. Replace it with node. */
|
||
*tree = node;
|
||
node->left = NULL;
|
||
node->right = NULL;
|
||
node->height = 1;
|
||
|
||
return;
|
||
}
|
||
|
||
/* Record busfault into the correct subtree. */
|
||
if (node->data > (*tree)->data)
|
||
RecordBusfault (&(*tree)->right, node);
|
||
else
|
||
RecordBusfault (&(*tree)->left, node);
|
||
|
||
/* Balance the tree. */
|
||
RebalanceBusfault (tree);
|
||
}
|
||
|
||
static Busfault *
|
||
DetectBusfault (Busfault *tree, char *address)
|
||
{
|
||
/* This function is reentrant, but the functions that remove and
|
||
insert busfaults are not. */
|
||
|
||
if (!tree)
|
||
return NULL;
|
||
else if (address >= tree->data
|
||
&& address < tree->data + tree->ignored_area)
|
||
return tree;
|
||
|
||
/* Continue searching in the tree. */
|
||
if (address > tree->data)
|
||
/* Search in the right node. */
|
||
return DetectBusfault (tree->right, address);
|
||
|
||
/* Search in the left. */
|
||
return DetectBusfault (tree->left, address);
|
||
}
|
||
|
||
static void
|
||
DeleteMin (Busfault **tree, Busfault *out)
|
||
{
|
||
Busfault *old_root;
|
||
|
||
/* Delete and return the minimum value of the tree. */
|
||
|
||
XLAssert (*tree != NULL);
|
||
|
||
if (!(*tree)->left)
|
||
{
|
||
/* *tree contains the smallest value. */
|
||
old_root = *tree;
|
||
out->data = old_root->data;
|
||
out->ignored_area = old_root->ignored_area;
|
||
*tree = old_root->right;
|
||
XLFree (old_root);
|
||
}
|
||
else
|
||
/* Keep looking to the left. */
|
||
DeleteMin (&(*tree)->left, out);
|
||
|
||
RebalanceBusfault (tree);
|
||
}
|
||
|
||
static void
|
||
RemoveBusfault (Busfault **tree, char *data)
|
||
{
|
||
Busfault *old_root;
|
||
|
||
if (!*tree)
|
||
/* There should always be a busfault. */
|
||
abort ();
|
||
else if ((*tree)->data == data)
|
||
{
|
||
if ((*tree)->right)
|
||
/* Replace with min value of right subtree. */
|
||
DeleteMin (&(*tree)->right, *tree);
|
||
else
|
||
{
|
||
/* Splice out old root. */
|
||
old_root = *tree;
|
||
*tree = (*tree)->left;
|
||
XLFree (old_root);
|
||
}
|
||
}
|
||
else if (data > (*tree)->data)
|
||
/* Delete child from the right. */
|
||
RemoveBusfault (&(*tree)->right, data);
|
||
else
|
||
/* Delete from the left. */
|
||
RemoveBusfault (&(*tree)->left, data);
|
||
|
||
RebalanceBusfault (tree);
|
||
}
|
||
|
||
static void
|
||
HandleBusfault (int signal, siginfo_t *siginfo, void *ucontext)
|
||
{
|
||
/* SIGBUS received. If the faulting address is currently part of a
|
||
shared memory buffer, ignore. Otherwise, print an error and
|
||
return. Only reentrant functions must be called within this
|
||
signal handler. */
|
||
|
||
if (DetectBusfault (busfault_tree, siginfo->si_addr))
|
||
return;
|
||
|
||
write (2, "unexpected bus fault\n",
|
||
sizeof "unexpected bus fault\n");
|
||
_exit (EXIT_FAILURE);
|
||
}
|
||
|
||
static void
|
||
MaybeInstallBusHandler (void)
|
||
{
|
||
struct sigaction act;
|
||
|
||
/* If the SIGBUS handler is already installed, return. */
|
||
if (bus_handler_installed)
|
||
return;
|
||
|
||
bus_handler_installed = True;
|
||
memset (&act, 0, sizeof act);
|
||
|
||
/* Install a SIGBUS handler. When a client truncates the file
|
||
backing a shared memory buffer without notifying the compositor,
|
||
attempting to access the contents of the mapped memory beyond the
|
||
end of the file will result in SIGBUS being called, which we
|
||
handle here. */
|
||
|
||
act.sa_flags = SA_SIGINFO;
|
||
act.sa_sigaction = HandleBusfault;
|
||
|
||
if (sigaction (SIGBUS, &act, NULL))
|
||
{
|
||
perror ("sigaction");
|
||
abort ();
|
||
}
|
||
}
|
||
|
||
static void
|
||
BlockSigbus (void)
|
||
{
|
||
sigset_t sigset;
|
||
|
||
sigemptyset (&sigset);
|
||
sigaddset (&sigset, SIGBUS);
|
||
|
||
if (sigprocmask (SIG_BLOCK, &sigset, NULL))
|
||
{
|
||
perror ("sigprocmask");
|
||
abort ();
|
||
}
|
||
}
|
||
|
||
static void
|
||
UnblockSigbus (void)
|
||
{
|
||
sigset_t sigset;
|
||
|
||
sigemptyset (&sigset);
|
||
sigaddset (&sigset, SIGBUS);
|
||
|
||
if (sigprocmask (SIG_UNBLOCK, &sigset, NULL))
|
||
{
|
||
perror ("sigprocmask");
|
||
abort ();
|
||
}
|
||
}
|
||
|
||
/* These must not overlap. */
|
||
|
||
void
|
||
XLRecordBusfault (void *data, size_t data_size)
|
||
{
|
||
Busfault *node;
|
||
|
||
MaybeInstallBusHandler ();
|
||
|
||
BlockSigbus ();
|
||
node = XLMalloc (sizeof *node);
|
||
node->data = data;
|
||
node->ignored_area = data_size;
|
||
|
||
RecordBusfault (&busfault_tree, node);
|
||
UnblockSigbus ();
|
||
}
|
||
|
||
void
|
||
XLRemoveBusfault (void *data)
|
||
{
|
||
BlockSigbus ();
|
||
RemoveBusfault (&busfault_tree, data);
|
||
UnblockSigbus ();
|
||
}
|
||
|
||
Bool
|
||
XLAddFdFlag (int fd, int flag, Bool abort_on_error)
|
||
{
|
||
int flags, rc;
|
||
|
||
flags = fcntl (fd, F_GETFD);
|
||
|
||
if (flags < 0)
|
||
{
|
||
if (abort_on_error)
|
||
{
|
||
perror ("fcntl");
|
||
abort ();
|
||
}
|
||
else
|
||
return False;
|
||
}
|
||
|
||
rc = fcntl (fd, F_SETFD, flags | flag);
|
||
|
||
if (rc < 0)
|
||
{
|
||
if (abort_on_error)
|
||
{
|
||
perror ("fcntl");
|
||
abort ();
|
||
}
|
||
else
|
||
return False;
|
||
}
|
||
|
||
return True;
|
||
}
|
||
|
||
/* Functions for ports. */
|
||
|
||
#ifdef NeedPortPopcount
|
||
|
||
int
|
||
PortPopcount (unsigned long long int big)
|
||
{
|
||
int num_bits;
|
||
|
||
num_bits = 0;
|
||
|
||
while (big)
|
||
{
|
||
if (big & 1)
|
||
++num_bits;
|
||
|
||
big >>= 1;
|
||
}
|
||
|
||
return num_bits;
|
||
}
|
||
|
||
#endif /* NeedPortPopcount. */
|