/* * RFifoLock tests * * Copyright Red Hat, Inc. 2013 * * Authors: * Stefan Hajnoczi <stefanha@redhat.com> * * This work is licensed under the terms of the GNU LGPL, version 2 or later. * See the COPYING.LIB file in the top-level directory. */ #include <glib.h> #include "qemu-common.h" #include "qemu/rfifolock.h" static void test_nesting(void) { RFifoLock lock; /* Trivial test, ensure the lock is recursive */ rfifolock_init(&lock, NULL, NULL); rfifolock_lock(&lock); rfifolock_lock(&lock); rfifolock_lock(&lock); rfifolock_unlock(&lock); rfifolock_unlock(&lock); rfifolock_unlock(&lock); rfifolock_destroy(&lock); } typedef struct { RFifoLock lock; int fd[2]; } CallbackTestData; static void rfifolock_cb(void *opaque) { CallbackTestData *data = opaque; int ret; char c = 0; ret = write(data->fd[1], &c, sizeof(c)); g_assert(ret == 1); } static void *callback_thread(void *opaque) { CallbackTestData *data = opaque; /* The other thread holds the lock so the contention callback will be * invoked... */ rfifolock_lock(&data->lock); rfifolock_unlock(&data->lock); return NULL; } static void test_callback(void) { CallbackTestData data; QemuThread thread; int ret; char c; rfifolock_init(&data.lock, rfifolock_cb, &data); ret = qemu_pipe(data.fd); g_assert(ret == 0); /* Hold lock but allow the callback to kick us by writing to the pipe */ rfifolock_lock(&data.lock); qemu_thread_create(&thread, "callback_thread", callback_thread, &data, QEMU_THREAD_JOINABLE); ret = read(data.fd[0], &c, sizeof(c)); g_assert(ret == 1); rfifolock_unlock(&data.lock); /* If we got here then the callback was invoked, as expected */ qemu_thread_join(&thread); close(data.fd[0]); close(data.fd[1]); rfifolock_destroy(&data.lock); } int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); g_test_add_func("/nesting", test_nesting); g_test_add_func("/callback", test_callback); return g_test_run(); }