]> git.sur5r.net Git - i3/i3/blob - testcases/lib/StartXDummy.pm
Merge branch 'master' into next
[i3/i3] / testcases / lib / StartXDummy.pm
1 package StartXDummy;
2 # vim:ts=4:sw=4:expandtab
3
4 use strict;
5 use warnings;
6 use Exporter 'import';
7 use Time::HiRes qw(sleep);
8 use v5.10;
9
10 our @EXPORT = qw(start_xdummy);
11
12 my $x_socketpath = '/tmp/.X11-unix/X';
13
14 # reads in a whole file
15 sub slurp {
16     open(my $fh, '<', shift) or return '';
17     local $/;
18     <$fh>;
19 }
20
21 # forks an Xdummy or Xdmx process
22 sub fork_xserver {
23     my $displaynum = shift;
24     my $pid = fork();
25     die "Could not fork: $!" unless defined($pid);
26     if ($pid == 0) {
27         # Child, close stdout/stderr, then start Xdummy.
28         close STDOUT;
29         close STDERR;
30
31         exec @_;
32         exit 1;
33     }
34     push(@complete_run::CLEANUP, sub {
35         kill(15, $pid);
36         # Unlink the X11 socket, Xdmx seems to leave it there.
37         unlink($x_socketpath . $displaynum);
38     });
39
40     return $x_socketpath . $displaynum;
41 }
42
43 # Blocks until the socket paths specified in the given array reference actually
44 # exist.
45 sub wait_for_x {
46     my ($sockets_waiting) = @_;
47
48     # Wait until Xdmx actually runs. Pretty ugly solution, but as long as we
49     # can’t socket-activate X11…
50     while (1) {
51         @$sockets_waiting = grep { ! -S $_ } @$sockets_waiting;
52         last unless @$sockets_waiting;
53         sleep 0.1;
54     }
55 }
56
57 =head2 start_xdummy($parallel)
58
59 Starts C<$parallel> (or number of cores * 2 if undef) Xdummy processes (see
60 the file ./Xdummy) and returns two arrayrefs: a list of X11 display numbers to
61 the Xdummy processes and a list of PIDs of the processes.
62
63 =cut
64
65 sub start_xdummy {
66     my ($parallel, $numtests) = @_;
67
68     my @displays = ();
69     my @childpids = ();
70
71     # Yeah, I know it’s non-standard, but Perl’s POSIX module doesn’t have
72     # _SC_NPROCESSORS_CONF.
73     my $cpuinfo = slurp('/proc/cpuinfo');
74     my $num_cores = scalar grep { /model name/ } split("\n", $cpuinfo);
75     # If /proc/cpuinfo does not exist, we fall back to 2 cores.
76     $num_cores ||= 2;
77
78     # If unset, we use num_cores * 2, plus two extra xdummys to combine to a
79     # multi-monitor setup using Xdmx.
80     $parallel ||= ($num_cores * 2) + 2;
81
82     # If we are running a small number of tests, don’t over-parallelize.
83     $parallel = $numtests if $numtests < $parallel;
84
85     # Ensure we have at least 1 X-Server plus two X-Servers for multi-monitor
86     # tests.
87     $parallel = 3 if $parallel < 3;
88
89     # First get the last used display number, then increment it by one.
90     # Effectively falls back to 1 if no X server is running.
91     my ($displaynum) = map { /(\d+)$/ } reverse sort glob($x_socketpath . '*');
92     $displaynum++;
93
94     say "Starting $parallel Xdummy instances, starting at :$displaynum...";
95
96     my @sockets_waiting;
97     for (1 .. $parallel) {
98         # We use -config /dev/null to prevent Xdummy from using the system
99         # Xorg configuration. The tests should be independant from the
100         # actual system X configuration.
101         my $socket = fork_xserver($displaynum, './Xdummy', ":$displaynum",
102                 '-config', '/dev/null');
103         push(@displays, ":$displaynum");
104         push(@sockets_waiting, $socket);
105         $displaynum++;
106     }
107
108     wait_for_x(\@sockets_waiting);
109
110     # Now combine the last two displays to a multi-monitor display using Xdmx
111     my $first = pop @displays;
112     my $second = pop @displays;
113
114     # make sure this display isn’t in use yet
115     $displaynum++ while -e ($x_socketpath . $displaynum);
116     say 'starting xdmx on display :' . $displaynum;
117
118     my $multidpy = ":$displaynum";
119     my $socket = fork_xserver($displaynum, 'Xdmx', '+xinerama', '-xinput',
120             'local', '-display', $first, '-display', $second, '-ac', $multidpy);
121     wait_for_x([ $socket ]);
122
123     return \@displays, $multidpy;
124 }
125
126 1