1 // Copyright 2013 Intel Corporation. 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.
5 #include "ozone/wayland/display_poll_thread.h"
10 #include <sys/socket.h>
11 #include <sys/types.h>
12 #include <wayland-client.h>
14 #include "base/bind.h"
15 #include "ozone/wayland/display.h"
17 namespace ozonewayland {
18 const int MAX_EVENTS = 16;
21 int osEpollCreateCloExec(void);
23 static int setCloExecOrClose(int fd) {
29 flags = fcntl(fd, F_GETFD);
33 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
43 int osEpollCreateCloExec(void) {
47 fd = epoll_create1(EPOLL_CLOEXEC);
55 return setCloExecOrClose(fd);
59 WaylandDisplayPollThread::WaylandDisplayPollThread(wl_display* display)
60 : base::Thread("WaylandDisplayPollThread"),
62 polling_(true, false),
63 stop_polling_(true, false) {
67 WaylandDisplayPollThread::~WaylandDisplayPollThread() {
68 StopProcessingEvents();
71 void WaylandDisplayPollThread::StartProcessingEvents() {
72 DCHECK(!polling_.IsSignaled());
73 base::Thread::Options options;
74 options.message_loop_type = base::MessageLoop::TYPE_IO;
75 StartWithOptions(options);
76 SetPriority(base::kThreadPriority_Background);
77 message_loop_proxy()->PostTask(FROM_HERE, base::Bind(
78 &WaylandDisplayPollThread::DisplayRun, this));
81 void WaylandDisplayPollThread::StopProcessingEvents() {
82 if (polling_.IsSignaled())
83 stop_polling_.Signal();
88 void WaylandDisplayPollThread::CleanUp() {
89 SetThreadWasQuitProperly(true);
92 void WaylandDisplayPollThread::DisplayRun(WaylandDisplayPollThread* data) {
93 struct epoll_event ep[MAX_EVENTS];
94 int i, ret, count = 0;
96 bool epoll_err = false;
97 unsigned display_fd = wl_display_get_fd(data->display_);
98 int epoll_fd = osEpollCreateCloExec();
100 LOG(ERROR) << "Epoll creation failed.";
104 ep[0].events = EPOLLIN;
106 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, display_fd, &ep[0]) < 0) {
108 LOG(ERROR) << "epoll_ctl Add failed";
112 // Set the signal state. This is used to query from other threads (i.e.
113 // StopProcessingEvents on Main thread), if this thread is still polling.
114 data->polling_.Signal();
117 // http://cgit.freedesktop.org/wayland/weston/tree/clients/window.c#n5531.
119 wl_display_dispatch_pending(data->display_);
120 ret = wl_display_flush(data->display_);
121 if (ret < 0 && errno == EAGAIN) {
122 ep[0].events = EPOLLIN | EPOLLERR | EPOLLHUP;
123 epoll_ctl(epoll_fd, EPOLL_CTL_MOD, display_fd, &ep[0]);
124 } else if (ret < 0) {
128 // StopProcessingEvents has been called or we have been asked to stop
129 // polling. Break from the loop.
130 if (data->stop_polling_.IsSignaled())
133 count = epoll_wait(epoll_fd, ep, MAX_EVENTS, -1);
134 // Break if epoll wait returned value less than 0 and we aren't interrupted
136 if (count < 0 && errno != EINTR) {
137 LOG(ERROR) << "epoll_wait returned an error." << errno;
142 for (i = 0; i < count; i++) {
143 event = ep[i].events;
144 // We can have cases where EPOLLIN and EPOLLHUP are both set for
145 // example. Don't break if both flags are set.
146 if ((event & EPOLLERR || event & EPOLLHUP) &&
147 !(event & EPOLLIN)) {
152 if (event & EPOLLIN) {
153 ret = wl_display_dispatch(data->display_);
155 LOG(ERROR) << "wl_display_dispatch failed with an error." << errno;
167 data->polling_.Reset();
168 data->stop_polling_.Reset();
171 } // namespace ozonewayland