summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmit Shah <amit.shah@redhat.com>2010-08-23 13:55:16 +0530
committerAmit Shah <amit.shah@redhat.com>2010-08-23 13:55:16 +0530
commite1f100f1fbe0285c7efdfc30f38bece766e59efe (patch)
tree6c740d4f2d9c57b74ad27baa3db9abdd5cd85981
parent2c799e07ca9327ef662896c01856f2f6f5c0229d (diff)
downloadtest-virtserial-e1f100f1fbe0285c7efdfc30f38bece766e59efe.tar.gz
test-virtserial-e1f100f1fbe0285c7efdfc30f38bece766e59efe.tar.xz
test-virtserial-e1f100f1fbe0285c7efdfc30f38bece766e59efe.zip
auto-test: Introduce a threaded read/write test
Introduce a test that creates a new thread and blocks on a port for read. The parent thread then writes to the port, and later the host writes something to the port, unblocking the read. Signed-off-by: Amit Shah <amit.shah@redhat.com>
-rw-r--r--Makefile1
-rw-r--r--auto-virtserial-guest.c55
-rw-r--r--auto-virtserial.c90
-rw-r--r--virtserial.h2
4 files changed, 148 insertions, 0 deletions
diff --git a/Makefile b/Makefile
index 4cf5dab..6df0a67 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,5 @@
CFLAGS=-Wall -g
+LDFLAGS=-lpthread
all: test-virtserial auto-virtserial auto-virtserial-guest
diff --git a/auto-virtserial-guest.c b/auto-virtserial-guest.c
index eebf1f0..2c84c27 100644
--- a/auto-virtserial-guest.c
+++ b/auto-virtserial-guest.c
@@ -24,6 +24,7 @@
#include <error.h>
#include <fcntl.h>
#include <poll.h>
+#include <pthread.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
@@ -44,6 +45,8 @@ static int g_bigfile_fd;
static int g_length;
/* The 'name' field in the sysfs port info */
static char g_sysfs_name[1024];
+/* The thread that performs a blocking read operation */
+static pthread_t g_read_thread_id;
static ssize_t safewrite(int fd, const void *buf, size_t count)
@@ -413,6 +416,50 @@ out:
return ret;
}
+static void *t_blocked_read(void *arg)
+{
+ int port_nr = *(int *)arg;
+ int *ret;
+
+ ret = malloc(sizeof(int));
+ if (!ret)
+ return NULL;
+
+ *ret = read_port(port_nr);
+
+ return ret;
+}
+
+static int create_read_thread(int nr)
+{
+ int ret;
+
+ ret = pthread_create(&g_read_thread_id, NULL, &t_blocked_read, &nr);
+ if (ret)
+ return -errno;
+
+ /* Give a chance to the thread to start and block */
+ sleep(2);
+
+ return 0;
+}
+
+static int join_read_thread(int nr)
+{
+ int ret;
+ void *ret2;
+
+ ret = pthread_join(g_read_thread_id, &ret2);
+ if (ret)
+ return ret;
+
+ ret = *(int *)ret2;
+
+ free(ret2);
+
+ return ret;
+}
+
static void send_report(int cfd, int ret)
{
struct guest_packet gpkt;
@@ -539,6 +586,14 @@ back_to_open:
ret = send_guest_csum(gpkt.value);
send_report(cfd, ret);
break;
+ case KEY_CREATE_READ_THREAD:
+ ret = create_read_thread(gpkt.value);
+ send_report(cfd, ret);
+ break;
+ case KEY_JOIN_READ_THREAD:
+ ret = join_read_thread(gpkt.value);
+ send_report(cfd, ret);
+ break;
}
}
return 0;
diff --git a/auto-virtserial.c b/auto-virtserial.c
index 9503f74..f04a834 100644
--- a/auto-virtserial.c
+++ b/auto-virtserial.c
@@ -248,6 +248,24 @@ static int guest_open_guest_bigfile(int value)
return guest_cmd(&gpkt);
}
+static int guest_create_read_thread(int nr)
+{
+ struct guest_packet gpkt;
+
+ gpkt.key = KEY_CREATE_READ_THREAD;
+ gpkt.value = nr;
+ return guest_cmd(&gpkt);
+}
+
+static int guest_join_read_thread(int nr)
+{
+ struct guest_packet gpkt;
+
+ gpkt.key = KEY_JOIN_READ_THREAD;
+ gpkt.value = nr;
+ return guest_cmd(&gpkt);
+}
+
static void show_stats(void)
{
fprintf(stderr, "-----\n");
@@ -1095,6 +1113,71 @@ out_close:
return err;
}
+/*
+ * Tests guest's ability to be blocked on read in one thread while
+ * writing to the same chardev in another thread
+ *
+ * - Open guest port
+ * - Call threaded test
+ * - Wait for POLLOUT from guest for a specific timeout
+ * - Collect result.
+ *
+ * If POLLOUT doesn't get set, that means the test failed and the
+ * guest is stuck in a blocking read anyway. So this should be the
+ * last test to run.
+ */
+static int test_threaded_read_write(int nr)
+{
+ struct pollfd pollfd[1];
+ struct guest_packet gpkt;
+ int err, ret;
+
+ ret = guest_open_port(nr);
+ err = result(__func__, true, "open", ret, -1, -1, OP_GT, false);
+ if (err)
+ return err;
+
+ host_connect_chardev(nr);
+
+ guest_set_length(nr, sizeof(gpkt));
+
+ ret = guest_create_read_thread(nr);
+ err = result(__func__, true, "create thread",
+ ret, -1, -1, OP_GT, false);
+ if (err)
+ goto out;
+
+ ret = guest_write(nr, BUF_LENGTH);
+ err = result(__func__, chardevs[nr].caching, "guest_write",
+ ret, BUF_LENGTH, BUF_LENGTH, OP_EQ, false);
+ if (err)
+ goto out;
+
+ pollfd[0].fd = chardevs[nr].sock;
+ pollfd[0].events = POLLOUT;
+ /* Wait for 5s to see if guest writes out something */
+ ret = poll(pollfd, 1, 5000);
+ if (ret == -1)
+ error(errno, errno, "%s: poll\n", __func__);
+ if (!(pollfd[0].revents & POLLOUT))
+ error(EIO, EIO, "%s: no response from guest\n", __func__);
+
+ /*
+ * Write out something - doesn't matter what. This should make
+ * the guest read thread unblock and return.
+ */
+ write(chardevs[nr].sock, &gpkt, sizeof(gpkt));
+
+ ret = guest_join_read_thread(nr);
+ err = result(__func__, true, "read", ret,
+ sizeof(gpkt), sizeof(gpkt), OP_EQ, true);
+
+ host_close_chardev(nr);
+out:
+ guest_close_port(nr);
+ return err;
+}
+
enum {
TEST_OPEN = 0,
TEST_CLOSE,
@@ -1113,6 +1196,7 @@ enum {
TEST_H_FILE_SEND,
TEST_G_FILE_SEND,
TEST_CONSOLE,
+ TEST_THREADED_READ_WRITE,
TEST_END
};
@@ -1189,6 +1273,10 @@ static struct test_parameters {
.test_function = test_console,
.needs_guestok = false,
},
+ {
+ .test_function = test_threaded_read_write,
+ .needs_guestok = true,
+ },
};
static void post_test_cleanup(int nr)
@@ -1329,6 +1417,8 @@ static int start_tests(void)
/* The console test should work in any case. */
run_test(TEST_CONSOLE, 0);
+ run_test(TEST_THREADED_READ_WRITE, 2);
+
return 0;
}
diff --git a/virtserial.h b/virtserial.h
index 6ec37ab..298fcb5 100644
--- a/virtserial.h
+++ b/virtserial.h
@@ -16,6 +16,8 @@
#define KEY_OPEN_GUEST_BIGFILE 16
#define KEY_GUEST_BYTESTREAM 17
#define KEY_GUEST_CSUM 18
+#define KEY_CREATE_READ_THREAD 19
+#define KEY_JOIN_READ_THREAD 20
#define HOST_BIG_FILE "/tmp/amit/host-big-file"
#define GUEST_BIG_FILE "/tmp/amit/guest-big-file"