13464ebd5Sriastradh/**************************************************************************
23464ebd5Sriastradh *
3af69d88dSmrg * Copyright 2008 VMware, Inc.
43464ebd5Sriastradh * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
53464ebd5Sriastradh * Copyright 2010-2011 LunarG, Inc.
63464ebd5Sriastradh * All Rights Reserved.
73464ebd5Sriastradh *
83464ebd5Sriastradh * Permission is hereby granted, free of charge, to any person obtaining a
93464ebd5Sriastradh * copy of this software and associated documentation files (the
103464ebd5Sriastradh * "Software"), to deal in the Software without restriction, including
113464ebd5Sriastradh * without limitation the rights to use, copy, modify, merge, publish,
123464ebd5Sriastradh * distribute, sub license, and/or sell copies of the Software, and to
133464ebd5Sriastradh * permit persons to whom the Software is furnished to do so, subject to
143464ebd5Sriastradh * the following conditions:
153464ebd5Sriastradh *
163464ebd5Sriastradh * The above copyright notice and this permission notice (including the
173464ebd5Sriastradh * next paragraph) shall be included in all copies or substantial portions
183464ebd5Sriastradh * of the Software.
193464ebd5Sriastradh *
203464ebd5Sriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
213464ebd5Sriastradh * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
223464ebd5Sriastradh * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
233464ebd5Sriastradh * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
243464ebd5Sriastradh * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
253464ebd5Sriastradh * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
263464ebd5Sriastradh * DEALINGS IN THE SOFTWARE.
273464ebd5Sriastradh *
283464ebd5Sriastradh **************************************************************************/
293464ebd5Sriastradh
303464ebd5Sriastradh
314a49301eSmrg#include <stdlib.h>
327e995a2eSmrg#include <stdio.h>
337e995a2eSmrg#include <string.h>
344a49301eSmrg#include <assert.h>
357e995a2eSmrg#include "c11/threads.h"
367e995a2eSmrg
374a49301eSmrg#include "eglglobals.h"
387e995a2eSmrg#include "egldevice.h"
39cdc920a0Smrg#include "egldisplay.h"
407e995a2eSmrg
41d8407755Smaya#include "util/macros.h"
421463c08dSmrg#include "util/os_misc.h"
43d8407755Smaya
447e995a2eSmrg#ifdef HAVE_MINCORE
457e995a2eSmrg#include <unistd.h>
467e995a2eSmrg#include <sys/mman.h>
477e995a2eSmrg#endif
484a49301eSmrg
494a49301eSmrg
507e995a2eSmrgstatic mtx_t _eglGlobalMutex = _MTX_INITIALIZER_NP;
51af69d88dSmrg
524a49301eSmrgstruct _egl_global _eglGlobal =
534a49301eSmrg{
547e995a2eSmrg   .Mutex = &_eglGlobalMutex,
557e995a2eSmrg   .DisplayList = NULL,
567e995a2eSmrg   .DeviceList = &_eglSoftwareDevice,
571463c08dSmrg   .NumAtExitCalls = 2,
587e995a2eSmrg   .AtExitCalls = {
594a49301eSmrg      /* default AtExitCalls, called in reverse order */
607e995a2eSmrg      _eglFiniDevice, /* always called last */
617e995a2eSmrg      _eglFiniDisplay,
62af69d88dSmrg   },
63af69d88dSmrg
641463c08dSmrg#if USE_LIBGLVND
657e995a2eSmrg   .ClientOnlyExtensionString =
661463c08dSmrg#else
671463c08dSmrg   .ClientExtensionString =
681463c08dSmrg#endif
69af69d88dSmrg   "EGL_EXT_client_extensions"
707e995a2eSmrg   " EGL_EXT_device_base"
717e995a2eSmrg   " EGL_EXT_device_enumeration"
727e995a2eSmrg   " EGL_EXT_device_query"
73af69d88dSmrg   " EGL_EXT_platform_base"
747e995a2eSmrg   " EGL_KHR_client_get_all_proc_addresses"
751463c08dSmrg   " EGL_KHR_debug"
767e995a2eSmrg
771463c08dSmrg#if USE_LIBGLVND
781463c08dSmrg   ,
797e995a2eSmrg   .PlatformExtensionString =
801463c08dSmrg#else
811463c08dSmrg   " "
821463c08dSmrg#endif
831463c08dSmrg
841463c08dSmrg   "EGL_EXT_platform_device"
857e995a2eSmrg#ifdef HAVE_WAYLAND_PLATFORM
86af69d88dSmrg   " EGL_EXT_platform_wayland"
871463c08dSmrg   " EGL_KHR_platform_wayland"
887e995a2eSmrg#endif
897e995a2eSmrg#ifdef HAVE_X11_PLATFORM
907e995a2eSmrg   " EGL_EXT_platform_x11"
911463c08dSmrg   " EGL_KHR_platform_x11"
921463c08dSmrg#endif
931463c08dSmrg#ifdef HAVE_XCB_PLATFORM
941463c08dSmrg   " EGL_MESA_platform_xcb"
957e995a2eSmrg#endif
967e995a2eSmrg#ifdef HAVE_DRM_PLATFORM
97af69d88dSmrg   " EGL_MESA_platform_gbm"
981463c08dSmrg   " EGL_KHR_platform_gbm"
997e995a2eSmrg#endif
1007e995a2eSmrg   " EGL_MESA_platform_surfaceless"
1017e995a2eSmrg   "",
1027e995a2eSmrg
1037e995a2eSmrg   .debugCallback = NULL,
1047e995a2eSmrg   .debugTypesEnabled = _EGL_DEBUG_BIT_CRITICAL | _EGL_DEBUG_BIT_ERROR,
1054a49301eSmrg};
1064a49301eSmrg
107d63b28c1Smartinstatic EGLBoolean registered = EGL_FALSE;
1084a49301eSmrg
109d63b28c1Smartinstatic void __attribute__((__destructor__))
1104a49301eSmrg_eglAtExit(void)
1114a49301eSmrg{
1124a49301eSmrg   EGLint i;
113d63b28c1Smartin
114d63b28c1Smartin   if (!registered)
1157e995a2eSmrg      return;
116d63b28c1Smartin
1174a49301eSmrg   for (i = _eglGlobal.NumAtExitCalls - 1; i >= 0; i--)
1184a49301eSmrg      _eglGlobal.AtExitCalls[i]();
1194a49301eSmrg}
1204a49301eSmrg
1214a49301eSmrg
1224a49301eSmrgvoid
1234a49301eSmrg_eglAddAtExitCall(void (*func)(void))
1244a49301eSmrg{
1254a49301eSmrg   if (func) {
1267e995a2eSmrg      static EGLBoolean registered = EGL_FALSE;
1274a49301eSmrg
1287e995a2eSmrg      mtx_lock(_eglGlobal.Mutex);
1294a49301eSmrg
130d63b28c1Smartin      registered = EGL_TRUE;
1314a49301eSmrg
1324a49301eSmrg      assert(_eglGlobal.NumAtExitCalls < ARRAY_SIZE(_eglGlobal.AtExitCalls));
1334a49301eSmrg      _eglGlobal.AtExitCalls[_eglGlobal.NumAtExitCalls++] = func;
1344a49301eSmrg
1357e995a2eSmrg      mtx_unlock(_eglGlobal.Mutex);
1367e995a2eSmrg   }
1377e995a2eSmrg}
1387e995a2eSmrg
1397e995a2eSmrgEGLBoolean
1407e995a2eSmrg_eglPointerIsDereferencable(void *p)
1417e995a2eSmrg{
1427e995a2eSmrg   uintptr_t addr = (uintptr_t) p;
1431463c08dSmrg   uint64_t page_size = 0;
1441463c08dSmrg   os_get_page_size(&page_size);
1451463c08dSmrg#ifdef HAVE_MINCORE
1461463c08dSmrg   unsigned char valid = 0;
1477e995a2eSmrg
1487e995a2eSmrg   if (p == NULL)
1497e995a2eSmrg      return EGL_FALSE;
1507e995a2eSmrg
1517e995a2eSmrg   /* align addr to page_size */
1527e995a2eSmrg   addr &= ~(page_size - 1);
1537e995a2eSmrg
1541463c08dSmrg   /* mincore expects &valid to be unsigned char* on Linux but char* on BSD:
1551463c08dSmrg    * we cast pointers to void, to fix type mismatch warnings in all systems
1561463c08dSmrg    */
1571463c08dSmrg   if (mincore((void *) addr, page_size, (void*)&valid) < 0) {
1587e995a2eSmrg      return EGL_FALSE;
1597e995a2eSmrg   }
1607e995a2eSmrg
1617e995a2eSmrg   /* mincore() returns 0 on success, and -1 on failure.  The last parameter
1627e995a2eSmrg    * is a vector of bytes with one entry for each page queried.  mincore
1637e995a2eSmrg    * returns page residency information in the first bit of each byte in the
1647e995a2eSmrg    * vector.
1657e995a2eSmrg    *
1667e995a2eSmrg    * Residency doesn't actually matter when determining whether a pointer is
1677e995a2eSmrg    * dereferenceable, so the output vector can be ignored.  What matters is
1687e995a2eSmrg    * whether mincore succeeds. See:
1697e995a2eSmrg    *
1707e995a2eSmrg    *   http://man7.org/linux/man-pages/man2/mincore.2.html
1717e995a2eSmrg    */
1727e995a2eSmrg   return EGL_TRUE;
1737e995a2eSmrg#else
1741463c08dSmrg   // Without mincore(), we just assume that the first page is unmapped.
1751463c08dSmrg   return addr >= page_size;
1767e995a2eSmrg#endif
1774a49301eSmrg}
178