• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2022 Red Hat, Inc.
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that copyright
7  * notice and this permission notice appear in supporting documentation, and
8  * that the name of the copyright holders not be used in advertising or
9  * publicity pertaining to distribution of the software without specific,
10  * written prior permission.  The copyright holders make no representations
11  * about the suitability of this software for any purpose.  It is provided "as
12  * is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20  * OF THIS SOFTWARE.
21  */
22 
23 #include <poll.h>
24 #include <errno.h>
25 
26 #include "loader_wayland_helper.h"
27 
28 #ifndef HAVE_WL_DISPATCH_QUEUE_TIMEOUT
29 static int
wl_display_poll(struct wl_display * display,short int events,const struct timespec * timeout)30 wl_display_poll(struct wl_display *display,
31                 short int events,
32                 const struct timespec *timeout)
33 {
34    int ret;
35    struct pollfd pfd[1];
36    struct timespec now;
37    struct timespec deadline = {0};
38    struct timespec result;
39    struct timespec *remaining_timeout = NULL;
40 
41    if (timeout) {
42       clock_gettime(CLOCK_MONOTONIC, &now);
43       timespec_add(&deadline, &now, timeout);
44    }
45 
46    pfd[0].fd = wl_display_get_fd(display);
47    pfd[0].events = events;
48    do {
49       if (timeout) {
50          clock_gettime(CLOCK_MONOTONIC, &now);
51          timespec_sub_saturate(&result, &deadline, &now);
52          remaining_timeout = &result;
53       }
54       ret = ppoll(pfd, 1, remaining_timeout, NULL);
55    } while (ret == -1 && errno == EINTR);
56 
57    return ret;
58 }
59 
60 int
wl_display_dispatch_queue_timeout(struct wl_display * display,struct wl_event_queue * queue,const struct timespec * timeout)61 wl_display_dispatch_queue_timeout(struct wl_display *display,
62                                   struct wl_event_queue *queue,
63                                   const struct timespec *timeout)
64 {
65    int ret;
66    struct timespec now;
67    struct timespec deadline = {0};
68    struct timespec result;
69    struct timespec *remaining_timeout = NULL;
70 
71    if (timeout) {
72       clock_gettime(CLOCK_MONOTONIC, &now);
73       timespec_add(&deadline, &now, timeout);
74    }
75 
76    if (wl_display_prepare_read_queue(display, queue) == -1)
77       return wl_display_dispatch_queue_pending(display, queue);
78 
79    while (true) {
80       ret = wl_display_flush(display);
81 
82       if (ret != -1 || errno != EAGAIN)
83          break;
84 
85       if (timeout) {
86          clock_gettime(CLOCK_MONOTONIC, &now);
87          timespec_sub_saturate(&result, &deadline, &now);
88          remaining_timeout = &result;
89       }
90       ret = wl_display_poll(display, POLLOUT, remaining_timeout);
91 
92       if (ret <= 0) {
93          wl_display_cancel_read(display);
94          return ret;
95       }
96    }
97 
98    /* Don't stop if flushing hits an EPIPE; continue so we can read any
99     * protocol error that may have triggered it. */
100    if (ret < 0 && errno != EPIPE) {
101       wl_display_cancel_read(display);
102       return -1;
103    }
104 
105    while (true) {
106       if (timeout) {
107          clock_gettime(CLOCK_MONOTONIC, &now);
108          timespec_sub_saturate(&result, &deadline, &now);
109          remaining_timeout = &result;
110       }
111 
112       ret = wl_display_poll(display, POLLIN, remaining_timeout);
113       if (ret <= 0) {
114          wl_display_cancel_read(display);
115          break;
116       }
117 
118       ret = wl_display_read_events(display);
119       if (ret == -1)
120          break;
121 
122       ret = wl_display_dispatch_queue_pending(display, queue);
123       if (ret != 0)
124          break;
125 
126       /* wl_display_dispatch_queue_pending can return 0 if we ended up reading
127        * from WL fd, but there was no complete event to dispatch yet.
128        * Try reading again. */
129       if (wl_display_prepare_read_queue(display, queue) == -1)
130          return wl_display_dispatch_queue_pending(display, queue);
131    }
132 
133    return ret;
134 }
135 #endif
136 
137 #ifndef HAVE_WL_CREATE_QUEUE_WITH_NAME
138 struct wl_event_queue *
wl_display_create_queue_with_name(struct wl_display * display,const char * name)139 wl_display_create_queue_with_name(struct wl_display *display, const char *name)
140 {
141    return wl_display_create_queue(display);
142 }
143 #endif
144