All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/4] lib: extract ioctl_wrappers.c
@ 2014-03-12 15:39 Daniel Vetter
  2014-03-12 15:39 ` [PATCH 2/4] lib/ioctl_wrappers: api doc Daniel Vetter
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Daniel Vetter @ 2014-03-12 15:39 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

I want to group the ioctl wrappers and related functions into their
own documentation section.

Apparently gtkdoc refuses to obey this wish without a corespdonding
header. So appease it. Also gtkdoc seems to struggle with rebuilding a
bit ...

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 .../intel-gpu-tools/intel-gpu-tools-docs.xml       |   1 +
 lib/Makefile.sources                               |   2 +
 lib/drmtest.c                                      | 418 ------------------
 lib/drmtest.h                                      |  49 +--
 lib/ioctl_wrappers.c                               | 479 +++++++++++++++++++++
 lib/ioctl_wrappers.h                               |  82 ++++
 6 files changed, 566 insertions(+), 465 deletions(-)
 create mode 100644 lib/ioctl_wrappers.c
 create mode 100644 lib/ioctl_wrappers.h

diff --git a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
index a3a66f5393e0..bf85685fcbd5 100644
--- a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
+++ b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
@@ -20,6 +20,7 @@
     <xi:include href="xml/igt_debugfs.xml"/>
     <xi:include href="xml/igt_display.xml"/>
     <xi:include href="xml/igt_kms.xml"/>
+    <xi:include href="xml/ioctl_wrappers.xml"/>
     <xi:include href="xml/intel_batchbuffer.xml"/>
     <xi:include href="xml/intel_chipset.xml"/>
     <xi:include href="xml/intel_gpu_tools.xml"/>
diff --git a/lib/Makefile.sources b/lib/Makefile.sources
index cac9d1220ac2..ba4e8282c277 100644
--- a/lib/Makefile.sources
+++ b/lib/Makefile.sources
@@ -20,6 +20,8 @@ libintel_tools_la_SOURCES = 	\
 	intel_mmio.c		\
 	intel_pci.c		\
 	intel_reg.h		\
+	ioctl_wrappers.c	\
+	ioctl_wrappers.h	\
 	media_fill.c            \
 	media_fill.h            \
 	media_fill_gen7.c       \
diff --git a/lib/drmtest.c b/lib/drmtest.c
index 20918b7cac16..32bb85ad02bf 100644
--- a/lib/drmtest.c
+++ b/lib/drmtest.c
@@ -91,35 +91,6 @@ is_intel(int fd)
 	return IS_INTEL(devid);
 }
 
-bool gem_uses_aliasing_ppgtt(int fd)
-{
-	struct drm_i915_getparam gp;
-	int val;
-
-	gp.param = 18; /* HAS_ALIASING_PPGTT */
-	gp.value = &val;
-
-	if (ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp, sizeof(gp)))
-		return 0;
-
-	return val;
-}
-
-int gem_available_fences(int fd)
-{
-	struct drm_i915_getparam gp;
-	int val;
-
-	gp.param = I915_PARAM_NUM_FENCES_AVAIL;
-	gp.value = &val;
-
-	if (ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp, sizeof(gp)))
-		return 0;
-
-	return val;
-}
-
-
 #define LOCAL_I915_EXEC_VEBOX	(4 << 0)
 /* Ensure the gpu is idle by launching a nop execbuf and stalling for it. */
 void gem_quiescent_gpu(int fd)
@@ -336,395 +307,6 @@ int drm_open_any_render(void)
 	return fd;
 }
 
-int __gem_set_tiling(int fd, uint32_t handle, uint32_t tiling, uint32_t stride)
-{
-	struct drm_i915_gem_set_tiling st;
-	int ret;
-
-	memset(&st, 0, sizeof(st));
-	do {
-		st.handle = handle;
-		st.tiling_mode = tiling;
-		st.stride = tiling ? stride : 0;
-
-		ret = ioctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &st);
-	} while (ret == -1 && (errno == EINTR || errno == EAGAIN));
-	if (ret != 0)
-		return -errno;
-
-	igt_assert(st.tiling_mode == tiling);
-	return 0;
-}
-
-void gem_set_tiling(int fd, uint32_t handle, uint32_t tiling, uint32_t stride)
-{
-	igt_assert(__gem_set_tiling(fd, handle, tiling, stride) == 0);
-}
-
-bool gem_has_enable_ring(int fd,int param)
-{
-	drm_i915_getparam_t gp;
-	int ret, tmp;
-	memset(&gp, 0, sizeof(gp));
-
-	gp.value = &tmp;
-	gp.param = param;
-
-	ret = drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp);
-
-	if ((ret == 0) && (*gp.value > 0))
-		return true;
-	else
-		return false;
-}
-
-bool gem_has_bsd(int fd)
-{
-
-	return gem_has_enable_ring(fd,I915_PARAM_HAS_BSD);
-}
-
-bool gem_has_blt(int fd)
-{
-
-	return gem_has_enable_ring(fd,I915_PARAM_HAS_BLT);
-}
-
-#define LOCAL_I915_PARAM_HAS_VEBOX 22
-bool gem_has_vebox(int fd)
-{
-
-	return gem_has_enable_ring(fd,LOCAL_I915_PARAM_HAS_VEBOX);
-}
-
-int gem_get_num_rings(int fd)
-{
-	int num_rings = 1;	/* render ring is always available */
-
-	if (gem_has_bsd(fd))
-		num_rings++;
-	else
-		goto skip;
-
-	if (gem_has_blt(fd))
-		num_rings++;
-	else
-		goto skip;
-
-	if (gem_has_vebox(fd))
-		num_rings++;
-	else
-		goto skip;
-
-
-skip:
-	return num_rings;
-}
-
-struct local_drm_i915_gem_caching {
-	uint32_t handle;
-	uint32_t caching;
-};
-
-#define LOCAL_DRM_I915_GEM_SET_CACHEING    0x2f
-#define LOCAL_DRM_I915_GEM_GET_CACHEING    0x30
-#define LOCAL_DRM_IOCTL_I915_GEM_SET_CACHEING \
-	DRM_IOW(DRM_COMMAND_BASE + LOCAL_DRM_I915_GEM_SET_CACHEING, struct local_drm_i915_gem_caching)
-#define LOCAL_DRM_IOCTL_I915_GEM_GET_CACHEING \
-	DRM_IOWR(DRM_COMMAND_BASE + LOCAL_DRM_I915_GEM_GET_CACHEING, struct local_drm_i915_gem_caching)
-
-void gem_require_caching(int fd)
-{
-	struct local_drm_i915_gem_caching arg;
-	int ret;
-
-	arg.handle = gem_create(fd, 4096);
-	igt_assert(arg.handle != 0);
-
-	arg.caching = 0;
-	ret = ioctl(fd, LOCAL_DRM_IOCTL_I915_GEM_SET_CACHEING, &arg);
-	gem_close(fd, arg.handle);
-
-	igt_require(ret == 0);
-}
-
-void gem_set_caching(int fd, uint32_t handle, int caching)
-{
-	struct local_drm_i915_gem_caching arg;
-	int ret;
-
-	arg.handle = handle;
-	arg.caching = caching;
-	ret = ioctl(fd, LOCAL_DRM_IOCTL_I915_GEM_SET_CACHEING, &arg);
-
-	igt_assert(ret == 0 || (errno == ENOTTY || errno == EINVAL));
-	igt_require(ret == 0);
-}
-
-uint32_t gem_get_caching(int fd, uint32_t handle)
-{
-	struct local_drm_i915_gem_caching arg;
-	int ret;
-
-	arg.handle = handle;
-	arg.caching = 0;
-	ret = ioctl(fd, LOCAL_DRM_IOCTL_I915_GEM_GET_CACHEING, &arg);
-	igt_assert(ret == 0);
-
-	return arg.caching;
-}
-
-uint32_t gem_open(int fd, uint32_t name)
-{
-	struct drm_gem_open open_struct;
-	int ret;
-
-	open_struct.name = name;
-	ret = ioctl(fd, DRM_IOCTL_GEM_OPEN, &open_struct);
-	igt_assert(ret == 0);
-	igt_assert(open_struct.handle != 0);
-
-	return open_struct.handle;
-}
-
-uint32_t gem_flink(int fd, uint32_t handle)
-{
-	struct drm_gem_flink flink;
-	int ret;
-
-	flink.handle = handle;
-	ret = ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink);
-	igt_assert(ret == 0);
-
-	return flink.name;
-}
-
-void gem_close(int fd, uint32_t handle)
-{
-	struct drm_gem_close close_bo;
-
-	close_bo.handle = handle;
-	do_ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close_bo);
-}
-
-void gem_write(int fd, uint32_t handle, uint32_t offset, const void *buf, uint32_t size)
-{
-	struct drm_i915_gem_pwrite gem_pwrite;
-
-	gem_pwrite.handle = handle;
-	gem_pwrite.offset = offset;
-	gem_pwrite.size = size;
-	gem_pwrite.data_ptr = (uintptr_t)buf;
-	do_ioctl(fd, DRM_IOCTL_I915_GEM_PWRITE, &gem_pwrite);
-}
-
-void gem_read(int fd, uint32_t handle, uint32_t offset, void *buf, uint32_t length)
-{
-	struct drm_i915_gem_pread gem_pread;
-
-	gem_pread.handle = handle;
-	gem_pread.offset = offset;
-	gem_pread.size = length;
-	gem_pread.data_ptr = (uintptr_t)buf;
-	do_ioctl(fd, DRM_IOCTL_I915_GEM_PREAD, &gem_pread);
-}
-
-void gem_set_domain(int fd, uint32_t handle,
-		    uint32_t read_domains, uint32_t write_domain)
-{
-	struct drm_i915_gem_set_domain set_domain;
-
-	set_domain.handle = handle;
-	set_domain.read_domains = read_domains;
-	set_domain.write_domain = write_domain;
-
-	do_ioctl(fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain);
-}
-
-void gem_sync(int fd, uint32_t handle)
-{
-	gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
-}
-
-uint32_t __gem_create(int fd, int size)
-{
-	struct drm_i915_gem_create create;
-	int ret;
-
-	create.handle = 0;
-	create.size = size;
-	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create);
-
-	if (ret < 0)
-		return 0;
-	else
-		return create.handle;
-}
-
-uint32_t gem_create(int fd, int size)
-{
-	struct drm_i915_gem_create create;
-
-	create.handle = 0;
-	create.size = size;
-	do_ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create);
-	igt_assert(create.handle);
-
-	return create.handle;
-}
-
-void gem_execbuf(int fd, struct drm_i915_gem_execbuffer2 *execbuf)
-{
-	int ret;
-
-	ret = drmIoctl(fd,
-		       DRM_IOCTL_I915_GEM_EXECBUFFER2,
-		       execbuf);
-	igt_assert(ret == 0);
-}
-
-void *gem_mmap__gtt(int fd, uint32_t handle, int size, int prot)
-{
-	struct drm_i915_gem_mmap_gtt mmap_arg;
-	void *ptr;
-
-	mmap_arg.handle = handle;
-	if (drmIoctl(fd, DRM_IOCTL_I915_GEM_MMAP_GTT, &mmap_arg))
-		return NULL;
-
-	ptr = mmap64(0, size, prot, MAP_SHARED, fd, mmap_arg.offset);
-	if (ptr == MAP_FAILED)
-		ptr = NULL;
-
-	return ptr;
-}
-
-void *gem_mmap__cpu(int fd, uint32_t handle, int size, int prot)
-{
-	struct drm_i915_gem_mmap mmap_arg;
-
-	mmap_arg.handle = handle;
-	mmap_arg.offset = 0;
-	mmap_arg.size = size;
-	if (drmIoctl(fd, DRM_IOCTL_I915_GEM_MMAP, &mmap_arg))
-		return NULL;
-
-	return (void *)(uintptr_t)mmap_arg.addr_ptr;
-}
-
-uint64_t gem_available_aperture_size(int fd)
-{
-	struct drm_i915_gem_get_aperture aperture;
-
-	aperture.aper_size = 256*1024*1024;
-	do_ioctl(fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture);
-	return aperture.aper_available_size;
-}
-
-uint64_t gem_aperture_size(int fd)
-{
-	struct drm_i915_gem_get_aperture aperture;
-
-	aperture.aper_size = 256*1024*1024;
-	do_ioctl(fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture);
-	return aperture.aper_size;
-}
-
-uint64_t gem_mappable_aperture_size(void)
-{
-	struct pci_device *pci_dev;
-	int bar;
-	pci_dev = intel_get_pci_device();
-
-	if (intel_gen(pci_dev->device_id) < 3)
-		bar = 0;
-	else
-		bar = 2;
-
-	return pci_dev->regions[bar].size;
-}
-
-int gem_madvise(int fd, uint32_t handle, int state)
-{
-	struct drm_i915_gem_madvise madv;
-
-	madv.handle = handle;
-	madv.madv = state;
-	madv.retained = 1;
-	do_ioctl(fd, DRM_IOCTL_I915_GEM_MADVISE, &madv);
-
-	return madv.retained;
-}
-
-uint32_t gem_context_create(int fd)
-{
-	struct drm_i915_gem_context_create create;
-	int ret;
-
-	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_CONTEXT_CREATE, &create);
-	igt_require(ret == 0 || (errno != ENODEV && errno != EINVAL));
-	igt_assert(ret == 0);
-
-	return create.ctx_id;
-}
-
-void gem_sw_finish(int fd, uint32_t handle)
-{
-	struct drm_i915_gem_sw_finish finish;
-
-	finish.handle = handle;
-
-	do_ioctl(fd, DRM_IOCTL_I915_GEM_SW_FINISH, &finish);
-}
-
-bool gem_bo_busy(int fd, uint32_t handle)
-{
-	struct drm_i915_gem_busy busy;
-
-	busy.handle = handle;
-
-	do_ioctl(fd, DRM_IOCTL_I915_GEM_BUSY, &busy);
-
-	return !!busy.busy;
-}
-
-/* prime */
-int prime_handle_to_fd(int fd, uint32_t handle)
-{
-	struct drm_prime_handle args;
-
-	args.handle = handle;
-	args.flags = DRM_CLOEXEC;
-	args.fd = -1;
-
-	do_ioctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
-
-	return args.fd;
-}
-
-uint32_t prime_fd_to_handle(int fd, int dma_buf_fd)
-{
-	struct drm_prime_handle args;
-
-	args.fd = dma_buf_fd;
-	args.flags = 0;
-	args.handle = 0;
-
-	do_ioctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args);
-
-	return args.handle;
-}
-
-off_t prime_get_size(int dma_buf_fd)
-{
-	off_t ret;
-	ret = lseek(dma_buf_fd, 0, SEEK_END);
-	igt_assert(ret >= 0 || errno == ESPIPE);
-	igt_require(ret >= 0);
-
-	return ret;
-}
-
 /* signal interrupt helpers */
 static bool igt_only_list_subtests(void);
 
diff --git a/lib/drmtest.h b/lib/drmtest.h
index 40510dc0ef1e..61b989952d0c 100644
--- a/lib/drmtest.h
+++ b/lib/drmtest.h
@@ -44,6 +44,8 @@
 #include "intel_chipset.h"
 #include "intel_gpu_tools.h"
 
+#include "ioctl_wrappers.h"
+
 drm_intel_bo * gem_handle_to_libdrm_bo(drm_intel_bufmgr *bufmgr, int fd,
 				       const char *name, uint32_t handle);
 
@@ -53,53 +55,6 @@ int drm_open_any_render(void);
 
 void gem_quiescent_gpu(int fd);
 
-/* ioctl wrappers and similar stuff for bare metal testing */
-void gem_set_tiling(int fd, uint32_t handle, uint32_t tiling, uint32_t stride);
-int __gem_set_tiling(int fd, uint32_t handle, uint32_t tiling, uint32_t stride);
-bool gem_has_enable_ring(int fd,int param);
-bool gem_has_bsd(int fd);
-bool gem_has_blt(int fd);
-bool gem_has_vebox(int fd);
-int gem_get_num_rings(int fd);
-
-void gem_set_caching(int fd, uint32_t handle, int caching);
-uint32_t gem_get_caching(int fd, uint32_t handle);
-uint32_t gem_flink(int fd, uint32_t handle);
-uint32_t gem_open(int fd, uint32_t name);
-void gem_close(int fd, uint32_t handle);
-void gem_write(int fd, uint32_t handle, uint32_t offset,  const void *buf, uint32_t size);
-void gem_read(int fd, uint32_t handle, uint32_t offset, void *buf, uint32_t size);
-void gem_set_domain(int fd, uint32_t handle,
-		    uint32_t read_domains, uint32_t write_domain);
-void gem_sync(int fd, uint32_t handle);
-uint32_t __gem_create(int fd, int size);
-uint32_t gem_create(int fd, int size);
-void gem_execbuf(int fd, struct drm_i915_gem_execbuffer2 *execbuf);
-
-void *gem_mmap__gtt(int fd, uint32_t handle, int size, int prot);
-void *gem_mmap__cpu(int fd, uint32_t handle, int size, int prot);
-#define gem_mmap gem_mmap__gtt
-
-uint64_t gem_available_aperture_size(int fd);
-uint64_t gem_aperture_size(int fd);
-uint64_t gem_mappable_aperture_size(void);
-int gem_madvise(int fd, uint32_t handle, int state);
-
-uint32_t gem_context_create(int fd);
-
-void gem_sw_finish(int fd, uint32_t handle);
-
-bool gem_bo_busy(int fd, uint32_t handle);
-
-/* feature test helpers */
-bool gem_uses_aliasing_ppgtt(int fd);
-int gem_available_fences(int fd);
-
-/* prime */
-int prime_handle_to_fd(int fd, uint32_t handle);
-uint32_t prime_fd_to_handle(int fd, int dma_buf_fd);
-off_t prime_get_size(int dma_buf_fd);
-
 /* generally useful helpers */
 void igt_fork_signal_helper(void);
 void igt_stop_signal_helper(void);
diff --git a/lib/ioctl_wrappers.c b/lib/ioctl_wrappers.c
new file mode 100644
index 000000000000..d1e63c3d4df7
--- /dev/null
+++ b/lib/ioctl_wrappers.c
@@ -0,0 +1,479 @@
+/*
+ * Copyright © 2007, 2011, 2013, 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Eric Anholt <eric@anholt.net>
+ *    Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ */
+
+#ifndef ANDROID
+#define _GNU_SOURCE
+#else
+#include <libgen.h>
+#endif
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <signal.h>
+#include <pciaccess.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/utsname.h>
+#include <termios.h>
+
+#include "drmtest.h"
+#include "i915_drm.h"
+#include "intel_chipset.h"
+#include "intel_gpu_tools.h"
+#include "igt_debugfs.h"
+#include "../version.h"
+#include "config.h"
+
+#include "ioctl_wrappers.h"
+
+int __gem_set_tiling(int fd, uint32_t handle, uint32_t tiling, uint32_t stride)
+{
+	struct drm_i915_gem_set_tiling st;
+	int ret;
+
+	memset(&st, 0, sizeof(st));
+	do {
+		st.handle = handle;
+		st.tiling_mode = tiling;
+		st.stride = tiling ? stride : 0;
+
+		ret = ioctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &st);
+	} while (ret == -1 && (errno == EINTR || errno == EAGAIN));
+	if (ret != 0)
+		return -errno;
+
+	igt_assert(st.tiling_mode == tiling);
+	return 0;
+}
+
+void gem_set_tiling(int fd, uint32_t handle, uint32_t tiling, uint32_t stride)
+{
+	igt_assert(__gem_set_tiling(fd, handle, tiling, stride) == 0);
+}
+
+int gem_get_num_rings(int fd)
+{
+	int num_rings = 1;	/* render ring is always available */
+
+	if (gem_has_bsd(fd))
+		num_rings++;
+	else
+		goto skip;
+
+	if (gem_has_blt(fd))
+		num_rings++;
+	else
+		goto skip;
+
+	if (gem_has_vebox(fd))
+		num_rings++;
+	else
+		goto skip;
+
+
+skip:
+	return num_rings;
+}
+
+struct local_drm_i915_gem_caching {
+	uint32_t handle;
+	uint32_t caching;
+};
+
+#define LOCAL_DRM_I915_GEM_SET_CACHEING    0x2f
+#define LOCAL_DRM_I915_GEM_GET_CACHEING    0x30
+#define LOCAL_DRM_IOCTL_I915_GEM_SET_CACHEING \
+	DRM_IOW(DRM_COMMAND_BASE + LOCAL_DRM_I915_GEM_SET_CACHEING, struct local_drm_i915_gem_caching)
+#define LOCAL_DRM_IOCTL_I915_GEM_GET_CACHEING \
+	DRM_IOWR(DRM_COMMAND_BASE + LOCAL_DRM_I915_GEM_GET_CACHEING, struct local_drm_i915_gem_caching)
+
+void gem_set_caching(int fd, uint32_t handle, int caching)
+{
+	struct local_drm_i915_gem_caching arg;
+	int ret;
+
+	arg.handle = handle;
+	arg.caching = caching;
+	ret = ioctl(fd, LOCAL_DRM_IOCTL_I915_GEM_SET_CACHEING, &arg);
+
+	igt_assert(ret == 0 || (errno == ENOTTY || errno == EINVAL));
+	igt_require(ret == 0);
+}
+
+uint32_t gem_get_caching(int fd, uint32_t handle)
+{
+	struct local_drm_i915_gem_caching arg;
+	int ret;
+
+	arg.handle = handle;
+	arg.caching = 0;
+	ret = ioctl(fd, LOCAL_DRM_IOCTL_I915_GEM_GET_CACHEING, &arg);
+	igt_assert(ret == 0);
+
+	return arg.caching;
+}
+
+uint32_t gem_open(int fd, uint32_t name)
+{
+	struct drm_gem_open open_struct;
+	int ret;
+
+	open_struct.name = name;
+	ret = ioctl(fd, DRM_IOCTL_GEM_OPEN, &open_struct);
+	igt_assert(ret == 0);
+	igt_assert(open_struct.handle != 0);
+
+	return open_struct.handle;
+}
+
+uint32_t gem_flink(int fd, uint32_t handle)
+{
+	struct drm_gem_flink flink;
+	int ret;
+
+	flink.handle = handle;
+	ret = ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink);
+	igt_assert(ret == 0);
+
+	return flink.name;
+}
+
+void gem_close(int fd, uint32_t handle)
+{
+	struct drm_gem_close close_bo;
+
+	close_bo.handle = handle;
+	do_ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close_bo);
+}
+
+void gem_write(int fd, uint32_t handle, uint32_t offset, const void *buf, uint32_t size)
+{
+	struct drm_i915_gem_pwrite gem_pwrite;
+
+	gem_pwrite.handle = handle;
+	gem_pwrite.offset = offset;
+	gem_pwrite.size = size;
+	gem_pwrite.data_ptr = (uintptr_t)buf;
+	do_ioctl(fd, DRM_IOCTL_I915_GEM_PWRITE, &gem_pwrite);
+}
+
+void gem_read(int fd, uint32_t handle, uint32_t offset, void *buf, uint32_t length)
+{
+	struct drm_i915_gem_pread gem_pread;
+
+	gem_pread.handle = handle;
+	gem_pread.offset = offset;
+	gem_pread.size = length;
+	gem_pread.data_ptr = (uintptr_t)buf;
+	do_ioctl(fd, DRM_IOCTL_I915_GEM_PREAD, &gem_pread);
+}
+
+void gem_set_domain(int fd, uint32_t handle,
+		    uint32_t read_domains, uint32_t write_domain)
+{
+	struct drm_i915_gem_set_domain set_domain;
+
+	set_domain.handle = handle;
+	set_domain.read_domains = read_domains;
+	set_domain.write_domain = write_domain;
+
+	do_ioctl(fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain);
+}
+
+void gem_sync(int fd, uint32_t handle)
+{
+	gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
+}
+
+uint32_t __gem_create(int fd, int size)
+{
+	struct drm_i915_gem_create create;
+	int ret;
+
+	create.handle = 0;
+	create.size = size;
+	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create);
+
+	if (ret < 0)
+		return 0;
+	else
+		return create.handle;
+}
+
+uint32_t gem_create(int fd, int size)
+{
+	struct drm_i915_gem_create create;
+
+	create.handle = 0;
+	create.size = size;
+	do_ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create);
+	igt_assert(create.handle);
+
+	return create.handle;
+}
+
+void gem_execbuf(int fd, struct drm_i915_gem_execbuffer2 *execbuf)
+{
+	int ret;
+
+	ret = drmIoctl(fd,
+		       DRM_IOCTL_I915_GEM_EXECBUFFER2,
+		       execbuf);
+	igt_assert(ret == 0);
+}
+
+void *gem_mmap__gtt(int fd, uint32_t handle, int size, int prot)
+{
+	struct drm_i915_gem_mmap_gtt mmap_arg;
+	void *ptr;
+
+	mmap_arg.handle = handle;
+	if (drmIoctl(fd, DRM_IOCTL_I915_GEM_MMAP_GTT, &mmap_arg))
+		return NULL;
+
+	ptr = mmap64(0, size, prot, MAP_SHARED, fd, mmap_arg.offset);
+	if (ptr == MAP_FAILED)
+		ptr = NULL;
+
+	return ptr;
+}
+
+void *gem_mmap__cpu(int fd, uint32_t handle, int size, int prot)
+{
+	struct drm_i915_gem_mmap mmap_arg;
+
+	mmap_arg.handle = handle;
+	mmap_arg.offset = 0;
+	mmap_arg.size = size;
+	if (drmIoctl(fd, DRM_IOCTL_I915_GEM_MMAP, &mmap_arg))
+		return NULL;
+
+	return (void *)(uintptr_t)mmap_arg.addr_ptr;
+}
+
+int gem_madvise(int fd, uint32_t handle, int state)
+{
+	struct drm_i915_gem_madvise madv;
+
+	madv.handle = handle;
+	madv.madv = state;
+	madv.retained = 1;
+	do_ioctl(fd, DRM_IOCTL_I915_GEM_MADVISE, &madv);
+
+	return madv.retained;
+}
+
+uint32_t gem_context_create(int fd)
+{
+	struct drm_i915_gem_context_create create;
+	int ret;
+
+	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_CONTEXT_CREATE, &create);
+	igt_require(ret == 0 || (errno != ENODEV && errno != EINVAL));
+	igt_assert(ret == 0);
+
+	return create.ctx_id;
+}
+
+void gem_sw_finish(int fd, uint32_t handle)
+{
+	struct drm_i915_gem_sw_finish finish;
+
+	finish.handle = handle;
+
+	do_ioctl(fd, DRM_IOCTL_I915_GEM_SW_FINISH, &finish);
+}
+
+bool gem_bo_busy(int fd, uint32_t handle)
+{
+	struct drm_i915_gem_busy busy;
+
+	busy.handle = handle;
+
+	do_ioctl(fd, DRM_IOCTL_I915_GEM_BUSY, &busy);
+
+	return !!busy.busy;
+}
+
+
+/* feature test helpers */
+bool gem_uses_aliasing_ppgtt(int fd)
+{
+	struct drm_i915_getparam gp;
+	int val;
+
+	gp.param = 18; /* HAS_ALIASING_PPGTT */
+	gp.value = &val;
+
+	if (ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp, sizeof(gp)))
+		return 0;
+
+	return val;
+}
+
+int gem_available_fences(int fd)
+{
+	struct drm_i915_getparam gp;
+	int val;
+
+	gp.param = I915_PARAM_NUM_FENCES_AVAIL;
+	gp.value = &val;
+
+	if (ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp, sizeof(gp)))
+		return 0;
+
+	return val;
+}
+
+bool gem_has_enable_ring(int fd,int param)
+{
+	drm_i915_getparam_t gp;
+	int ret, tmp;
+	memset(&gp, 0, sizeof(gp));
+
+	gp.value = &tmp;
+	gp.param = param;
+
+	ret = drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp);
+
+	if ((ret == 0) && (*gp.value > 0))
+		return true;
+	else
+		return false;
+}
+
+bool gem_has_bsd(int fd)
+{
+
+	return gem_has_enable_ring(fd,I915_PARAM_HAS_BSD);
+}
+
+bool gem_has_blt(int fd)
+{
+
+	return gem_has_enable_ring(fd,I915_PARAM_HAS_BLT);
+}
+
+#define LOCAL_I915_PARAM_HAS_VEBOX 22
+bool gem_has_vebox(int fd)
+{
+
+	return gem_has_enable_ring(fd,LOCAL_I915_PARAM_HAS_VEBOX);
+}
+
+uint64_t gem_available_aperture_size(int fd)
+{
+	struct drm_i915_gem_get_aperture aperture;
+
+	aperture.aper_size = 256*1024*1024;
+	do_ioctl(fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture);
+	return aperture.aper_available_size;
+}
+
+uint64_t gem_aperture_size(int fd)
+{
+	struct drm_i915_gem_get_aperture aperture;
+
+	aperture.aper_size = 256*1024*1024;
+	do_ioctl(fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture);
+	return aperture.aper_size;
+}
+
+uint64_t gem_mappable_aperture_size(void)
+{
+	struct pci_device *pci_dev;
+	int bar;
+	pci_dev = intel_get_pci_device();
+
+	if (intel_gen(pci_dev->device_id) < 3)
+		bar = 0;
+	else
+		bar = 2;
+
+	return pci_dev->regions[bar].size;
+}
+
+void gem_require_caching(int fd)
+{
+	struct local_drm_i915_gem_caching arg;
+	int ret;
+
+	arg.handle = gem_create(fd, 4096);
+	igt_assert(arg.handle != 0);
+
+	arg.caching = 0;
+	ret = ioctl(fd, LOCAL_DRM_IOCTL_I915_GEM_SET_CACHEING, &arg);
+	gem_close(fd, arg.handle);
+
+	igt_require(ret == 0);
+}
+
+/* prime */
+int prime_handle_to_fd(int fd, uint32_t handle)
+{
+	struct drm_prime_handle args;
+
+	args.handle = handle;
+	args.flags = DRM_CLOEXEC;
+	args.fd = -1;
+
+	do_ioctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
+
+	return args.fd;
+}
+
+uint32_t prime_fd_to_handle(int fd, int dma_buf_fd)
+{
+	struct drm_prime_handle args;
+
+	args.fd = dma_buf_fd;
+	args.flags = 0;
+	args.handle = 0;
+
+	do_ioctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args);
+
+	return args.handle;
+}
+
+off_t prime_get_size(int dma_buf_fd)
+{
+	off_t ret;
+	ret = lseek(dma_buf_fd, 0, SEEK_END);
+	igt_assert(ret >= 0 || errno == ESPIPE);
+	igt_require(ret >= 0);
+
+	return ret;
+}
+
diff --git a/lib/ioctl_wrappers.h b/lib/ioctl_wrappers.h
new file mode 100644
index 000000000000..50706faec932
--- /dev/null
+++ b/lib/ioctl_wrappers.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright © 2007,2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Eric Anholt <eric@anholt.net>
+ *    Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ */
+
+
+#ifndef IOCTL_WRAPPERS_H
+#define IOCTL_WRAPPERS_H
+
+/* ioctl_wrappers.c:
+ *
+ * ioctl wrappers and similar stuff for bare metal testing */
+void gem_set_tiling(int fd, uint32_t handle, uint32_t tiling, uint32_t stride);
+int __gem_set_tiling(int fd, uint32_t handle, uint32_t tiling, uint32_t stride);
+int gem_get_num_rings(int fd);
+
+void gem_set_caching(int fd, uint32_t handle, int caching);
+uint32_t gem_get_caching(int fd, uint32_t handle);
+uint32_t gem_flink(int fd, uint32_t handle);
+uint32_t gem_open(int fd, uint32_t name);
+void gem_close(int fd, uint32_t handle);
+void gem_write(int fd, uint32_t handle, uint32_t offset,  const void *buf, uint32_t size);
+void gem_read(int fd, uint32_t handle, uint32_t offset, void *buf, uint32_t size);
+void gem_set_domain(int fd, uint32_t handle,
+		    uint32_t read_domains, uint32_t write_domain);
+void gem_sync(int fd, uint32_t handle);
+uint32_t __gem_create(int fd, int size);
+uint32_t gem_create(int fd, int size);
+void gem_execbuf(int fd, struct drm_i915_gem_execbuffer2 *execbuf);
+
+void *gem_mmap__gtt(int fd, uint32_t handle, int size, int prot);
+void *gem_mmap__cpu(int fd, uint32_t handle, int size, int prot);
+#define gem_mmap gem_mmap__gtt
+
+int gem_madvise(int fd, uint32_t handle, int state);
+
+uint32_t gem_context_create(int fd);
+
+void gem_sw_finish(int fd, uint32_t handle);
+
+bool gem_bo_busy(int fd, uint32_t handle);
+
+/* feature test helpers */
+bool gem_has_enable_ring(int fd,int param);
+bool gem_has_bsd(int fd);
+bool gem_has_blt(int fd);
+bool gem_has_vebox(int fd);
+bool gem_uses_aliasing_ppgtt(int fd);
+int gem_available_fences(int fd);
+uint64_t gem_available_aperture_size(int fd);
+uint64_t gem_aperture_size(int fd);
+uint64_t gem_mappable_aperture_size(void);
+
+/* prime */
+int prime_handle_to_fd(int fd, uint32_t handle);
+uint32_t prime_fd_to_handle(int fd, int dma_buf_fd);
+off_t prime_get_size(int dma_buf_fd);
+
+#endif /* IOCTL_WRAPPERS_H */
-- 
1.8.5.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/4] lib/ioctl_wrappers: api doc
  2014-03-12 15:39 [PATCH 1/4] lib: extract ioctl_wrappers.c Daniel Vetter
@ 2014-03-12 15:39 ` Daniel Vetter
  2014-03-12 15:39 ` [PATCH 3/4] lib: extract igt_core.c Daniel Vetter
  2014-03-12 15:39 ` [PATCH 4/4] lib/igt_core: api documentation Daniel Vetter
  2 siblings, 0 replies; 4+ messages in thread
