Commit 09dee2a6 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'linux-kselftest-4.10-rc1-update' of...

Merge tag 'linux-kselftest-4.10-rc1-update' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest

Pull kselftest updates from Shuah Khan:
 "This update consists of:

   - new tests to exercise the Sync Kernel Infrastructure. These tests
     are part of a battery of Android libsync tests and are re-written
     to test the new sync user-space interfaces from Emilio López, and
     Gustavo Padovan.

   - test to run hw-independent mock tests for i915.ko from Chris Wilson

   - a new gpio test case from Bamvor Jian Zhang

   - missing gitignore additions"

* tag 'linux-kselftest-4.10-rc1-update' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest:
  selftest/gpio: add gpio test case
  selftest: sync: improve assert() failure message
  kselftests: Exercise hw-independent mock tests for i915.ko
  selftests: add missing gitignore files/dirs
  selftests: add missing set-tz to timers .gitignore
  selftest: sync: stress test for merges
  selftest: sync: stress consumer/producer test
  selftest: sync: stress test for parallelism
  selftest: sync: wait tests for sw_sync framework
  selftest: sync: merge tests for sw_sync framework
  selftest: sync: fence tests for sw_sync framework
  selftest: sync: basic tests for sw_sync framework
parents d25b6af9 22f6592b
......@@ -7,6 +7,7 @@ TARGETS += exec
TARGETS += firmware
TARGETS += ftrace
TARGETS += futex
TARGETS += gpio
TARGETS += ipc
TARGETS += kcmp
TARGETS += lib
......@@ -24,6 +25,7 @@ TARGETS += seccomp
TARGETS += sigaltstack
TARGETS += size
TARGETS += static_keys
TARGETS += sync
TARGETS += sysctl
ifneq (1, $(quicktest))
TARGETS += timers
......
#!/bin/sh
# Runs hardware independent tests for i915 (drivers/gpu/drm/i915)
if ! /sbin/modprobe -q -r i915; then
echo "drivers/gpu/i915: [SKIP]"
exit 77
fi
if /sbin/modprobe -q i915 mock_selftests=-1; then
echo "drivers/gpu/i915: ok"
else
echo "drivers/gpu/i915: [FAIL]"
exit 1
fi
TEST_PROGS := gpio-mockup.sh
TEST_FILES := gpio-mockup-sysfs.sh $(BINARIES)
BINARIES := gpio-mockup-chardev
include ../lib.mk
all: $(BINARIES)
clean:
$(RM) $(BINARIES)
CFLAGS += -O2 -g -std=gnu99 -Wall -I../../../../usr/include/
LDLIBS += -lmount -I/usr/include/libmount
$(BINARIES): ../../../gpio/gpio-utils.o ../../../../usr/include/linux/gpio.h
../../../gpio/gpio-utils.o:
make ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C ../../../gpio
../../../../usr/include/linux/gpio.h:
make -C ../../../.. headers_install INSTALL_HDR_PATH=$(shell pwd)/../../../../usr/
/*
* GPIO chardev test helper
*
* Copyright (C) 2016 Bamvor Jian Zhang
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#define _GNU_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <getopt.h>
#include <sys/ioctl.h>
#include <libmount.h>
#include <err.h>
#include <dirent.h>
#include <linux/gpio.h>
#include "../../../gpio/gpio-utils.h"
#define CONSUMER "gpio-selftest"
#define GC_NUM 10
enum direction {
OUT,
IN
};
static int get_debugfs(char **path)
{
struct libmnt_context *cxt;
struct libmnt_table *tb;
struct libmnt_iter *itr = NULL;
struct libmnt_fs *fs;
int found = 0;
cxt = mnt_new_context();
if (!cxt)
err(EXIT_FAILURE, "libmount context allocation failed");
itr = mnt_new_iter(MNT_ITER_FORWARD);
if (!itr)
err(EXIT_FAILURE, "failed to initialize libmount iterator");
if (mnt_context_get_mtab(cxt, &tb))
err(EXIT_FAILURE, "failed to read mtab");
while (mnt_table_next_fs(tb, itr, &fs) == 0) {
const char *type = mnt_fs_get_fstype(fs);
if (!strcmp(type, "debugfs")) {
found = 1;
break;
}
}
if (found)
asprintf(path, "%s/gpio", mnt_fs_get_target(fs));
mnt_free_iter(itr);
mnt_free_context(cxt);
if (!found)
return -1;
return 0;
}
static int gpio_debugfs_get(const char *consumer, int *dir, int *value)
{
char *debugfs;
FILE *f;
char *line = NULL;
size_t len = 0;
char *cur;
int found = 0;
if (get_debugfs(&debugfs) != 0)
err(EXIT_FAILURE, "debugfs is not mounted");
f = fopen(debugfs, "r");
if (!f)
err(EXIT_FAILURE, "read from gpio debugfs failed");
/*
* gpio-2 ( |gpio-selftest ) in lo
*/
while (getline(&line, &len, f) != -1) {
cur = strstr(line, consumer);
if (cur == NULL)
continue;
cur = strchr(line, ')');
if (!cur)
continue;
cur += 2;
if (!strncmp(cur, "out", 3)) {
*dir = OUT;
cur += 4;
} else if (!strncmp(cur, "in", 2)) {
*dir = IN;
cur += 4;
}
if (!strncmp(cur, "hi", 2))
*value = 1;
else if (!strncmp(cur, "lo", 2))
*value = 0;
found = 1;
break;
}
free(debugfs);
fclose(f);
free(line);
if (!found)
return -1;
return 0;
}
static struct gpiochip_info *list_gpiochip(const char *gpiochip_name, int *ret)
{
struct gpiochip_info *cinfo;
struct gpiochip_info *current;
const struct dirent *ent;
DIR *dp;
char *chrdev_name;
int fd;
int i = 0;
cinfo = calloc(sizeof(struct gpiochip_info) * 4, GC_NUM + 1);
if (!cinfo)
err(EXIT_FAILURE, "gpiochip_info allocation failed");
current = cinfo;
dp = opendir("/dev");
if (!dp) {
*ret = -errno;
goto error_out;
} else {
*ret = 0;
}
while (ent = readdir(dp), ent) {
if (check_prefix(ent->d_name, "gpiochip")) {
*ret = asprintf(&chrdev_name, "/dev/%s", ent->d_name);
if (*ret < 0)
goto error_out;
fd = open(chrdev_name, 0);
if (fd == -1) {
*ret = -errno;
fprintf(stderr, "Failed to open %s\n",
chrdev_name);
goto error_close_dir;
}
*ret = ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, current);
if (*ret == -1) {
perror("Failed to issue CHIPINFO IOCTL\n");
goto error_close_dir;
}
close(fd);
if (strcmp(current->label, gpiochip_name) == 0
|| check_prefix(current->label, gpiochip_name)) {
*ret = 0;
current++;
i++;
}
}
}
if ((!*ret && i == 0) || *ret < 0) {
free(cinfo);
cinfo = NULL;
}
if (!*ret && i > 0) {
cinfo = realloc(cinfo, sizeof(struct gpiochip_info) * 4 * i);
*ret = i;
}
error_close_dir:
closedir(dp);
error_out:
if (*ret < 0)
err(EXIT_FAILURE, "list gpiochip failed: %s", strerror(*ret));
return cinfo;
}
int gpio_pin_test(struct gpiochip_info *cinfo, int line, int flag, int value)
{
struct gpiohandle_data data;
unsigned int lines[] = {line};
int fd;
int debugfs_dir = IN;
int debugfs_value = 0;
int ret;
data.values[0] = value;
ret = gpiotools_request_linehandle(cinfo->name, lines, 1, flag, &data,
CONSUMER);
if (ret < 0)
goto fail_out;
else
fd = ret;
ret = gpio_debugfs_get(CONSUMER, &debugfs_dir, &debugfs_value);
if (ret) {
ret = -EINVAL;
goto fail_out;
}
if (flag & GPIOHANDLE_REQUEST_INPUT) {
if (debugfs_dir != IN) {
errno = -EINVAL;
ret = -errno;
}
} else if (flag & GPIOHANDLE_REQUEST_OUTPUT) {
if (flag & GPIOHANDLE_REQUEST_ACTIVE_LOW)
debugfs_value = !debugfs_value;
if (!(debugfs_dir == OUT && value == debugfs_value))
errno = -EINVAL;
ret = -errno;
}
gpiotools_release_linehandle(fd);
fail_out:
if (ret)
err(EXIT_FAILURE, "gpio<%s> line<%d> test flag<0x%x> value<%d>",
cinfo->name, line, flag, value);
return ret;
}
void gpio_pin_tests(struct gpiochip_info *cinfo, unsigned int line)
{
printf("line<%d>", line);
gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_OUTPUT, 0);
printf(".");
gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_OUTPUT, 1);
printf(".");
gpio_pin_test(cinfo, line,
GPIOHANDLE_REQUEST_OUTPUT | GPIOHANDLE_REQUEST_ACTIVE_LOW,
0);
printf(".");
gpio_pin_test(cinfo, line,
GPIOHANDLE_REQUEST_OUTPUT | GPIOHANDLE_REQUEST_ACTIVE_LOW,
1);
printf(".");
gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_INPUT, 0);
printf(".");
}
/*
* ./gpio-mockup-chardev gpio_chip_name_prefix is_valid_gpio_chip
* Return 0 if successful or exit with EXIT_FAILURE if test failed.
* gpio_chip_name_prefix: The prefix of gpiochip you want to test. E.g.
* gpio-mockup
* is_valid_gpio_chip: Whether the gpio_chip is valid. 1 means valid,
* 0 means invalid which could not be found by
* list_gpiochip.
*/
int main(int argc, char *argv[])
{
char *prefix;
int valid;
struct gpiochip_info *cinfo;
struct gpiochip_info *current;
int i;
int ret;
if (argc < 3) {
printf("Usage: %s prefix is_valid", argv[0]);
exit(EXIT_FAILURE);
}
prefix = argv[1];
valid = strcmp(argv[2], "true") == 0 ? 1 : 0;
printf("Test gpiochip %s: ", prefix);
cinfo = list_gpiochip(prefix, &ret);
if (!cinfo) {
if (!valid && ret == 0) {
printf("Invalid test successful\n");
ret = 0;
goto out;
} else {
ret = -EINVAL;
goto out;
}
} else if (cinfo && !valid) {
ret = -EINVAL;
goto out;
}
current = cinfo;
for (i = 0; i < ret; i++) {
gpio_pin_tests(current, 0);
gpio_pin_tests(current, current->lines - 1);
gpio_pin_tests(current, random() % current->lines);
current++;
}
ret = 0;
printf("successful\n");
out:
if (ret)
fprintf(stderr, "gpio<%s> test failed\n", prefix);
if (cinfo)
free(cinfo);
if (ret)
exit(EXIT_FAILURE);
return ret;
}
is_consistent()
{
val=
active_low_sysfs=`cat $GPIO_SYSFS/gpio$nr/active_low`
val_sysfs=`cat $GPIO_SYSFS/gpio$nr/value`
dir_sysfs=`cat $GPIO_SYSFS/gpio$nr/direction`
gpio_this_debugfs=`cat $GPIO_DEBUGFS |grep "gpio-$nr" | sed "s/(.*)//g"`
dir_debugfs=`echo $gpio_this_debugfs | awk '{print $2}'`
val_debugfs=`echo $gpio_this_debugfs | awk '{print $3}'`
if [ $val_debugfs = "lo" ]; then
val=0
elif [ $val_debugfs = "hi" ]; then
val=1
fi
if [ $active_low_sysfs = "1" ]; then
if [ $val = "0" ]; then
val="1"
else
val="0"
fi
fi
if [ $val_sysfs = $val ] && [ $dir_sysfs = $dir_debugfs ]; then
echo -n "."
else
echo "test fail, exit"
die
fi
}
test_pin_logic()
{
nr=$1
direction=$2
active_low=$3
value=$4
echo $direction > $GPIO_SYSFS/gpio$nr/direction
echo $active_low > $GPIO_SYSFS/gpio$nr/active_low
if [ $direction = "out" ]; then
echo $value > $GPIO_SYSFS/gpio$nr/value
fi
is_consistent $nr
}
test_one_pin()
{
nr=$1
echo -n "test pin<$nr>"
echo $nr > $GPIO_SYSFS/export 2>/dev/null
if [ X$? != X0 ]; then
echo "test GPIO pin $nr failed"
die
fi
#"Checking if the sysfs is consistent with debugfs: "
is_consistent $nr
#"Checking the logic of active_low: "
test_pin_logic $nr out 1 1
test_pin_logic $nr out 1 0
test_pin_logic $nr out 0 1
test_pin_logic $nr out 0 0
#"Checking the logic of direction: "
test_pin_logic $nr in 1 1
test_pin_logic $nr out 1 0
test_pin_logic $nr low 0 1
test_pin_logic $nr high 0 0
echo $nr > $GPIO_SYSFS/unexport
echo "successful"
}
test_one_pin_fail()
{
nr=$1
echo $nr > $GPIO_SYSFS/export 2>/dev/null
if [ X$? != X0 ]; then
echo "test invalid pin $nr successful"
else
echo "test invalid pin $nr failed"
echo $nr > $GPIO_SYSFS/unexport 2>/dev/null
die
fi
}
list_chip()
{
echo `ls -d $GPIO_DRV_SYSFS/gpiochip* 2>/dev/null`
}
test_chip()
{
chip=$1
name=`basename $chip`
base=`cat $chip/base`
ngpio=`cat $chip/ngpio`
printf "%-10s %-5s %-5s\n" $name $base $ngpio
if [ $ngpio = "0" ]; then
echo "number of gpio is zero is not allowed".
fi
test_one_pin $base
test_one_pin $(($base + $ngpio - 1))
test_one_pin $((( RANDOM % $ngpio ) + $base ))
}
test_chips_sysfs()
{
gpiochip=`list_chip $module`
if [ X"$gpiochip" = X ]; then
if [ X"$valid" = Xfalse ]; then
echo "successful"
else
echo "fail"
die
fi
else
for chip in $gpiochip; do
test_chip $chip
done
fi
}
#!/bin/bash
#exit status
#1: run as non-root user
#2: sysfs/debugfs not mount
#3: insert module fail when gpio-mockup is a module.
#4: other reason.
SYSFS=
GPIO_SYSFS=
GPIO_DRV_SYSFS=
DEBUGFS=
GPIO_DEBUGFS=
dev_type=
module=
usage()
{
echo "Usage:"
echo "$0 [-f] [-m name] [-t type]"
echo "-f: full test. It maybe conflict with existence gpio device."
echo "-m: module name, default name is gpio-mockup. It could also test"
echo " other gpio device."
echo "-t: interface type: chardev(char device) and sysfs(being"
echo " deprecated). The first one is default"
echo ""
echo "$0 -h"
echo "This usage"
}
prerequisite()
{
msg="skip all tests:"
if [ $UID != 0 ]; then
echo $msg must be run as root >&2
exit 1
fi
SYSFS=`mount -t sysfs | head -1 | awk '{ print $3 }'`
if [ ! -d "$SYSFS" ]; then
echo $msg sysfs is not mounted >&2
exit 2
fi
GPIO_SYSFS=`echo $SYSFS/class/gpio`
GPIO_DRV_SYSFS=`echo $SYSFS/devices/platform/$module/gpio`
DEBUGFS=`mount -t debugfs | head -1 | awk '{ print $3 }'`
if [ ! -d "$DEBUGFS" ]; then
echo $msg debugfs is not mounted >&2
exit 2
fi
GPIO_DEBUGFS=`echo $DEBUGFS/gpio`
source gpio-mockup-sysfs.sh
}
try_insert_module()
{
if [ -d "$GPIO_DRV_SYSFS" ]; then
echo "$GPIO_DRV_SYSFS exist. Skip insert module"
else
modprobe -q $module $1
if [ X$? != X0 ]; then
echo $msg insmod $module failed >&2
exit 3
fi
fi
}
remove_module()
{
modprobe -r -q $module
}
die()
{
remove_module
exit 4
}
test_chips()
{
if [ X$dev_type = Xsysfs ]; then
echo "WARNING: sysfs ABI of gpio is going to deprecated."
test_chips_sysfs $*
else
$BASE/gpio-mockup-chardev $*
fi
}
gpio_test()
{
param=$1
valid=$2
if [ X"$param" = X ]; then
die
fi
try_insert_module "gpio_mockup_ranges=$param"
echo -n "GPIO $module test with ranges: <"
echo "$param>: "
printf "%-10s %s\n" $param
test_chips $module $valid
remove_module
}
BASE=`dirname $0`
dev_type=
TEMP=`getopt -o fhm:t: -n '$0' -- "$@"`
if [ "$?" != "0" ]; then
echo "Parameter process failed, Terminating..." >&2
exit 1
fi
# Note the quotes around `$TEMP': they are essential!
eval set -- "$TEMP"
while true; do
case $1 in
-f)
full_test=true
shift
;;
-h)
usage
exit
;;
-m)
module=$2
shift 2
;;
-t)
dev_type=$2
shift 2
;;
--)
shift
break
;;
*)
echo "Internal error!"
exit 1
;;
esac
done
if [ X"$module" = X ]; then
module="gpio-mockup"
fi
if [ X$dev_type != Xsysfs ]; then
dev_type="chardev"
fi
prerequisite
echo "1. Test dynamic allocation of gpio successful means insert gpiochip and"
echo " manipulate gpio pin successful"
gpio_test "-1,32" true
gpio_test "-1,32,-1,32" true
gpio_test "-1,32,-1,32,-1,32" true
if [ X$full_test = Xtrue ]; then
gpio_test "-1,32,32,64" true
gpio_test "-1,32,40,64,-1,5" true
gpio_test "-1,32,32,64,-1,32" true
gpio_test "0,32,32,64,-1,32,-1,32" true
gpio_test "-1,32,-1,32,0,32,32,64" true
echo "2. Do basic test: successful means insert gpiochip and"
echo " manipulate gpio pin successful"
gpio_test "0,32" true
gpio_test "0,32,32,64" true
gpio_test "0,32,40,64,64,96" true
fi
echo "3. Error test: successful means insert gpiochip failed"
echo "3.1 Test number of gpio overflow"
#Currently: The max number of gpio(1024) is defined in arm architecture.
gpio_test "-1,32,-1,1024" false
if [ X$full_test = Xtrue ]; then
echo "3.2 Test zero line of gpio"
gpio_test "0,0" false
echo "3.3 Test range overlap"
echo "3.3.1 Test corner case"
gpio_test "0,32,0,1" false
gpio_test "0,32,32,64,32,40" false
gpio_test "0,32,35,64,35,45" false
gpio_test "0,32,31,32" false
gpio_test "0,32,32,64,36,37" false
gpio_test "0,32,35,64,34,36" false
echo "3.3.2 Test inserting invalid second gpiochip"
gpio_test "0,32,30,35" false
gpio_test "0,32,1,5" false
gpio_test "10,32,9,14" false
gpio_test "10,32,30,35" false
echo "3.3.3 Test others"
gpio_test "0,32,40,56,39,45" false
gpio_test "0,32,40,56,30,33" false
gpio_test "0,32,40,56,30,41" false
gpio_test "0,32,40,56,20,21" false
fi
echo GPIO test PASS
CFLAGS += -O2 -g -std=gnu89 -pthread -Wall -Wextra
CFLAGS += -I../../../../usr/include/
LDFLAGS += -pthread
TEST_PROGS = sync_test
all: $(TEST_PROGS)
include ../lib.mk
OBJS = sync_test.o sync.o
TESTS += sync_alloc.o
TESTS += sync_fence.o
TESTS += sync_merge.o
TESTS += sync_wait.o
TESTS += sync_stress_parallelism.o
TESTS += sync_stress_consumer.o
TESTS += sync_stress_merge.o
sync_test: $(OBJS) $(TESTS)
clean:
$(RM) sync_test $(OBJS) $(TESTS)
/*
* sw_sync abstraction
*
* Copyright 2015-2016 Collabora Ltd.
*
* Based on the implementation from the Android Open Source Project,
*
* Copyright 2013 Google, Inc
*
* 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 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.
*/
#ifndef SELFTESTS_SW_SYNC_H
#define SELFTESTS_SW_SYNC_H
/*
* sw_sync is mainly intended for testing and should not be compiled into
* production kernels
*/
int sw_sync_timeline_create(void);
int sw_sync_timeline_is_valid(int fd);
int sw_sync_timeline_inc(int fd, unsigned int count);
void sw_sync_timeline_destroy(int fd);
int sw_sync_fence_create(int fd, const char *name, unsigned int value);
int sw_sync_fence_is_valid(int fd);
void sw_sync_fence_destroy(int fd);
#endif
/*
* sync / sw_sync abstraction
* Copyright 2015-2016 Collabora Ltd.
*
* Based on the implementation from the Android Open Source Project,
*
* Copyright 2012 Google, Inc
*
* 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 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.
*/
#include <fcntl.h>
#include <malloc.h>
#include <poll.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "sync.h"
#include "sw_sync.h"
#include <linux/sync_file.h>
/* SW_SYNC ioctls */
struct sw_sync_create_fence_data {
__u32 value;
char name[32];
__s32 fence;
};
#define SW_SYNC_IOC_MAGIC 'W'
#define SW_SYNC_IOC_CREATE_FENCE _IOWR(SW_SYNC_IOC_MAGIC, 0,\
struct sw_sync_create_fence_data)
#define SW_SYNC_IOC_INC _IOW(SW_SYNC_IOC_MAGIC, 1, __u32)
int sync_wait(int fd, int timeout)
{
struct pollfd fds;
fds.fd = fd;
fds.events = POLLIN | POLLERR;
return poll(&fds, 1, timeout);
}
int sync_merge(const char *name, int fd1, int fd2)
{
struct sync_merge_data data = {};
int err;
data.fd2 = fd2;
strncpy(data.name, name, sizeof(data.name) - 1);
data.name[sizeof(data.name) - 1] = '\0';
err = ioctl(fd1, SYNC_IOC_MERGE, &data);
if (err < 0)
return err;
return data.fence;
}
static struct sync_file_info *sync_file_info(int fd)
{
struct sync_file_info *info;
struct sync_fence_info *fence_info;
int err, num_fences;
info = calloc(1, sizeof(*info));
if (info == NULL)
return NULL;
err = ioctl(fd, SYNC_IOC_FILE_INFO, info);
if (err < 0) {
free(info);
return NULL;
}
num_fences = info->num_fences;
if (num_fences) {
info->flags = 0;
info->num_fences = num_fences;
fence_info = calloc(num_fences, sizeof(*fence_info));
if (!fence_info) {
free(info);
return NULL;
}
info->sync_fence_info = (uint64_t)fence_info;
err = ioctl(fd, SYNC_IOC_FILE_INFO, info);
if (err < 0) {
free(fence_info);
free(info);
return NULL;
}
}
return info;
}
static void sync_file_info_free(struct sync_file_info *info)
{
free((void *)info->sync_fence_info);
free(info);
}
int sync_fence_size(int fd)
{
int count;
struct sync_file_info *info = sync_file_info(fd);
if (!info)
return 0;
count = info->num_fences;
sync_file_info_free(info);
return count;
}
int sync_fence_count_with_status(int fd, int status)
{
unsigned int i, count = 0;
struct sync_fence_info *fence_info = NULL;
struct sync_file_info *info = sync_file_info(fd);
if (!info)
return -1;
fence_info = (struct sync_fence_info *)info->sync_fence_info;
for (i = 0 ; i < info->num_fences ; i++) {
if (fence_info[i].status == status)
count++;
}
sync_file_info_free(info);
return count;
}
int sw_sync_timeline_create(void)
{
return open("/sys/kernel/debug/sync/sw_sync", O_RDWR);
}
int sw_sync_timeline_inc(int fd, unsigned int count)
{
__u32 arg = count;
return ioctl(fd, SW_SYNC_IOC_INC, &arg);
}
int sw_sync_timeline_is_valid(int fd)
{
int status;
if (fd == -1)
return 0;
status = fcntl(fd, F_GETFD, 0);
return (status >= 0);
}
void sw_sync_timeline_destroy(int fd)
{
if (sw_sync_timeline_is_valid(fd))
close(fd);
}
int sw_sync_fence_create(int fd, const char *name, unsigned int value)
{
struct sw_sync_create_fence_data data = {};
int err;
data.value = value;
strncpy(data.name, name, sizeof(data.name) - 1);
data.name[sizeof(data.name) - 1] = '\0';
err = ioctl(fd, SW_SYNC_IOC_CREATE_FENCE, &data);
if (err < 0)
return err;
return data.fence;
}
int sw_sync_fence_is_valid(int fd)
{
/* Same code! */
return sw_sync_timeline_is_valid(fd);
}
void sw_sync_fence_destroy(int fd)
{
if (sw_sync_fence_is_valid(fd))
close(fd);
}
/*
* sync abstraction
* Copyright 2015-2016 Collabora Ltd.
*
* Based on the implementation from the Android Open Source Project,
*
* Copyright 2012 Google, Inc
*
* 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 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.
*/
#ifndef SELFTESTS_SYNC_H
#define SELFTESTS_SYNC_H
#define FENCE_STATUS_ERROR (-1)
#define FENCE_STATUS_ACTIVE (0)
#define FENCE_STATUS_SIGNALED (1)
int sync_wait(int fd, int timeout);
int sync_merge(const char *name, int fd1, int fd2);
int sync_fence_size(int fd);
int sync_fence_count_with_status(int fd, int status);
#endif
/*
* sync allocation tests
* Copyright 2015-2016 Collabora Ltd.
*
* Based on the implementation from the Android Open Source Project,
*
* Copyright 2012 Google, Inc
*
* 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 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.
*/
#include "sync.h"
#include "sw_sync.h"
#include "synctest.h"
int test_alloc_timeline(void)
{
int timeline, valid;
timeline = sw_sync_timeline_create();
valid = sw_sync_timeline_is_valid(timeline);
ASSERT(valid, "Failure allocating timeline\n");
sw_sync_timeline_destroy(timeline);
return 0;
}
int test_alloc_fence(void)
{
int timeline, fence, valid;
timeline = sw_sync_timeline_create();
valid = sw_sync_timeline_is_valid(timeline);
ASSERT(valid, "Failure allocating timeline\n");
fence = sw_sync_fence_create(timeline, "allocFence", 1);
valid = sw_sync_fence_is_valid(fence);
ASSERT(valid, "Failure allocating fence\n");
sw_sync_fence_destroy(fence);
sw_sync_timeline_destroy(timeline);
return 0;
}
int test_alloc_fence_negative(void)
{
int fence, timeline;
timeline = sw_sync_timeline_create();
ASSERT(timeline > 0, "Failure allocating timeline\n");
fence = sw_sync_fence_create(-1, "fence", 1);
ASSERT(fence < 0, "Success allocating negative fence\n");
sw_sync_fence_destroy(fence);
sw_sync_timeline_destroy(timeline);
return 0;
}
/*
* sync fence tests with one timeline
* Copyright 2015-2016 Collabora Ltd.
*
* Based on the implementation from the Android Open Source Project,
*
* Copyright 2012 Google, Inc
*
* 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 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.
*/
#include "sync.h"
#include "sw_sync.h"
#include "synctest.h"
int test_fence_one_timeline_wait(void)
{
int fence, valid, ret;
int timeline = sw_sync_timeline_create();
valid = sw_sync_timeline_is_valid(timeline);
ASSERT(valid, "Failure allocating timeline\n");
fence = sw_sync_fence_create(timeline, "allocFence", 5);
valid = sw_sync_fence_is_valid(fence);
ASSERT(valid, "Failure allocating fence\n");
/* Wait on fence until timeout */
ret = sync_wait(fence, 0);
ASSERT(ret == 0, "Failure waiting on fence until timeout\n");
/* Advance timeline from 0 -> 1 */
ret = sw_sync_timeline_inc(timeline, 1);
ASSERT(ret == 0, "Failure advancing timeline\n");
/* Wait on fence until timeout */
ret = sync_wait(fence, 0);
ASSERT(ret == 0, "Failure waiting on fence until timeout\n");
/* Signal the fence */
ret = sw_sync_timeline_inc(timeline, 4);
ASSERT(ret == 0, "Failure signaling the fence\n");
/* Wait successfully */
ret = sync_wait(fence, 0);
ASSERT(ret > 0, "Failure waiting on fence\n");
/* Go even further, and confirm wait still succeeds */
ret = sw_sync_timeline_inc(timeline, 10);
ASSERT(ret == 0, "Failure going further\n");
ret = sync_wait(fence, 0);
ASSERT(ret > 0, "Failure waiting ahead\n");
sw_sync_fence_destroy(fence);
sw_sync_timeline_destroy(timeline);
return 0;
}
int test_fence_one_timeline_merge(void)
{
int a, b, c, d, valid;
int timeline = sw_sync_timeline_create();
/* create fence a,b,c and then merge them all into fence d */
a = sw_sync_fence_create(timeline, "allocFence", 1);
b = sw_sync_fence_create(timeline, "allocFence", 2);
c = sw_sync_fence_create(timeline, "allocFence", 3);
valid = sw_sync_fence_is_valid(a) &&
sw_sync_fence_is_valid(b) &&
sw_sync_fence_is_valid(c);
ASSERT(valid, "Failure allocating fences\n");
d = sync_merge("mergeFence", b, a);
d = sync_merge("mergeFence", c, d);
valid = sw_sync_fence_is_valid(d);
ASSERT(valid, "Failure merging fences\n");
/* confirm all fences have one active point (even d) */
ASSERT(sync_fence_count_with_status(a, FENCE_STATUS_ACTIVE) == 1,
"a has too many active fences!\n");
ASSERT(sync_fence_count_with_status(a, FENCE_STATUS_ACTIVE) == 1,
"b has too many active fences!\n");
ASSERT(sync_fence_count_with_status(a, FENCE_STATUS_ACTIVE) == 1,
"c has too many active fences!\n");
ASSERT(sync_fence_count_with_status(a, FENCE_STATUS_ACTIVE) == 1,
"d has too many active fences!\n");
/* confirm that d is not signaled until the max of a,b,c */
sw_sync_timeline_inc(timeline, 1);
ASSERT(sync_fence_count_with_status(a, FENCE_STATUS_SIGNALED) == 1,
"a did not signal!\n");
ASSERT(sync_fence_count_with_status(d, FENCE_STATUS_ACTIVE) == 1,
"d signaled too early!\n");
sw_sync_timeline_inc(timeline, 1);
ASSERT(sync_fence_count_with_status(b, FENCE_STATUS_SIGNALED) == 1,
"b did not signal!\n");
ASSERT(sync_fence_count_with_status(d, FENCE_STATUS_ACTIVE) == 1,
"d signaled too early!\n");
sw_sync_timeline_inc(timeline, 1);
ASSERT(sync_fence_count_with_status(c, FENCE_STATUS_SIGNALED) == 1,
"c did not signal!\n");
ASSERT(sync_fence_count_with_status(d, FENCE_STATUS_ACTIVE) == 0 &&
sync_fence_count_with_status(d, FENCE_STATUS_SIGNALED) == 1,
"d did not signal!\n");
sw_sync_fence_destroy(d);
sw_sync_fence_destroy(c);
sw_sync_fence_destroy(b);
sw_sync_fence_destroy(a);
sw_sync_timeline_destroy(timeline);
return 0;
}
/*
* sync fence merge tests
* Copyright 2015-2016 Collabora Ltd.
*
* Based on the implementation from the Android Open Source Project,
*
* Copyright 2012 Google, Inc
*
* 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 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.
*/
#include "sync.h"
#include "sw_sync.h"
#include "synctest.h"
int test_fence_merge_same_fence(void)
{
int fence, valid, merged;
int timeline = sw_sync_timeline_create();
valid = sw_sync_timeline_is_valid(timeline);
ASSERT(valid, "Failure allocating timeline\n");
fence = sw_sync_fence_create(timeline, "allocFence", 5);
valid = sw_sync_fence_is_valid(fence);
ASSERT(valid, "Failure allocating fence\n");
merged = sync_merge("mergeFence", fence, fence);
valid = sw_sync_fence_is_valid(fence);
ASSERT(valid, "Failure merging fence\n");
ASSERT(sync_fence_count_with_status(merged, FENCE_STATUS_SIGNALED) == 0,
"fence signaled too early!\n");
sw_sync_timeline_inc(timeline, 5);
ASSERT(sync_fence_count_with_status(merged, FENCE_STATUS_SIGNALED) == 1,
"fence did not signal!\n");
sw_sync_fence_destroy(merged);
sw_sync_fence_destroy(fence);
sw_sync_timeline_destroy(timeline);
return 0;
}
/*
* sync stress test: producer/consumer
* Copyright 2015-2016 Collabora Ltd.
*
* Based on the implementation from the Android Open Source Project,
*
* Copyright 2012 Google, Inc
*
* 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 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.
*/
#include <pthread.h>
#include "sync.h"
#include "sw_sync.h"
#include "synctest.h"
/* IMPORTANT NOTE: if you see this test failing on your system, it may be
* due to a shortage of file descriptors. Please ensure your system has
* a sensible limit for this test to finish correctly.
*/
/* Returns 1 on error, 0 on success */
static int busy_wait_on_fence(int fence)
{
int error, active;
do {
error = sync_fence_count_with_status(fence, FENCE_STATUS_ERROR);
ASSERT(error == 0, "Error occurred on fence\n");
active = sync_fence_count_with_status(fence,
FENCE_STATUS_ACTIVE);
} while (active);
return 0;
}
static struct {
int iterations;
int threads;
int counter;
int consumer_timeline;
int *producer_timelines;
pthread_mutex_t lock;
} test_data_mpsc;
static int mpsc_producer_thread(void *d)
{
int id = (long)d;
int fence, valid, i;
int *producer_timelines = test_data_mpsc.producer_timelines;
int consumer_timeline = test_data_mpsc.consumer_timeline;
int iterations = test_data_mpsc.iterations;
for (i = 0; i < iterations; i++) {
fence = sw_sync_fence_create(consumer_timeline, "fence", i);
valid = sw_sync_fence_is_valid(fence);
ASSERT(valid, "Failure creating fence\n");
/*
* Wait for the consumer to finish. Use alternate
* means of waiting on the fence
*/
if ((iterations + id) % 8 != 0) {
ASSERT(sync_wait(fence, -1) > 0,
"Failure waiting on fence\n");
} else {
ASSERT(busy_wait_on_fence(fence) == 0,
"Failure waiting on fence\n");
}
/*
* Every producer increments the counter, the consumer
* checks and erases it
*/
pthread_mutex_lock(&test_data_mpsc.lock);
test_data_mpsc.counter++;
pthread_mutex_unlock(&test_data_mpsc.lock);
ASSERT(sw_sync_timeline_inc(producer_timelines[id], 1) == 0,
"Error advancing producer timeline\n");
sw_sync_fence_destroy(fence);
}
return 0;
}
static int mpcs_consumer_thread(void)
{
int fence, merged, tmp, valid, it, i;
int *producer_timelines = test_data_mpsc.producer_timelines;
int consumer_timeline = test_data_mpsc.consumer_timeline;
int iterations = test_data_mpsc.iterations;
int n = test_data_mpsc.threads;
for (it = 1; it <= iterations; it++) {
fence = sw_sync_fence_create(producer_timelines[0], "name", it);
for (i = 1; i < n; i++) {
tmp = sw_sync_fence_create(producer_timelines[i],
"name", it);
merged = sync_merge("name", tmp, fence);
sw_sync_fence_destroy(tmp);
sw_sync_fence_destroy(fence);
fence = merged;
}
valid = sw_sync_fence_is_valid(fence);
ASSERT(valid, "Failure merging fences\n");
/*
* Make sure we see an increment from every producer thread.
* Vary the means by which we wait.
*/
if (iterations % 8 != 0) {
ASSERT(sync_wait(fence, -1) > 0,
"Producers did not increment as expected\n");
} else {
ASSERT(busy_wait_on_fence(fence) == 0,
"Producers did not increment as expected\n");
}
ASSERT(test_data_mpsc.counter == n * it,
"Counter value mismatch!\n");
/* Release the producer threads */
ASSERT(sw_sync_timeline_inc(consumer_timeline, 1) == 0,
"Failure releasing producer threads\n");
sw_sync_fence_destroy(fence);
}
return 0;
}
int test_consumer_stress_multi_producer_single_consumer(void)
{
int iterations = 1 << 12;
int n = 5;
long i, ret;
int producer_timelines[n];
int consumer_timeline;
pthread_t threads[n];
consumer_timeline = sw_sync_timeline_create();
for (i = 0; i < n; i++)
producer_timelines[i] = sw_sync_timeline_create();
test_data_mpsc.producer_timelines = producer_timelines;
test_data_mpsc.consumer_timeline = consumer_timeline;
test_data_mpsc.iterations = iterations;
test_data_mpsc.threads = n;
test_data_mpsc.counter = 0;
pthread_mutex_init(&test_data_mpsc.lock, NULL);
for (i = 0; i < n; i++) {
pthread_create(&threads[i], NULL, (void * (*)(void *))
mpsc_producer_thread, (void *)i);
}
/* Consumer thread runs here */
ret = mpcs_consumer_thread();
for (i = 0; i < n; i++)
pthread_join(threads[i], NULL);
return ret;
}
/*
* sync stress test: merging
* Copyright 2015-2016 Collabora Ltd.
*
* Based on the implementation from the Android Open Source Project,
*
* Copyright 2012 Google, Inc
*
* 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 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.
*/
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "sync.h"
#include "sw_sync.h"
#include "synctest.h"
int test_merge_stress_random_merge(void)
{
int i, size, ret;
int timeline_count = 32;
int merge_count = 1024 * 32;
int timelines[timeline_count];
int fence_map[timeline_count];
int fence, tmpfence, merged, valid;
int timeline, timeline_offset, sync_point;
srand(time(NULL));
for (i = 0; i < timeline_count; i++)
timelines[i] = sw_sync_timeline_create();
fence = sw_sync_fence_create(timelines[0], "fence", 0);
valid = sw_sync_fence_is_valid(fence);
ASSERT(valid, "Failure creating fence\n");
memset(fence_map, -1, sizeof(fence_map));
fence_map[0] = 0;
/*
* Randomly create sync_points out of a fixed set of timelines,
* and merge them together
*/
for (i = 0; i < merge_count; i++) {
/* Generate sync_point. */
timeline_offset = rand() % timeline_count;
timeline = timelines[timeline_offset];
sync_point = rand();
/* Keep track of the latest sync_point in each timeline. */
if (fence_map[timeline_offset] == -1)
fence_map[timeline_offset] = sync_point;
else if (fence_map[timeline_offset] < sync_point)
fence_map[timeline_offset] = sync_point;
/* Merge */
tmpfence = sw_sync_fence_create(timeline, "fence", sync_point);
merged = sync_merge("merge", tmpfence, fence);
sw_sync_fence_destroy(tmpfence);
sw_sync_fence_destroy(fence);
fence = merged;
valid = sw_sync_fence_is_valid(merged);
ASSERT(valid, "Failure creating fence i\n");
}
size = 0;
for (i = 0; i < timeline_count; i++)
if (fence_map[i] != -1)
size++;
/* Confirm our map matches the fence. */
ASSERT(sync_fence_size(fence) == size,
"Quantity of elements not matching\n");
/* Trigger the merged fence */
for (i = 0; i < timeline_count; i++) {
if (fence_map[i] != -1) {
ret = sync_wait(fence, 0);
ASSERT(ret == 0,
"Failure waiting on fence until timeout\n");
/* Increment the timeline to the last sync_point */
sw_sync_timeline_inc(timelines[i], fence_map[i]);
}
}
/* Check that the fence is triggered. */
ret = sync_wait(fence, 0);
ASSERT(ret > 0, "Failure triggering fence\n");
sw_sync_fence_destroy(fence);
for (i = 0; i < timeline_count; i++)
sw_sync_timeline_destroy(timelines[i]);
return 0;
}
/*
* sync stress test: parallelism
* Copyright 2015-2016 Collabora Ltd.
*
* Based on the implementation from the Android Open Source Project,
*
* Copyright 2012 Google, Inc
*
* 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 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.
*/
#include <pthread.h>
#include "sync.h"
#include "sw_sync.h"
#include "synctest.h"
static struct {
int iterations;
int timeline;
int counter;
} test_data_two_threads;
static int test_stress_two_threads_shared_timeline_thread(void *d)
{
int thread_id = (long)d;
int timeline = test_data_two_threads.timeline;
int iterations = test_data_two_threads.iterations;
int fence, valid, ret, i;
for (i = 0; i < iterations; i++) {
fence = sw_sync_fence_create(timeline, "fence",
i * 2 + thread_id);
valid = sw_sync_fence_is_valid(fence);
ASSERT(valid, "Failure allocating fence\n");
/* Wait on the prior thread to complete */
ret = sync_wait(fence, -1);
ASSERT(ret > 0, "Problem occurred on prior thread\n");
/*
* Confirm the previous thread's writes are visible
* and then increment
*/
ASSERT(test_data_two_threads.counter == i * 2 + thread_id,
"Counter got damaged!\n");
test_data_two_threads.counter++;
/* Kick off the other thread */
ret = sw_sync_timeline_inc(timeline, 1);
ASSERT(ret == 0, "Advancing timeline failed\n");
sw_sync_fence_destroy(fence);
}
return 0;
}
int test_stress_two_threads_shared_timeline(void)
{
pthread_t a, b;
int valid;
int timeline = sw_sync_timeline_create();
valid = sw_sync_timeline_is_valid(timeline);
ASSERT(valid, "Failure allocating timeline\n");
test_data_two_threads.iterations = 1 << 16;
test_data_two_threads.counter = 0;
test_data_two_threads.timeline = timeline;
/*
* Use a single timeline to synchronize two threads
* hammmering on the same counter.
*/
pthread_create(&a, NULL, (void *(*)(void *))
test_stress_two_threads_shared_timeline_thread,
(void *)0);
pthread_create(&b, NULL, (void *(*)(void *))
test_stress_two_threads_shared_timeline_thread,
(void *)1);
pthread_join(a, NULL);
pthread_join(b, NULL);
/* make sure the threads did not trample on one another */
ASSERT(test_data_two_threads.counter ==
test_data_two_threads.iterations * 2,
"Counter has unexpected value\n");
sw_sync_timeline_destroy(timeline);
return 0;
}
/*
* sync test runner
* Copyright 2015-2016 Collabora Ltd.
*
* Based on the implementation from the Android Open Source Project,
*
* Copyright 2012 Google, Inc
*
* 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 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.
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "synctest.h"
static int run_test(int (*test)(void), char *name)
{
int result;
pid_t childpid;
fflush(stdout);
childpid = fork();
if (childpid) {
waitpid(childpid, &result, 0);
if (WIFEXITED(result))
return WEXITSTATUS(result);
return 1;
}
printf("[RUN]\tExecuting %s\n", name);
exit(test());
}
int main(void)
{
int err = 0;
printf("[RUN]\tTesting sync framework\n");
err += RUN_TEST(test_alloc_timeline);
err += RUN_TEST(test_alloc_fence);
err += RUN_TEST(test_alloc_fence_negative);
err += RUN_TEST(test_fence_one_timeline_wait);
err += RUN_TEST(test_fence_one_timeline_merge);
err += RUN_TEST(test_fence_merge_same_fence);
err += RUN_TEST(test_fence_multi_timeline_wait);
err += RUN_TEST(test_stress_two_threads_shared_timeline);
err += RUN_TEST(test_consumer_stress_multi_producer_single_consumer);
err += RUN_TEST(test_merge_stress_random_merge);
if (err)
printf("[FAIL]\tsync errors: %d\n", err);
else
printf("[OK]\tsync\n");
return !!err;
}
/*
* sync fence wait tests
* Copyright 2015-2016 Collabora Ltd.
*
* Based on the implementation from the Android Open Source Project,
*
* Copyright 2012 Google, Inc
*
* 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 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.
*/
#include "sync.h"
#include "sw_sync.h"
#include "synctest.h"
int test_fence_multi_timeline_wait(void)
{
int timelineA, timelineB, timelineC;
int fenceA, fenceB, fenceC, merged;
int valid, active, signaled, ret;
timelineA = sw_sync_timeline_create();
timelineB = sw_sync_timeline_create();
timelineC = sw_sync_timeline_create();
fenceA = sw_sync_fence_create(timelineA, "fenceA", 5);
fenceB = sw_sync_fence_create(timelineB, "fenceB", 5);
fenceC = sw_sync_fence_create(timelineC, "fenceC", 5);
merged = sync_merge("mergeFence", fenceB, fenceA);
merged = sync_merge("mergeFence", fenceC, merged);
valid = sw_sync_fence_is_valid(merged);
ASSERT(valid, "Failure merging fence from various timelines\n");
/* Confirm fence isn't signaled */
active = sync_fence_count_with_status(merged, FENCE_STATUS_ACTIVE);
ASSERT(active == 3, "Fence signaled too early!\n");
ret = sync_wait(merged, 0);
ASSERT(ret == 0,
"Failure waiting on fence until timeout\n");
ret = sw_sync_timeline_inc(timelineA, 5);
active = sync_fence_count_with_status(merged, FENCE_STATUS_ACTIVE);
signaled = sync_fence_count_with_status(merged, FENCE_STATUS_SIGNALED);
ASSERT(active == 2 && signaled == 1,
"Fence did not signal properly!\n");
ret = sw_sync_timeline_inc(timelineB, 5);
active = sync_fence_count_with_status(merged, FENCE_STATUS_ACTIVE);
signaled = sync_fence_count_with_status(merged, FENCE_STATUS_SIGNALED);
ASSERT(active == 1 && signaled == 2,
"Fence did not signal properly!\n");
ret = sw_sync_timeline_inc(timelineC, 5);
active = sync_fence_count_with_status(merged, FENCE_STATUS_ACTIVE);
signaled = sync_fence_count_with_status(merged, FENCE_STATUS_SIGNALED);
ASSERT(active == 0 && signaled == 3,
"Fence did not signal properly!\n");
/* confirm you can successfully wait */
ret = sync_wait(merged, 100);
ASSERT(ret > 0, "Failure waiting on signaled fence\n");
sw_sync_fence_destroy(merged);
sw_sync_fence_destroy(fenceC);
sw_sync_fence_destroy(fenceB);
sw_sync_fence_destroy(fenceA);
sw_sync_timeline_destroy(timelineC);
sw_sync_timeline_destroy(timelineB);
sw_sync_timeline_destroy(timelineA);
return 0;
}
/*
* sync tests
* Copyright 2015-2016 Collabora Ltd.
*
* Based on the implementation from the Android Open Source Project,
*
* Copyright 2012 Google, Inc
*
* 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 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.
*/
#ifndef SELFTESTS_SYNCTEST_H
#define SELFTESTS_SYNCTEST_H
#include <stdio.h>
#define ASSERT(cond, msg) do { \
if (!(cond)) { \
printf("[ERROR]\t%s", (msg)); \
return 1; \
} \
} while (0)
#define RUN_TEST(x) run_test((x), #x)
/* Allocation tests */
int test_alloc_timeline(void);
int test_alloc_fence(void);
int test_alloc_fence_negative(void);
/* Fence tests with one timeline */
int test_fence_one_timeline_wait(void);
int test_fence_one_timeline_merge(void);
/* Fence merge tests */
int test_fence_merge_same_fence(void);
/* Fence wait tests */
int test_fence_multi_timeline_wait(void);
/* Stress test - parallelism */
int test_stress_two_threads_shared_timeline(void);
/* Stress test - consumer */
int test_consumer_stress_multi_producer_single_consumer(void);
/* Stress test - merging */
int test_merge_stress_random_merge(void);
#endif
......@@ -17,3 +17,4 @@ skew_consistency
threadtest
valid-adjtimex
adjtick
set-tz
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment