*.o
+*.so
*.d
-xl_event_test
+async_test
-SRCS = thread_test.c xl_eventloop.c testcase.c xl_event_test.c
+SRCS = testcase_runner.c eventloop_runner.c testcase_utils.c async_test.c
CFLAGS = -Wall -Wextra -Werror -pedantic -g
-LDFLAGS = -pthread -lxenlight
+LDFLAGS = -Wl,-export-dynamic
+LDLIBS = -pthread -lxenctrl -lxlutil -lxenlight -ldl
+TESTS = $(wildcard test_*.c)
+ALL_SRCS = $(SRCS) $(TESTS)
-all: xl_event_test
-xl_event_test: $(SRCS:.c=.o)
+.PHONY: all
+all: async_test $(TESTS:.c=.so)
+async_test: $(SRCS:.c=.o)
+
+
+test_%.o: CFLAGS += -fPIC
+
+test_%.so: test_%.o
+ $(CC) -shared $< -o $@
%.d: %.c
$(CC) -M $< > $@
.PHONY: clean
clean:
- rm -f $(SRCS:.c=.o) $(SRCS:.c=.d) xl_event_test
+ rm -f $(ALL_SRCS:.c=.o) $(ALL_SRCS:.c=.d) $(TESTS:.c=.so) async_test
--include $(SRCS:.c=.d)
+-include $(ALL_SRCS:.c=.d)
--- /dev/null
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "testcase_runner.h"
+#include "eventloop_runner.h"
+
+int main(int argc, char **argv)
+{
+ struct test t;
+ xentoollog_logger *logger;
+ char *test_path;
+ void *test_plugin;
+ void *(*testcase) (struct test *);
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s <testcase>\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ /* dlopen only looks outside the standard library directories
+ if the path contains a slash. Resolve the real path to
+ the test file, to ensure that this is the case. */
+ test_path = realpath(argv[1], NULL);
+ if (!test_path) {
+ perror(argv[1]);
+ exit(EXIT_FAILURE);
+ }
+
+ test_plugin = dlopen(test_path, RTLD_NOW);
+ free(test_path);
+ if (!test_plugin) {
+ fprintf(stderr, "%s\n", dlerror());
+ exit(EXIT_FAILURE);
+ }
+ dlerror();
+
+ *(void **)(&testcase) = dlsym(test_plugin, "testcase");
+ if (!testcase) {
+ fprintf(stderr, "%s\n", dlerror());
+ exit(EXIT_FAILURE);
+ }
+ dlerror();
+
+ logger = (xentoollog_logger *)
+ xtl_createlogger_stdiostream(stderr, XTL_PROGRESS, 0);
+
+ if (! !test_spawn(&t, logger, testcase)) {
+ perror("Failed to spawn test thread");
+ exit(EXIT_FAILURE);
+ }
+
+ eventloop_start(&t);
+
+ fprintf(stderr, "Waiting for test thread to exit\n");
+ test_join(&t);
+ fprintf(stderr, "Test thread exited\n");
+ test_destroy(&t);
+ xtl_logger_destroy(logger);
+ dlclose(test_plugin);
+
+ exit(EXIT_SUCCESS);
+}
--- /dev/null
+#include <assert.h>
+#include <libxl.h>
+#include <libxl_event.h>
+#include <poll.h>
+
+#include "eventloop_runner.h"
+#include "testcase_runner.h"
+
+enum { NUM_POLL_FDS = 32 };
+struct pollfd pollfds[NUM_POLL_FDS];
+
+int eventloop_run;
+
+void init_pollfds(struct pollfd *pollfds, int numfds)
+{
+ int i;
+
+ for (i = 0; i < numfds; i++) {
+ pollfds[i].fd = -1;
+ pollfds[i].events = 0;
+ pollfds[i].revents = 0;
+ }
+}
+
+void log_poll_events(struct pollfd pfd)
+{
+ if (pfd.revents & POLLIN) {
+ fprintf(stderr, "fd %d readable\n", pfd.fd);
+ }
+
+ if (pfd.revents & POLLOUT) {
+ fprintf(stderr, "fd %d writeable\n", pfd.fd);
+ }
+
+ if (pfd.revents & POLLPRI) {
+ fprintf(stderr, "fd %d priority readable\n", pfd.fd);
+ }
+
+ if (pfd.revents & POLLERR) {
+ fprintf(stderr, "fd %d output error\n", pfd.fd);
+ }
+
+ if (pfd.revents & POLLHUP) {
+ fprintf(stderr, "fd %d hung up\n", pfd.fd);
+ }
+
+ if (pfd.revents & POLLNVAL) {
+ fprintf(stderr, "fd %d not open\n", pfd.fd);
+ }
+}
+
+void eventloop_start(struct test *tc)
+{
+ int rc;
+
+ eventloop_run = 1;
+
+ while (eventloop_run) {
+ int i;
+ int nfds = NUM_POLL_FDS;
+ int timeout;
+ struct timeval now;
+
+ init_pollfds(pollfds, NUM_POLL_FDS);
+ gettimeofday(&now, NULL);
+ libxl_osevent_beforepoll(tc->ctx, &nfds, pollfds, &timeout, now);
+ rc = poll(pollfds, NUM_POLL_FDS, 2000);
+
+ if (rc == 0) {
+ send_eventloop_timeout(tc);
+ continue;
+ }
+
+ for (;;) {
+ libxl_event *event;
+ rc = libxl_event_check(tc->ctx, &event, LIBXL_EVENTMASK_ALL, 0,
+ 0);
+ if (rc == ERROR_NOT_READY) {
+ printf("libxl_event_check found no events\n");
+ break;
+ }
+ send_libxl_event(tc, event->type);
+ libxl_event_free(tc->ctx, event);
+ }
+
+ for (i = 0; i < NUM_POLL_FDS; i++) {
+ if (pollfds[i].fd != -1 && pollfds[i].revents != 0) {
+ struct pollfd *pfd = &pollfds[i];
+ log_poll_events(*pfd);
+ send_fd_event(tc, pfd->fd);
+ }
+ }
+
+ gettimeofday(&now, NULL);
+ libxl_osevent_afterpoll(tc->ctx, nfds, pollfds, now);
+ }
+}
+
+void eventloop_halt()
+{
+ eventloop_run = 0;
+}
--- /dev/null
+#ifndef __XL_EVENTLOOP_H
+#define __XL_EVENTLOOP_H
+
+struct test;
+
+void eventloop_start(struct test *tc);
+void eventloop_halt();
+
+#endif /* __XL_EVENTLOOP_H */
--- /dev/null
+#include <assert.h>
+#include <libxl.h>
+#include <libxl_event.h>
+#include "testcase_runner.h"
+#include "eventloop_runner.h"
+#include "testcase_utils.h"
+
+/*
+ TODO:
+ libxl__bootloader_run may add a cancellable point, but we don't enter
+ it because we provide the kernel and ramdisk along with the root image.
+ */
+
+#if 0
+void cleanup_and_exit(libxl_domain_config * dc)
+{
+
+}
+#endif
+
+void *testcase(struct test *tc)
+{
+ int count = 0;
+ int run = 1;
+
+ while (run) {
+ uint32_t domid;
+ libxl_domain_config dc;
+ struct event ev;
+ int i;
+
+ count++;
+ printf("\n****** Will cancel after %d events ******\n", count);
+
+ init_domain_config(&dc, "test_domain_create_new",
+ "/root/vmlinuz-4.0.4-301.fc22.x86_64",
+ "/root/foobar.img",
+ "/root/Fedora-Cloud-Base-22-20150521.x86_64.qcow2",
+ "/root/init.iso");
+
+ do_domain_create(tc, &dc, &domid);
+
+ /* Wait for some number of events before cancelling.
+ Eventloop timeouts are ignored as they could happen at
+ any time. The test ends if the callback occurs while
+ we are still waiting for an event - after the callback,
+ the API call can no longer be cancelled.
+ */
+ for (i = 0; i < count; i++) {
+ wait_for(tc, ~EV_EVENTLOOP, &ev);
+ if (ev.type == EV_LIBXL_CALLBACK) {
+ run = 0;
+ break;
+ }
+ if (run) {
+ libxl_ao_cancel(tc->ctx, &tc->ao_how);
+ wait_for(tc, EV_LIBXL_CALLBACK, &ev);
+ }
+
+ printf("domid: %d\n", domid);
+ libxl_domain_config_dispose(&dc);
+
+ /* If cancellation succeeded, the domain will probably have
+ been created with all of its associated devices attached, but
+ the device emulator will probably not have been spawned - no
+ qemu-system-i386 process with -xen-domid equal to our domid
+ will exist */
+
+ assert(!libxl_domain_info(tc->ctx, NULL, domid));
+ libxl_domain_destroy(tc->ctx, domid, 0);
+ /* wait_for(tc, EV_LIBXL_CALLBACK, &ev); */
+ }
+ }
+
+ eventloop_halt();
+ pthread_exit(NULL);
+}
--- /dev/null
+#include <assert.h>
+#include <libxl.h>
+#include <libxl_event.h>
+#include "testcase_runner.h"
+#include "eventloop_runner.h"
+#include "testcase_utils.h"
+
+void *testcase(struct test *tc)
+{
+ uint32_t domid;
+ struct event ev;
+ libxl_domain_config dc;
+
+ printf("thread started\n");
+
+ init_domain_config(&dc, "test_domain_suspend",
+ "/root/vmlinuz-4.0.4-301.fc22.x86_64",
+ "/root/foobar.img",
+ "/root/Fedora-Cloud-Base-22-20150521.x86_64.qcow2",
+ "/root/init.iso");
+ do_domain_create(tc, &dc, &domid);
+
+ wait_for(tc, EV_LIBXL_CALLBACK, &ev);
+ printf("domid: %d\n", domid);
+ libxl_domain_config_dispose(&dc);
+
+ libxl_domain_unpause(tc->ctx, domid);
+ printf("domain %d unpaused\n", domid);
+
+ printf("waiting for domain to boot\n");
+ wait_for_n(tc, EV_EVENTLOOP, 10, &ev);
+
+ /* Start a suspend, and immediately cancel it */
+ do_domain_suspend(tc, domid);
+ wait_for(tc, EV_FD_EVENT, &ev);
+ libxl_ao_cancel(tc->ctx, &tc->ao_how);
+
+ wait_for(tc, EV_LIBXL_CALLBACK, &ev);
+ printf("domain %d suspended\n", domid);
+
+ eventloop_halt();
+ pthread_exit(NULL);
+}
+++ /dev/null
-#include <libxl.h>
-#include "thread_test.h"
-#include "xl_eventloop.h"
-
-void *
-testcase(struct test *tc)
-{
- uint32_t domid;
- libxl_domain_config dc;
-
- printf("thread started\n");
-
- init_domain_config(&dc, "badger", "/root/vmlinuz-4.0.4-301.fc22.x86_64");
- do_domain_create(tc, &dc, &domid);
- wait_for(tc, EV_LIBXL_CALLBACK); /* need to be able to distingish out callback from others */
- libxl_domain_config_dispose(&dc);
- printf("domain %d created\n", domid);
-
- libxl_domain_unpause(tc->ctx, domid);
- printf("domain %d unpaused\n", domid);
-
- wait_for_n(tc, EV_EVENTLOOP, 10);
- do_domain_suspend(tc, domid);
- wait_for(tc, EV_LIBXL_CALLBACK);
- printf("domain %d suspended\n", domid);
-
- pthread_exit(NULL);
-}
-
+++ /dev/null
-#ifndef __TESTCASE_H
-#define __TESTCASE_H
-
-void *testcase(struct test *tc);
-
-#endif /* __TESTCASE_H */
--- /dev/null
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "testcase_runner.h"
+
+enum { RX = 0, TX = 1 };
+
+int
+test_spawn(struct test *tc, xentoollog_logger * logger,
+ void *(*fn) (struct test *))
+{
+ /* Initialize the test structure */
+ libxl_ctx_alloc(&tc->ctx, LIBXL_VERSION, 0, logger);
+
+ /* Initialize the mailbox */
+ if (pipe(tc->mailbox) != 0) {
+ perror("pipe");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Spawn a thread to run the test case */
+ return pthread_create(&tc->thread, NULL, (void *(*)(void *))fn, tc);
+}
+
+void test_join(struct test *tc)
+{
+ /* we should capture and return retval here */
+ pthread_join(tc->thread, NULL);
+}
+
+void test_destroy(struct test *tc)
+{
+ if (tc->mailbox[RX] >= 0) {
+ close(tc->mailbox[RX]);
+ }
+
+ if (tc->mailbox[TX] >= 0) {
+ close(tc->mailbox[TX]);
+ }
+
+ libxl_ctx_free(tc->ctx);
+}
+
+int send_event(struct test *tc, struct event ev)
+{
+ return write(tc->mailbox[TX], (char *)&ev, sizeof(ev));
+}
+
+void recv_event(struct test *tc, struct event *ev)
+{
+ printf("waiting for event\n");
+ read(tc->mailbox[RX], (char *)ev, sizeof(*ev));
+}
+
+/* Wait until the an event matching the expected mask is posted.
+ Ignores and discards any non-matching events received in the meantime. */
+void wait_for(struct test *tc, enum event_type mask, struct event *ev)
+{
+ do {
+ recv_event(tc, ev);
+ } while (!(ev->type & mask));
+}
+
+/* Wait until the the specified number of the expected events are posted.
+ Ignores and discards any other events received in the meantime. */
+void
+wait_for_n(struct test *tc, enum event_type mask, int count, struct event *ev)
+{
+ while (count--) {
+ wait_for(tc, mask, ev);
+ }
+}
+
+int send_fd_event(struct test *tc, int fd)
+{
+ struct event ev;
+ ev.type = EV_FD_EVENT;
+ ev.u.fd_event.fd = fd;
+ printf("-> EV_FD_EVENT\n");
+ return send_event(tc, ev);
+}
+
+int send_libxl_event(struct test *tc, libxl_event_type type)
+{
+ struct event ev;
+ ev.type = EV_LIBXL_EVENT;
+ ev.u.libxl_event.type = type;
+ printf("-> EV_LIBXL_EVENT");
+ return send_event(tc, ev);
+}
+
+int send_libxl_callback_event(struct test *tc, int rc)
+{
+ struct event ev;
+ ev.type = EV_LIBXL_CALLBACK;
+ ev.u.callback_event.rc = rc;
+ printf("-> EV_LIBXL_CALLBACK\n");
+ return send_event(tc, ev);
+}
+
+int send_eventloop_timeout(struct test *tc)
+{
+ struct event ev;
+ ev.type = EV_EVENTLOOP;
+ printf("-> EV_EVENTLOOP_TICK\n");
+ return send_event(tc, ev);
+}
--- /dev/null
+#ifndef __THREAD_TEST_H
+#define __THREAD_TEST_H
+
+#include <libxl.h>
+#include <pthread.h>
+
+enum event_type {
+ EV_NONE = 0x0000,
+ EV_TEST_START = 0x0001,
+ EV_LIBXL_CALLBACK = 0x0002,
+ EV_FD_EVENT = 0x0004,
+ EV_EVENTLOOP = 0x0008,
+ EV_LIBXL_EVENT = 0x0010,
+ EV_ANY = 0xffff
+};
+
+struct event {
+ enum event_type type;
+ union {
+ struct {
+ int fd;
+ } fd_event;
+ struct {
+ int rc;
+ } callback_event;
+ struct {
+ libxl_event_type type;
+ } libxl_event;
+ } u;
+};
+
+struct test {
+ /*
+ * Test task structure.
+ */
+
+ /*
+ * Pointer to the libxl context structure.
+ * The memory which this points to is allocated and
+ * owned by libxl.
+ */
+ libxl_ctx *ctx;
+
+ /*
+ * Structure defining per-function callbacks.
+ * Must outlive the asynchronous call which uses it.
+ */
+ libxl_asyncop_how ao_how;
+
+ /* The thread running the test */
+ pthread_t thread;
+ int mailbox[2];
+};
+
+int test_spawn(struct test *tc, xentoollog_logger * logger,
+ void *(*fn) (struct test *));
+void test_join(struct test *tc);
+void test_destroy(struct test *tc);
+int send_event(struct test *tc, struct event ev);
+void recv_event(struct test *tc, struct event *ev);
+void wait_for(struct test *tc, enum event_type mask, struct event *ev);
+void wait_for_n(struct test *tc, enum event_type mask, int count,
+ struct event *ev);
+int send_fd_event(struct test *tc, int fd);
+int send_libxl_callback_event(struct test *tc, int rc);
+int send_libxl_event(struct test *tc, libxl_event_type type);
+int send_eventloop_timeout(struct test *tc);
+
+#endif /* __THREAD_TEST_H */
--- /dev/null
+#include <fcntl.h>
+#include <libxl.h>
+#include <stdlib.h>
+
+#include "testcase_utils.h"
+#include "testcase_runner.h"
+
+void print_domain_config(libxl_ctx * ctx, char *msg, libxl_domain_config * dc)
+{
+ char *json = libxl_domain_config_to_json(ctx, dc);
+ printf("%s: %s\n", msg, json);
+ free(json);
+}
+
+void
+init_domain_config(libxl_domain_config * dc,
+ char *name, char *kernel, char *ramdisk,
+ char *hdd, char *cdrom)
+{
+ libxl_device_disk *disk;
+
+ libxl_domain_config_init(dc);
+
+ dc->c_info.name = strdup(name);
+ dc->c_info.type = LIBXL_DOMAIN_TYPE_PV;
+ dc->b_info.type = LIBXL_DOMAIN_TYPE_PV;
+ dc->b_info.max_memkb = 512 * 1024;
+ dc->b_info.u.pv.kernel = strdup(kernel);
+ dc->b_info.u.pv.ramdisk = strdup(ramdisk);
+ dc->b_info.cmdline = strdup("root=/dev/xvda1 selinux=0 console=hvc0");
+
+ /* need to add devices here; create returns immediatly otherwise
+ use xlu_disk_parse */
+ dc->num_disks = 0;
+ dc->disks = NULL;
+
+ dc->disks = malloc(sizeof(*dc->disks) * 2);
+ dc->num_disks = 2;
+
+ disk = &dc->disks[0];
+ libxl_device_disk_init(disk);
+ disk->pdev_path = strdup(hdd);
+ disk->vdev = strdup("xvda");
+ disk->format = LIBXL_DISK_FORMAT_QCOW2;
+ disk->readwrite = 1;
+
+ disk = &dc->disks[1];
+ libxl_device_disk_init(disk);
+ disk->pdev_path = strdup(cdrom);
+ disk->vdev = strdup("xvdb");
+ disk->format = LIBXL_DISK_FORMAT_RAW;
+ disk->removable = 1;
+ disk->is_cdrom = 1;
+}
+
+void generic_callback(libxl_ctx * ctx
+ __attribute__ ((unused)), int rc, void *for_callback)
+{
+ struct test *tc = for_callback;
+ send_libxl_callback_event(tc, rc);
+}
+
+int
+do_domain_create(struct test *t, libxl_domain_config * dc,
+ uint32_t * domid_out)
+{
+ t->ao_how.callback = generic_callback;
+ t->ao_how.u.for_callback = t;
+
+ return libxl_domain_create_new(t->ctx, dc, domid_out, &t->ao_how, 0);
+}
+
+int do_domain_suspend(struct test *t, uint32_t domid)
+{
+ int fd = open("/tmp/suspend", O_RDWR | O_CREAT | O_TRUNC); /* XXX leaked */
+
+ t->ao_how.callback = generic_callback;
+ t->ao_how.u.for_callback = t;
+
+ return libxl_domain_suspend(t->ctx, domid, fd, LIBXL_SUSPEND_LIVE,
+ &t->ao_how);
+}
--- /dev/null
+#ifndef __TESTCASE_UTILS_H
+#define __TESTCASE_UTILS_H
+
+#include <libxl.h>
+
+struct test;
+
+void init_domain_config(libxl_domain_config * dc,
+ char *name, char *kernel, char *ramdisk,
+ char *hdd, char *cdrom);
+int do_domain_create(struct test *t, libxl_domain_config * dc,
+ uint32_t * domid_out);
+int do_domain_suspend(struct test *t, uint32_t domid);
+
+#endif /* __TESTCASE_UTILS */
+++ /dev/null
-#include <assert.h>
-#include <pthread.h>
-#include <stdio.h>
-
-#include "thread_test.h"
-#include "xl_eventloop.h"
-
-
-int
-test_spawn(struct test *tc, xentoollog_logger *logger,
- void *(*fn)(struct test *))
-{
- /* Initialize the test structure */
- libxl_ctx_alloc(&tc->ctx, LIBXL_VERSION, 0, logger);
- register_callbacks(tc);
-
- /* Initialize the mailbox */
- pthread_mutex_init(&tc->mailbox_lock, NULL);
- pthread_cond_init(&tc->producer_cv, NULL);
- pthread_cond_init(&tc->consumer_cv, NULL);
- tc->mailbox.type = EV_NONE;
-
- /* Spawn a thread to run the test case */
- return pthread_create(&tc->thread, NULL,
- (void *(*)(void *)) fn, tc);
-}
-
-
-void
-test_destroy(struct test *tc) {
- pthread_mutex_destroy(&tc->mailbox_lock);
- pthread_cond_destroy(&tc->producer_cv);
- pthread_cond_destroy(&tc->consumer_cv);
- libxl_ctx_free(tc->ctx);
-}
-
-
-void
-send_event(struct test *tc, struct event ev)
-{
- pthread_mutex_lock(&tc->mailbox_lock);
- while (tc->mailbox.type != EV_NONE) {
- pthread_cond_wait(&tc->producer_cv, &tc->mailbox_lock);
- }
- tc->mailbox = ev;
- pthread_cond_signal(&tc->consumer_cv);
- pthread_mutex_unlock(&tc->mailbox_lock);
-}
-
-
-void
-recv_event(struct test *tc, struct event *ev)
-{
- pthread_mutex_lock(&tc->mailbox_lock);
- while (tc->mailbox.type == EV_NONE) {
- pthread_cond_wait(&tc->consumer_cv, &tc->mailbox_lock);
- }
- *ev = tc->mailbox;
- tc->mailbox.type = EV_NONE;
- pthread_cond_signal(&tc->producer_cv);
- pthread_mutex_unlock(&tc->mailbox_lock);
-}
-
-
-/* Wait until the an event matching the expected mask is posted.
- Ignores and discards any non-matching events received in the meantime. */
-void
-wait_for(struct test *tc, enum event_type expected)
-{
- struct event received;
- do {
- recv_event(tc, &received);
- } while(!(received.type & expected));
-}
-
-
-/* Wait until the the specified number of the expected events are posted.
- Ignores and discards any other events received in the meantime. */
-void
-wait_for_n(struct test *tc, enum event_type expected, int count)
-{
- while(count--) {
- wait_for(tc, expected);
- }
-}
-
-
-void
-send_fd_event(struct test *tc, int fd)
-{
- struct event ev;
- ev.type = EV_FD_EVENT;
- ev.u.fd = fd;
- send_event(tc, ev);
- printf("-> EV_FD_EVENT\n");
-}
-
-
-void
-send_libxl_callback_event(struct test *tc)
-{
- struct event ev;
- ev.type = EV_LIBXL_CALLBACK;
- send_event(tc, ev);
- printf("-> EV_LIBXL_CALLBACK\n");
-}
-
-
-void
-send_eventloop(struct test *tc)
-{
- struct event ev;
- ev.type = EV_EVENTLOOP;
- send_event(tc, ev);
- printf("-> EV_EVENTLOOP_TICK\n");
-}
-
+++ /dev/null
-#ifndef __THREAD_TEST_H
-#define __THREAD_TEST_H
-
-#include <libxl.h>
-#include <pthread.h>
-
-enum event_type {
- EV_NONE = 0x0000,
- EV_TEST_START = 0x0001,
- EV_LIBXL_CALLBACK = 0x0002,
- EV_FD_EVENT = 0x0004,
- EV_EVENTLOOP = 0x0008,
- EV_ANY = 0xffff
-};
-
-
-struct event {
- enum event_type type;
- union {
- int fd;
- } u;
-};
-
-struct test {
- /*
- * Test task structure.
- */
-
- /*
- * Pointer to the libxl context structure.
- * The memory which this points to is allocated and
- * owned by libxl.
- */
- libxl_ctx *ctx;
-
- /*
- * Structures containing the hooks which libxl
- * uses to register its timers and its interest in
- * file descriptors.
- * These structures must outlive the libxl context
- * in which they are used, so it makes sense to
- * keep them here alongside the ctx pointer.
- */
- libxl_event_hooks xl_ev_hooks;
- libxl_osevent_hooks xl_os_ev_hooks;
-
- /*
- * Structure defining per-function callbacks.
- * Must outlive the asynchronous call which uses it.
- */
- libxl_asyncop_how ao_how;
-
- /* The thread running the test */
- pthread_t thread;
-
- /* Test thread's mailbox and locks */
- pthread_mutex_t mailbox_lock;
- pthread_cond_t producer_cv;
- pthread_cond_t consumer_cv;
- struct event mailbox;
-};
-
-
-int test_spawn(struct test *tc, xentoollog_logger *logger,
- void *(*fn)(struct test *));
-void test_destroy(struct test *tc);
-void send_event(struct test *tc, struct event ev);
-void recv_event(struct test *tc, struct event *ev);
-void wait_for(struct test *tc, enum event_type expected);
-void wait_for_n(struct test *tc, enum event_type expected, int count);
-void send_fd_event(struct test *tc, int fd);
-void send_libxl_callback_event(struct test *tc);
-void send_eventloop(struct test *tc);
-
-#endif /* __THREAD_TEST_H */
+++ /dev/null
-int
-main(int argc __attribute__((unused)),
- char **argv __attribute__((unused)))
-{
- struct test t;
- test_init(&t);
- test_spawn(&t, testcase);
-
- send_fd_event(&t, 0);
- send_fd_event(&t, 1);
- send_fd_event(&t, 2);
- send_fd_event(&t, 3);
- send_fd_event(&t, 4);
-
- send_libxl_callback_event(&t);
- send_libxl_callback_event(&t);
-
- send_eventloop(&t);
-
- pthread_join(t.thread, NULL);
- test_destroy(&t);
- pthread_exit(NULL);
-}
-
+++ /dev/null
-#include <libxl_event.h>
-#include <stdlib.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#include <unistd.h>
-
-#include <sys/select.h>
-
-#include "xl_eventloop.h"
-#include "thread_test.h"
-#include "testcase.h"
-
-int
-main(int argc __attribute__((unused)), char **argv __attribute__((unused)))
-{
- struct test t;
- xentoollog_logger *logger;
-
- init_pollfds(pollfds, NUM_POLL_FDS);
-
- logger = (xentoollog_logger*)
- xtl_createlogger_stdiostream(stderr, XTL_PROGRESS, 0);
-
- if (!!test_spawn(&t, logger, testcase)) {
- perror("Failed to spawn test thread");
- exit(EXIT_FAILURE);
- }
-
- while (1) {
- int i, rc;
-
- rc = poll(pollfds, NUM_POLL_FDS, 2000);
- if (rc == 0) {
- send_eventloop(&t);
- continue;
- }
-
- for (i = 0; i < NUM_POLL_FDS; i++) {
-
- if (pollfds[i].revents & POLLIN) {
- fprintf(stderr, "fd %d readable\n", pollfds[i].fd);
- }
- if (pollfds[i].revents & POLLOUT) {
- fprintf(stderr, "fd %d writeable\n", pollfds[i].fd);
- }
- if (pollfds[i].revents & POLLPRI) {
- fprintf(stderr, "fd %d priority readable\n", pollfds[i].fd);
- }
- if (pollfds[i].revents & POLLERR) {
- fprintf(stderr, "fd %d output error\n", pollfds[i].fd);
- }
- if (pollfds[i].revents & POLLHUP) {
- fprintf(stderr, "fd %d hung up\n", pollfds[i].fd);
- }
- if (pollfds[i].revents & POLLNVAL) {
- fprintf(stderr, "fd %d not open\n", pollfds[i].fd);
- }
-
- if (pollfds[i].revents != 0) {
- struct libxl_task *lxt = &libxl_tasks[i];
- struct pollfd *pfd = &pollfds[i];
-
- libxl_osevent_occurred_fd(lxt->task->ctx, lxt->for_libxl,
- pfd->fd, pfd->events, pfd->revents);
- send_fd_event(&t, pfd->fd);
- }
- }
- }
-
- test_destroy(&t);
- xtl_logger_destroy(logger);
- exit(EXIT_SUCCESS);
-}
+++ /dev/null
-#include <assert.h>
-#include <libxl.h>
-#include <libxl_event.h>
-#include <stdlib.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#include <unistd.h>
-
-#include <sys/select.h>
-#include <string.h>
-#include "xl_eventloop.h"
-#include "thread_test.h"
-
-/*
- * These operations may need to be protected by a lock, since
- * the worker thread will make calls which require file descriptors
- * to be registered and the event loop will deregister them.
- * Alternatively, the test case will need to ask for file descriptors
- * to be registered and deregistered by sending messages to the main
- * event loop.
- */
-
-void
-init_pollfds(struct pollfd *pollfds, int numfds)
-{
- int i;
- for (i = 0; i < numfds; i++) {
- pollfds[i].fd = -1;
- pollfds[i].events = 0;
- pollfds[i].revents = 0;
- }
-}
-
-int
-add_poll_fd(struct pollfd *pollfds, int numfds, int fd, short events)
-{
- int i;
- for (i = 0; i < numfds; i++) {
- if (pollfds[i].fd == -1) {
- pollfds[i].fd = fd;
- pollfds[i].events = events;
- pollfds[i].revents = 0;
- return i;
- }
- }
-
- return -1;
-}
-
-int
-modify_poll_fd(struct pollfd *pollfds, int numfds, int slot, int fd, short events)
-{
- assert(slot < numfds);
- assert(pollfds[slot].fd == fd);
- pollfds[slot].events = events;
- return 0;
-}
-
-int
-remove_poll_fd(struct pollfd *pollfds, int numfds, int slot, int fd)
-{
- assert(slot < numfds);
- assert (pollfds[slot].fd != -1);
- assert (pollfds[slot].fd == fd);
- pollfds[slot].fd = -1;
- pollfds[slot].events = 0;
- pollfds[slot].revents = 0;
- return 0;
-}
-
-
-int
-fd_register(void *user, int fd, void **for_app_registration_out,
- short events, void *for_libxl)
-{
- int slot;
- struct test *t;
- struct libxl_task *lxt;
- t = user;
-
- slot = add_poll_fd(pollfds, NUM_POLL_FDS, fd, events);
- lxt = &libxl_tasks[slot];
- lxt->task = t;
- lxt->slot = slot;
- lxt->for_libxl = for_libxl;
- *for_app_registration_out = lxt;
-
- return 0;
-}
-
-int
-fd_modify(void *user, int fd, void **for_app_registration_update,
- short events)
-{
- struct test *t;
- struct libxl_task *lxt;
-
- assert(user);
- assert(for_app_registration_update);
- assert(*for_app_registration_update);
-
- t = user;
- lxt = *for_app_registration_update;
-
- modify_poll_fd(pollfds, NUM_POLL_FDS, lxt->slot, fd, events);
-
- return 0;
-}
-
-void
-fd_deregister(void *user, int fd, void *for_app_registration)
-{
- struct test *t;
- struct libxl_task *lxt;
-
-
- t = user;
- lxt = for_app_registration;
-
- remove_poll_fd(pollfds, NUM_POLL_FDS, lxt->slot, fd);
-
-}
-
-int
-timeout_register(void *user __attribute__((unused)),
- void **for_app_registration_out __attribute__((unused)),
- struct timeval abs __attribute__((unused)),
- void *for_libxl __attribute__((unused)))
-{
- return 0;
-}
-
-/* only ever called with abs={0,0}, meaning ASAP */
-int
-timeout_modify(void *user __attribute__((unused)), void **for_app_registration_update __attribute__((unused)),
- struct timeval abs __attribute__((unused)))
-{
- return 0;
-}
-
-/* will never be called */
-void
-timeout_deregister(void *user __attribute__((unused)), void *for_app_registration __attribute__((unused)))
-{
-}
-
-
-void
-print_domain_config(libxl_ctx *ctx, char *msg, libxl_domain_config *dc) {
- char *json = libxl_domain_config_to_json(ctx, dc);
- printf("%s: %s\n", msg, json);
- free(json);
-}
-
-
-void
-libxlEventHandler(void *data __attribute__((unused)), /* const */ libxl_event *event __attribute__((unused)))
-{
-}
-
-void
-register_callbacks(struct test *t)
-{
- /*
- * Register the hook functions which libxl will call
- * to register its timers and its interest in file
- * descriptors used for operations such as suspend
- * and resume.
- * The structs containing these hooks must outlive
- * the xl context.
- * Each callback will be called with a pointer to the
- * task structure.
- */
-
- /* Register ordinary async callbacks */
- t->xl_ev_hooks.event_occurs_mask = LIBXL_EVENTMASK_ALL;
- t->xl_ev_hooks.event_occurs = libxlEventHandler;
- t->xl_ev_hooks.disaster = 0;
- libxl_event_register_callbacks(t->ctx, &t->xl_ev_hooks, t);
-
- /* Register eventloop integration callbacks */
- t->xl_os_ev_hooks.fd_register = fd_register;
- t->xl_os_ev_hooks.fd_modify = fd_modify;
- t->xl_os_ev_hooks.fd_deregister = fd_deregister;
- t->xl_os_ev_hooks.timeout_register = timeout_register;
- t->xl_os_ev_hooks.timeout_modify = timeout_modify;
- t->xl_os_ev_hooks.timeout_deregister = timeout_deregister;
- libxl_osevent_register_hooks(t->ctx, &t->xl_os_ev_hooks, t);
-}
-
-void domain_create_cb(libxl_ctx *ctx, int rc, void *for_callback);
-
-void
-init_domain_config(libxl_domain_config *dc, char *name, char *kernel)
-{
- libxl_device_disk *disk;
-
- libxl_domain_config_init(dc);
-
- /* should we be using xlu_cfg_replace_string? */
- dc->c_info.name = strdup(name);
- dc->c_info.type = LIBXL_DOMAIN_TYPE_PV;
- dc->b_info.type = LIBXL_DOMAIN_TYPE_PV;
- dc->b_info.max_memkb = 512*1024;
- dc->b_info.u.pv.kernel = strdup(kernel);
- dc->b_info.u.pv.ramdisk = strdup("/root/foobar.img");
- dc->b_info.cmdline = strdup("root=/dev/xvda1 selinux=0 console=hvc0");
-
- /* need to add devices here; create returns immediatly otherwise
- use xlu_disk_parse? xlu_cfg_readfile? */
- dc->num_disks = 0;
- dc->disks = NULL;
-
- dc->disks = malloc(sizeof(*dc->disks) * 2);
- dc->num_disks = 2;
-
- disk = &dc->disks[0];
- libxl_device_disk_init(disk);
- disk->pdev_path = strdup("/root/Fedora-Cloud-Base-22-20150521.x86_64.qcow2");
- disk->vdev = strdup("xvda");
- disk->format = LIBXL_DISK_FORMAT_QCOW2;
- disk->readwrite = 1;
-
- disk = &dc->disks[1];
- libxl_device_disk_init(disk);
- disk->pdev_path = strdup("/root/init.iso");
- disk->vdev = strdup("xvdb");
- disk->format = LIBXL_DISK_FORMAT_RAW;
- disk->removable = 1;
- disk->is_cdrom = 1;
-}
-
-int
-do_domain_create(struct test *t, libxl_domain_config *dc, uint32_t *domid_out)
-{
- /* speak to andy cooper about valgrind runes to handle xen hypercalls */
-
- t->ao_how.callback = domain_create_cb;
- t->ao_how.u.for_callback = t; /* need to carry the other data to be freed */
-
- return libxl_domain_create_new(t->ctx, dc, domid_out, &t->ao_how, 0);
-}
-
-void
-domain_create_cb(libxl_ctx *ctx __attribute__((unused)),
- int rc __attribute__((unused)), void *for_callback)
-{
- struct test *tc = for_callback;
- send_libxl_callback_event(tc);
-}
-
-
-void domain_suspend_cb(libxl_ctx *ctx, int rc, void *for_callback);
-
-int
-do_domain_suspend(struct test *t, uint32_t domid)
-{
- /* need to issue a suspend in order to get an event channel wait
- * which should ask to register an fd or something else for us above */
- int fd = open("/tmp/suspend", O_RDWR|O_CREAT|O_TRUNC);
-
- t->ao_how.callback = domain_suspend_cb;
- /* t->ao_how.u.for_callback = (void*) fd; could rely on the test case to provide and close the fd - it can track it in a local variable */
-
- return libxl_domain_suspend(t->ctx, domid, fd, LIBXL_SUSPEND_LIVE, &t->ao_how);
-}
-
-void
-domain_suspend_cb(libxl_ctx *ctx __attribute__((unused)),
- int rc __attribute__((unused)),
- void *for_callback __attribute__((unused)))
-{
- /* struct test *t = for_callback; */
- /* close(t->in_args.domain_suspend.fd); */
- printf("< domain_suspend_cb()\n");
-}
-
+++ /dev/null
-#ifndef __XL_EVENTLOOP_H
-#define __XL_EVENTLOOP_H
-
-#include <libxl.h>
-#include <libxl_event.h>
-
-struct test;
-struct libxl_task {
- struct test *task;
- int slot;
- void *for_libxl;
-};
-
-
-enum { NUM_POLL_FDS = 10 };
-struct pollfd pollfds[NUM_POLL_FDS];
-struct libxl_task libxl_tasks[NUM_POLL_FDS];
-
-void init_pollfds(struct pollfd *pollfds, int numfds);
-
-void init_domain_config(libxl_domain_config *dc, char *name, char *kernel);
-
-void register_callbacks(struct test *t);
-int do_domain_create(struct test *t, libxl_domain_config *dc, uint32_t *domid_out);
-int do_domain_suspend(struct test *t, uint32_t domid);
-
-#endif /* __XL_EVENTLOOP_H */
#include <sys/select.h>
#include <string.h>
-void
-disk_test(XLU_Config *config, const char *spec)
+void disk_test(XLU_Config * config, const char *spec)
{
- libxl_device_disk disk;
- libxl_device_disk_init(&disk);
- xlu_disk_parse(config, 1, &spec, &disk);
+ libxl_device_disk disk;
+ libxl_device_disk_init(&disk);
+ xlu_disk_parse(config, 1, &spec, &disk);
}
-int
-main(int argc, char **argv)
+int main(int argc, char **argv)
{
- int err;
- XLU_Config *config;
- XLU_ConfigList *config_list;
- int count;
-
- FILE *report;
- char *report_filename = "/tmp/xlu.out";
- const char *response;
-
- if (argc != 2) {
- fprintf(stderr, "%s: no config file provided\n", argv[0]);
- exit(-1);
- }
-
- report = fopen(report_filename, "w+");
-
- config = xlu_cfg_init(report, report_filename);
- if (!config) {
- perror("xlu_cfg_init");
- exit(-1);
- }
-
- err = xlu_cfg_readfile(config, argv[1]);
- if (err != 0) {
- perror("xlu_cfg_readfile");
- exit(-1);
- }
-
- err = xlu_cfg_get_string(config, "name", &response, 1);
- if (err != 0) {
- perror("xlu_cfg_get_string");
- exit(-1);
- }
- printf("name: %s\n", response);
-
- err = xlu_cfg_get_string(config, "kernel", &response, 1);
- if (err != 0) {
- perror("xlu_cfg_get_string");
- exit(-1);
- }
- printf("kernel: %s\n", response);
-
- err = xlu_cfg_get_list(config, "disk", &config_list, &count, 1);
- if (err != 0) {
- perror("xlu_cfg_get_string");
- exit(-1);
- }
- printf("disk: %d items\n", count);
-
- disk_test(config, "qcow2:/root/Fedora-Cloud-Base-22-20150521.x86_64.qcow2,xvda,w");
- disk_test(config, "file:/root/init.iso,xvdb:cdrom,r");
- xlu_cfg_destroy(config);
- exit(0);
+ int err;
+ XLU_Config *config;
+ XLU_ConfigList *config_list;
+ int count;
+
+ FILE *report;
+ char *report_filename = "/tmp/xlu.out";
+ const char *response;
+
+ if (argc != 2) {
+ fprintf(stderr, "%s: no config file provided\n", argv[0]);
+ exit(-1);
+ }
+
+ report = fopen(report_filename, "w+");
+
+ config = xlu_cfg_init(report, report_filename);
+ if (!config) {
+ perror("xlu_cfg_init");
+ exit(-1);
+ }
+
+ err = xlu_cfg_readfile(config, argv[1]);
+ if (err != 0) {
+ perror("xlu_cfg_readfile");
+ exit(-1);
+ }
+
+ err = xlu_cfg_get_string(config, "name", &response, 1);
+ if (err != 0) {
+ perror("xlu_cfg_get_string");
+ exit(-1);
+ }
+ printf("name: %s\n", response);
+
+ err = xlu_cfg_get_string(config, "kernel", &response, 1);
+ if (err != 0) {
+ perror("xlu_cfg_get_string");
+ exit(-1);
+ }
+ printf("kernel: %s\n", response);
+
+ err = xlu_cfg_get_list(config, "disk", &config_list, &count, 1);
+ if (err != 0) {
+ perror("xlu_cfg_get_string");
+ exit(-1);
+ }
+ printf("disk: %d items\n", count);
+
+ disk_test(config,
+ "qcow2:/root/Fedora-Cloud-Base-22-20150521.x86_64.qcow2,xvda,w");
+ disk_test(config, "file:/root/init.iso,xvdb:cdrom,r");
+ xlu_cfg_destroy(config);
+ exit(0);
}
-