From: Daniel Vetter @ 2014-03-12 15:39 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

Also some tiny polish to function interface:
- @caching in gem_set_tiling should be uint32_t to match the ioctl
  struct.
- s/size/length/ for gem_write/read.
- move gem_get_num_rings to the other ring feature helpers.

v2: Also demote gem_require_ring from static inline and move it, too.

v3: Also move gem_handle_to_libdrm_bo.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 lib/drmtest.c        |  17 --
 lib/drmtest.h        |  27 ---
 lib/ioctl_wrappers.c | 459 ++++++++++++++++++++++++++++++++++++++++++++++++---
 lib/ioctl_wrappers.h |  21 ++-
 4 files changed, 449 insertions(+), 75 deletions(-)

diff --git a/lib/drmtest.c b/lib/drmtest.c
index 32bb85ad02bf..b518b8116c00 100644
--- a/lib/drmtest.c
+++ b/lib/drmtest.c
@@ -59,23 +59,6 @@
 /* This file contains a bunch of wrapper functions to directly use gem ioctls.
  * Mostly useful to write kernel tests. */
 
-drm_intel_bo *
-gem_handle_to_libdrm_bo(drm_intel_bufmgr *bufmgr, int fd, const char *name, uint32_t handle)
-{
-	struct drm_gem_flink flink;
-	int ret;
-	drm_intel_bo *bo;
-
-	flink.handle = handle;
-	ret = ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink);
-	igt_assert(ret == 0);
-
-	bo = drm_intel_bo_gem_create_from_name(bufmgr, name, flink.name);
-	igt_assert(bo);
-
-	return bo;
-}
-
 static int
 is_intel(int fd)
 {
diff --git a/lib/drmtest.h b/lib/drmtest.h
index 61b989952d0c..a0b6e9fca28b 100644
--- a/lib/drmtest.h
+++ b/lib/drmtest.h
@@ -46,9 +46,6 @@
 
 #include "ioctl_wrappers.h"
 
-drm_intel_bo * gem_handle_to_libdrm_bo(drm_intel_bufmgr *bufmgr, int fd,
-				       const char *name, uint32_t handle);
-
 int drm_get_card(void);
 int drm_open_any(void);
 int drm_open_any_render(void);
@@ -309,30 +306,6 @@ extern enum igt_log_level igt_log_level;
 		} \
 	} while (0)
 
-/* check functions which auto-skip tests by calling igt_skip() */
-void gem_require_caching(int fd);
-static inline void gem_require_ring(int fd, int ring_id)
-{
-	switch (ring_id) {
-	case I915_EXEC_RENDER:
-		return;
-	case I915_EXEC_BLT:
-		igt_require(HAS_BLT_RING(intel_get_drm_devid(fd)));
-		return;
-	case I915_EXEC_BSD:
-		igt_require(HAS_BSD_RING(intel_get_drm_devid(fd)));
-		return;
-#ifdef I915_EXEC_VEBOX
-	case I915_EXEC_VEBOX:
-		igt_require(gem_has_vebox(fd));
-		return;
-#endif
-	default:
-		assert(0);
-		return;
-	}
-}
-
 /* helpers to automatically reduce test runtime in simulation */
 bool igt_run_in_simulation(void);
 #define SLOW_QUICK(slow,quick) (igt_run_in_simulation() ? (quick) : (slow))
diff --git a/lib/ioctl_wrappers.c b/lib/ioctl_wrappers.c
index d1e63c3d4df7..60512c7e1ab5 100644
--- a/lib/ioctl_wrappers.c
+++ b/lib/ioctl_wrappers.c
@@ -58,6 +58,53 @@
 
 #include "ioctl_wrappers.h"
 
+/**
+ * SECTION:ioctl_wrappers
+ * @short_description: ioctl wrappers and related functions
+ * @title: ioctl wrappers
+ *
+ * This helper library contains simple functions to wrap the raw drm/i915 kernel
+ * ioctls. The normal versions never pass any error codes to the caller and use
+ * igt_assert() to check for error conditions instead. For some ioctls raw
+ * wrappers which do pass on error codes are available. These raw wrappers have
+ * a __ prefix.
+ *
+ * For wrappers which check for feature bits there can also be two versions: The
+ * normal one simply returns a boolean to the caller. But when skipping the
+ * testcase entirely is the right action then it's better to use igt_skip()
+ * directly in the wrapper. Such functions have _require_ in their name to
+ * distinguish them.
+ */
+
+/**
+ * gem_handle_to_libdrm_bo:
+ * @bufmgr: libdrm buffer manager instance
+ * @fd: open i915 drm file descriptor
+ * @name: buffer name in libdrm
+ * @handle: gem buffer object handle
+ *
+ * This helper function imports a raw gem buffer handle into the libdrm buffer
+ * manager.
+ *
+ * Returns: The imported libdrm buffer manager object.
+ */
+drm_intel_bo *
+gem_handle_to_libdrm_bo(drm_intel_bufmgr *bufmgr, int fd, const char *name, uint32_t handle)
+{
+	struct drm_gem_flink flink;
+	int ret;
+	drm_intel_bo *bo;
+
+	flink.handle = handle;
+	ret = ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink);
+	igt_assert(ret == 0);
+
+	bo = drm_intel_bo_gem_create_from_name(bufmgr, name, flink.name);
+	igt_assert(bo);
+
+	return bo;
+}
+
 int __gem_set_tiling(int fd, uint32_t handle, uint32_t tiling, uint32_t stride)
 {
 	struct drm_i915_gem_set_tiling st;
@@ -78,35 +125,20 @@ int __gem_set_tiling(int fd, uint32_t handle, uint32_t tiling, uint32_t stride)
 	return 0;
 }
 
+/**
+ * gem_set_tiling:
+ * @fd: open i915 drm file descriptor
+ * @handle: gem buffer object handle
+ * @tiling: tiling mode bits
+ * @stride: stride of the buffer when using a tiled mode, otherwise must be 0
+ *
+ * This wraps the SET_TILING ioctl.
+ */
 void gem_set_tiling(int fd, uint32_t handle, uint32_t tiling, uint32_t stride)
 {
 	igt_assert(__gem_set_tiling(fd, handle, tiling, stride) == 0);
 }
 
