On 01/12/2012 10:20 AM, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange(a)redhat.com>
Currently the LXC controller attempts to deal with EOF on a
tty by spawning a thread todo a edge triggered epoll_wait().
s/todo a edge /to do an edge-/
This avoids the normal event loop spinning on POLLHUP. There
is a subtle mistake though - even after seeing POLLHUP on a
master PTY, it is still perfectly possible & valid to write
data to the PTY. There is a buffer that can be filled with
data, even when no client is present.
The second mistake is that the epoll_wait() thread was not
looking for the EPOLLOUT condition, so when a new client
connects to the LXC console, it had to explicitly send a
character before any queued output would appear.
Finally, there was in fact no need to spawn a new thread to
deal with epoll_wait(). The epoll file descriptor itself
can be poll()'d on normally.
This patch attempts to deal with all these problems.
- The blocking epoll_wait() thread is replaced by a poll
on the epoll file descriptor which then does a non-blocking
epoll_wait() to handle events
- Even if POLLHUP is seen, we continue trying to write
any pending output until getting EAGAIN from write.
- Once write returns EAGAIN, we modify the epoll event
mask to also look for EPOLLOUT
The description makes sense; now on to the code :)
+ } else if (console->hostEpoll) {
+ VIR_DEBUG("Stop epoll oldContEvents=%x", console->hostEpoll);
+ if (epoll_ctl(console->epollFd, EPOLL_CTL_DEL, console->hostFd, NULL) <
0) {
+ virReportSystemError(errno, "%s",
+ _("Unable to add epoll fd"));
s/add/remove/ in the error message
+ } else if (console->contEpoll) {
+ VIR_DEBUG("Stop epoll oldContEvents=%x", console->contEpoll);
+ if (epoll_ctl(console->epollFd, EPOLL_CTL_DEL, console->contFd, NULL) <
0) {
+ virReportSystemError(errno, "%s",
+ _("Unable to add epoll fd"));
And again.
@@ -1103,9 +1163,32 @@ static int lxcControllerMain(int serverFd,
}
for (i = 0 ; i < nFds ; i++) {
+ consoles[i].epollFd = -1;
+ consoles[i].epollFd = -1;
Why do you have this line twice? Did you mean to initialize epollWatch
instead?
+ consoles[i].hostWatch = -1;
+ consoles[i].contWatch = -1;
+ }
+
+ for (i = 0 ; i < nFds ; i++) {
consoles[i].hostFd = hostFds[i];
consoles[i].contFd = contFds[i];
+ if ((consoles[i].epollFd = epoll_create(2)) < 0) {
Should we be using epoll_create1(EPOLL_CLOEXEC)?
Overall, it looks fairly clean; I'm assuming that you actually tested
with it, and I didn't hit any compilation errors. And the man page for
poll definitely recommends that you must plow on until EAGAIN if you use
EPOLLET, so this new code certainly looks cleaner in that regards.
I'm okay giving ACK with nits fixed.
--
Eric Blake eblake(a)redhat.com +1-919-301-3266
Libvirt virtualization library
http://libvirt.org