summaryrefslogtreecommitdiffstats
path: root/auto-virtserial-guest.c
diff options
context:
space:
mode:
authorAmit Shah <amit.shah@redhat.com>2010-08-25 19:00:53 +0530
committerAmit Shah <amit.shah@redhat.com>2010-08-26 09:43:22 +0530
commitf50f751a4980447a465e5039272ae0b0d8708aed (patch)
treec77458b29b629c9596e2c9b5af05ce660d393f9e /auto-virtserial-guest.c
parentd99d351e8b683835b43060b562fd68163902d89a (diff)
downloadtest-virtserial-f50f751a4980447a465e5039272ae0b0d8708aed.tar.gz
test-virtserial-f50f751a4980447a465e5039272ae0b0d8708aed.tar.xz
test-virtserial-f50f751a4980447a465e5039272ae0b0d8708aed.zip
auto-virtserial: Add guest SIGIO tests
The guest can receive the SIGIO signal on host connection and disconnection events. This commit just adds a simple test for one open/close event. A lot more are to be added, as explained in the comments. Signed-off-by: Amit Shah <amit.shah@redhat.com>
Diffstat (limited to 'auto-virtserial-guest.c')
-rw-r--r--auto-virtserial-guest.c110
1 files changed, 108 insertions, 2 deletions
diff --git a/auto-virtserial-guest.c b/auto-virtserial-guest.c
index cef1d26..ce3e6e5 100644
--- a/auto-virtserial-guest.c
+++ b/auto-virtserial-guest.c
@@ -36,6 +36,7 @@
#include "virtserial.h"
#define CONTROL_PORT "/dev/vport0p1"
+#define MAX_PORTS 10
/* The fd to work with for read / write requests. Set by the open message */
static int g_fd;
@@ -47,7 +48,10 @@ static int g_length;
static char g_sysfs_name[1024];
/* The thread that performs a blocking read operation */
static pthread_t g_read_thread_id;
-
+/* Array to hold fds of all open ports. Used for polling host connect events */
+static int g_open_fds[MAX_PORTS];
+/* Array to hold poll results of g_open_fds from the sigio_handler() */
+static int g_poll_results[MAX_PORTS];
static ssize_t safewrite(int fd, const void *buf, size_t count)
{
@@ -148,7 +152,7 @@ static char *get_port_dev(unsigned int nr)
static int open_port(int nr)
{
char *buf;
- int fd;
+ int fd, ret;
buf = get_port_dev(nr);
if (!buf)
@@ -159,6 +163,19 @@ static int open_port(int nr)
if (fd == -1)
return -errno;
g_fd = fd;
+
+ ret = fcntl(fd, F_SETOWN, getpid());
+ if (ret < 0) {
+ perror("F_SETOWN");
+ }
+ ret = fcntl(fd, F_GETFL);
+ ret = fcntl(fd, F_SETFL, ret | O_ASYNC);
+ if (ret < 0) {
+ perror("F_SETFL");
+ }
+
+ if (nr < MAX_PORTS)
+ g_open_fds[nr] = fd;
return fd;
}
@@ -220,6 +237,11 @@ static int close_port(int nr)
if (ret < 0)
ret = -errno;
g_length = 0;
+
+ if (nr < MAX_PORTS) {
+ g_open_fds[nr] = -1;
+ g_poll_results[nr] = 0;
+ }
return ret;
}
@@ -462,6 +484,76 @@ static int join_read_thread(int nr)
return ret;
}
+static int get_port_from_fd(int fd)
+{
+ unsigned int i;
+
+ for (i = 0; i < MAX_PORTS; i++) {
+ if (g_open_fds[i] == fd)
+ return i;
+ }
+ return -1;
+}
+
+static void sigio_handler(int signal)
+{
+ struct pollfd pollfds[MAX_PORTS];
+ unsigned int i, j;
+ int ret;
+
+ for (i = 0, j = 0; i < MAX_PORTS; i++) {
+ if (g_open_fds[i] > -1) {
+ pollfds[j].fd = g_open_fds[i];
+ pollfds[j++].events = POLLIN|POLLOUT;
+ }
+ }
+ ret = safepoll(pollfds, j, 0);
+ if (ret == -1) {
+ for (i = 0; i < MAX_PORTS; i++)
+ g_poll_results[i] = 0;
+ return;
+ }
+
+ for (i = 0; i < j; i++) {
+ int port;
+
+ port = get_port_from_fd(pollfds[i].fd);
+ if (port == -1)
+ continue;
+ g_poll_results[port] = pollfds[i].revents;
+ }
+}
+
+static int install_sigio_handler(void)
+{
+ struct sigaction action;
+ unsigned int i;
+ int ret;
+
+ action.sa_handler = sigio_handler;
+ action.sa_flags = 0;
+ ret = sigemptyset(&action.sa_mask);
+ if (ret) {
+ ret = -errno;
+ goto out;
+ }
+
+ ret = sigaction(SIGIO, &action, NULL);
+ if (ret)
+ ret = -errno;
+
+out:
+ for (i = 0; i < MAX_PORTS; i++)
+ g_poll_results[i] = 0;
+
+ return ret;
+}
+
+static int get_sigio_result(int nr)
+{
+ return g_poll_results[nr];
+}
+
static void send_report(int cfd, int ret)
{
struct guest_packet gpkt;
@@ -475,6 +567,7 @@ int main(int argc, char *argv[])
{
struct guest_packet gpkt;
struct pollfd pollfd[1];
+ unsigned int i;
int ret, cfd;
/*
@@ -486,6 +579,12 @@ int main(int argc, char *argv[])
*/
spawn_console(0);
+ /*
+ * Have to install it right away. Else we'll start getting
+ * SIGIOs and the default action is to terminate the process.
+ */
+ install_sigio_handler();
+
ret = access(CONTROL_PORT, R_OK|W_OK);
if (ret == -1)
error(errno, errno, "No control port found %s", CONTROL_PORT);
@@ -501,6 +600,9 @@ back_to_open:
if (ret < 0)
error(-ret, -ret, "write control port");
+ for (i = 0; i < MAX_PORTS; i++)
+ g_open_fds[i] = -1;
+
pollfd[0].fd = cfd;
pollfd[0].events = POLLIN;
@@ -596,6 +698,10 @@ back_to_open:
ret = join_read_thread(gpkt.value);
send_report(cfd, ret);
break;
+ case KEY_GET_SIGIO_RESULT:
+ ret = get_sigio_result(gpkt.value);
+ send_report(cfd, ret);
+ break;
default:
send_report(cfd, -ERANGE);
break;