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) {
65 epoll_fd_ = osEpollCreateCloExec();
67 LOG(ERROR) << "Epoll creation failed.";
70 WaylandDisplayPollThread::~WaylandDisplayPollThread() {
71 StopProcessingEvents();
74 void WaylandDisplayPollThread::StartProcessingEvents() {
75 DCHECK(!polling_.IsSignaled() && epoll_fd_);
76 base::Thread::Options options;
77 options.message_loop_type = base::MessageLoop::TYPE_IO;
78 StartWithOptions(options);
79 SetPriority(base::kThreadPriority_Background);
80 message_loop_proxy()->PostTask(FROM_HERE, base::Bind(
81 &WaylandDisplayPollThread::DisplayRun, this));
84 void WaylandDisplayPollThread::StopProcessingEvents() {
85 if (polling_.IsSignaled())
86 stop_polling_.Signal();
91 void WaylandDisplayPollThread::CleanUp() {
92 SetThreadWasQuitProperly(true);
97 void WaylandDisplayPollThread::DisplayRun(WaylandDisplayPollThread* data) {
98 struct epoll_event ep[MAX_EVENTS];
99 int i, ret, count = 0;
101 bool epoll_err = false;
102 unsigned display_fd = wl_display_get_fd(data->display_);
103 int epoll_fd = data->epoll_fd_;
104 ep[0].events = EPOLLIN;
106 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, display_fd, &ep[0]) < 0) {
109 LOG(ERROR) << "epoll_ctl Add failed";
113 // Set the signal state. This is used to query from other threads (i.e.
114 // StopProcessingEvents on Main thread), if this thread is still polling.
115 data->polling_.Signal();
118 // http://cgit.freedesktop.org/wayland/weston/tree/clients/window.c#n5531.
120 wl_display_dispatch_pending(data->display_);
121 ret = wl_display_flush(data->display_);
122 if (ret < 0 && errno == EAGAIN) {
123 ep[0].events = EPOLLIN | EPOLLERR | EPOLLHUP;
124 epoll_ctl(epoll_fd, EPOLL_CTL_MOD, display_fd, &ep[0]);
125 } else if (ret < 0) {
129 // StopProcessingEvents has been called or we have been asked to stop
130 // polling. Break from the loop.
131 if (data->stop_polling_.IsSignaled())
134 count = epoll_wait(epoll_fd, ep, MAX_EVENTS, -1);
135 // Break if epoll wait returned value less than 0 and we aren't interrupted
137 if (count < 0 && errno != EINTR) {
138 LOG(ERROR) << "epoll_wait returned an error." << errno;
143 for (i = 0; i < count; i++) {
144 event = ep[i].events;
145 // We can have cases where EPOLLIN and EPOLLHUP are both set for
146 // example. Don't break if both flags are set.
147 if ((event & EPOLLERR || event & EPOLLHUP) &&
148 !(event & EPOLLIN)) {
153 if (event & EPOLLIN) {
154 ret = wl_display_dispatch(data->display_);
156 LOG(ERROR) << "wl_display_dispatch failed with an error." << errno;
167 data->polling_.Reset();
168 data->stop_polling_.Reset();
171 } // namespace ozonewayland