qemu/io/channel-watch.c
Daniel P. Berrange 1c809fa01d io: add helper module for creating watches on FDs
A number of the channel implementations will require the
ability to create watches on file descriptors / sockets.
To avoid duplicating this code in each channel, provide a
helper API for dealing with file descriptor watches.

There are two watch implementations provided. The first
is useful for bi-directional file descriptors such as
sockets, regular files, character devices, etc. The
second works with a pair of unidirectional file descriptors
such as pipes.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2015-12-18 12:18:05 +00:00

199 lines
5.0 KiB
C

/*
* QEMU I/O channels watch helper APIs
*
* Copyright (c) 2015 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#include "io/channel-watch.h"
typedef struct QIOChannelFDSource QIOChannelFDSource;
struct QIOChannelFDSource {
GSource parent;
GPollFD fd;
QIOChannel *ioc;
GIOCondition condition;
};
typedef struct QIOChannelFDPairSource QIOChannelFDPairSource;
struct QIOChannelFDPairSource {
GSource parent;
GPollFD fdread;
GPollFD fdwrite;
QIOChannel *ioc;
GIOCondition condition;
};
static gboolean
qio_channel_fd_source_prepare(GSource *source G_GNUC_UNUSED,
gint *timeout)
{
*timeout = -1;
return FALSE;
}
static gboolean
qio_channel_fd_source_check(GSource *source)
{
QIOChannelFDSource *ssource = (QIOChannelFDSource *)source;
return ssource->fd.revents & ssource->condition;
}
static gboolean
qio_channel_fd_source_dispatch(GSource *source,
GSourceFunc callback,
gpointer user_data)
{
QIOChannelFunc func = (QIOChannelFunc)callback;
QIOChannelFDSource *ssource = (QIOChannelFDSource *)source;
return (*func)(ssource->ioc,
ssource->fd.revents & ssource->condition,
user_data);
}
static void
qio_channel_fd_source_finalize(GSource *source)
{
QIOChannelFDSource *ssource = (QIOChannelFDSource *)source;
object_unref(OBJECT(ssource->ioc));
}
static gboolean
qio_channel_fd_pair_source_prepare(GSource *source G_GNUC_UNUSED,
gint *timeout)
{
*timeout = -1;
return FALSE;
}
static gboolean
qio_channel_fd_pair_source_check(GSource *source)
{
QIOChannelFDPairSource *ssource = (QIOChannelFDPairSource *)source;
GIOCondition poll_condition = ssource->fdread.revents |
ssource->fdwrite.revents;
return poll_condition & ssource->condition;
}
static gboolean
qio_channel_fd_pair_source_dispatch(GSource *source,
GSourceFunc callback,
gpointer user_data)
{
QIOChannelFunc func = (QIOChannelFunc)callback;
QIOChannelFDPairSource *ssource = (QIOChannelFDPairSource *)source;
GIOCondition poll_condition = ssource->fdread.revents |
ssource->fdwrite.revents;
return (*func)(ssource->ioc,
poll_condition & ssource->condition,
user_data);
}
static void
qio_channel_fd_pair_source_finalize(GSource *source)
{
QIOChannelFDPairSource *ssource = (QIOChannelFDPairSource *)source;
object_unref(OBJECT(ssource->ioc));
}
GSourceFuncs qio_channel_fd_source_funcs = {
qio_channel_fd_source_prepare,
qio_channel_fd_source_check,
qio_channel_fd_source_dispatch,
qio_channel_fd_source_finalize
};
GSourceFuncs qio_channel_fd_pair_source_funcs = {
qio_channel_fd_pair_source_prepare,
qio_channel_fd_pair_source_check,
qio_channel_fd_pair_source_dispatch,
qio_channel_fd_pair_source_finalize
};
GSource *qio_channel_create_fd_watch(QIOChannel *ioc,
int fd,
GIOCondition condition)
{
GSource *source;
QIOChannelFDSource *ssource;
source = g_source_new(&qio_channel_fd_source_funcs,
sizeof(QIOChannelFDSource));
ssource = (QIOChannelFDSource *)source;
ssource->ioc = ioc;
object_ref(OBJECT(ioc));
ssource->condition = condition;
ssource->fd.fd = fd;
ssource->fd.events = condition;
g_source_add_poll(source, &ssource->fd);
return source;
}
GSource *qio_channel_create_fd_pair_watch(QIOChannel *ioc,
int fdread,
int fdwrite,
GIOCondition condition)
{
GSource *source;
QIOChannelFDPairSource *ssource;
source = g_source_new(&qio_channel_fd_pair_source_funcs,
sizeof(QIOChannelFDPairSource));
ssource = (QIOChannelFDPairSource *)source;
ssource->ioc = ioc;
object_ref(OBJECT(ioc));
ssource->condition = condition;
ssource->fdread.fd = fdread;
ssource->fdread.events = condition & G_IO_IN;
ssource->fdwrite.fd = fdwrite;
ssource->fdwrite.events = condition & G_IO_OUT;
g_source_add_poll(source, &ssource->fdread);
g_source_add_poll(source, &ssource->fdwrite);
return source;
}