1#include <dirent.h>
2#include <dlfcn.h>
3#include <stdio.h>
4#include <vdpau/vdpau.h>
5#include <vdpau/vdpau_x11.h>
6#include <X11/Xlib.h>
7
8#define PASS 0
9#define FAIL 1
10#define SKIP 77
11
12static int countOpenFDs(void)
13{
14    DIR *dir = opendir("/proc/self/fd");
15    int count = 0;
16
17    if (!dir) {
18        fprintf(stderr, "Couldn't open /proc/self/fd; skipping file descriptor "
19                "leak test\n");
20        return 0;
21    }
22
23    while (readdir(dir) != NULL) {
24        count++;
25    }
26
27    closedir(dir);
28    return count;
29}
30
31int main(void)
32{
33    // Work around a bug in libXext: dlclosing it after it has registered the
34    // Generic Event Extension causes an identical bug to the one this program
35    // is trying to test for.
36    int nOpenFDs = countOpenFDs();
37    void *libXext = dlopen("libXext.so.6", RTLD_LAZY);
38    void *libvdpau = dlopen("../src/.libs/libvdpau.so", RTLD_LAZY);
39    Display *dpy = XOpenDisplay(NULL);
40    VdpDeviceCreateX11 *pvdp_device_create_x11;
41    VdpDevice device;
42    VdpGetProcAddress *get_proc_address;
43    VdpStatus status;
44
45    if (!libXext) {
46        fprintf(stderr, "Failed to open libXext.so.6: %s", dlerror());
47        return SKIP;
48    }
49
50    if (!libvdpau) {
51        fprintf(stderr, "Failed to open libvdpau.so: %s", dlerror());
52        return FAIL;
53    }
54
55    if (!dpy) {
56        fprintf(stderr, "Failed to connect to X display %s\n", XDisplayName(NULL));
57        return SKIP;
58    }
59
60    pvdp_device_create_x11 = dlsym(libvdpau, "vdp_device_create_x11");
61    if (!pvdp_device_create_x11) {
62        fprintf(stderr, "Failed to find the symbol vdp_device_create_x11\n");
63        return FAIL;
64    }
65
66    status = pvdp_device_create_x11(dpy, 0, &device, &get_proc_address);
67    if (status == VDP_STATUS_OK) {
68        // It's okay if creating the device fails.  This will still install the
69        // DRI2 extension in libX11 and trigger the bug.
70        VdpDeviceDestroy *pvdp_device_destroy;
71
72        status = get_proc_address(device, VDP_FUNC_ID_DEVICE_DESTROY, (void**)&pvdp_device_destroy);
73        if (status != VDP_STATUS_OK) {
74            fprintf(stderr, "Failed to find the VdpDeviceDestroy function: %d\n", status);
75            return FAIL;
76        }
77
78        pvdp_device_destroy(device);
79    }
80
81    dlclose(libvdpau);
82    XCloseDisplay(dpy);
83
84    // Make sure no file descriptors were leaked.
85    if (countOpenFDs() != nOpenFDs) {
86        fprintf(stderr, "Mismatch in the number of open file descriptors!\n");
87        return FAIL;
88    }
89
90    return PASS;
91}
92