Home | History | Annotate | Download | only in xdisplaycheck
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 //
      5 // This is a small program that tries to connect to the X server.  It
      6 // continually retries until it connects or 30 seconds pass.  If it fails
      7 // to connect to the X server or fails to find needed functiona, it returns
      8 // an error code of -1.
      9 //
     10 // This is to help verify that a useful X server is available before we start
     11 // start running tests on the build bots.
     12 
     13 #include <errno.h>
     14 #include <stdio.h>
     15 #include <string.h>
     16 #include <time.h>
     17 #include <X11/Xlib.h>
     18 
     19 #if defined(USE_AURA)
     20 #include <X11/extensions/XInput2.h>
     21 #endif
     22 
     23 void Sleep(int duration_ms) {
     24   struct timespec sleep_time, remaining;
     25 
     26   // Contains the portion of duration_ms >= 1 sec.
     27   sleep_time.tv_sec = duration_ms / 1000;
     28   duration_ms -= sleep_time.tv_sec * 1000;
     29 
     30   // Contains the portion of duration_ms < 1 sec.
     31   sleep_time.tv_nsec = duration_ms * 1000 * 1000;  // nanoseconds.
     32 
     33   while (nanosleep(&sleep_time, &remaining) == -1 && errno == EINTR)
     34     sleep_time = remaining;
     35 }
     36 
     37 class XScopedDisplay {
     38  public:
     39   XScopedDisplay() : display_(NULL) {}
     40   ~XScopedDisplay() {
     41     if (display_) XCloseDisplay(display_);
     42   }
     43 
     44   void set(Display* display) { display_ = display; }
     45   Display* display() { return display_; }
     46 
     47  private:
     48   Display* display_;
     49 };
     50 
     51 int main(int argc, char* argv[]) {
     52   XScopedDisplay scoped_display;
     53   if (argv[1] && strcmp(argv[1], "--noserver") == 0) {
     54     scoped_display.set(XOpenDisplay(NULL));
     55     if (scoped_display.display()) {
     56       fprintf(stderr, "Found unexpected connectable display %s\n",
     57               XDisplayName(NULL));
     58     }
     59     // Return success when we got an unexpected display so that the code
     60     // without the --noserver is the same, but slow, rather than inverted.
     61     return !scoped_display.display();
     62   }
     63 
     64   int kNumTries = 78;  // 78*77/2 * 10 = 30s of waiting
     65   int tries;
     66   for (tries = 0; tries < kNumTries; ++tries) {
     67     scoped_display.set(XOpenDisplay(NULL));
     68     if (scoped_display.display())
     69       break;
     70     Sleep(10 * tries);
     71   }
     72 
     73   if (!scoped_display.display()) {
     74     fprintf(stderr, "Failed to connect to %s\n", XDisplayName(NULL));
     75     return -1;
     76   }
     77 
     78   fprintf(stderr, "Connected after %d retries\n", tries);
     79 
     80 #if defined(USE_AURA)
     81   // Check for XInput2
     82   int opcode, event, err;
     83   if (!XQueryExtension(scoped_display.display(), "XInputExtension", &opcode,
     84                        &event, &err)) {
     85     fprintf(stderr,
     86         "Failed to get XInputExtension on %s.\n", XDisplayName(NULL));
     87     return -1;
     88   }
     89 
     90   int major = 2, minor = 0;
     91   if (XIQueryVersion(scoped_display.display(), &major, &minor) == BadRequest) {
     92     fprintf(stderr,
     93         "Server does not have XInput2 on %s.\n", XDisplayName(NULL));
     94     return -1;
     95   }
     96 
     97   // Ask for the list of devices. This can cause some Xvfb to crash.
     98   int count = 0;
     99   XIDeviceInfo* devices =
    100       XIQueryDevice(scoped_display.display(), XIAllDevices, &count);
    101   if (devices)
    102     XIFreeDeviceInfo(devices);
    103 
    104   fprintf(stderr,
    105       "XInput2 verified initially sane on %s.\n", XDisplayName(NULL));
    106 #endif
    107   return 0;
    108 }
    109 
    110 #if defined(LEAK_SANITIZER)
    111 // XOpenDisplay leaks memory if it takes more than one try to connect. This
    112 // causes LSan bots to fail. We don't care about memory leaks in xdisplaycheck
    113 // anyway, so just disable LSan completely.
    114 extern "C" int __lsan_is_turned_off() { return 1; }
    115 #endif
    116