/* * Copyright © 2025 Collabora, Ltd. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #include "x11_display.h" #include "util/macros.h" #include "util/log.h" #include #include #ifdef HAVE_SYS_SHM_H #include #include #endif bool x11_xlib_display_is_thread_safe(Display *dpy) { static bool warned = false; /* 'lock_fns' is the XLockDisplay function pointer of the X11 display 'dpy'. * It will be NULL if XInitThreads wasn't called. */ if (likely(dpy->lock_fns != NULL)) return true; if (unlikely(!warned)) { fprintf(stderr, "Xlib is not thread-safe. This should never be the " "case starting with XLib 1.8. Either upgrade XLib " "or call XInitThreads() from your app.\n"); warned = true; } return false; } #ifdef HAVE_SYS_SHM_H bool x11_xcb_display_supports_xshm(xcb_connection_t *con) { xcb_generic_error_t *error; xcb_query_extension_cookie_t shm_cookie; xcb_query_extension_reply_t *shm_reply; bool has_mit_shm; int shmid; void *shm_addr = (void *) -1; xcb_shm_seg_t shm_seg; bool ret = true; shm_cookie = xcb_query_extension(con, 7, "MIT-SHM"); shm_reply = xcb_query_extension_reply(con, shm_cookie, NULL); has_mit_shm = shm_reply && shm_reply->present; free(shm_reply); if (!has_mit_shm) return false; /* Check if we're a remote client by attempting to detach segment 0. * Remote clients will get BadRequest, local clients get BadValue, * since 'info' has an invalid segment name. */ if ((error = xcb_request_check(con, xcb_shm_detach_checked(con, 0)))) { bool is_remote = error->error_code == BadRequest; free(error); if (is_remote) return false; } /* We're a local client. Now verify we can actually attach SHM. * In some container setups, the X server reports MIT-SHM support * but the client lacks permission to attach shared memory. */ shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0600); if (shmid < 0) { mesa_logd("shared memory allocation error: %s", strerror(errno)); return false; } shm_addr = shmat(shmid, NULL, 0); if (shm_addr == (void *) -1) { mesa_logd("shmat failed: %s", strerror(errno)); ret = false; goto check_xshm_cleanup; } shm_seg = xcb_generate_id(con); error = xcb_request_check(con, xcb_shm_attach_checked(con, shm_seg, shmid, 0)); if (error) { mesa_logd("Failed to attach to x11 shm with error: %u", error->error_code); free(error); ret = false; goto check_xshm_cleanup; } /* Only detach if it was attached successfully */ xcb_shm_detach(con, shm_seg); check_xshm_cleanup: if (shm_addr != (void *) -1) shmdt(shm_addr); shmctl(shmid, IPC_RMID, NULL); return ret; } #endif