toolkit/xre/glxtest.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     2  * vim: sw=2 ts=8 et :
     3  */
     4 /* This Source Code Form is subject to the terms of the Mozilla Public
     5  * License, v. 2.0. If a copy of the MPL was not distributed with this
     6  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     9 //////////////////////////////////////////////////////////////////////////////
    10 //
    11 // Explanation: See bug 639842. Safely getting GL driver info on X11 is hard, because the only way to do
    12 // that is to create a GL context and call glGetString(), but with bad drivers,
    13 // just creating a GL context may crash.
    14 //
    15 // This file implements the idea to do that in a separate process.
    16 //
    17 // The only non-static function here is fire_glxtest_process(). It creates a pipe, publishes its 'read' end as the
    18 // mozilla::widget::glxtest_pipe global variable, forks, and runs that GLX probe in the child process,
    19 // which runs the glxtest() static function. This creates a X connection, a GLX context, calls glGetString, and writes that
    20 // to the 'write' end of the pipe.
    22 #include <cstdio>
    23 #include <cstdlib>
    24 #include <unistd.h>
    25 #include <dlfcn.h>
    26 #include "nscore.h"
    27 #include <fcntl.h>
    28 #include "stdint.h"
    30 #ifdef __SUNPRO_CC
    31 #include <stdio.h>
    32 #endif
    34 #include "X11/Xlib.h"
    35 #include "X11/Xutil.h"
    37 // stuff from glx.h
    38 typedef struct __GLXcontextRec *GLXContext;
    39 typedef XID GLXPixmap;
    40 typedef XID GLXDrawable;
    41 /* GLX 1.3 and later */
    42 typedef struct __GLXFBConfigRec *GLXFBConfig;
    43 typedef XID GLXFBConfigID;
    44 typedef XID GLXContextID;
    45 typedef XID GLXWindow;
    46 typedef XID GLXPbuffer;
    47 #define GLX_RGBA        4
    48 #define GLX_RED_SIZE    8
    49 #define GLX_GREEN_SIZE  9
    50 #define GLX_BLUE_SIZE   10
    52 // stuff from gl.h
    53 typedef uint8_t GLubyte;
    54 typedef uint32_t GLenum;
    55 #define GL_VENDOR       0x1F00
    56 #define GL_RENDERER     0x1F01
    57 #define GL_VERSION      0x1F02
    59 namespace mozilla {
    60 namespace widget {
    61 // the read end of the pipe, which will be used by GfxInfo
    62 extern int glxtest_pipe;
    63 // the PID of the glxtest process, to pass to waitpid()
    64 extern pid_t glxtest_pid;
    65 }
    66 }
    68 // the write end of the pipe, which we're going to write to
    69 static int write_end_of_the_pipe = -1;
    71 // C++ standard collides with C standard in that it doesn't allow casting void* to function pointer types.
    72 // So the work-around is to convert first to size_t.
    73 // http://www.trilithium.com/johan/2004/12/problem-with-dlsym/
    74 template<typename func_ptr_type>
    75 static func_ptr_type cast(void *ptr)
    76 {
    77   return reinterpret_cast<func_ptr_type>(
    78            reinterpret_cast<size_t>(ptr)
    79          );
    80 }
    82 static void fatal_error(const char *str)
    83 {
    84   write(write_end_of_the_pipe, str, strlen(str));
    85   write(write_end_of_the_pipe, "\n", 1);
    86   _exit(EXIT_FAILURE);
    87 }
    89 static int
    90 x_error_handler(Display *, XErrorEvent *ev)
    91 {
    92   enum { bufsize = 1024 };
    93   char buf[bufsize];
    94   int length = snprintf(buf, bufsize,
    95                         "X error occurred in GLX probe, error_code=%d, request_code=%d, minor_code=%d\n",
    96                         ev->error_code,
    97                         ev->request_code,
    98                         ev->minor_code);
    99   write(write_end_of_the_pipe, buf, length);
   100   _exit(EXIT_FAILURE);
   101   return 0;
   102 }
   105 // glxtest is declared inside extern "C" so that the name is not mangled.
   106 // The name is used in build/valgrind/x86_64-redhat-linux-gnu.sup to suppress
   107 // memory leak errors because we run it inside a short lived fork and we don't
   108 // care about leaking memory
   109 extern "C" {
   111 void glxtest()
   112 {
   113   // we want to redirect to /dev/null stdout, stderr, and while we're at it,
   114   // any PR logging file descriptors. To that effect, we redirect all positive
   115   // file descriptors up to what open() returns here. In particular, 1 is stdout and 2 is stderr.
   116   int fd = open("/dev/null", O_WRONLY);
   117   for (int i = 1; i < fd; i++)
   118     dup2(fd, i);
   119   close(fd);
   121   if (getenv("MOZ_AVOID_OPENGL_ALTOGETHER"))
   122     fatal_error("The MOZ_AVOID_OPENGL_ALTOGETHER environment variable is defined");
   124   ///// Open libGL and load needed symbols /////
   125 #ifdef __OpenBSD__
   126   #define LIBGL_FILENAME "libGL.so"
   127 #else
   128   #define LIBGL_FILENAME "libGL.so.1"
   129 #endif
   130   void *libgl = dlopen(LIBGL_FILENAME, RTLD_LAZY);
   131   if (!libgl)
   132     fatal_error("Unable to load " LIBGL_FILENAME);
   134   typedef void* (* PFNGLXGETPROCADDRESS) (const char *);
   135   PFNGLXGETPROCADDRESS glXGetProcAddress = cast<PFNGLXGETPROCADDRESS>(dlsym(libgl, "glXGetProcAddress"));
   137   if (!glXGetProcAddress)
   138     fatal_error("Unable to find glXGetProcAddress in " LIBGL_FILENAME);
   140   typedef GLXFBConfig* (* PFNGLXQUERYEXTENSION) (Display *, int *, int *);
   141   PFNGLXQUERYEXTENSION glXQueryExtension = cast<PFNGLXQUERYEXTENSION>(glXGetProcAddress("glXQueryExtension"));
   143   typedef GLXFBConfig* (* PFNGLXQUERYVERSION) (Display *, int *, int *);
   144   PFNGLXQUERYVERSION glXQueryVersion = cast<PFNGLXQUERYVERSION>(dlsym(libgl, "glXQueryVersion"));
   146   typedef XVisualInfo* (* PFNGLXCHOOSEVISUAL) (Display *, int, int *);
   147   PFNGLXCHOOSEVISUAL glXChooseVisual = cast<PFNGLXCHOOSEVISUAL>(glXGetProcAddress("glXChooseVisual"));
   149   typedef GLXContext (* PFNGLXCREATECONTEXT) (Display *, XVisualInfo *, GLXContext, Bool);
   150   PFNGLXCREATECONTEXT glXCreateContext = cast<PFNGLXCREATECONTEXT>(glXGetProcAddress("glXCreateContext"));
   152   typedef Bool (* PFNGLXMAKECURRENT) (Display*, GLXDrawable, GLXContext);
   153   PFNGLXMAKECURRENT glXMakeCurrent = cast<PFNGLXMAKECURRENT>(glXGetProcAddress("glXMakeCurrent"));
   155   typedef void (* PFNGLXDESTROYCONTEXT) (Display*, GLXContext);
   156   PFNGLXDESTROYCONTEXT glXDestroyContext = cast<PFNGLXDESTROYCONTEXT>(glXGetProcAddress("glXDestroyContext"));
   158   typedef GLubyte* (* PFNGLGETSTRING) (GLenum);
   159   PFNGLGETSTRING glGetString = cast<PFNGLGETSTRING>(glXGetProcAddress("glGetString"));
   161   if (!glXQueryExtension ||
   162       !glXQueryVersion ||
   163       !glXChooseVisual ||
   164       !glXCreateContext ||
   165       !glXMakeCurrent ||
   166       !glXDestroyContext ||
   167       !glGetString)
   168   {
   169     fatal_error("glXGetProcAddress couldn't find required functions");
   170   }
   171   ///// Open a connection to the X server /////
   172   Display *dpy = XOpenDisplay(nullptr);
   173   if (!dpy)
   174     fatal_error("Unable to open a connection to the X server");
   176   ///// Check that the GLX extension is present /////
   177   if (!glXQueryExtension(dpy, nullptr, nullptr))
   178     fatal_error("GLX extension missing");
   180   XSetErrorHandler(x_error_handler);
   182   ///// Get a visual /////
   183    int attribs[] = {
   184       GLX_RGBA,
   185       GLX_RED_SIZE, 1,
   186       GLX_GREEN_SIZE, 1,
   187       GLX_BLUE_SIZE, 1,
   188       None };
   189   XVisualInfo *vInfo = glXChooseVisual(dpy, DefaultScreen(dpy), attribs);
   190   if (!vInfo)
   191     fatal_error("No visuals found");
   193   // using a X11 Window instead of a GLXPixmap does not crash
   194   // fglrx in indirect rendering. bug 680644
   195   Window window;
   196   XSetWindowAttributes swa;
   197   swa.colormap = XCreateColormap(dpy, RootWindow(dpy, vInfo->screen),
   198                                  vInfo->visual, AllocNone);
   200   swa.border_pixel = 0;
   201   window = XCreateWindow(dpy, RootWindow(dpy, vInfo->screen),
   202                        0, 0, 16, 16,
   203                        0, vInfo->depth, InputOutput, vInfo->visual,
   204                        CWBorderPixel | CWColormap, &swa);
   206   ///// Get a GL context and make it current //////
   207   GLXContext context = glXCreateContext(dpy, vInfo, nullptr, True);
   208   glXMakeCurrent(dpy, window, context);
   210   ///// Look for this symbol to determine texture_from_pixmap support /////
   211   void* glXBindTexImageEXT = glXGetProcAddress("glXBindTexImageEXT"); 
   213   ///// Get GL vendor/renderer/versions strings /////
   214   enum { bufsize = 1024 };
   215   char buf[bufsize];
   216   const GLubyte *vendorString = glGetString(GL_VENDOR);
   217   const GLubyte *rendererString = glGetString(GL_RENDERER);
   218   const GLubyte *versionString = glGetString(GL_VERSION);
   220   if (!vendorString || !rendererString || !versionString)
   221     fatal_error("glGetString returned null");
   223   int length = snprintf(buf, bufsize,
   224                         "VENDOR\n%s\nRENDERER\n%s\nVERSION\n%s\nTFP\n%s\n",
   225                         vendorString,
   226                         rendererString,
   227                         versionString,
   228                         glXBindTexImageEXT ? "TRUE" : "FALSE");
   229   if (length >= bufsize)
   230     fatal_error("GL strings length too large for buffer size");
   232   ///// Clean up. Indeed, the parent process might fail to kill us (e.g. if it doesn't need to check GL info)
   233   ///// so we might be staying alive for longer than expected, so it's important to consume as little memory as
   234   ///// possible. Also we want to check that we're able to do that too without generating X errors.
   235   glXMakeCurrent(dpy, None, nullptr); // must release the GL context before destroying it
   236   glXDestroyContext(dpy, context);
   237   XDestroyWindow(dpy, window);
   238   XFreeColormap(dpy, swa.colormap);
   240 #ifdef NS_FREE_PERMANENT_DATA // conditionally defined in nscore.h, don't forget to #include it above
   241   XCloseDisplay(dpy);
   242 #else
   243   // This XSync call wanted to be instead:
   244   //   XCloseDisplay(dpy);
   245   // but this can cause 1-minute stalls on certain setups using Nouveau, see bug 973192
   246   XSync(dpy, False);
   247 #endif
   249   dlclose(libgl);
   251   ///// Finally write data to the pipe
   252   write(write_end_of_the_pipe, buf, length);
   253 }
   255 }
   257 /** \returns true in the child glxtest process, false in the parent process */
   258 bool fire_glxtest_process()
   259 {
   260   int pfd[2];
   261   if (pipe(pfd) == -1) {
   262       perror("pipe");
   263       return false;
   264   }
   265   pid_t pid = fork();
   266   if (pid < 0) {
   267       perror("fork");
   268       close(pfd[0]);
   269       close(pfd[1]);
   270       return false;
   271   }
   272   // The child exits early to avoid running the full shutdown sequence and avoid conflicting with threads 
   273   // we have already spawned (like the profiler).
   274   if (pid == 0) {
   275       close(pfd[0]);
   276       write_end_of_the_pipe = pfd[1];
   277       glxtest();
   278       close(pfd[1]);
   279       _exit(0);
   280   }
   282   close(pfd[1]);
   283   mozilla::widget::glxtest_pipe = pfd[0];
   284   mozilla::widget::glxtest_pid = pid;
   285   return false;
   286 }

mercurial