diff --git a/miext/sync/misyncshm.c b/miext/sync/misyncshm.c index f48533dd1..e74ded7e9 100644 --- a/miext/sync/misyncshm.c +++ b/miext/sync/misyncshm.c @@ -27,8 +27,10 @@ #include #include +#include "os/busfault.h" #include "os/osdep.h" +#include "os.h" #include "scrnintstr.h" #include "misync_priv.h" #include "misyncstr.h" @@ -41,18 +43,106 @@ static DevPrivateKeyRec syncShmFencePrivateKey; typedef struct _SyncShmFencePrivate { struct xshmfence *fence; int fd; +#ifdef BUSFAULT + struct busfault *busfault; +#endif } SyncShmFencePrivateRec, *SyncShmFencePrivatePtr; #define SYNC_FENCE_PRIV(pFence) \ (SyncShmFencePrivatePtr) dixLookupPrivate(&(pFence)->devPrivates, &syncShmFencePrivateKey) +#ifdef BUSFAULT + +#include + +#define SYNC_SHM_FENCE_ACCESS(pFence, pPriv, call) \ + do { \ + if ((pPriv)->fence && (pPriv)->busfault) { \ + sigjmp_buf jmp; \ + if (sigsetjmp(jmp, 1) == 0) { \ + busfault_set_jmp((pPriv)->busfault, &jmp); \ + call; \ + busfault_set_jmp((pPriv)->busfault, NULL); \ + } else { \ + ErrorF("shared memory fence 0x%x truncated by client\n",\ + (unsigned int) (pFence)->sync.id); \ + miSyncShmFenceDiscard(pFence); \ + } \ + } else if ((pPriv)->fence) { \ + call; \ + } \ + } while (0) + + +/* Cover the full mmap VMA; xshmfence maps a small object which the + * kernel rounds up to a page. */ +static unsigned int pagesize; + +static void +initPageSize(void) +{ + if (!pagesize) { +#ifdef _SC_PAGESIZE + pagesize = sysconf(_SC_PAGESIZE); +#else + pagesize = getpagesize(); +#endif + } +} + +static void +miSyncShmFenceDiscard(SyncFence *pFence) +{ + SyncShmFencePrivatePtr pPriv = SYNC_FENCE_PRIV(pFence); + + if (pPriv->busfault) { + busfault_unregister(pPriv->busfault); + pPriv->busfault = NULL; + } + if (pPriv->fence) { + xshmfence_unmap_shm(pPriv->fence); + pPriv->fence = NULL; + close(pPriv->fd); + } +} + +static void +miSyncShmFenceBusfaultNotify(void *context) +{ + SyncFence *pFence = context; + + ErrorF("shared memory fence 0x%x truncated by client\n", + (unsigned int) pFence->sync.id); + /* Drop the mapping; the fence XID remains and further ops use + * the in-server SyncFence state only. */ + miSyncShmFenceDiscard(pFence); +} + +static void +miSyncShmFenceRegisterBusfault(SyncFence *pFence) +{ + SyncShmFencePrivatePtr pPriv = SYNC_FENCE_PRIV(pFence); + + pPriv->busfault = busfault_register_mmap(pPriv->fence, pagesize, + miSyncShmFenceBusfaultNotify, + pFence); + if (!pPriv->busfault) + ErrorF("shared memory fence 0x%x could not register for truncation detection\n", + (unsigned int) pFence->sync.id); +} +#endif /* BUSFAULT */ + static void miSyncShmFenceSetTriggered(SyncFence * pFence) { SyncShmFencePrivatePtr pPriv = SYNC_FENCE_PRIV(pFence); +#ifdef BUSFAULT + SYNC_SHM_FENCE_ACCESS(pFence, pPriv, xshmfence_trigger(pPriv->fence)); +#else if (pPriv->fence) xshmfence_trigger(pPriv->fence); +#endif miSyncFenceSetTriggered(pFence); } @@ -61,8 +151,12 @@ miSyncShmFenceReset(SyncFence * pFence) { SyncShmFencePrivatePtr pPriv = SYNC_FENCE_PRIV(pFence); +#ifdef BUSFAULT + SYNC_SHM_FENCE_ACCESS(pFence, pPriv, xshmfence_reset(pPriv->fence)); +#else if (pPriv->fence) xshmfence_reset(pPriv->fence); +#endif miSyncFenceReset(pFence); } @@ -71,6 +165,24 @@ miSyncShmFenceCheckTriggered(SyncFence * pFence) { SyncShmFencePrivatePtr pPriv = SYNC_FENCE_PRIV(pFence); +#ifdef BUSFAULT + if (pPriv->fence && pPriv->busfault) { + sigjmp_buf jmp; + if (sigsetjmp(jmp, 1) == 0) { + Bool result; + + busfault_set_jmp(pPriv->busfault, &jmp); + result = xshmfence_query(pPriv->fence); + busfault_set_jmp(pPriv->busfault, NULL); + return result; + } else { + ErrorF("shared memory fence 0x%x truncated by client\n", + (unsigned int) pFence->sync.id); + miSyncShmFenceDiscard(pFence); + return miSyncFenceCheckTriggered(pFence); + } + } +#endif if (pPriv->fence) return xshmfence_query(pPriv->fence); else @@ -114,9 +226,15 @@ miSyncShmScreenDestroyFence(ScreenPtr pScreen, SyncFence * pFence) SyncShmFencePrivatePtr pPriv = SYNC_FENCE_PRIV(pFence); if (pPriv->fence) { +#ifdef BUSFAULT + /* Wake waiters if possible; SIGBUS discards via longjmp. */ + SYNC_SHM_FENCE_ACCESS(pFence, pPriv, xshmfence_trigger(pPriv->fence)); + miSyncShmFenceDiscard(pFence); +#else xshmfence_trigger(pPriv->fence); xshmfence_unmap_shm(pPriv->fence); close(pPriv->fd); +#endif } miSyncScreenDestroyFence(pScreen, pFence); } @@ -131,6 +249,9 @@ miSyncShmCreateFenceFromFd(ScreenPtr pScreen, SyncFence *pFence, int fd, Bool in fd = os_move_fd(fd); pPriv->fence = xshmfence_map_shm(fd); if (pPriv->fence) { +#ifdef BUSFAULT + miSyncShmFenceRegisterBusfault(pFence); +#endif pPriv->fd = fd; return Success; } @@ -154,6 +275,9 @@ miSyncShmGetFenceFd(ScreenPtr pScreen, SyncFence *pFence) close (pPriv->fd); return -1; } +#ifdef BUSFAULT + miSyncShmFenceRegisterBusfault(pFence); +#endif } return pPriv->fd; } @@ -177,6 +301,10 @@ Bool miSyncShmScreenInit(ScreenPtr pScreen) return FALSE; } +#ifdef BUSFAULT + initPageSize(); +#endif + funcs = miSyncGetScreenFuncs(pScreen); funcs->CreateFence = miSyncShmScreenCreateFence;