-int gem_get_num_rings(int fd)
-{
-	int num_rings = 1;	/* render ring is always available */
-
-	if (gem_has_bsd(fd))
-		num_rings++;
-	else
-		goto skip;
-
-	if (gem_has_blt(fd))
-		num_rings++;
-	else
-		goto skip;
-
-	if (gem_has_vebox(fd))
-		num_rings++;
-	else
-		goto skip;
-
-
-skip:
-	return num_rings;
-}
-
 struct local_drm_i915_gem_caching {
 	uint32_t handle;
 	uint32_t caching;
@@ -119,7 +151,18 @@ struct local_drm_i915_gem_caching {
 #define LOCAL_DRM_IOCTL_I915_GEM_GET_CACHEING \
 	DRM_IOWR(DRM_COMMAND_BASE + LOCAL_DRM_I915_GEM_GET_CACHEING, struct local_drm_i915_gem_caching)
 
-void gem_set_caching(int fd, uint32_t handle, int caching)
+/**
+ * gem_set_caching:
+ * @fd: open i915 drm file descriptor
+ * @handle: gem buffer object handle
+ * @caching: caching mode bits
+ *
+ * This wraps the SET_CACHING ioctl. Note that this function internally calls
+ * igt_require() when SET_CACHING isn't available, hence automatically skips the
+ * test. Therefore always extract test logic which uses this into its own
+ * subtest.
+ */
+void gem_set_caching(int fd, uint32_t handle, uint32_t caching)
 {
 	struct local_drm_i915_gem_caching arg;
 	int ret;
@@ -132,6 +175,15 @@ void gem_set_caching(int fd, uint32_t handle, int caching)
 	igt_require(ret == 0);
 }
 
+/**
+ * gem_get_caching:
+ * @fd: open i915 drm file descriptor
+ * @handle: gem buffer object handle
+ *
+ * This wraps the GET_CACHING ioctl.
+ *
+ * Returns: The current caching mode bits.
+ */
 uint32_t gem_get_caching(int fd, uint32_t handle)
 {
 	struct local_drm_i915_gem_caching arg;
@@ -145,6 +197,15 @@ uint32_t gem_get_caching(int fd, uint32_t handle)
 	return arg.caching;
 }
 
+/**
+ * gem_open:
+ * @fd: open i915 drm file descriptor
+ * @name: flink buffer name
+ *
+ * This wraps the GEM_OPEN ioctl, which is used to import an flink name.
+ *
+ * Returns: gem file-private buffer handle of the open object.
+ */
 uint32_t gem_open(int fd, uint32_t name)
 {
 	struct drm_gem_open open_struct;
@@ -158,6 +219,17 @@ uint32_t gem_open(int fd, uint32_t name)
 	return open_struct.handle;
 }
 
+/**
+ * gem_flink:
+ * @fd: open i915 drm file descriptor
+ * @handle: file-private gem buffer object handle
+ *
+ * This wraps the GEM_FLINK ioctl, which is used to export a gem buffer object
+ * into the device-global flink namespace. See gem_open() for opening such a
+ * buffer name on a different i915 drm file descriptor.
+ *
+ * Returns: The created flink buffer name.
+ */
 uint32_t gem_flink(int fd, uint32_t handle)
 {
 	struct drm_gem_flink flink;
@@ -170,6 +242,14 @@ uint32_t gem_flink(int fd, uint32_t handle)
 	return flink.name;
 }
 
+/**
+ * gem_close:
+ * @fd: open i915 drm file descriptor
+ * @handle: gem buffer object handle
+ *
+ * This wraps the GEM_CLOSE ioctl, which to release a file-private gem buffer
+ * handle.
+ */
 void gem_close(int fd, uint32_t handle)
 {
 	struct drm_gem_close close_bo;
@@ -178,17 +258,39 @@ void gem_close(int fd, uint32_t handle)
 	do_ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close_bo);
 }
 
-void gem_write(int fd, uint32_t handle, uint32_t offset, const void *buf, uint32_t size)
+/**
+ * gem_write:
+ * @fd: open i915 drm file descriptor
+ * @handle: gem buffer object handle
+ * @offset: offset within the buffer of the subrange
+ * @buf: pointer to the data to write into the buffer
+ * @length: size of the subrange
+ *
+ * This wraps the PWRITE ioctl, which is to upload a linear data to a subrange
+ * of a gem buffer object.
+ */
+void gem_write(int fd, uint32_t handle, uint32_t offset, const void *buf, uint32_t length)
 {
 	struct drm_i915_gem_pwrite gem_pwrite;
 
 	gem_pwrite.handle = handle;
 	gem_pwrite.offset = offset;
-	gem_pwrite.size = size;
+	gem_pwrite.size = length;
 	gem_pwrite.data_ptr = (uintptr_t)buf;
 	do_ioctl(fd, DRM_IOCTL_I915_GEM_PWRITE, &gem_pwrite);
 }
 
+/**
+ * gem_read:
+ * @fd: open i915 drm file descriptor
+ * @handle: gem buffer object handle
+ * @offset: offset within the buffer of the subrange
+ * @buf: pointer to the data to read into
+ * @length: size of the subrange
+ *
+ * This wraps the PREAD ioctl, which is to download a linear data to a subrange
+ * of a gem buffer object.
+ */
 void gem_read(int fd, uint32_t handle, uint32_t offset, void *buf, uint32_t length)
 {
 	struct drm_i915_gem_pread gem_pread;
@@ -200,6 +302,18 @@ void gem_read(int fd, uint32_t handle, uint32_t offset, void *buf, uint32_t leng
 	do_ioctl(fd, DRM_IOCTL_I915_GEM_PREAD, &gem_pread);
 }
 
+/**
+ * gem_set_domain:
+ * @fd: open i915 drm file descriptor
+ * @handle: gem buffer object handle
+ * @read_domains: gem domain bits for read access
+ * @write_domain: gem domain bit for write access
+ *
+ * This wraps the SET_DOMAIN ioctl, which is used to control the coherency of
+ * the gem buffer object between the cpu and gtt mappings. It is also use to
+ * synchronize with outstanding rendering in general, but for that use-case
+ * please have a look at gem_sync().
+ */
 void gem_set_domain(int fd, uint32_t handle,
 		    uint32_t read_domains, uint32_t write_domain)
 {
@@ -212,6 +326,14 @@ void gem_set_domain(int fd, uint32_t handle,
 	do_ioctl(fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain);
 }
 
+/**
+ * gem_sync:
+ * @fd: open i915 drm file descriptor
+ * @handle: gem buffer object handle
+ *
+ * This is a wrapper around gem_set_domain() which simply blocks for any
+ * outstanding rendering to complete.
+ */
 void gem_sync(int fd, uint32_t handle)
 {
 	gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
@@ -232,6 +354,16 @@ uint32_t __gem_create(int fd, int size)
 		return create.handle;
 }
 
+/**
+ * gem_create:
+ * @fd: open i915 drm file descriptor
+ * @size: desired size of the buffer
+ *
+ * This wraps the GEM_CREATE ioctl, which allocates a new gem buffer object of
+ * @size.
+ *
+ * Returns: The file-private handle of the created buffer object
+ */
 uint32_t gem_create(int fd, int size)
 {
 	struct drm_i915_gem_create create;
@@ -244,6 +376,14 @@ uint32_t gem_create(int fd, int size)
 	return create.handle;
 }
 
+/**
+ * gem_execbuf:
+ * @fd: open i915 drm file descriptor
+ * @execbuf: execbuffer data structure
+ *
+ * This wraps the EXECBUFFER2 ioctl, which submits a batchbuffer for the gpu to
+ * run.
+ */
 void gem_execbuf(int fd, struct drm_i915_gem_execbuffer2 *execbuf)
 {
 	int ret;
@@ -254,6 +394,18 @@ void gem_execbuf(int fd, struct drm_i915_gem_execbuffer2 *execbuf)
 	igt_assert(ret == 0);
 }
 
+/**
+ * gem_mmap__gtt:
+ * @fd: open i915 drm file descriptor
+ * @handle: gem buffer object handle
+ * @size: size of the gem buffer
+ * @prot: memory protection bits as used by mmap()
+ *
+ * This functions wraps up procedure to establish a memory mapping through the
+ * GTT.
+ *
+ * Returns: A pointer to the created memory mapping.
+ */
 void *gem_mmap__gtt(int fd, uint32_t handle, int size, int prot)
 {
 	struct drm_i915_gem_mmap_gtt mmap_arg;
@@ -270,6 +422,18 @@ void *gem_mmap__gtt(int fd, uint32_t handle, int size, int prot)
 	return ptr;
 }
 
+/**
+ * gem_mmap__cpu:
+ * @fd: open i915 drm file descriptor
+ * @handle: gem buffer object handle
+ * @size: size of the gem buffer
+ * @prot: memory protection bits as used by mmap()
+ *
+ * This functions wraps up procedure to establish a memory mapping through
+ * direct cpu access, bypassing the gpu completely.
+ *
+ * Returns: A pointer to the created memory mapping.
+ */
 void *gem_mmap__cpu(int fd, uint32_t handle, int size, int prot)
 {
 	struct drm_i915_gem_mmap mmap_arg;
@@ -283,6 +447,20 @@ void *gem_mmap__cpu(int fd, uint32_t handle, int size, int prot)
 	return (void *)(uintptr_t)mmap_arg.addr_ptr;
 }
 
+/**
+ * gem_madvise:
+ * @fd: open i915 drm file descriptor
+ * @handle: gem buffer object handle
+ * @state: desired madvise state
+ *
+ * This is a wraps the MADVISE ioctl, which is used in libdrm to implement
+ * opportunistic buffer object caching. Objects in the cache are set to DONTNEED
+ * (internally in the kernel tracked as purgeable objects). When such a cached
+ * object is in need again it must be set back to WILLNEED before first use.
+ *
+ * Returns: When setting the madvise state to WILLNEED this returns whether the
+ * backing storage was still avialable or not.
+ */
 int gem_madvise(int fd, uint32_t handle, int state)
 {
 	struct drm_i915_gem_madvise madv;
@@ -295,6 +473,17 @@ int gem_madvise(int fd, uint32_t handle, int state)
 	return madv.retained;
 }
 
+/**
+ * gem_context_create:
+ * @fd: open i915 drm file descriptor
+ *
+ * This is a wraps the CONTEXT_CREATE ioctl, which is used to allocate a new
+ * hardware context. Not that similarly to gem_set_caching() this wrapper calls
+ * igt_require() internally to correctly skip on kernels and platforms where hw
+ * context support is not available.
+ *
+ * Returns: The id of the allocated hw context.
+ */
 uint32_t gem_context_create(int fd)
 {
 	struct drm_i915_gem_context_create create;
@@ -307,6 +496,15 @@ uint32_t gem_context_create(int fd)
 	return create.ctx_id;
 }
 
+/**
+ * gem_sw_finish:
+ * @fd: open i915 drm file descriptor
+ * @handle: gem buffer object handle
+ *
+ * This is a wraps the SW_FINISH ioctl, which is used to flush out frontbuffer
+ * rendering done through the direct cpu memory mappings. Shipping userspace
+ * does _not_ call this after frontbuffer rendering through gtt memory mappings.
+ */
 void gem_sw_finish(int fd, uint32_t handle)
 {
 	struct drm_i915_gem_sw_finish finish;
@@ -316,6 +514,16 @@ void gem_sw_finish(int fd, uint32_t handle)
 	do_ioctl(fd, DRM_IOCTL_I915_GEM_SW_FINISH, &finish);
 }
 
+/**
+ * gem_bo_busy:
+ * @fd: open i915 drm file descriptor
+ * @handle: gem buffer object handle
+ *
+ * This is a wraps the BUSY ioctl, which tells whether a buffer object is still
+ * actively used by the gpu in a execbuffer.
+ *
+ * Returns: The busy state of the buffer object.
+ */
 bool gem_bo_busy(int fd, uint32_t handle)
 {
 	struct drm_i915_gem_busy busy;
@@ -329,6 +537,19 @@ bool gem_bo_busy(int fd, uint32_t handle)
 
 
 /* feature test helpers */
+
+/**
+ * gem_uses_aliasing_ppgtt:
+ * @fd: open i915 drm file descriptor
+ *
+ * Feature test macro to check whether the kernel internally uses ppgtt to
+ * execute batches. The /aliasing/ in the function name is a bit a misnomer,
+ * this driver parameter is also true when full ppgtt address spaces are
+ * availabel since for batchbuffer construction only ppgtt or global gtt is
+ * relevant.
+ *
+ * Returns: Whether batches are run through ppgtt.
+ */
 bool gem_uses_aliasing_ppgtt(int fd)
 {
 	struct drm_i915_getparam gp;
@@ -343,6 +564,15 @@ bool gem_uses_aliasing_ppgtt(int fd)
 	return val;
 }
 
+/**
+ * gem_uses_aliasing_ppgtt:
+ * @fd: open i915 drm file descriptor
+ *
+ * Feature test macro to query the kernel for the number of available fences
+ * useable in a batchbuffer. Only relevant for pre-gen4.
+ *
+ * Returns: The number of available fences.
+ */
 int gem_available_fences(int fd)
 {
 	struct drm_i915_getparam gp;
@@ -357,6 +587,51 @@ int gem_available_fences(int fd)
 	return val;
 }
 
+/**
+ * gem_get_num_rings:
+ * @fd: open i915 drm file descriptor
+ *
+ * Feature test macro to query the number of avaible rings. This is useful in
+ * test loops which need to step through all rings and similar logic.
+ *
+ * For more explicit tests of ring availability see gem_has_enable_ring() and
+ * the ring specific versions like gem_has_bsd().
+ *
+ * Returns: The number of available rings.
+ */
+int gem_get_num_rings(int fd)
+{
+	int num_rings = 1;	/* render ring is always available */
+
+	if (gem_has_bsd(fd))
+		num_rings++;
+	else
+		goto skip;
+
+	if (gem_has_blt(fd))
+		num_rings++;
+	else
+		goto skip;
+
+	if (gem_has_vebox(fd))
+		num_rings++;
+	else
+		goto skip;
+
+
+skip:
+	return num_rings;
+}
+
+/**
+ * gem_has_enable_ring:
+ * @fd: open i915 drm file descriptor
+ * @param: ring flag bit as used in gem_execbuf()
+ *
+ * Feature test macro to query whether a specific ring is available.
+ *
+ * Returns: Whether the ring is avaible or not.
+ */
 bool gem_has_enable_ring(int fd,int param)
 {
 	drm_i915_getparam_t gp;
@@ -374,12 +649,34 @@ bool gem_has_enable_ring(int fd,int param)
 		return false;
 }
 
+/**
+ * gem_has_bsd:
+ * @fd: open i915 drm file descriptor
+ *
+ * Feature test macro to query whether the BSD ring is available. This is simply
+ * a specific version of gem_has_enable_ring() for the BSD ring.
+ *
+ * Note that recent Bspec calls this the VCS ring for Video Command Submission.
+ *
+ * Returns: Whether the BSD ring is avaible or not.
+ */
 bool gem_has_bsd(int fd)
 {
 
 	return gem_has_enable_ring(fd,I915_PARAM_HAS_BSD);
 }
 
+/**
+ * gem_has_blt:
+ * @fd: open i915 drm file descriptor
+ *
+ * Feature test macro to query whether the blitter ring is available. This is simply
+ * a specific version of gem_has_enable_ring() for the blitter ring.
+ *
+ * Note that recent Bspec calls this the BCS ring for Blitter Command Submission.
+ *
+ * Returns: Whether the blitter ring is avaible or not.
+ */
 bool gem_has_blt(int fd)
 {
 
@@ -387,12 +684,33 @@ bool gem_has_blt(int fd)
 }
 
 #define LOCAL_I915_PARAM_HAS_VEBOX 22
+/**
+ * gem_has_vebox:
+ * @fd: open i915 drm file descriptor
+ *
+ * Feature test macro to query whether the vebox ring is available. This is simply
+ * a specific version of gem_has_enable_ring() for the vebox ring.
+ *
+ * Note that recent Bspec calls this the VECS ring for Video Enhancement Command
+ * Submission.
+ *
+ * Returns: Whether the vebox ring is avaible or not.
+ */
 bool gem_has_vebox(int fd)
 {
 
 	return gem_has_enable_ring(fd,LOCAL_I915_PARAM_HAS_VEBOX);
 }
 
+/**
+ * gem_available_aperture_size:
+ * @fd: open i915 drm file descriptor
+ *
+ * Feature test macro to query the kernel for the available gpu aperture size
+ * useable in a batchbuffer.
+ *
+ * Returns: The available gtt address space size.
+ */
 uint64_t gem_available_aperture_size(int fd)
 {
 	struct drm_i915_gem_get_aperture aperture;
@@ -402,6 +720,14 @@ uint64_t gem_available_aperture_size(int fd)
 	return aperture.aper_available_size;
 }
 
+/**
+ * gem_aperture_size:
+ * @fd: open i915 drm file descriptor
+ *
+ * Feature test macro to query the kernel for the total gpu aperture size.
+ *
+ * Returns: The total gtt address space size.
+ */
 uint64_t gem_aperture_size(int fd)
 {
 	struct drm_i915_gem_get_aperture aperture;
@@ -411,6 +737,15 @@ uint64_t gem_aperture_size(int fd)
 	return aperture.aper_size;
 }
 
+/**
+ * gem_aperture_size:
+ * @fd: open i915 drm file descriptor
+ *
+ * Feature test macro to query the kernel for the mappable gpu aperture size.
+ * This is the area avaialble for GTT memory mappings.
+ *
+ * Returns: The mappable gtt address space size.
+ */
 uint64_t gem_mappable_aperture_size(void)
 {
 	struct pci_device *pci_dev;
@@ -425,6 +760,13 @@ uint64_t gem_mappable_aperture_size(void)
 	return pci_dev->regions[bar].size;
 }
 
+/**
+ * gem_require_caching:
+ * @fd: open i915 drm file descriptor
+ *
+ * Feature test macro to query whether buffer object caching control is
+ * available. Automatically skips through igt_require() if not.
+ */
 void gem_require_caching(int fd)
 {
 	struct local_drm_i915_gem_caching arg;
@@ -440,7 +782,50 @@ void gem_require_caching(int fd)
 	igt_require(ret == 0);
 }
 
+/**
+ * gem_require_ring:
+ * @fd: open i915 drm file descriptor
+ * @id: ring flag bit as used in gem_execbuf()
+ *
+ * Feature test macro to query whether a specific ring is available.
+ * In contrast to gem_has_enable_ring() this automagically skips if the ring
+ * isn't available by calling igt_require().
+ */
+void gem_require_ring(int fd, int ring_id)
+{
+	switch (ring_id) {
+	case I915_EXEC_RENDER:
+		return;
+	case I915_EXEC_BLT:
+		igt_require(HAS_BLT_RING(intel_get_drm_devid(fd)));
+		return;
+	case I915_EXEC_BSD:
+		igt_require(HAS_BSD_RING(intel_get_drm_devid(fd)));
+		return;
+#ifdef I915_EXEC_VEBOX
+	case I915_EXEC_VEBOX:
+		igt_require(gem_has_vebox(fd));
+		return;
+#endif
+	default:
+		assert(0);
+		return;
+	}
+}
+
 /* prime */
+
+/**
+ * prime_handle_to_fd:
+ * @fd: open i915 drm file descriptor
+ * @handle: file-private gem buffer object handle
+ *
+ * This wraps the PRIME_HANDLE_TO_FD ioctl, which is used to export a gem buffer
+ * object into a global (i.e. potentially cross-device) dma-buf file-descriptor
+ * handle.
+ *
+ * Returns: The created dma-buf fd handle.
+ */
 int prime_handle_to_fd(int fd, uint32_t handle)
 {
 	struct drm_prime_handle args;
@@ -454,6 +839,16 @@ int prime_handle_to_fd(int fd, uint32_t handle)
 	return args.fd;
 }
 
+/**
+ * prime_fd_to_handle:
+ * @fd: open i915 drm file descriptor
+ * @dma_buf_fd: dma-buf fd handle
+ *
+ * This wraps the PRIME_FD_TO_HANDLE ioctl, which is used to import a dma-buf
+ * file-descriptor into a gem buffer object.
+ *
+ * Returns: The created gem buffer object handle.
+ */
 uint32_t prime_fd_to_handle(int fd, int dma_buf_fd)
 {
 	struct drm_prime_handle args;
@@ -467,6 +862,16 @@ uint32_t prime_fd_to_handle(int fd, int dma_buf_fd)
 	return args.handle;
 }
 
+/**
+ * prime_get_size:
+ * @dma_buf_fd: dma-buf fd handle
+ *
+ * This wraps the lseek() protocol used to query the invariant size of a
+ * dma-buf.  Not all kernels support this, which is check with igt_require() and
+ * so will result in automagic test skipping.
+ *
+ * Returns: The lifetime-invariant size of the dma-buf object.
+ */
 off_t prime_get_size(int dma_buf_fd)
 {
 	off_t ret;
diff --git a/lib/ioctl_wrappers.h b/lib/ioctl_wrappers.h
index 50706faec932..6e3eb0f2d0dc 100644
--- a/lib/ioctl_wrappers.h
+++ b/lib/ioctl_wrappers.h
@@ -30,20 +30,23 @@
 #ifndef IOCTL_WRAPPERS_H
 #define IOCTL_WRAPPERS_H
 
+/* libdrm interfacing */
+drm_intel_bo * gem_handle_to_libdrm_bo(drm_intel_bufmgr *bufmgr, int fd,
+				       const char *name, uint32_t handle);
+
 /* ioctl_wrappers.c:
  *
  * ioctl wrappers and similar stuff for bare metal testing */
 void gem_set_tiling(int fd, uint32_t handle, uint32_t tiling, uint32_t stride);
 int __gem_set_tiling(int fd, uint32_t handle, uint32_t tiling, uint32_t stride);
-int gem_get_num_rings(int fd);
 
-void gem_set_caching(int fd, uint32_t handle, int caching);
+void gem_set_caching(int fd, uint32_t handle, uint32_t caching);
 uint32_t gem_get_caching(int fd, uint32_t handle);
 uint32_t gem_flink(int fd, uint32_t handle);
 uint32_t gem_open(int fd, uint32_t name);
 void gem_close(int fd, uint32_t handle);
-void gem_write(int fd, uint32_t handle, uint32_t offset,  const void *buf, uint32_t size);
-void gem_read(int fd, uint32_t handle, uint32_t offset, void *buf, uint32_t size);
+void gem_write(int fd, uint32_t handle, uint32_t offset,  const void *buf, uint32_t length);
+void gem_read(int fd, uint32_t handle, uint32_t offset, void *buf, uint32_t length);
 void gem_set_domain(int fd, uint32_t handle,
 		    uint32_t read_domains, uint32_t write_domain);
 void gem_sync(int fd, uint32_t handle);
@@ -53,6 +56,11 @@ void gem_execbuf(int fd, struct drm_i915_gem_execbuffer2 *execbuf);
 
 void *gem_mmap__gtt(int fd, uint32_t handle, int size, int prot);
 void *gem_mmap__cpu(int fd, uint32_t handle, int size, int prot);
+/**
+ * gem_mmap:
+ *
+ * This is a simple convenience alias to gem_mmap__gtt()
+ */
 #define gem_mmap gem_mmap__gtt
 
 int gem_madvise(int fd, uint32_t handle, int state);
@@ -64,6 +72,7 @@ void gem_sw_finish(int fd, uint32_t handle);
 bool gem_bo_busy(int fd, uint32_t handle);
 
 /* feature test helpers */
+int gem_get_num_rings(int fd);
 bool gem_has_enable_ring(int fd,int param);
 bool gem_has_bsd(int fd);
 bool gem_has_blt(int fd);
@@ -74,6 +83,10 @@ uint64_t gem_available_aperture_size(int fd);
 uint64_t gem_aperture_size(int fd);
 uint64_t gem_mappable_aperture_size(void);
 
+/* check functions which auto-skip tests by calling igt_skip() */
+void gem_require_caching(int fd);
+void gem_require_ring(int fd, int ring_id);
+
 /* prime */
 int prime_handle_to_fd(int fd, uint32_t handle);
 uint32_t prime_fd_to_handle(int fd, int dma_buf_fd);
-- 
1.8.5.2

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 3/4] lib: extract igt_core.c
  2014-03-12 15:39 [PATCH 1/4] lib: extract ioctl_wrappers.c Daniel Vetter
  2014-03-12 15:39 ` [PATCH 2/4] lib/ioctl_wrappers: api doc Daniel Vetter
@ 2014-03-12 15:39 ` Daniel Vetter
  2014-03-12 15:39 ` [PATCH 4/4] lib/igt_core: api documentation Daniel Vetter
  2 siblings, 0 replies; 4+ messages in thread
From: Daniel Vetter @ 2014-03-12 15:39 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

Same game as with ioctl_wrappers.c.

To split was rather clean except for the static function
oom_adjust_for_doom. But that was a bug, the calls to it in the
various open helpers should simply be done at init and fork time.
Which was already the case, except for simple testcase.  So fix it up.

While at it also start with a small section header for the
documentation.

v2: Don't forget to update the xml template ...

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 .../intel-gpu-tools/intel-gpu-tools-docs.xml       |   1 +
 lib/Makefile.sources                               |   2 +
 lib/drmtest.c                                      | 830 +------------------
 lib/drmtest.h                                      | 269 +-----
 lib/igt_core.c                                     | 901 +++++++++++++++++++++
 lib/igt_core.h                                     | 305 +++++++
 6 files changed, 1213 insertions(+), 1095 deletions(-)
 create mode 100644 lib/igt_core.c
 create mode 100644 lib/igt_core.h

diff --git a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
index bf85685fcbd5..6723fe1f2e78 100644
--- a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
+++ b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
@@ -17,6 +17,7 @@
     <title>Intel GPU Tools</title>
     <xi:include href="xml/debug.xml"/>
     <xi:include href="xml/drmtest.xml"/>
+    <xi:include href="xml/igt_core.xml"/>
     <xi:include href="xml/igt_debugfs.xml"/>
     <xi:include href="xml/igt_display.xml"/>
     <xi:include href="xml/igt_kms.xml"/>
diff --git a/lib/Makefile.sources b/lib/Makefile.sources
index ba4e8282c277..a3a679c1c41e 100644
--- a/lib/Makefile.sources
+++ b/lib/Makefile.sources
@@ -41,5 +41,7 @@ libintel_tools_la_SOURCES = 	\
 	intel_iosf.c		\
 	igt_kms.c \
 	igt_kms.h \
+	igt_core.c \
+	igt_core.h \
 	$(NULL)
 
diff --git a/lib/drmtest.c b/lib/drmtest.c
index b518b8116c00..a5aac4dce126 100644
--- a/lib/drmtest.c
+++ b/lib/drmtest.c
@@ -167,16 +167,6 @@ int drm_get_card(void)
 	return -1;
 }
 
-static void oom_adjust_for_doom(void)
-{
-	int fd;
-	const char always_kill[] = "1000";
-
-	fd = open("/proc/self/oom_score_adj", O_WRONLY);
-	igt_assert(fd != -1);
-	igt_assert(write(fd, always_kill, sizeof(always_kill)) == sizeof(always_kill));
-}
-
 /** Open the first DRM device we can find, searching up to 16 device nodes */
 static int __drm_open_any(void)
 {
@@ -195,8 +185,6 @@ static int __drm_open_any(void)
 		fd = -1;
 	}
 
-	oom_adjust_for_doom();
-
 	return fd;
 }
 
@@ -226,8 +214,6 @@ static int __drm_open_any_render(void)
 		return fd;
 	}
 
-	oom_adjust_for_doom();
-
 	return fd;
 }
 
@@ -291,10 +277,6 @@ int drm_open_any_render(void)
 }
 
 /* signal interrupt helpers */
-static bool igt_only_list_subtests(void);
-
-static unsigned int exit_handler_count;
-
 static struct igt_helper_process signal_helper;
 long long int sig_stat;
 static void __attribute__((noreturn)) signal_helper_process(pid_t pid)
@@ -334,609 +316,7 @@ void igt_stop_signal_helper(void)
 	sig_stat = 0;
 }
 
-/* subtests helpers */
-static bool list_subtests = false;
-static char *run_single_subtest = NULL;
-static const char *in_subtest = NULL;
-static bool in_fixture = false;
-static bool test_with_subtests = false;
-static enum {
-	CONT = 0, SKIP, FAIL
-} skip_subtests_henceforth = CONT;
-
-/* fork support state */
-pid_t *test_children;
-int num_test_children;
-int test_children_sz;
-bool test_child;
-
-bool __igt_fixture(void)
-{
-	assert(!in_fixture);
-
-	if (igt_only_list_subtests())
-		return false;
-
-	if (skip_subtests_henceforth)
-		return false;
-
-	in_fixture = true;
-	return true;
-}
-
-void __igt_fixture_complete(void)
-{
-	assert(in_fixture);
-
-	in_fixture = false;
-}
-
-void __igt_fixture_end(void)
-{
-	assert(in_fixture);
-
-	in_fixture = false;
-	longjmp(igt_subtest_jmpbuf, 1);
-}
-
-bool igt_exit_called;
-static void check_igt_exit(int sig)
-{
-	/* When not killed by a signal check that igt_exit() has been properly
-	 * called. */
-	assert(sig != 0 || igt_exit_called);
-}
-
-
-static void print_version(void)
-{
-	struct utsname uts;
-
-	if (list_subtests)
-		return;
-
-	uname(&uts);
-
-	fprintf(stdout, "IGT-Version: %s-%s (%s) (%s: %s %s)\n", PACKAGE_VERSION,
-		IGT_GIT_SHA1, TARGET_CPU_PLATFORM,
-		uts.sysname, uts.release, uts.machine);
-}
-
-static void print_usage(const char *command_str, const char *help_str,
-			bool output_on_stderr)
-{
-	FILE *f = output_on_stderr ? stderr : stdout;
-
-	fprintf(f, "Usage: %s [OPTIONS]\n"
-		   "  --list-subtests\n"
-		   "  --run-subtest <pattern>\n", command_str);
-	if (help_str)
-		fprintf(f, "%s\n", help_str);
-}
-
-int igt_subtest_init_parse_opts(int argc, char **argv,
-				const char *extra_short_opts,
-				struct option *extra_long_opts,
-				const char *help_str,
-				igt_opt_handler_t extra_opt_handler)
-{
-	int c, option_index = 0;
-	static struct option long_options[] = {
-		{"list-subtests", 0, 0, 'l'},
-		{"run-subtest", 1, 0, 'r'},
-		{"help", 0, 0, 'h'},
-	};
-	const char *command_str;
-	char *short_opts;
-	struct option *combined_opts;
-	int extra_opt_count;
-	int all_opt_count;
-	int ret = 0;
-
-	test_with_subtests = true;
-
-	command_str = argv[0];
-	if (strrchr(command_str, '/'))
-		command_str = strrchr(command_str, '/') + 1;
-
-	/* First calculate space for all passed-in extra long options */
-	all_opt_count = 0;
-	while (extra_long_opts && extra_long_opts[all_opt_count].name)
-		all_opt_count++;
-	extra_opt_count = all_opt_count;
-
-	all_opt_count += ARRAY_SIZE(long_options);
-
-	combined_opts = malloc(all_opt_count * sizeof(*combined_opts));
-	memcpy(combined_opts, extra_long_opts,
-	       extra_opt_count * sizeof(*combined_opts));
-
-	/* Copy the subtest long options (and the final NULL entry) */
-	memcpy(&combined_opts[extra_opt_count], long_options,
-		ARRAY_SIZE(long_options) * sizeof(*combined_opts));
-
-	ret = asprintf(&short_opts, "%sh",
-		       extra_short_opts ? extra_short_opts : "");
-	assert(ret >= 0);
-
-	while ((c = getopt_long(argc, argv, short_opts, combined_opts,
-			       &option_index)) != -1) {
-		switch(c) {
-		case 'l':
-			if (!run_single_subtest)
-				list_subtests = true;
-			break;
-		case 'r':
-			if (!list_subtests)
-				run_single_subtest = strdup(optarg);
-			break;
-		case 'h':
-			print_usage(command_str, help_str, false);
-			ret = -1;
-			goto out;
-		case '?':
-			if (opterr) {
-				print_usage(command_str, help_str, true);
-				ret = -2;
-				goto out;
-			}
-			/*
-			 * Just ignore the error, since the unknown argument
-			 * can be something the caller understands and will
-			 * parse by doing a second getopt scanning.
-			 */
-			break;
-		default:
-			ret = extra_opt_handler(c, option_index);
-			if (ret)
-				goto out;
-		}
-	}
-
-	igt_install_exit_handler(check_igt_exit);
-	oom_adjust_for_doom();
-
-out:
-	free(short_opts);
-	free(combined_opts);
-	print_version();
-
-	return ret;
-}
-
-enum igt_log_level igt_log_level = IGT_LOG_INFO;
-
-static void common_init(void)
-{
-	char *env = getenv("IGT_LOG_LEVEL");
-
-	if (!env)
-		return;
-
-	if (strcmp(env, "debug") == 0)
-		igt_log_level = IGT_LOG_DEBUG;
-	else if (strcmp(env, "info") == 0)
-		igt_log_level = IGT_LOG_INFO;
-	else if (strcmp(env, "warn") == 0)
-		igt_log_level = IGT_LOG_WARN;
-	else if (strcmp(env, "none") == 0)
-		igt_log_level = IGT_LOG_NONE;
-}
-
-void igt_subtest_init(int argc, char **argv)
-{
-	int ret;
-
-	/* supress getopt errors about unknown options */
-	opterr = 0;
-
-	ret = igt_subtest_init_parse_opts(argc, argv, NULL, NULL, NULL, NULL);
-	if (ret < 0)
-		/* exit with no error for -h/--help */
-		exit(ret == -1 ? 0 : ret);
-
-	/* reset opt parsing */
-	optind = 1;
-
-	common_init();
-}
-
-void igt_simple_init(void)
-{
-	print_version();
-
-	common_init();
-}
-
-/*
- * Note: Testcases which use these helpers MUST NOT output anything to stdout
- * outside of places protected by igt_run_subtest checks - the piglit
- * runner adds every line to the subtest list.
- */
-bool __igt_run_subtest(const char *subtest_name)
-{
-	assert(!in_subtest);
-	assert(!in_fixture);
-
-	if (list_subtests) {
-		printf("%s\n", subtest_name);
-		return false;
-	}
-
-	if (run_single_subtest &&
-	    strcmp(subtest_name, run_single_subtest) != 0)
-		return false;
-
-	if (skip_subtests_henceforth) {
-		printf("Subtest %s: %s\n", subtest_name,
-		       skip_subtests_henceforth == SKIP ?
-		       "SKIP" : "FAIL");
-		return false;
-	}
-
-	return (in_subtest = subtest_name);
-}
-
-const char *igt_subtest_name(void)
-{
-	return in_subtest;
-}
-
-static bool igt_only_list_subtests(void)
-{
-	return list_subtests;
-}
-
-static bool skipped_one = false;
-static bool succeeded_one = false;
-static bool failed_one = false;
-static int igt_exitcode;
-
-static void exit_subtest(const char *) __attribute__((noreturn));
-static void exit_subtest(const char *result)
-{
-	printf("Subtest %s: %s\n", in_subtest, result);
-	in_subtest = NULL;
-	longjmp(igt_subtest_jmpbuf, 1);
-}
-
-void igt_skip(const char *f, ...)
-{
-	va_list args;
-	skipped_one = true;
-
-	assert(!test_child);
-
-	if (!igt_only_list_subtests()) {
-		va_start(args, f);
-		vprintf(f, args);
-		va_end(args);
-	}
-
-	if (in_subtest) {
-		exit_subtest("SKIP");
-	} else if (test_with_subtests) {
-		skip_subtests_henceforth = SKIP;
-		assert(in_fixture);
-		__igt_fixture_end();
-	} else {
-		exit(77);
-	}
-}
-
-void __igt_skip_check(const char *file, const int line,
-		      const char *func, const char *check,
-		      const char *f, ...)
-{
-	va_list args;
-	int err = errno;
-
-	if (f) {
-		static char *buf;
-
-		/* igt_skip never returns, so try to not leak too badly. */
-		if (buf)
-			free(buf);
-
-		va_start(args, f);
-		vasprintf(&buf, f, args);
-		va_end(args);
-
-		igt_skip("Test requirement not met in function %s, file %s:%i:\n"
-			 "Last errno: %i, %s\n"
-			 "Test requirement: (%s)\n%s",
-			 func, file, line, err, strerror(err), check, buf);
-	} else {
-		igt_skip("Test requirement not met in function %s, file %s:%i:\n"
-			 "Last errno: %i, %s\n"
-			 "Test requirement: (%s)\n",
-			 func, file, line, err, strerror(err), check);
-	}
-}
-
-void igt_success(void)
-{
-	succeeded_one = true;
-	if (in_subtest)
-		exit_subtest("SUCCESS");
-}
-
-void igt_fail(int exitcode)
-{
-	assert(exitcode != 0 && exitcode != 77);
-
-	if (!failed_one)
-		igt_exitcode = exitcode;
-
-	failed_one = true;
-
-	/* Silent exit, parent will do the yelling. */
-	if (test_child)
-		exit(exitcode);
-
-	if (in_subtest)
-		exit_subtest("FAIL");
-	else {
-		assert(!test_with_subtests || in_fixture);
-
-		if (in_fixture) {
-			skip_subtests_henceforth = FAIL;
-			__igt_fixture_end();
-		}
-
-		exit(exitcode);
-	}
-}
-
-static bool run_under_gdb(void)
-{
-	char buf[1024];
-
-	sprintf(buf, "/proc/%d/exe", getppid());
-	return (readlink (buf, buf, sizeof (buf)) != -1 &&
-		strncmp(basename(buf), "gdb", 3) == 0);
-}
-
-void __igt_fail_assert(int exitcode, const char *file,
-		       const int line, const char *func, const char *assertion,
-		       const char *f, ...)
-{
-	va_list args;
-	int err = errno;
-
-	printf("Test assertion failure function %s, file %s:%i:\n"
-	       "Last errno: %i, %s\n"
-	       "Failed assertion: %s\n",
-	       func, file, line, err, strerror(err), assertion);
-
-	if (f) {
-		va_start(args, f);
-		vprintf(f, args);
-		va_end(args);
-	}
-
-	if (run_under_gdb())
-		abort();
-	igt_fail(exitcode);
-}
-
-void igt_exit(void)
-{
-	igt_exit_called = true;
-
-	if (igt_only_list_subtests())
-		exit(0);
-
-	if (!test_with_subtests)
-		exit(0);
-
-	/* Calling this without calling one of the above is a failure */
-	assert(skipped_one || succeeded_one || failed_one);
-
-	if (failed_one)
-		exit(igt_exitcode);
-	else if (succeeded_one)
-		exit(0);
-	else
-		exit(77);
-}
-
-static int helper_process_count;
-static pid_t helper_process_pids[] =
-{ -1, -1, -1, -1};
-
-static void reset_helper_process_list(void)
-{
-	for (int i = 0; i < ARRAY_SIZE(helper_process_pids); i++)
-		helper_process_pids[i] = -1;
-	helper_process_count = 0;
-}
-
-static void fork_helper_exit_handler(int sig)
-{
-	for (int i = 0; i < ARRAY_SIZE(helper_process_pids); i++) {
-		pid_t pid = helper_process_pids[i];
-		int status, ret;
-
-		if (pid != -1) {
-			/* Someone forgot to fill up the array? */
-			assert(pid != 0);
-
-			ret = kill(pid, SIGQUIT);
-			assert(ret == 0);
-			while (waitpid(pid, &status, 0) == -1 &&
-			       errno == EINTR)
-				;
-			helper_process_count--;
-		}
-	}
-
-	assert(helper_process_count == 0);
-}
-
-bool __igt_fork_helper(struct igt_helper_process *proc)
-{
-	pid_t pid;
-	int id;
-
-	assert(!proc->running);
-	assert(helper_process_count < ARRAY_SIZE(helper_process_pids));
-
-	for (id = 0; helper_process_pids[id] != -1; id++)
-		;
-
-	igt_install_exit_handler(fork_helper_exit_handler);
-
-	switch (pid = fork()) {
-	case -1:
-		igt_assert(0);
-	case 0:
-		exit_handler_count = 0;
-		reset_helper_process_list();
-		oom_adjust_for_doom();
-
-		return true;
-	default:
-		proc->running = true;
-		proc->pid = pid;
-		proc->id = id;
-		helper_process_pids[id] = pid;
-		helper_process_count++;
-
-		return false;
-	}
-
-}
-
-void igt_stop_helper(struct igt_helper_process *proc)
-{
-	int status, ret;
-
-	assert(proc->running);
-
-	ret = kill(proc->pid,
-		   proc->use_SIGKILL ? SIGKILL : SIGQUIT);
-	assert(ret == 0);
-	while (waitpid(proc->pid, &status, 0) == -1 &&
-	       errno == EINTR)
-		;
-	igt_assert(WIFSIGNALED(status) &&
-		   WTERMSIG(status) == (proc->use_SIGKILL ? SIGKILL : SIGQUIT));
-
-	proc->running = false;
-
-	helper_process_pids[proc->id] = -1;
-	helper_process_count--;
-}
-
-void igt_wait_helper(struct igt_helper_process *proc)
-{
-	int status;
-
-	assert(proc->running);
-
-	while (waitpid(proc->pid, &status, 0) == -1 &&
-	       errno == EINTR)
-		;
-	igt_assert(WIFEXITED(status) && WEXITSTATUS(status) == 0);
-
-	proc->running = false;
-
-	helper_process_pids[proc->id] = -1;
-	helper_process_count--;
-}
-
-static void children_exit_handler(int sig)
-{
-	int ret;
-
-	assert(!test_child);
-
-	for (int nc = 0; nc < num_test_children; nc++) {
-		int status = -1;
-		ret = kill(test_children[nc], SIGQUIT);
-		assert(ret == 0);
-
-		while (waitpid(test_children[nc], &status, 0) == -1 &&
-		       errno == EINTR)
-			;
-	}
-
-	num_test_children = 0;
-}
-
-bool __igt_fork(void)
-{
-	assert(!test_with_subtests || in_subtest);
-	assert(!test_child);
-
-	igt_install_exit_handler(children_exit_handler);
-
-	if (num_test_children >= test_children_sz) {
-		if (!test_children_sz)
-			test_children_sz = 4;
-		else
-			test_children_sz *= 2;
-
-		test_children = realloc(test_children,
-					sizeof(pid_t)*test_children_sz);
-		igt_assert(test_children);
-	}
-
-	switch (test_children[num_test_children++] = fork()) {
-	case -1:
-		igt_assert(0);
-	case 0:
-		test_child = true;
-		exit_handler_count = 0;
-		reset_helper_process_list();
-		oom_adjust_for_doom();
-
-		return true;
-	default:
-		return false;
-	}
-
-}
-
-/**
- * igt_waitchildren:
- *
- * Wait for all children forked with igt_fork
- *
- * The magic here is that exit codes from children will be correctly propagated
- */
-void igt_waitchildren(void)
-{
-	assert(!test_child);
-
-	for (int nc = 0; nc < num_test_children; nc++) {
-		int status = -1;
-		while (waitpid(test_children[nc], &status, 0) == -1 &&
-		       errno == EINTR)
-			;
-
-		if (status != 0) {
-			if (WIFEXITED(status)) {
-				printf("child %i failed with exit status %i\n",
-				       nc, WEXITSTATUS(status));
-				igt_fail(WEXITSTATUS(status));
-			} else if (WIFSIGNALED(status)) {
-				printf("child %i died with signal %i, %s\n",
-				       nc, WTERMSIG(status),
-				       strsignal(WTERMSIG(status)));
-				igt_fail(99);
-			} else {
-				printf("Unhandled failure in child %i\n", nc);
-				abort();
-			}
-		}
-	}
-
-	num_test_children = 0;
-}
-
-static bool env_set(const char *env_var, bool default_value)
+bool igt_env_set(const char *env_var, bool default_value)
 {
 	char *val;
 
@@ -947,59 +327,12 @@ static bool env_set(const char *env_var, bool default_value)
 	return atoi(val) != 0;
 }
 
-bool igt_run_in_simulation(void)
-{
-	static int simulation = -1;
-
-	if (simulation == -1)
-		simulation = env_set("INTEL_SIMULATION", false);
-
-	return simulation;
-}
-
-/**
- * igt_skip_on_simulation:
- *
- * Skip tests when INTEL_SIMULATION env war is set
- *
- * Skip the test when running on simulation (and that's relevant only when
- * we're not in the mode where we list the subtests).
- *
- * This function is subtest aware (since it uses igt_skip) and so can be used to
- * skip specific subtests or all subsequent subtests.
- */
-void igt_skip_on_simulation(void)
-{
-	if (igt_only_list_subtests())
-		return;
-
-	igt_require(!igt_run_in_simulation());
-}
-
-void igt_log(enum igt_log_level level, const char *format, ...)
-{
-	va_list args;
-
-	assert(format);
-
-	if (igt_log_level > level)
-		return;
-
-	va_start(args, format);
-	if (level == IGT_LOG_WARN) {
-		fflush(stdout);
-		vfprintf(stderr, format, args);
-	} else
-		vprintf(format, args);
-	va_end(args);
-}
-
 bool drmtest_dump_aub(void)
 {
 	static int dump_aub = -1;
 
 	if (dump_aub == -1)
-		dump_aub = env_set("IGT_DUMP_AUB", false);
+		dump_aub = igt_env_set("IGT_DUMP_AUB", false);
 
 	return dump_aub;
 }
@@ -1092,165 +425,6 @@ void igt_cleanup_aperture_trashers(void)
 	free(trash_bos);
 }
 
-#define MAX_SIGNALS		32
-#define MAX_EXIT_HANDLERS	5
-
-static struct {
-	sighandler_t handler;
-	bool installed;
-} orig_sig[MAX_SIGNALS];
-
-static igt_exit_handler_t exit_handler_fn[MAX_EXIT_HANDLERS];
-static bool exit_handler_disabled;
-static sigset_t saved_sig_mask;
-static const int handled_signals[] =
-	{ SIGINT, SIGHUP, SIGTERM, SIGQUIT, SIGPIPE, SIGABRT, SIGSEGV, SIGBUS };
-
-static int install_sig_handler(int sig_num, sighandler_t handler)
-{
-	orig_sig[sig_num].handler = signal(sig_num, handler);
-
-	if (orig_sig[sig_num].handler == SIG_ERR)
-		return -1;
-
-	orig_sig[sig_num].installed = true;
-
-	return 0;
-}
-
-static void restore_sig_handler(int sig_num)
-{
-	/* Just restore the default so that we properly fall over. */
-	signal(sig_num, SIG_DFL);
-}
-
-static void restore_all_sig_handler(void)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(orig_sig); i++)
-		restore_sig_handler(i);
-}
-
-static void call_exit_handlers(int sig)
-{
-	int i;
-
-	if (!exit_handler_count) {
-		return;
-	}
-
-	for (i = exit_handler_count - 1; i >= 0; i--)
-		exit_handler_fn[i](sig);
-
-	/* ensure we don't get called twice */
-	exit_handler_count = 0;
-}
-
-static void igt_atexit_handler(void)
-{
-	restore_all_sig_handler();
-
-	if (!exit_handler_disabled)
-		call_exit_handlers(0);
-}
-
-static void fatal_sig_handler(int sig)
-{
-	pid_t pid, tid;
-
-	restore_all_sig_handler();
-
-	/*
-	 * exit_handler_disabled is always false here, since when we set it
-	 * we also block signals.
-	 */
-	call_exit_handlers(sig);
-
-	/* Workaround cached PID and TID races on glibc and Bionic libc. */
-	pid = syscall(SYS_getpid);
-	tid = syscall(SYS_gettid);
-
-	syscall(SYS_tgkill, pid, tid, sig);
-}
-
-/*
- * Set a handler that will be called either when the process calls exit() or
- * returns from the main function, or one of the signals in 'handled_signals'
- * is raised. MAX_EXIT_HANDLERS handlers can be installed, each of which will
- * be called only once, even if a subsequent signal is raised. If the exit
- * handlers are called due to a signal, the signal will be re-raised with the
- * original signal disposition after all handlers returned.
- *
- * The handler will be passed the signal number if called due to a signal, or
- * 0 otherwise.
- */
-void igt_install_exit_handler(igt_exit_handler_t fn)
-{
-	int i;
-
-	for (i = 0; i < exit_handler_count; i++)
-		if (exit_handler_fn[i] == fn)
-			return;
-
-	igt_assert(exit_handler_count < MAX_EXIT_HANDLERS);
-
-	exit_handler_fn[exit_handler_count] = fn;
-	exit_handler_count++;
-
-	if (exit_handler_count > 1)
-		return;
-
-	for (i = 0; i < ARRAY_SIZE(handled_signals); i++) {
-		if (install_sig_handler(handled_signals[i],
-					fatal_sig_handler))
-			goto err;
-	}
-
-	if (atexit(igt_atexit_handler))
-		goto err;
-
-	return;
-err:
-	restore_all_sig_handler();
-	exit_handler_count--;
-
-	igt_assert_f(0, "failed to install the signal handler\n");
-}
-
-void igt_disable_exit_handler(void)
-{
-	sigset_t set;
-	int i;
-
-	if (exit_handler_disabled)
-		return;
-
-	sigemptyset(&set);
-	for (i = 0; i < ARRAY_SIZE(handled_signals); i++)
-		sigaddset(&set, handled_signals[i]);
-
-	if (sigprocmask(SIG_BLOCK, &set, &saved_sig_mask)) {
-		perror("sigprocmask");
-		return;
-	}
-
-	exit_handler_disabled = true;
-}
-
-void igt_enable_exit_handler(void)
-{
-	if (!exit_handler_disabled)
-		return;
-
-	if (sigprocmask(SIG_SETMASK, &saved_sig_mask, NULL)) {
-		perror("sigprocmask");
-		return;
-	}
-
-	exit_handler_disabled = false;
-}
-
 #define PREFAULT_DEBUGFS "/sys/module/i915/parameters/prefault_disable"
 static void igt_prefault_control(bool enable)
 {
diff --git a/lib/drmtest.h b/lib/drmtest.h
index a0b6e9fca28b..f9f21d396c44 100644
--- a/lib/drmtest.h
+++ b/lib/drmtest.h
@@ -45,6 +45,7 @@
 #include "intel_gpu_tools.h"
 
 #include "ioctl_wrappers.h"
+#include "igt_core.h"
 
 int drm_get_card(void);
 int drm_open_any(void);
@@ -61,266 +62,7 @@ void igt_permute_array(void *array, unsigned size,
 						 unsigned i,
 						 unsigned j));
 void igt_progress(const char *header, uint64_t i, uint64_t total);
-
-/**
- * igt_simple_init:
- *
- * Init for simple tests without subtests
- */
-void igt_simple_init(void);
-#define igt_simple_main \
-	static void igt_tokencat(__real_main, __LINE__)(void); \
-	int main(int argc, char **argv) { \
-		igt_simple_init(); \
-		igt_tokencat(__real_main, __LINE__)(); \
-		exit(0); \
-	} \
-	static void igt_tokencat(__real_main, __LINE__)(void) \
-
-/* subtest infrastructure */
-jmp_buf igt_subtest_jmpbuf;
-void igt_subtest_init(int argc, char **argv);
-typedef int (*igt_opt_handler_t)(int opt, int opt_index);
-struct option;
-int igt_subtest_init_parse_opts(int argc, char **argv,
-				const char *extra_short_opts,
-				struct option *extra_long_opts,
-				const char *help_str,
-				igt_opt_handler_t opt_handler);
-bool __igt_run_subtest(const char *subtest_name);
-/**
- * igt_subtest:
- *
- * Denote a subtest code block
- *
- * Magic control flow which denotes a subtest code block. Within that codeblock
- * igt_skip|success will only bail out of the subtest. The _f variant accepts a
- * printf format string, which is useful for constructing combinatorial tests.
- */
-#define igt_tokencat2(x, y) x ## y
-#define igt_tokencat(x, y) igt_tokencat2(x, y)
-#define __igt_subtest_f(tmp, format...) \
-	for (char tmp [256]; \
-	     snprintf( tmp , sizeof( tmp ), \
-		      format), \
-	     __igt_run_subtest( tmp ) && \
-	     (setjmp(igt_subtest_jmpbuf) == 0); \
-	     igt_success())
-
-/**
- * igt_subtest_f:
- * @...: format string
- *
- * Denote a subtest code block
- *
- * Like #igt_subtest, but also accepts a printf format string
- */
-#define igt_subtest_f(f...) \
-	__igt_subtest_f(igt_tokencat(__tmpchar, __LINE__), f)
-#define igt_subtest(name) for (; __igt_run_subtest((name)) && \
-				   (setjmp(igt_subtest_jmpbuf) == 0); \
-				   igt_success())
-const char *igt_subtest_name(void);
-#define igt_main \
-	static void igt_tokencat(__real_main, __LINE__)(void); \
-	int main(int argc, char **argv) { \
-		igt_subtest_init(argc, argv); \
-		igt_tokencat(__real_main, __LINE__)(); \
-		igt_exit(); \
-	} \
-	static void igt_tokencat(__real_main, __LINE__)(void) \
-
-
-/**
- * igt_skip:
- *
- * Subtest aware test skipping
- *
- * For tests with subtests this will either bail out of the current subtest or
- * mark all subsequent subtests as SKIP (in case some global setup code failed).
- *
- * For normal tests without subtest it will directly exit.
- */
-__attribute__((format(printf, 1, 2)))
-void igt_skip(const char *f, ...) __attribute__((noreturn));
-__attribute__((format(printf, 5, 6)))
-void __igt_skip_check(const char *file, const int line,
-		      const char *func, const char *check,
-		      const char *format, ...) __attribute__((noreturn));
-/**
- * igt_success:
- *
- * Complete a (subtest) as successfull
- *
- * This bails out of a subtests and marks it as successful. For global tests it
- * it won't bail out of anything.
- */
-void igt_success(void);
-
-/**
- * igt_fail:
- *
- * Fail a testcase
- *
- * For subtest it just bails out of the subtest, when run in global context it
- * will exit. Note that it won't attempt to keep on running further tests,
- * presuming that some mandatory setup failed.
- */
-void igt_fail(int exitcode) __attribute__((noreturn));
-__attribute__((format(printf, 6, 7)))
-void __igt_fail_assert(int exitcode, const char *file,
-		       const int line, const char *func, const char *assertion,
-		       const char *format, ...)
-	__attribute__((noreturn));
-/**
- * igt_exit:
- *
- * exit() for igts
- *
- * This will exit the test with the right exit code when subtests have been
- * skipped. For normal tests it exits with a successful exit code, presuming
- * everything has worked out. For subtests it also checks that at least one
- * subtest has been run (save when only listing subtests.
- */
-void igt_exit(void) __attribute__((noreturn));
-/**
- * igt_assert:
- *
- * Fails (sub-)test if a condition is not met
- *
- * Should be used everywhere where a test checks results.
- */
-#define igt_assert(expr) \
-	do { if (!(expr)) \
-		__igt_fail_assert(99, __FILE__, __LINE__, __func__, #expr , NULL); \
-	} while (0)
-#define igt_assert_f(expr, f...) \
-	do { if (!(expr)) \
-		__igt_fail_assert(99, __FILE__, __LINE__, __func__, #expr , f); \
-	} while (0)
-/**
- * igt_assert_cmptint:
- *
- * Like #igt_assert, but displays the values being compared on failure.
- */
-#define igt_assert_cmpint(n1, cmp, n2) \
-	do { \
-		int __n1 = (n1), __n2 = (n2); \
-		if (__n1 cmp __n2) ; else \
-		__igt_fail_assert(99, __FILE__, __LINE__, __func__, \
-				  #n1 " " #cmp " " #n2, \
-				  "error: %d %s %d\n", __n1, #cmp, __n2); \
-	} while (0)
-
-/**
- * igt_require:
- *
- * Skip a (sub-)test if a condition is not met
- *
- * This is useful to streamline the skip logic since it allows for a more flat
- * code control flow.
- */
-#define igt_require(expr) igt_skip_on(!(expr))
-#define igt_skip_on(expr) \
-	do { if ((expr)) \
-		__igt_skip_check(__FILE__, __LINE__, __func__, #expr , NULL); \
-	} while (0)
-#define igt_require_f(expr, f...) igt_skip_on_f(!(expr), f)
-#define igt_skip_on_f(expr, f...) \
-	do { if ((expr)) \
-		__igt_skip_check(__FILE__, __LINE__, __func__, #expr , f); \
-	} while (0)
-
-bool __igt_fixture(void);
-void __igt_fixture_complete(void);
-void __igt_fixture_end(void) __attribute__((noreturn));
-/**
- * igt_fixture:
- *
- * Annotate global test fixture code
- *
- * Testcase with subtests often need to set up a bunch of global state as the
- * common test fixture. To avoid such code interferring with the subtest
- * enumeration (e.g. when enumerating on systemes without an intel gpu) such
- * blocks should be annotated with igt_fixture.
- */
-#define igt_fixture for (int igt_tokencat(__tmpint,__LINE__) = 0; \
-			 igt_tokencat(__tmpint,__LINE__) < 1 && \
-			 __igt_fixture() && \
-			 (setjmp(igt_subtest_jmpbuf) == 0); \
-			 igt_tokencat(__tmpint,__LINE__) ++, \
-			 __igt_fixture_complete())
-
-bool __igt_fork(void);
-/**
- * igt_fork:
- * @child: name of the int variable with the child number
- * @num_children: number of children to fork
- *
- * Fork parallel test threads with fork()
- *
- * Joining all test threads should be done with igt_waitchildren to ensure that
- * the exit codes of all children are properly reflected in the test status.
- */
-#define igt_fork(child, num_children) \
-	for (int child = 0; child < (num_children); child++) \
-		for (; __igt_fork(); exit(0))
-void igt_waitchildren(void);
-
-struct igt_helper_process {
-	bool running;
-	bool use_SIGKILL;
-	pid_t pid;
-	int id;
-};
-bool __igt_fork_helper(struct igt_helper_process *proc);
-void igt_stop_helper(struct igt_helper_process *proc);
-void igt_wait_helper(struct igt_helper_process *proc);
-#define igt_fork_helper(proc) \
-	for (; __igt_fork_helper(proc); exit(0))
-
-/* logging support */
-enum igt_log_level {
-	IGT_LOG_DEBUG,
-	IGT_LOG_INFO,
-	IGT_LOG_WARN,
-	IGT_LOG_NONE,
-};
-__attribute__((format(printf, 2, 3)))
-void igt_log(enum igt_log_level level, const char *format, ...);
-#define igt_debug(f...) igt_log(IGT_LOG_DEBUG, f)
-#define igt_info(f...) igt_log(IGT_LOG_INFO, f)
-#define igt_warn(f...) igt_log(IGT_LOG_WARN, f)
-extern enum igt_log_level igt_log_level;
-
-#define igt_warn_on(condition) do {\
-		if (condition) \
-			igt_warn("Warning on condition %s in fucntion %s, file %s:%i\n", \
-				 #condition, __func__, __FILE__, __LINE__); \
-	} while (0)
-#define igt_warn_on_f(condition, f...) do {\
-		if (condition) {\
-			igt_warn("Warning on condition %s in fucntion %s, file %s:%i\n", \
-				 #condition, __func__, __FILE__, __LINE__); \
-			igt_warn(f); \
-		} \
-	} while (0)
-
-/* helpers to automatically reduce test runtime in simulation */
-bool igt_run_in_simulation(void);
-#define SLOW_QUICK(slow,quick) (igt_run_in_simulation() ? (quick) : (slow))
-/**
- * igt_skip_on_simulation:
- *
- * Skip tests when INTEL_SIMULATION env war is set
- *
- * Skip the test when running on simulation (and that's relevant only when
- * we're not in the mode where we list the subtests).
- *
- * This function is subtest aware (since it uses igt_skip) and so can be used to
- * skip specific subtests or all subsequent subtests.
- */
-void igt_skip_on_simulation(void);
+bool igt_env_set(const char *env_var, bool default_value);
 
 bool drmtest_dump_aub(void);
 
@@ -332,13 +74,6 @@ void igt_cleanup_aperture_trashers(void);
 #define do_or_die(x) igt_assert((x) == 0)
 #define do_ioctl(fd, ptr, sz) igt_assert(drmIoctl((fd), (ptr), (sz)) == 0)
 
-typedef void (*igt_exit_handler_t)(int sig);
-
-/* reliable atexit helpers, also work when killed by a signal (if possible) */
-void igt_install_exit_handler(igt_exit_handler_t fn);
-void igt_enable_exit_handler(void);
-void igt_disable_exit_handler(void);
-
 /* set vt into graphics mode, required to prevent fbcon from interfering */
 void igt_set_vt_graphics_mode(void);
 
diff --git a/lib/igt_core.c b/lib/igt_core.c
new file mode 100644
index 000000000000..27c159c69ae8
--- /dev/null
+++ b/lib/igt_core.c
@@ -0,0 +1,901 @@
+/*
+ * Copyright © 2007, 2011, 2013, 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Eric Anholt <eric@anholt.net>
+ *    Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ */
+
+#ifndef ANDROID
+#define _GNU_SOURCE
+#else
+#include <libgen.h>
+#endif
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <signal.h>
+#include <pciaccess.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/utsname.h>
+#include <termios.h>
+
+#include "drmtest.h"
+#include "i915_drm.h"
+#include "intel_chipset.h"
+#include "intel_gpu_tools.h"
+#include "igt_debugfs.h"
+#include "../version.h"
+#include "config.h"
+
+#include "igt_core.h"
+
+/**
+ * SECTION:igt_core
+ * @short_description: Core i-g-t testing support
+ * @title: i-g-t core
+ *
+ * This libary implements the core of the i-g-t test support infrastructure.
+ * Main features are the subtest enumeration, cmdline option parsing helpers for
+ * subtest handling and various helpers to structure testcases with subtests and
+ * handle subtest test results.
+ *
+ * Auxiliary code provides exit handlers, support for forked processes with test
+ * result propagation. Other generally useful functionality includes optional
+ * structure logging infrastructure and some support code for running reduced
+ * test set on in simulated hardware environments.
+ */
+
+static unsigned int exit_handler_count;
+
+/* subtests helpers */
+static bool list_subtests = false;
+static char *run_single_subtest = NULL;
+static const char *in_subtest = NULL;
+static bool in_fixture = false;
+static bool test_with_subtests = false;
+static enum {
+	CONT = 0, SKIP, FAIL
+} skip_subtests_henceforth = CONT;
+
+/* fork support state */
+pid_t *test_children;
+int num_test_children;
+int test_children_sz;
+bool test_child;
+
+bool __igt_fixture(void)
+{
+	assert(!in_fixture);
+
+	if (igt_only_list_subtests())
+		return false;
+
+	if (skip_subtests_henceforth)
+		return false;
+
+	in_fixture = true;
+	return true;
+}
+
+void __igt_fixture_complete(void)
+{
+	assert(in_fixture);
+
+	in_fixture = false;
+}
+
+void __igt_fixture_end(void)
+{
+	assert(in_fixture);
+
+	in_fixture = false;
+	longjmp(igt_subtest_jmpbuf, 1);
+}
+
+bool igt_exit_called;
+static void check_igt_exit(int sig)
+{
+	/* When not killed by a signal check that igt_exit() has been properly
+	 * called. */
+	assert(sig != 0 || igt_exit_called);
+}
+
+static void print_version(void)
+{
+	struct utsname uts;
+
+	if (list_subtests)
+		return;
+
+	uname(&uts);
+
+	fprintf(stdout, "IGT-Version: %s-%s (%s) (%s: %s %s)\n", PACKAGE_VERSION,
+		IGT_GIT_SHA1, TARGET_CPU_PLATFORM,
+		uts.sysname, uts.release, uts.machine);
+}
+
+static void print_usage(const char *command_str, const char *help_str,
+			bool output_on_stderr)
+{
+	FILE *f = output_on_stderr ? stderr : stdout;
+
+	fprintf(f, "Usage: %s [OPTIONS]\n"
+		   "  --list-subtests\n"
+		   "  --run-subtest <pattern>\n", command_str);
+	if (help_str)
+		fprintf(f, "%s\n", help_str);
+}
+
+static void oom_adjust_for_doom(void)
+{
+	int fd;
+	const char always_kill[] = "1000";
+
+	fd = open("/proc/self/oom_score_adj", O_WRONLY);
+	igt_assert(fd != -1);
+	igt_assert(write(fd, always_kill, sizeof(always_kill)) == sizeof(always_kill));
+}
+
+int igt_subtest_init_parse_opts(int argc, char **argv,
+				const char *extra_short_opts,
+				struct option *extra_long_opts,
+				const char *help_str,
+				igt_opt_handler_t extra_opt_handler)
+{
+	int c, option_index = 0;
+	static struct option long_options[] = {
+		{"list-subtests", 0, 0, 'l'},
+		{"run-subtest", 1, 0, 'r'},
+		{"help", 0, 0, 'h'},
+	};
+	const char *command_str;
+	char *short_opts;
+	struct option *combined_opts;
+	int extra_opt_count;
+	int all_opt_count;
+	int ret = 0;
+
+	test_with_subtests = true;
+
+	command_str = argv[0];
+	if (strrchr(command_str, '/'))
+		command_str = strrchr(command_str, '/') + 1;
+
+	/* First calculate space for all passed-in extra long options */
+	all_opt_count = 0;
+	while (extra_long_opts && extra_long_opts[all_opt_count].name)
+		all_opt_count++;
+	extra_opt_count = all_opt_count;
+
+	all_opt_count += ARRAY_SIZE(long_options);
+
+	combined_opts = malloc(all_opt_count * sizeof(*combined_opts));
+	memcpy(combined_opts, extra_long_opts,
+	       extra_opt_count * sizeof(*combined_opts));
+
+	/* Copy the subtest long options (and the final NULL entry) */
+	memcpy(&combined_opts[extra_opt_count], long_options,
+		ARRAY_SIZE(long_options) * sizeof(*combined_opts));
+
+	ret = asprintf(&short_opts, "%sh",
+		       extra_short_opts ? extra_short_opts : "");
+	assert(ret >= 0);
+
+	while ((c = getopt_long(argc, argv, short_opts, combined_opts,
+			       &option_index)) != -1) {
+		switch(c) {
+		case 'l':
+			if (!run_single_subtest)
+				list_subtests = true;
+			break;
+		case 'r':
+			if (!list_subtests)
+				run_single_subtest = strdup(optarg);
+			break;
+		case 'h':
+			print_usage(command_str, help_str, false);
+			ret = -1;
+			goto out;
+		case '?':
+			if (opterr) {
+				print_usage(command_str, help_str, true);
+				ret = -2;
+				goto out;
+			}
+			/*
+			 * Just ignore the error, since the unknown argument
+			 * can be something the caller understands and will
+			 * parse by doing a second getopt scanning.
+			 */
+			break;
+		default:
+			ret = extra_opt_handler(c, option_index);
+			if (ret)
+				goto out;
+		}
+	}
+
+	igt_install_exit_handler(check_igt_exit);
+	oom_adjust_for_doom();
+
+out:
+	free(short_opts);
+	free(combined_opts);
+	print_version();
+
+	return ret;
+}
+
+enum igt_log_level igt_log_level = IGT_LOG_INFO;
+
+static void common_init(void)
+{
+	char *env = getenv("IGT_LOG_LEVEL");
+
+	if (!env)
+		return;
+
+	if (strcmp(env, "debug") == 0)
+		igt_log_level = IGT_LOG_DEBUG;
+	else if (strcmp(env, "info") == 0)
+		igt_log_level = IGT_LOG_INFO;
+	else if (strcmp(env, "warn") == 0)
+		igt_log_level = IGT_LOG_WARN;
+	else if (strcmp(env, "none") == 0)
+		igt_log_level = IGT_LOG_NONE;
+}
+
+void igt_subtest_init(int argc, char **argv)
+{
+	int ret;
+
+	/* supress getopt errors about unknown options */
+	opterr = 0;
+
+	ret = igt_subtest_init_parse_opts(argc, argv, NULL, NULL, NULL, NULL);
+	if (ret < 0)
+		/* exit with no error for -h/--help */
+		exit(ret == -1 ? 0 : ret);
+
+	/* reset opt parsing */
+	optind = 1;
+
+	common_init();
+}
+
+void igt_simple_init(void)
+{
+	print_version();
+
+	oom_adjust_for_doom();
+
+	common_init();
+}
+
+/*
+ * Note: Testcases which use these helpers MUST NOT output anything to stdout
+ * outside of places protected by igt_run_subtest checks - the piglit
+ * runner adds every line to the subtest list.
+ */
+bool __igt_run_subtest(const char *subtest_name)
+{
+	assert(!in_subtest);
+	assert(!in_fixture);
+
+	if (list_subtests) {
+		printf("%s\n", subtest_name);
+		return false;
+	}
+
+	if (run_single_subtest &&
+	    strcmp(subtest_name, run_single_subtest) != 0)
+		return false;
+
+	if (skip_subtests_henceforth) {
+		printf("Subtest %s: %s\n", subtest_name,
+		       skip_subtests_henceforth == SKIP ?
+		       "SKIP" : "FAIL");
+		return false;
+	}
+
+	return (in_subtest = subtest_name);
+}
+
+const char *igt_subtest_name(void)
+{
+	return in_subtest;
+}
+
+bool igt_only_list_subtests(void)
+{
+	return list_subtests;
+}
+
+static bool skipped_one = false;
+static bool succeeded_one = false;
+static bool failed_one = false;
+static int igt_exitcode;
+
+static void exit_subtest(const char *) __attribute__((noreturn));
+static void exit_subtest(const char *result)
+{
+	printf("Subtest %s: %s\n", in_subtest, result);
+	in_subtest = NULL;
+	longjmp(igt_subtest_jmpbuf, 1);
+}
+
+void igt_skip(const char *f, ...)
+{
+	va_list args;
+	skipped_one = true;
+
+	assert(!test_child);
+
+	if (!igt_only_list_subtests()) {
+		va_start(args, f);
+		vprintf(f, args);
+		va_end(args);
+	}
+
+	if (in_subtest) {
+		exit_subtest("SKIP");
+	} else if (test_with_subtests) {
+		skip_subtests_henceforth = SKIP;
+		assert(in_fixture);
+		__igt_fixture_end();
+	} else {
+		exit(77);
+	}
+}
+
+void __igt_skip_check(const char *file, const int line,
+		      const char *func, const char *check,
+		      const char *f, ...)
+{
+	va_list args;
+	int err = errno;
+
+	if (f) {
+		static char *buf;
+
+		/* igt_skip never returns, so try to not leak too badly. */
+		if (buf)
+			free(buf);
+
+		va_start(args, f);
+		vasprintf(&buf, f, args);
+		va_end(args);
+
+		igt_skip("Test requirement not met in function %s, file %s:%i:\n"
+			 "Last errno: %i, %s\n"
+			 "Test requirement: (%s)\n%s",
+			 func, file, line, err, strerror(err), check, buf);
+	} else {
+		igt_skip("Test requirement not met in function %s, file %s:%i:\n"
+			 "Last errno: %i, %s\n"
+			 "Test requirement: (%s)\n",
+			 func, file, line, err, strerror(err), check);
+	}
+}
+
+void igt_success(void)
+{
+	succeeded_one = true;
+	if (in_subtest)
+		exit_subtest("SUCCESS");
+}
+
+void igt_fail(int exitcode)
+{
+	assert(exitcode != 0 && exitcode != 77);
+
+	if (!failed_one)
+		igt_exitcode = exitcode;
+
+	failed_one = true;
+
+	/* Silent exit, parent will do the yelling. */
+	if (test_child)
+		exit(exitcode);
+
+	if (in_subtest)
+		exit_subtest("FAIL");
+	else {
+		assert(!test_with_subtests || in_fixture);
+
+		if (in_fixture) {
+			skip_subtests_henceforth = FAIL;
+			__igt_fixture_end();
+		}
+
+		exit(exitcode);
+	}
+}
+
+static bool run_under_gdb(void)
+{
+	char buf[1024];
+
+	sprintf(buf, "/proc/%d/exe", getppid());
+	return (readlink (buf, buf, sizeof (buf)) != -1 &&
+		strncmp(basename(buf), "gdb", 3) == 0);
+}
+
+void __igt_fail_assert(int exitcode, const char *file,
+		       const int line, const char *func, const char *assertion,
+		       const char *f, ...)
+{
+	va_list args;
+	int err = errno;
+
+	printf("Test assertion failure function %s, file %s:%i:\n"
+	       "Last errno: %i, %s\n"
+	       "Failed assertion: %s\n",
+	       func, file, line, err, strerror(err), assertion);
+
+	if (f) {
+		va_start(args, f);
+		vprintf(f, args);
+		va_end(args);
+	}
+
+	if (run_under_gdb())
+		abort();
+	igt_fail(exitcode);
+}
+
+void igt_exit(void)
+{
+	igt_exit_called = true;
+
+	if (igt_only_list_subtests())
+		exit(0);
+
+	if (!test_with_subtests)
+		exit(0);
+
+	/* Calling this without calling one of the above is a failure */
+	assert(skipped_one || succeeded_one || failed_one);
+
+	if (failed_one)
+		exit(igt_exitcode);
+	else if (succeeded_one)
+		exit(0);
+	else
+		exit(77);
+}
+
+/* fork support code */
+static int helper_process_count;
+static pid_t helper_process_pids[] =
+{ -1, -1, -1, -1};
+
+static void reset_helper_process_list(void)
+{
+	for (int i = 0; i < ARRAY_SIZE(helper_process_pids); i++)
+		helper_process_pids[i] = -1;
+	helper_process_count = 0;
+}
+
+static void fork_helper_exit_handler(int sig)
+{
+	for (int i = 0; i < ARRAY_SIZE(helper_process_pids); i++) {
+		pid_t pid = helper_process_pids[i];
+		int status, ret;
+
+		if (pid != -1) {
+			/* Someone forgot to fill up the array? */
+			assert(pid != 0);
+
+			ret = kill(pid, SIGQUIT);
+			assert(ret == 0);
+			while (waitpid(pid, &status, 0) == -1 &&
+			       errno == EINTR)
+				;
+			helper_process_count--;
+		}
+	}
+
+	assert(helper_process_count == 0);
+}
+
+bool __igt_fork_helper(struct igt_helper_process *proc)
+{
+	pid_t pid;
+	int id;
+
+	assert(!proc->running);
+	assert(helper_process_count < ARRAY_SIZE(helper_process_pids));
+
+	for (id = 0; helper_process_pids[id] != -1; id++)
+		;
+
+	igt_install_exit_handler(fork_helper_exit_handler);
+
+	switch (pid = fork()) {
+	case -1:
+		igt_assert(0);
+	case 0:
+		exit_handler_count = 0;
+		reset_helper_process_list();
+		oom_adjust_for_doom();
+
+		return true;
+	default:
+		proc->running = true;
+		proc->pid = pid;
+		proc->id = id;
+		helper_process_pids[id] = pid;
+		helper_process_count++;
+
+		return false;
+	}
+
+}
+
+void igt_stop_helper(struct igt_helper_process *proc)
+{
+	int status, ret;
+
+	assert(proc->running);
+
+	ret = kill(proc->pid,
+		   proc->use_SIGKILL ? SIGKILL : SIGQUIT);
+	assert(ret == 0);
+	while (waitpid(proc->pid, &status, 0) == -1 &&
+	       errno == EINTR)
+		;
+	igt_assert(WIFSIGNALED(status) &&
+		   WTERMSIG(status) == (proc->use_SIGKILL ? SIGKILL : SIGQUIT));
+
+	proc->running = false;
+
+	helper_process_pids[proc->id] = -1;
+	helper_process_count--;
+}
+
+void igt_wait_helper(struct igt_helper_process *proc)
+{
+	int status;
+
+	assert(proc->running);
+
+	while (waitpid(proc->pid, &status, 0) == -1 &&
+	       errno == EINTR)
+		;
+	igt_assert(WIFEXITED(status) && WEXITSTATUS(status) == 0);
+
+	proc->running = false;
+
+	helper_process_pids[proc->id] = -1;
+	helper_process_count--;
+}
+
+static void children_exit_handler(int sig)
+{
+	int ret;
+
+	assert(!test_child);
+
+	for (int nc = 0; nc < num_test_children; nc++) {
+		int status = -1;
+		ret = kill(test_children[nc], SIGQUIT);
+		assert(ret == 0);
+
+		while (waitpid(test_children[nc], &status, 0) == -1 &&
+		       errno == EINTR)
+			;
+	}
+
+	num_test_children = 0;
+}
+
+bool __igt_fork(void)
+{
+	assert(!test_with_subtests || in_subtest);
+	assert(!test_child);
+
+	igt_install_exit_handler(children_exit_handler);
+
+	if (num_test_children >= test_children_sz) {
+		if (!test_children_sz)
+			test_children_sz = 4;
+		else
+			test_children_sz *= 2;
+
+		test_children = realloc(test_children,
+					sizeof(pid_t)*test_children_sz);
+		igt_assert(test_children);
+	}
+
+	switch (test_children[num_test_children++] = fork()) {
+	case -1:
+		igt_assert(0);
+	case 0:
+		test_child = true;
+		exit_handler_count = 0;
+		reset_helper_process_list();
+		oom_adjust_for_doom();
+
+		return true;
+	default:
+		return false;
+	}
+
+}
+
+/**
+ * igt_waitchildren:
+ *
+ * Wait for all children forked with igt_fork
+ *
+ * The magic here is that exit codes from children will be correctly propagated
+ */
+void igt_waitchildren(void)
+{
+	assert(!test_child);
+
+	for (int nc = 0; nc < num_test_children; nc++) {
+		int status = -1;
+		while (waitpid(test_children[nc], &status, 0) == -1 &&
+		       errno == EINTR)
+			;
+
+		if (status != 0) {
+			if (WIFEXITED(status)) {
+				printf("child %i failed with exit status %i\n",
+				       nc, WEXITSTATUS(status));
+				igt_fail(WEXITSTATUS(status));
+			} else if (WIFSIGNALED(status)) {
+				printf("child %i died with signal %i, %s\n",
+				       nc, WTERMSIG(status),
+				       strsignal(WTERMSIG(status)));
+				igt_fail(99);
+			} else {
+				printf("Unhandled failure in child %i\n", nc);
+				abort();
+			}
+		}
+	}
+
+	num_test_children = 0;
+}
+
+/* exit handler code */
+#define MAX_SIGNALS		32
+#define MAX_EXIT_HANDLERS	5
+
+static struct {
+	sighandler_t handler;
+	bool installed;
+} orig_sig[MAX_SIGNALS];
+
+static igt_exit_handler_t exit_handler_fn[MAX_EXIT_HANDLERS];
+static bool exit_handler_disabled;
+static sigset_t saved_sig_mask;
+static const int handled_signals[] =
+	{ SIGINT, SIGHUP, SIGTERM, SIGQUIT, SIGPIPE, SIGABRT, SIGSEGV, SIGBUS };
+
+static int install_sig_handler(int sig_num, sighandler_t handler)
+{
+	orig_sig[sig_num].handler = signal(sig_num, handler);
+
+	if (orig_sig[sig_num].handler == SIG_ERR)
+		return -1;
+
+	orig_sig[sig_num].installed = true;
+
+	return 0;
+}
+
+static void restore_sig_handler(int sig_num)
+{
+	/* Just restore the default so that we properly fall over. */
+	signal(sig_num, SIG_DFL);
+}
+
+static void restore_all_sig_handler(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(orig_sig); i++)
+		restore_sig_handler(i);
+}
+
+static void call_exit_handlers(int sig)
+{
+	int i;
+
+	if (!exit_handler_count) {
+		return;
+	}
+
+	for (i = exit_handler_count - 1; i >= 0; i--)
+		exit_handler_fn[i](sig);
+
+	/* ensure we don't get called twice */
+	exit_handler_count = 0;
+}
+
+static void igt_atexit_handler(void)
+{
+	restore_all_sig_handler();
+
+	if (!exit_handler_disabled)
+		call_exit_handlers(0);
+}
+
+static void fatal_sig_handler(int sig)
+{
+	pid_t pid, tid;
+
+	restore_all_sig_handler();
+
+	/*
+	 * exit_handler_disabled is always false here, since when we set it
+	 * we also block signals.
+	 */
+	call_exit_handlers(sig);
+
+	/* Workaround cached PID and TID races on glibc and Bionic libc. */
+	pid = syscall(SYS_getpid);
+	tid = syscall(SYS_gettid);
+
+	syscall(SYS_tgkill, pid, tid, sig);
+}
+
+/*
+ * Set a handler that will be called either when the process calls exit() or
+ * returns from the main function, or one of the signals in 'handled_signals'
+ * is raised. MAX_EXIT_HANDLERS handlers can be installed, each of which will
+ * be called only once, even if a subsequent signal is raised. If the exit
+ * handlers are called due to a signal, the signal will be re-raised with the
+ * original signal disposition after all handlers returned.
+ *
+ * The handler will be passed the signal number if called due to a signal, or
+ * 0 otherwise.
+ */
+void igt_install_exit_handler(igt_exit_handler_t fn)
+{
+	int i;
+
+	for (i = 0; i < exit_handler_count; i++)
+		if (exit_handler_fn[i] == fn)
+			return;
+
+	igt_assert(exit_handler_count < MAX_EXIT_HANDLERS);
+
+	exit_handler_fn[exit_handler_count] = fn;
+	exit_handler_count++;
+
+	if (exit_handler_count > 1)
+		return;
+
+	for (i = 0; i < ARRAY_SIZE(handled_signals); i++) {
+		if (install_sig_handler(handled_signals[i],
+					fatal_sig_handler))
+			goto err;
+	}
+
+	if (atexit(igt_atexit_handler))
+		goto err;
+
+	return;
+err:
+	restore_all_sig_handler();
+	exit_handler_count--;
+
+	igt_assert_f(0, "failed to install the signal handler\n");
+}
+
+void igt_disable_exit_handler(void)
+{
+	sigset_t set;
+	int i;
+
+	if (exit_handler_disabled)
+		return;
+
+	sigemptyset(&set);
+	for (i = 0; i < ARRAY_SIZE(handled_signals); i++)
+		sigaddset(&set, handled_signals[i]);
+
+	if (sigprocmask(SIG_BLOCK, &set, &saved_sig_mask)) {
+		perror("sigprocmask");
+		return;
+	}
+
+	exit_handler_disabled = true;
+}
+
+void igt_enable_exit_handler(void)
+{
+	if (!exit_handler_disabled)
+		return;
+
+	if (sigprocmask(SIG_SETMASK, &saved_sig_mask, NULL)) {
+		perror("sigprocmask");
+		return;
+	}
+
+	exit_handler_disabled = false;
+}
+
+/* simulation enviroment support */
+bool igt_run_in_simulation(void)
+{
+	static int simulation = -1;
+
+	if (simulation == -1)
+		simulation = igt_env_set("INTEL_SIMULATION", false);
+
+	return simulation;
+}
+
+/**
+ * igt_skip_on_simulation:
+ *
+ * Skip tests when INTEL_SIMULATION env war is set
+ *
+ * Skip the test when running on simulation (and that's relevant only when
+ * we're not in the mode where we list the subtests).
+ *
+ * This function is subtest aware (since it uses igt_skip) and so can be used to
+ * skip specific subtests or all subsequent subtests.
+ */
+void igt_skip_on_simulation(void)
+{
+	if (igt_only_list_subtests())
+		return;
+
+	igt_require(!igt_run_in_simulation());
+}
+
+/* structured logging */
+void igt_log(enum igt_log_level level, const char *format, ...)
+{
+	va_list args;
+
+	assert(format);
+
+	if (igt_log_level > level)
+		return;
+
+	va_start(args, format);
+	if (level == IGT_LOG_WARN) {
+		fflush(stdout);
+		vfprintf(stderr, format, args);
+	} else
+		vprintf(format, args);
+	va_end(args);
+}
+
diff --git a/lib/igt_core.h b/lib/igt_core.h
new file mode 100644
index 000000000000..1ec0bfcb883d
--- /dev/null
+++ b/lib/igt_core.h
@@ -0,0 +1,305 @@
+/*
+ * Copyright © 2007,2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Eric Anholt <eric@anholt.net>
+ *    Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ */
+
+
+#ifndef IGT_CORE_H
+#define IGT_CORE_H
+
+bool igt_only_list_subtests(void);
+
+bool __igt_fixture(void);
+void __igt_fixture_complete(void);
+void __igt_fixture_end(void) __attribute__((noreturn));
+/**
+ * igt_fixture:
+ *
+ * Annotate global test fixture code
+ *
+ * Testcase with subtests often need to set up a bunch of global state as the
+ * common test fixture. To avoid such code interferring with the subtest
+ * enumeration (e.g. when enumerating on systemes without an intel gpu) such
+ * blocks should be annotated with igt_fixture.
+ */
+#define igt_fixture for (int igt_tokencat(__tmpint,__LINE__) = 0; \
+			 igt_tokencat(__tmpint,__LINE__) < 1 && \
+			 __igt_fixture() && \
+			 (setjmp(igt_subtest_jmpbuf) == 0); \
+			 igt_tokencat(__tmpint,__LINE__) ++, \
+			 __igt_fixture_complete())
+
+/* subtest infrastructure */
+jmp_buf igt_subtest_jmpbuf;
+void igt_subtest_init(int argc, char **argv);
+typedef int (*igt_opt_handler_t)(int opt, int opt_index);
+struct option;
+int igt_subtest_init_parse_opts(int argc, char **argv,
+				const char *extra_short_opts,
+				struct option *extra_long_opts,
+				const char *help_str,
+				igt_opt_handler_t opt_handler);
+
+bool __igt_run_subtest(const char *subtest_name);
+/**
+ * igt_subtest:
+ *
+ * Denote a subtest code block
+ *
+ * Magic control flow which denotes a subtest code block. Within that codeblock
+ * igt_skip|success will only bail out of the subtest. The _f variant accepts a
+ * printf format string, which is useful for constructing combinatorial tests.
+ */
+#define igt_tokencat2(x, y) x ## y
+#define igt_tokencat(x, y) igt_tokencat2(x, y)
+#define __igt_subtest_f(tmp, format...) \
+	for (char tmp [256]; \
+	     snprintf( tmp , sizeof( tmp ), \
+		      format), \
+	     __igt_run_subtest( tmp ) && \
+	     (setjmp(igt_subtest_jmpbuf) == 0); \
+	     igt_success())
+
+/**
+ * igt_subtest_f:
+ * @...: format string
+ *
+ * Denote a subtest code block
+ *
+ * Like #igt_subtest, but also accepts a printf format string
+ */
+#define igt_subtest_f(f...) \
+	__igt_subtest_f(igt_tokencat(__tmpchar, __LINE__), f)
+#define igt_subtest(name) for (; __igt_run_subtest((name)) && \
+				   (setjmp(igt_subtest_jmpbuf) == 0); \
+				   igt_success())
+const char *igt_subtest_name(void);
+#define igt_main \
+	static void igt_tokencat(__real_main, __LINE__)(void); \
+	int main(int argc, char **argv) { \
+		igt_subtest_init(argc, argv); \
+		igt_tokencat(__real_main, __LINE__)(); \
+		igt_exit(); \
+	} \
+	static void igt_tokencat(__real_main, __LINE__)(void) \
+
+/**
+ * igt_simple_init:
+ *
+ * Init for simple tests without subtests
+ */
+void igt_simple_init(void);
+#define igt_simple_main \
+	static void igt_tokencat(__real_main, __LINE__)(void); \
+	int main(int argc, char **argv) { \
+		igt_simple_init(); \
+		igt_tokencat(__real_main, __LINE__)(); \
+		exit(0); \
+	} \
+	static void igt_tokencat(__real_main, __LINE__)(void) \
+
+/**
+ * igt_skip:
+ *
+ * Subtest aware test skipping
+ *
+ * For tests with subtests this will either bail out of the current subtest or
+ * mark all subsequent subtests as SKIP (in case some global setup code failed).
+ *
+ * For normal tests without subtest it will directly exit.
+ */
+__attribute__((format(printf, 1, 2)))
+void igt_skip(const char *f, ...) __attribute__((noreturn));
+__attribute__((format(printf, 5, 6)))
+void __igt_skip_check(const char *file, const int line,
+		      const char *func, const char *check,
+		      const char *format, ...) __attribute__((noreturn));
+/**
+ * igt_success:
+ *
+ * Complete a (subtest) as successfull
+ *
+ * This bails out of a subtests and marks it as successful. For global tests it
+ * it won't bail out of anything.
+ */
+void igt_success(void);
+
+/**
+ * igt_fail:
+ *
+ * Fail a testcase
+ *
+ * For subtest it just bails out of the subtest, when run in global context it
+ * will exit. Note that it won't attempt to keep on running further tests,
+ * presuming that some mandatory setup failed.
+ */
+void igt_fail(int exitcode) __attribute__((noreturn));
+__attribute__((format(printf, 6, 7)))
+void __igt_fail_assert(int exitcode, const char *file,
+		       const int line, const char *func, const char *assertion,
+		       const char *format, ...)
+	__attribute__((noreturn));
+/**
+ * igt_exit:
+ *
+ * exit() for igts
+ *
+ * This will exit the test with the right exit code when subtests have been
+ * skipped. For normal tests it exits with a successful exit code, presuming
+ * everything has worked out. For subtests it also checks that at least one
+ * subtest has been run (save when only listing subtests.
+ */
+void igt_exit(void) __attribute__((noreturn));
+/**
+ * igt_assert:
+ *
+ * Fails (sub-)test if a condition is not met
+ *
+ * Should be used everywhere where a test checks results.
+ */
+#define igt_assert(expr) \
+	do { if (!(expr)) \
+		__igt_fail_assert(99, __FILE__, __LINE__, __func__, #expr , NULL); \
+	} while (0)
+#define igt_assert_f(expr, f...) \
+	do { if (!(expr)) \
+		__igt_fail_assert(99, __FILE__, __LINE__, __func__, #expr , f); \
+	} while (0)
+/**
+ * igt_assert_cmptint:
+ *
+ * Like #igt_assert, but displays the values being compared on failure.
+ */
+#define igt_assert_cmpint(n1, cmp, n2) \
+	do { \
+		int __n1 = (n1), __n2 = (n2); \
+		if (__n1 cmp __n2) ; else \
+		__igt_fail_assert(99, __FILE__, __LINE__, __func__, \
+				  #n1 " " #cmp " " #n2, \
+				  "error: %d %s %d\n", __n1, #cmp, __n2); \
+	} while (0)
+
+/**
+ * igt_require:
+ *
+ * Skip a (sub-)test if a condition is not met
+ *
+ * This is useful to streamline the skip logic since it allows for a more flat
+ * code control flow.
+ */
+#define igt_require(expr) igt_skip_on(!(expr))
+#define igt_skip_on(expr) \
+	do { if ((expr)) \
+		__igt_skip_check(__FILE__, __LINE__, __func__, #expr , NULL); \
+	} while (0)
+#define igt_require_f(expr, f...) igt_skip_on_f(!(expr), f)
+#define igt_skip_on_f(expr, f...) \
+	do { if ((expr)) \
+		__igt_skip_check(__FILE__, __LINE__, __func__, #expr , f); \
+	} while (0)
+
+/* fork support code */
+bool __igt_fork(void);
+/**
+ * igt_fork:
+ * @child: name of the int variable with the child number
+ * @num_children: number of children to fork
+ *
+ * Fork parallel test threads with fork()
+ *
+ * Joining all test threads should be done with igt_waitchildren to ensure that
+ * the exit codes of all children are properly reflected in the test status.
+ */
+#define igt_fork(child, num_children) \
+	for (int child = 0; child < (num_children); child++) \
+		for (; __igt_fork(); exit(0))
+void igt_waitchildren(void);
+
+struct igt_helper_process {
+	bool running;
+	bool use_SIGKILL;
+	pid_t pid;
+	int id;
+};
+bool __igt_fork_helper(struct igt_helper_process *proc);
+void igt_stop_helper(struct igt_helper_process *proc);
+void igt_wait_helper(struct igt_helper_process *proc);
+#define igt_fork_helper(proc) \
+	for (; __igt_fork_helper(proc); exit(0))
+
+/* exit handler code */
+typedef void (*igt_exit_handler_t)(int sig);
+
+/* reliable atexit helpers, also work when killed by a signal (if possible) */
+void igt_install_exit_handler(igt_exit_handler_t fn);
+void igt_enable_exit_handler(void);
+void igt_disable_exit_handler(void);
+
+/* helpers to automatically reduce test runtime in simulation */
+bool igt_run_in_simulation(void);
+#define SLOW_QUICK(slow,quick) (igt_run_in_simulation() ? (quick) : (slow))
+/**
+ * igt_skip_on_simulation:
+ *
+ * Skip tests when INTEL_SIMULATION env war is set
+ *
+ * Skip the test when running on simulation (and that's relevant only when
+ * we're not in the mode where we list the subtests).
+ *
+ * This function is subtest aware (since it uses igt_skip) and so can be used to
+ * skip specific subtests or all subsequent subtests.
+ */
+void igt_skip_on_simulation(void);
+
+/* structured logging */
+enum igt_log_level {
+	IGT_LOG_DEBUG,
+	IGT_LOG_INFO,
+	IGT_LOG_WARN,
+	IGT_LOG_NONE,
+};
+__attribute__((format(printf, 2, 3)))
+void igt_log(enum igt_log_level level, const char *format, ...);
+#define igt_debug(f...) igt_log(IGT_LOG_DEBUG, f)
+#define igt_info(f...) igt_log(IGT_LOG_INFO, f)
+#define igt_warn(f...) igt_log(IGT_LOG_WARN, f)
+extern enum igt_log_level igt_log_level;
+
+#define igt_warn_on(condition) do {\
+		if (condition) \
+			igt_warn("Warning on condition %s in fucntion %s, file %s:%i\n", \
+				 #condition, __func__, __FILE__, __LINE__); \
+	} while (0)
+#define igt_warn_on_f(condition, f...) do {\
+		if (condition) {\
+			igt_warn("Warning on condition %s in fucntion %s, file %s:%i\n", \
+				 #condition, __func__, __FILE__, __LINE__); \
+			igt_warn(f); \
+		} \
+	} while (0)
+
+
+#endif /* IGT_CORE_H */
-- 
1.8.5.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 4/4] lib/igt_core: api documentation
  2014-03-12 15:39 [PATCH 1/4] lib: extract ioctl_wrappers.c Daniel Vetter
  2014-03-12 15:39 ` [PATCH 2/4] lib/ioctl_wrappers: api doc Daniel Vetter
  2014-03-12 15:39 ` [PATCH 3/4] lib: extract igt_core.c Daniel Vetter
@ 2014-03-12 15:39 ` Daniel Vetter
  2 siblings, 0 replies; 4+ messages in thread
From: Daniel Vetter @ 2014-03-12 15:39 UTC (permalink / raw)
  To: Intel Graphics Development; +Cc: Daniel Vetter

At most a bit of comment of function declaration movement for more
polish. One tricky bit is to #ifdef out (only for gtkdoc of course)
the struct option; forward declaration - gtkdoc needlessly lists it.

FIXME: The struct documentation for igt_helper_process somehow doesn't
get picked up ... Same issue seems to be with the igt_log_level enum,
I've shoveled the relevant documentation into igt_log in free-form for
now.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 lib/igt_core.c | 197 +++++++++++++++++++++++++++++++++++---
 lib/igt_core.h | 298 +++++++++++++++++++++++++++++++++++++++++++--------------
 2 files changed, 412 insertions(+), 83 deletions(-)

diff --git a/lib/igt_core.c b/lib/igt_core.c
index 27c159c69ae8..13259b611c23 100644
--- a/lib/igt_core.c
+++ b/lib/igt_core.c
@@ -72,6 +72,17 @@
  * result propagation. Other generally useful functionality includes optional
  * structure logging infrastructure and some support code for running reduced
  * test set on in simulated hardware environments.
+ *
+ * When writing tests with subtests it is extremely important that nothing
+ * interferes with the subtest enumeration. In i-g-t subtests are enumerated at
+ * runtime, which allows powerful testcase enumeration. But it makes subtest
+ * enumeration a bit more tricky since the test code needs to be careful to
+ * never run any code which might fail (like trying to do privileged operations
+ * or opening device driver nodes).
+ *
+ * To allow this i-g-t provides #igt_fixture code blocks for setup code outside
+ * of subtests and automatically skips the subtest code blocks themselves. For
+ * special cases igt_only_list_subtests() is also provided.
  */
 
 static unsigned int exit_handler_count;
@@ -165,6 +176,25 @@ static void oom_adjust_for_doom(void)
 	igt_assert(write(fd, always_kill, sizeof(always_kill)) == sizeof(always_kill));
 }
 
+/**
+ * igt_subtest_init_parse_opts:
+ * @argc: argc from the test's main()
+ * @argv: argv from the test's main()
+ * @extra_short_opts: getopt_long() compliant list with additional short options
+ * @extra_long_opts: getopt_long() compliant list with additional long options
+ * @help_str: help string for the additional options
+ * @extra_opt_handler: handler for the additional options
+ *
+ * This function handles the subtest related cmdline options and allows an
+ * arbitrary set of additional options. This is useful for tests which have
+ * additional knobs to tune when run manually like the number of rounds execute
+ * or the size of the allocated buffer objects.
+ *
+ * Tests without special needs should just use igt_subtest_init() or use
+ * #igt_main directly instead of their own main() function.
+ *
+ * Returns: Forwards any option parsing errors from getopt_long.
+ */
 int igt_subtest_init_parse_opts(int argc, char **argv,
 				const char *extra_short_opts,
 				struct option *extra_long_opts,
@@ -274,6 +304,19 @@ static void common_init(void)
 		igt_log_level = IGT_LOG_NONE;
 }
 
+/**
+ * igt_subtest_init:
+ * @argc: argc from the test's main()
+ * @argv: argv from the test's main()
+ *
+ * This initializes the for tests with subtests without the need for additional
+ * cmdline options. It is just a simplified version of
+ * igt_subtest_init_parse_opts().
+ *
+ * If there's not a reason to the contrary it's less error prone to just use an
+ * #igt_main block instead of stitching the tests's main() function together
+ * manually.
+ */
 void igt_subtest_init(int argc, char **argv)
 {
 	int ret;
@@ -292,6 +335,15 @@ void igt_subtest_init(int argc, char **argv)
 	common_init();
 }
 
+/**
+ * igt_simple_init:
+ *
+ * This initializes a simple test without any support for subtests.
+ *
+ * If there's not a reason to the contrary it's less error prone to just use an
+ * #igt_simple_main block instead of stitching the tests's main() function together
+ * manually.
+ */
 void igt_simple_init(void)
 {
 	print_version();
@@ -330,11 +382,23 @@ bool __igt_run_subtest(const char *subtest_name)
 	return (in_subtest = subtest_name);
 }
 
+/**
+ * igt_subtest_name:
+ *
+ * Returns: The name of the currently executed subtest or NULL if called from
+ * outside a subtest block.
+ */
 const char *igt_subtest_name(void)
 {
 	return in_subtest;
 }
 
+/**
+ * igt_only_list_subtests:
+ *
+ * Returns: Returns true if only subtest should be listed and any setup code
+ * must be skipped, false otherwise.
+ */
 bool igt_only_list_subtests(void)
 {
 	return list_subtests;
@@ -353,6 +417,20 @@ static void exit_subtest(const char *result)
 	longjmp(igt_subtest_jmpbuf, 1);
 }
 
+/**
+ * igt_skip:
+ * @f: format string
+ * @...: optional arguments used in the format string
+ *
+ * Subtest aware test skipping. The format string is printed to stderr as the
+ * reason why the test skipped.
+ *
+ * For tests with subtests this will either bail out of the current subtest or
+ * mark all subsequent subtests as SKIP (presuming some global setup code
+ * failed).
+ *
+ * For normal tests without subtest it will directly exit.
+ */
 void igt_skip(const char *f, ...)
 {
 	va_list args;
@@ -407,6 +485,14 @@ void __igt_skip_check(const char *file, const int line,
 	}
 }
 
+/**
+ * igt_success:
+ *
+ * Complete a (subtest) as successfull
+ *
+ * This bails out of a subtests and marks it as successful. For global tests it
+ * it won't bail out of anything.
+ */
 void igt_success(void)
 {
 	succeeded_one = true;
@@ -414,6 +500,21 @@ void igt_success(void)
 		exit_subtest("SUCCESS");
 }
 
+/**
+ * igt_fail:
+ * @exitcode: exitcode
+ *
+ * Fail a testcase. The exitcode is used as the exit code of the test process.
+ * It may not be 0 (which indicates success) or 77 (which indicates a skipped
+ * test).
+ *
+ * For tests with subtests this will either bail out of the current subtest or
+ * mark all subsequent subtests as FAIL (presuming some global setup code
+ * failed).
+ *
+ * For normal tests without subtest it will directly exit with the given
+ * exitcode.
+ */
 void igt_fail(int exitcode)
 {
 	assert(exitcode != 0 && exitcode != 77);
@@ -473,6 +574,21 @@ void __igt_fail_assert(int exitcode, const char *file,
 	igt_fail(exitcode);
 }
 
+/**
+ * igt_exit:
+ *
+ * exit() for both types (simple and with subtests) of i-g-t tests.
+ *
+ * This will exit the test with the right exit code when subtests have been
+ * skipped. For normal tests it exits with a successful exit code, presuming
+ * everything has worked out. For subtests it also checks that at least one
+ * subtest has been run (save when only listing subtests.
+ *
+ * It is an error to normally exit a test with subtests without calling
+ * igt_exit() - without it the result reporting will be wrong. To avoid such
+ * issues it is highly recommended to use #igt_main instead of a hand-rolled
+ * main() function.
+ */
 void igt_exit(void)
 {
 	igt_exit_called = true;
@@ -562,6 +678,13 @@ bool __igt_fork_helper(struct igt_helper_process *proc)
 
 }
 
+/**
+ * igt_stop_helper:
+ * @proc: #igt_helper_process structure
+ *
+ * Terminates a helper process. It is an error to call this on a helper process
+ * which hasn't been spawned yet.
+ */
 void igt_stop_helper(struct igt_helper_process *proc)
 {
 	int status, ret;
@@ -583,6 +706,13 @@ void igt_stop_helper(struct igt_helper_process *proc)
 	helper_process_count--;
 }
 
+/**
+ * igt_wait_helper:
+ * @proc: #igt_helper_process structure
+ *
+ * Joins a helper process. It is an error to call this on a helper process which
+ * hasn't been spawned yet.
+ */
 void igt_wait_helper(struct igt_helper_process *proc)
 {
 	int status;
@@ -656,9 +786,15 @@ bool __igt_fork(void)
 /**
  * igt_waitchildren:
  *
- * Wait for all children forked with igt_fork
+ * Wait for all children forked with igt_fork.
  *
  * The magic here is that exit codes from children will be correctly propagated
+ * to the main thread, including the relevant exitcode if a child thread failed.
+ * Of course if multiple children failed with differen exitcodes the resulting
+ * exitcode will be non-deterministic.
+ *
+ * Note that igt_skip() will not be forwarded, feature tests need to be done
+ * before spawning threads with igt_fork().
  */
 void igt_waitchildren(void)
 {
@@ -773,7 +909,10 @@ static void fatal_sig_handler(int sig)
 	syscall(SYS_tgkill, pid, tid, sig);
 }
 
-/*
+/**
+ * igt_install_exit_handler:
+ * @fn: exit handler function
+ *
  * Set a handler that will be called either when the process calls exit() or
  * returns from the main function, or one of the signals in 'handled_signals'
  * is raised. MAX_EXIT_HANDLERS handlers can be installed, each of which will
@@ -782,7 +921,10 @@ static void fatal_sig_handler(int sig)
  * original signal disposition after all handlers returned.
  *
  * The handler will be passed the signal number if called due to a signal, or
- * 0 otherwise.
+ * 0 otherwise. Exit handlers can also be used from test children spawned with
+ * igt_fork(), but not from within helper processes spawned with
+ * igt_helper_process(). The list of exit handlers is reset when forking to
+ * avoid issues with children cleanup up the parent's state too early.
  */
 void igt_install_exit_handler(igt_exit_handler_t fn)
 {
@@ -817,6 +959,12 @@ err:
 	igt_assert_f(0, "failed to install the signal handler\n");
 }
 
+/**
+ * igt_disable_exit_handler:
+ *
+ * Temporarily disable all exit handlers. Useful for library code doing tricky
+ * things.
+ */
 void igt_disable_exit_handler(void)
 {
 	sigset_t set;
@@ -837,6 +985,12 @@ void igt_disable_exit_handler(void)
 	exit_handler_disabled = true;
 }
 
+/**
+ * igt_enable_exit_handler:
+ *
+ * Re-enable all exit handlers temporarily disabled with
+ * igt_disable_exit_handler().
+ */
 void igt_enable_exit_handler(void)
 {
 	if (!exit_handler_disabled)
@@ -851,6 +1005,16 @@ void igt_enable_exit_handler(void)
 }
 
 /* simulation enviroment support */
+
+/**
+ * igt_run_in_simulation:
+ *
+ * This function can be used to select a reduced test set when running in
+ * simulation enviroments. This i-g-t mode is selected by setting the
+ * INTEL_SIMULATION enviroment variable to 1.
+ *
+ * Returns: True when run in simulation mode, false otherwise.
+ */
 bool igt_run_in_simulation(void)
 {
 	static int simulation = -1;
@@ -864,13 +1028,8 @@ bool igt_run_in_simulation(void)
 /**
  * igt_skip_on_simulation:
  *
- * Skip tests when INTEL_SIMULATION env war is set
- *
- * Skip the test when running on simulation (and that's relevant only when
- * we're not in the mode where we list the subtests).
- *
- * This function is subtest aware (since it uses igt_skip) and so can be used to
- * skip specific subtests or all subsequent subtests.
+ * Skip tests when INTEL_SIMULATION environment variable is set. It uses
+ * igt_skip() internally and hence is fully subtest aware.
  */
 void igt_skip_on_simulation(void)
 {
@@ -881,6 +1040,23 @@ void igt_skip_on_simulation(void)
 }
 
 /* structured logging */
+
+/**
+ * igt_log:
+ * @level: #igt_log_level
+ * @format: format string
+ * @...: optional arguments used in the format string
+ *
+ * This is the generic structure logging helper function. i-g-t testcase should
+ * output all normal message to stdout. Warning level message should be printed
+ * to stderr and the test runner should treat this as an intermediate result
+ * between SUCESS and FAILURE.
+ *
+ * The log level can be set through the IGT_LOG_LEVEL enviroment variable with
+ * values "debug", "info", "warn" and "none". By default verbose debug message
+ * are disabled. "none" completely disables all output and is not recommended
+ * since crucial issues only reported at the IGT_LOG_WARN level are ignored.
+ */
 void igt_log(enum igt_log_level level, const char *format, ...)
 {
 	va_list args;
@@ -898,4 +1074,3 @@ void igt_log(enum igt_log_level level, const char *format, ...)
 		vprintf(format, args);
 	va_end(args);
 }
-
diff --git a/lib/igt_core.h b/lib/igt_core.h
index 1ec0bfcb883d..0e3d7be00d1e 100644
--- a/lib/igt_core.h
+++ b/lib/igt_core.h
@@ -30,8 +30,6 @@
 #ifndef IGT_CORE_H
 #define IGT_CORE_H
 
-bool igt_only_list_subtests(void);
-
 bool __igt_fixture(void);
 void __igt_fixture_complete(void);
 void __igt_fixture_end(void) __attribute__((noreturn));
@@ -56,25 +54,42 @@ void __igt_fixture_end(void) __attribute__((noreturn));
 jmp_buf igt_subtest_jmpbuf;
 void igt_subtest_init(int argc, char **argv);
 typedef int (*igt_opt_handler_t)(int opt, int opt_index);
+#ifndef __GTK_DOC_IGNORE__ /* gtkdoc wants to document this forward decl */
 struct option;
+#endif
 int igt_subtest_init_parse_opts(int argc, char **argv,
 				const char *extra_short_opts,
 				struct option *extra_long_opts,
 				const char *help_str,
-				igt_opt_handler_t opt_handler);
+				igt_opt_handler_t extra_opt_handler);
 
 bool __igt_run_subtest(const char *subtest_name);
+#define __igt_tokencat2(x, y) x ## y
+
+/**
+ * igt_tokencat:
+ * @x: first variable
+ * @y: second variable
+ *
+ * C preprocessor helper to concatenate two variables while properly expanding
+ * them.
+ */
+#define igt_tokencat(x, y) __igt_tokencat2(x, y)
+
 /**
  * igt_subtest:
+ * @name: name of the subtest
  *
- * Denote a subtest code block
+ * This is a magic control flow block which denotes a subtest code block. Within
+ * that codeblock igt_skip|success will only bail out of the subtest. The _f
+ * variant accepts a printf format string, which is useful for constructing
+ * combinatorial tests.
  *
- * Magic control flow which denotes a subtest code block. Within that codeblock
- * igt_skip|success will only bail out of the subtest. The _f variant accepts a
- * printf format string, which is useful for constructing combinatorial tests.
+ * This is a simpler version of igt_subtest_f()
  */
-#define igt_tokencat2(x, y) x ## y
-#define igt_tokencat(x, y) igt_tokencat2(x, y)
+#define igt_subtest(name) for (; __igt_run_subtest((name)) && \
+				   (setjmp(igt_subtest_jmpbuf) == 0); \
+				   igt_success())
 #define __igt_subtest_f(tmp, format...) \
 	for (char tmp [256]; \
 	     snprintf( tmp , sizeof( tmp ), \
@@ -85,18 +100,29 @@ bool __igt_run_subtest(const char *subtest_name);
 
 /**
  * igt_subtest_f:
- * @...: format string
+ * @...: format string and optional arguments
  *
- * Denote a subtest code block
+ * This is a magic control flow block which denotes a subtest code block. Within
+ * that codeblock igt_skip|success will only bail out of the subtest. The _f
+ * variant accepts a printf format string, which is useful for constructing
+ * combinatorial tests.
  *
- * Like #igt_subtest, but also accepts a printf format string
+ * Like igt_subtest(), but also accepts a printf format string instead of a
+ * static string.
  */
 #define igt_subtest_f(f...) \
 	__igt_subtest_f(igt_tokencat(__tmpchar, __LINE__), f)
-#define igt_subtest(name) for (; __igt_run_subtest((name)) && \
-				   (setjmp(igt_subtest_jmpbuf) == 0); \
-				   igt_success())
+
 const char *igt_subtest_name(void);
+bool igt_only_list_subtests(void);
+
+/**
+ * igt_main:
+ *
+ * This is a magic control flow block used instead of a main() function for
+ * tests with subtests. Open-coding the main() function is only recommended if
+ * the test needs to parse additional cmdline arguments of its own.
+ */
 #define igt_main \
 	static void igt_tokencat(__real_main, __LINE__)(void); \
 	int main(int argc, char **argv) { \
@@ -112,6 +138,14 @@ const char *igt_subtest_name(void);
  * Init for simple tests without subtests
  */
 void igt_simple_init(void);
+
+/**
+ * igt_simple_main:
+ *
+ * This is a magic control flow block used instead of a main() function for
+ * simple tests. Open-coding the main() function is only recommended if
+ * the test needs to parse additional cmdline arguments of its own.
+ */
 #define igt_simple_main \
 	static void igt_tokencat(__real_main, __LINE__)(void); \
 	int main(int argc, char **argv) { \
@@ -121,62 +155,27 @@ void igt_simple_init(void);
 	} \
 	static void igt_tokencat(__real_main, __LINE__)(void) \
 
-/**
- * igt_skip:
- *
- * Subtest aware test skipping
- *
- * For tests with subtests this will either bail out of the current subtest or
- * mark all subsequent subtests as SKIP (in case some global setup code failed).
- *
- * For normal tests without subtest it will directly exit.
- */
 __attribute__((format(printf, 1, 2)))
 void igt_skip(const char *f, ...) __attribute__((noreturn));
 __attribute__((format(printf, 5, 6)))
 void __igt_skip_check(const char *file, const int line,
 		      const char *func, const char *check,
 		      const char *format, ...) __attribute__((noreturn));
-/**
- * igt_success:
- *
- * Complete a (subtest) as successfull
- *
- * This bails out of a subtests and marks it as successful. For global tests it
- * it won't bail out of anything.
- */
 void igt_success(void);
 
-/**
- * igt_fail:
- *
- * Fail a testcase
- *
- * For subtest it just bails out of the subtest, when run in global context it
- * will exit. Note that it won't attempt to keep on running further tests,
- * presuming that some mandatory setup failed.
- */
 void igt_fail(int exitcode) __attribute__((noreturn));
 __attribute__((format(printf, 6, 7)))
 void __igt_fail_assert(int exitcode, const char *file,
 		       const int line, const char *func, const char *assertion,
 		       const char *format, ...)
 	__attribute__((noreturn));
-/**
- * igt_exit:
- *
- * exit() for igts
- *
- * This will exit the test with the right exit code when subtests have been
- * skipped. For normal tests it exits with a successful exit code, presuming
- * everything has worked out. For subtests it also checks that at least one
- * subtest has been run (save when only listing subtests.
- */
 void igt_exit(void) __attribute__((noreturn));
+
 /**
  * igt_assert:
+ * @expr: condition to test
  *
- * Fails (sub-)test if a condition is not met
+ * Fails (sub-)test if the condition is not met
  *
  * Should be used everywhere where a test checks results.
  */
@@ -184,14 +183,36 @@ void igt_exit(void) __attribute__((noreturn));
 	do { if (!(expr)) \
 		__igt_fail_assert(99, __FILE__, __LINE__, __func__, #expr , NULL); \
 	} while (0)
+
+/**
+ * igt_assert_f:
+ * @expr: condition to test
+ * @...: format string and optional arguments
+ *
+ * Fails (sub-)test if the condition is not met
+ *
+ * Should be used everywhere where a test checks results.
+ *
+ * In addition to the plain igt_assert() helper this allows to print additional
+ * information to help debugging test failures.
+ */
 #define igt_assert_f(expr, f...) \
 	do { if (!(expr)) \
 		__igt_fail_assert(99, __FILE__, __LINE__, __func__, #expr , f); \
 	} while (0)
+
 /**
- * igt_assert_cmptint:
+ * igt_assert_cmpint:
+ * @n1: first value
+ * @cmp: compare operator
+ * @n2: second value
+ *
+ * Fails (sub-)test if the condition is not met
+ *
+ * Should be used everywhere where a test compares two integer values.
  *
- * Like #igt_assert, but displays the values being compared on failure.
+ * Like igt_assert(), but displays the values being compared on failure instead
+ * of simply printing the stringified expression.
  */
 #define igt_assert_cmpint(n1, cmp, n2) \
 	do { \
@@ -204,18 +225,61 @@ void igt_exit(void) __attribute__((noreturn));
 
 /**
  * igt_require:
+ * @expr: condition to test
  *
- * Skip a (sub-)test if a condition is not met
+ * Skip a (sub-)test if a condition is not met.
  *
- * This is useful to streamline the skip logic since it allows for a more flat
- * code control flow.
+ * Should be used everywhere where a test checks results to decide about
+ * skipping. This is useful to streamline the skip logic since it allows for a more flat
+ * code control flow, similar to igt_assert()
  */
 #define igt_require(expr) igt_skip_on(!(expr))
+
+/**
+ * igt_skip_on:
+ * @expr: condition to test
+ *
+ * Skip a (sub-)test if a condition is met.
+ *
+ * Should be used everywhere where a test checks results to decide about
+ * skipping. This is useful to streamline the skip logic since it allows for a more flat
+ * code control flow, similar to igt_assert()
+ */
 #define igt_skip_on(expr) \
 	do { if ((expr)) \
 		__igt_skip_check(__FILE__, __LINE__, __func__, #expr , NULL); \
 	} while (0)
+
+/**
+ * igt_require_f:
+ * @expr: condition to test
+ * @...: format string and optional arguments
+ *
+ * Skip a (sub-)test if a condition is not met.
+ *
+ * Should be used everywhere where a test checks results to decide about
+ * skipping. This is useful to streamline the skip logic since it allows for a more flat
+ * code control flow, similar to igt_assert()
+ *
+ * In addition to the plain igt_require() helper this allows to print additional
+ * information to help debugging test failures.
+ */
 #define igt_require_f(expr, f...) igt_skip_on_f(!(expr), f)
+
+/**
+ * igt_skip_on_f:
+ * @expr: condition to test
+ * @...: format string and optional arguments
+ *
+ * Skip a (sub-)test if a condition is met.
+ *
+ * Should be used everywhere where a test checks results to decide about
+ * skipping. This is useful to streamline the skip logic since it allows for a more flat
+ * code control flow, similar to igt_assert()
+ *
+ * In addition to the plain igt_skip_on() helper this allows to print additional
+ * information to help debugging test failures.
+ */
 #define igt_skip_on_f(expr, f...) \
 	do { if ((expr)) \
 		__igt_skip_check(__FILE__, __LINE__, __func__, #expr , f); \
@@ -223,21 +287,37 @@ void igt_exit(void) __attribute__((noreturn));
 
 /* fork support code */
 bool __igt_fork(void);
+
 /**
  * igt_fork:
  * @child: name of the int variable with the child number
  * @num_children: number of children to fork
  *
- * Fork parallel test threads with fork()
+ * This is a magic control flow block which spawns parallel test threads with
+ * fork().
+ *
+ * The test children execute in parallel to the main test thread. Joining all
+ * test threads should be done with igt_waitchildren to ensure that the exit
+ * codes of all children are properly reflected in the test status.
  *
- * Joining all test threads should be done with igt_waitchildren to ensure that
- * the exit codes of all children are properly reflected in the test status.
+ * Note that igt_skip() will not be forwarded, feature tests need to be done
+ * before spawning threads with igt_fork().
  */
 #define igt_fork(child, num_children) \
 	for (int child = 0; child < (num_children); child++) \
 		for (; __igt_fork(); exit(0))
 void igt_waitchildren(void);
 
+/**
+ * igt_helper_process_t:
+ * @running: indicates whether the process is currently running
+ * @use_SIGKILL: whether the helper should be terminated with SIGKILL or SIGQUIT
+ * @pid: pid of the helper if @running is true
+ * @id: internal id
+ *
+ * Tracking structure for helper processes. Users of the i-g-t library should
+ * only set @use_SIGKILL directly.
+ */
 struct igt_helper_process {
 	bool running;
 	bool use_SIGKILL;
@@ -245,12 +325,40 @@ struct igt_helper_process {
 	int id;
 };
 bool __igt_fork_helper(struct igt_helper_process *proc);
-void igt_stop_helper(struct igt_helper_process *proc);
-void igt_wait_helper(struct igt_helper_process *proc);
+
+/**
+ * igt_fork_helper:
+ * @proc: #igt_helper_process structure
+ *
+ * This is a magic control flow block which denotes an asynchronous helper
+ * process block. The difference compared to igt_fork() is that failures from
+ * the child process will not be forwarded, making this construct more suitable
+ * for background processes. Common use cases are regular interference of the
+ * main test thread through e.g. sending signals or evicting objects through
+ * debugfs. Through the explicit #igt_helper_process they can also be controlled
+ * in a more fine-grained way than test children spawned through igt_fork().
+ *
+ * For tests with subtest helper process can be started outside of a
+ * #igt_subtest block.
+ *
+ * Calling igt_wait_helper() joins a helper process and igt_stop_helper()
+ * forcefully terminates it.
+ */
 #define igt_fork_helper(proc) \
 	for (; __igt_fork_helper(proc); exit(0))
+void igt_wait_helper(struct igt_helper_process *proc);
+void igt_stop_helper(struct igt_helper_process *proc);
 
 /* exit handler code */
+
+/**
+ * igt_exit_handler_t:
+ * @sig: Signal number which caused the exit or 0.
+ *
+ * Exit handler type used by igt_install_exit_handler(). Note that exit handlers
+ * can potentially be run from signal handling contexts, the @sig parameter can
+ * be used to figure this out and act accordingly.
+ */
 typedef void (*igt_exit_handler_t)(int sig);
 
 /* reliable atexit helpers, also work when killed by a signal (if possible) */
@@ -260,18 +368,16 @@ void igt_disable_exit_handler(void);
 
 /* helpers to automatically reduce test runtime in simulation */
 bool igt_run_in_simulation(void);
-#define SLOW_QUICK(slow,quick) (igt_run_in_simulation() ? (quick) : (slow))
 /**
- * igt_skip_on_simulation:
- *
- * Skip tests when INTEL_SIMULATION env war is set
+ * SLOW_QUICK:
+ * @slow: value in simulation mode
+ * @quick: value in normal mode
  *
- * Skip the test when running on simulation (and that's relevant only when
- * we're not in the mode where we list the subtests).
- *
- * This function is subtest aware (since it uses igt_skip) and so can be used to
- * skip specific subtests or all subsequent subtests.
+ * Simple macro to select between two values (e.g. number of test rounds or test
+ * buffer size) depending upon whether i-g-t is run in simulation mode or not.
  */
+#define SLOW_QUICK(slow,quick) (igt_run_in_simulation() ? (quick) : (slow))
+
 void igt_skip_on_simulation(void);
 
 /* structured logging */
@@ -283,16 +389,64 @@ enum igt_log_level {
 };
 __attribute__((format(printf, 2, 3)))
 void igt_log(enum igt_log_level level, const char *format, ...);
+
+/**
+ * igt_debug:
+ * @...: format string and optional arguments
+ *
+ * Wrapper for igt_log for message at the IGT_LOG_DEBUG level.
+ */
 #define igt_debug(f...) igt_log(IGT_LOG_DEBUG, f)
+
+/**
+ * igt_info:
+ * @...: format string and optional arguments
+ *
+ * Wrapper for igt_log for message at the IGT_LOG_INFO level.
+ */
 #define igt_info(f...) igt_log(IGT_LOG_INFO, f)
+
+/**
+ * igt_warn:
+ * @...: format string and optional arguments
+ *
+ * Wrapper for igt_log for message at the IGT_LOG_WARN level.
+ */
 #define igt_warn(f...) igt_log(IGT_LOG_WARN, f)
 extern enum igt_log_level igt_log_level;
 
+/**
+ * igt_warn_on:
+ * @condition: condition to test
+ *
+ * Print a IGT_LOG_WARN level message if a condition is not met.
+ *
+ * Should be used everywhere where a test checks results to decide about
+ * printing warnings. This is useful to streamline the test logic since it
+ * allows for a more flat code control flow, similar to igt_assert()
+ */
 #define igt_warn_on(condition) do {\
 		if (condition) \
 			igt_warn("Warning on condition %s in fucntion %s, file %s:%i\n", \
 				 #condition, __func__, __FILE__, __LINE__); \
 	} while (0)
+
+/**
+ * igt_warn_on_f:
+ * @condition: condition to test
+ * @...: format string and optional arguments
+ *
+ * Skip a (sub-)test if a condition is not met.
+ *
+ * Print a IGT_LOG_WARN level message if a condition is not met.
+ *
+ * Should be used everywhere where a test checks results to decide about
+ * printing warnings. This is useful to streamline the test logic since it
+ * allows for a more flat code control flow, similar to igt_assert()
+ *
+ * In addition to the plain igt_warn_on_f() helper this allows to print
+ * additional information (again as warnings) to help debugging test failures.
+ */
 #define igt_warn_on_f(condition, f...) do {\
 		if (condition) {\
 			igt_warn("Warning on condition %s in fucntion %s, file %s:%i\n", \
-- 
1.8.5.2

^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2014-03-12 15:40 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-03-12 15:39 [PATCH 1/4] lib: extract ioctl_wrappers.c Daniel Vetter
2014-03-12 15:39 ` [PATCH 2/4] lib/ioctl_wrappers: api doc Daniel Vetter
2014-03-12 15:39 ` [PATCH 3/4] lib: extract igt_core.c Daniel Vetter
2014-03-12 15:39 ` [PATCH 4/4] lib/igt_core: api documentation Daniel Vetter

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.