Skip to content

Commit 3e53341

Browse files
committed
Delay connecting with gui-daemon until after starting Xorg
Until now, Xorg was started only after connecting with gui-daemon and receiving xconf message. This was mostly because initial resolution/video mem specified in the xorg.conf couldn't later be changed and that affects maximum working resolution. Since 49420c5 "Increase screen pixmap size beyond initial video RAM if needed", this is no longer a problem. The only parameter (still) needed before starting Xorg is GUI domain id, but this is available on the command line. Change gui-agent to start Xorg earlier and only then wait for gui-daemon. This allows starting all of the user session earlier, optimizing startup time. This is especially relevant for VMs started on boot (before user logs in), when GUI daemon isn't started yet. And also helpful for preloaded disposables, which may start user session as part of preloading now. The current implementation is rather naive: it starts Xorg with hardcoded 1920x1080 resolution (which will later be updated by the qubes.SetMonitorLayout qrexec call), selects which events it want to receive and then waits for the GUI daemon. Especially, no events are actually processed before GUI daemon connects. This assumes all events will be queued and can be processed after GUI daemon connection. Very similar approach is already taken on GUI daemon re-connection, and it works. This makes the msg_xconf sent by the gui-daemon completely ignored. There is a potential issue, if too many events get queued before GUI daemon connects and some get dropped. It's unclear how Xlib handles that (and what is the limit), but if that happens there are two alternative solutions: 1. Start processing events normally, especially collect info about all relevant windows, but dont send anything to GUI daemon before it connects - this basically requires changing write_struct() (and other similar places) to check if GUI daemon is connected. And once GUI daemon connects (first event received on the vchan FD), call send_all_windows_info(). 2. Wait for GUI daemon before registering for events, but then iterate over all windows to collect necessary info and send it to dom0. This approach theoretically can be more reliable (and might even allow restarting gui-agent without restarting Xorg as a side effect), but it's unclear if all data can be rebuilt this way. Especially tray icons may be problematic, as it isn't any window property, but a message sent to relevant selection owner (but theoretically https://tronche.com/gui/x/icccm/sec-2.html#s-2.8 provides solution for this issue). QubesOS/qubes-issues#9940 (comment)
1 parent 31d173c commit 3e53341

File tree

2 files changed

+35
-42
lines changed

2 files changed

+35
-42
lines changed

appvm-scripts/usrbin/qubes-run-xorg

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,14 @@
2626

2727
## This script is triggered by qubes-gui-agent systemd service.
2828

29-
#expects W, H, MEM and DEPTH env vars to be set by invoker
29+
#expects W, H, MEM and DEPTH env vars to be set by invoker, but use default
30+
# values if they aren't
31+
32+
[ -n "$W" ] || W=1920
33+
[ -n "$H" ] || H=1080
34+
[ -n "$MEM" ] || MEM=$(( W * H * 4 / 1024 ))
35+
[ -n "$DEPTH" ] || DEPTH=24
36+
3037
DUMMY_MAX_CLOCK=300 #hardcoded in dummy_drv
3138
PREFERRED_HSYNC=50
3239
RES="$W"x"$H"

gui-agent/vmside.c

Lines changed: 27 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2176,23 +2176,19 @@ static void handle_close(Ghandles * g, XID winid)
21762176

21772177
/* start X server, returns its PID
21782178
*/
2179-
static pid_t do_execute_xorg(
2180-
char *w_str, char *h_str, char *mem_str, char *depth_str,
2181-
char *gui_domid_str)
2179+
static pid_t do_execute_xorg(Ghandles *g)
21822180
{
21832181
pid_t pid;
21842182
int fd;
2183+
char gui_domid_str[12];
21852184

21862185
pid = fork();
21872186
switch (pid) {
21882187
case -1:
21892188
perror("fork");
21902189
return -1;
21912190
case 0:
2192-
setenv("W", w_str, 1);
2193-
setenv("H", h_str, 1);
2194-
setenv("MEM", mem_str, 1);
2195-
setenv("DEPTH", depth_str, 1);
2191+
snprintf(gui_domid_str, sizeof(gui_domid_str), "%u", g->domid);
21962192
setenv("GUI_DOMID", gui_domid_str, 1);
21972193
/* don't leak other FDs */
21982194
for (fd = 3; fd < 256; fd++)
@@ -2374,27 +2370,11 @@ static void handle_message(Ghandles * g)
23742370
}
23752371
}
23762372

2377-
static pid_t get_xconf_and_run_x(Ghandles *g)
2378-
{
2379-
struct msg_xconf xconf;
2380-
char w_str[12], h_str[12], mem_str[12], depth_str[12], gui_domid_str[12];
2381-
pid_t x_pid;
2382-
read_struct(g->vchan, xconf);
2383-
snprintf(w_str, sizeof(w_str), "%d", xconf.w);
2384-
snprintf(h_str, sizeof(h_str), "%d", xconf.h);
2385-
snprintf(mem_str, sizeof(mem_str), "%d", xconf.mem);
2386-
snprintf(depth_str, sizeof(depth_str), "%d", xconf.depth);
2387-
snprintf(gui_domid_str, sizeof(gui_domid_str), "%u", g->domid);
2388-
x_pid = do_execute_xorg(w_str, h_str, mem_str, depth_str, gui_domid_str);
2389-
if (x_pid == (pid_t)-1) {
2390-
errx(1, "X server startup failed");
2391-
}
2392-
return x_pid;
2393-
}
2394-
23952373
static void handshake(Ghandles *g)
23962374
{
23972375
uint32_t version = PROTOCOL_VERSION;
2376+
struct msg_xconf xconf;
2377+
23982378
write_struct(g->vchan, version);
23992379
version = 0;
24002380
read_struct(g->vchan, version);
@@ -2407,12 +2387,14 @@ static void handshake(Ghandles *g)
24072387
PROTOCOL_VERSION_MAJOR, PROTOCOL_VERSION_MINOR,
24082388
major_version, minor_version);
24092389
g->protocol_version = version;
2390+
2391+
/* discard */
2392+
read_struct(g->vchan, xconf);
24102393
}
24112394

24122395
static void handle_guid_disconnect(void)
24132396
{
24142397
Ghandles *g = ghandles_for_vchan_reinitialize;
2415-
struct msg_xconf xconf;
24162398

24172399
if (!ghandles_for_vchan_reinitialize) {
24182400
fprintf(stderr, "gui-daemon disconnected before fully initialized, "
@@ -2425,8 +2407,6 @@ static void handle_guid_disconnect(void)
24252407
while (libvchan_is_open(g->vchan) == VCHAN_WAITING)
24262408
libvchan_wait(g->vchan);
24272409
handshake(g);
2428-
/* discard */
2429-
read_struct(g->vchan, xconf);
24302410
send_all_windows_info(g);
24312411
}
24322412

@@ -2580,18 +2560,8 @@ int main(int argc, char **argv)
25802560
g.clipboard_wipe =
25812561
access("/run/qubes-service/gui-agent-clipboard-wipe", F_OK) == 0;
25822562

2583-
g.vchan = libvchan_server_init(g.domid, 6000, 4096, 4096);
2584-
if (!g.vchan) {
2585-
fprintf(stderr, "vchan initialization failed\n");
2586-
exit(1);
2587-
}
2588-
/* wait for gui daemon */
2589-
while (libvchan_is_open(g.vchan) == VCHAN_WAITING)
2590-
libvchan_wait(g.vchan);
2591-
saved_argv = argv;
2592-
vchan_register_at_eof(handle_guid_disconnect);
2593-
25942563
ghandles_for_vchan_reinitialize = &g;
2564+
25952565
struct sigaction sigchld_handler = {
25962566
.sa_sigaction = handle_sigchld,
25972567
.sa_flags = SA_SIGINFO,
@@ -2607,8 +2577,10 @@ int main(int argc, char **argv)
26072577
if (sigaction(SIGTERM, &sigterm_handler, NULL))
26082578
err(1, "sigaction");
26092579

2610-
handshake(&g);
2611-
g.x_pid = get_xconf_and_run_x(&g);
2580+
g.x_pid = do_execute_xorg(&g);
2581+
if (g.x_pid == (pid_t)-1) {
2582+
errx(1, "X server startup failed");
2583+
}
26122584

26132585
mkghandles(&g);
26142586
/* Turn on Composite for all children of root window. This way X server
@@ -2677,6 +2649,20 @@ int main(int argc, char **argv)
26772649
fprintf(stderr,
26782650
"Acquired MANAGER selection for tray\n");
26792651
}
2652+
2653+
g.vchan = libvchan_server_init(g.domid, 6000, 4096, 4096);
2654+
if (!g.vchan) {
2655+
fprintf(stderr, "vchan initialization failed\n");
2656+
exit(1);
2657+
}
2658+
/* wait for gui daemon */
2659+
while (libvchan_is_open(g.vchan) == VCHAN_WAITING)
2660+
libvchan_wait(g.vchan);
2661+
saved_argv = argv;
2662+
vchan_register_at_eof(handle_guid_disconnect);
2663+
2664+
handshake(&g);
2665+
26802666
xfd = ConnectionNumber(g.display);
26812667
struct pollfd fds[] = {
26822668
{ .fd = -1, .events = POLLIN | POLLHUP, .revents = 0 },

0 commit comments

Comments
 (0)