blob: 20dfbbb98f5808ebc3b43d8d9b7d06f7d68e86b2 [file] [log] [blame]
/*
* Copyright © 2016 Collabora, Ltd.
*
* 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:
* Robert Foss <robert.foss@collabora.com>
*/
#include <pthread.h>
#include <semaphore.h>
#include <stdint.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include "igt.h"
#include "igt_aux.h"
#include "igt_primes.h"
#include "sw_sync.h"
IGT_TEST_DESCRIPTION("Test SW Sync Framework");
typedef struct {
int timeline;
uint32_t thread_id;
volatile uint32_t * volatile counter;
sem_t *sem;
} data_t;
static void test_alloc_timeline(void)
{
int timeline;
timeline = sw_sync_timeline_create();
close(timeline);
}
static void test_alloc_fence(void)
{
int in_fence;
int timeline;
timeline = sw_sync_timeline_create();
in_fence = sw_sync_timeline_create_fence(timeline, 0);
close(in_fence);
close(timeline);
}
static void test_alloc_fence_invalid_timeline(void)
{
igt_assert_f(__sw_sync_timeline_create_fence(-1, 0) < 0,
"Did not fail to create fence on invalid timeline\n");
}
static void test_timeline_closed(void)
{
int fence;
int timeline;
timeline = sw_sync_timeline_create();
fence = sw_sync_timeline_create_fence(timeline, 1);
close(timeline);
igt_assert_f(sync_fence_wait(fence, 0) == 0,
"Failure waiting on unsignaled fence on closed timeline\n");
igt_assert_f(sync_fence_status(fence) == -ENOENT,
"Failure in marking up an unsignaled fence on closed timeline\n");
}
static void test_timeline_closed_signaled(void)
{
int fence;
int timeline;
timeline = sw_sync_timeline_create();
fence = sw_sync_timeline_create_fence(timeline, 1);
sw_sync_timeline_inc(timeline, 1);
close(timeline);
igt_assert_f(sync_fence_wait(fence, 0) == 0,
"Failure waiting on signaled fence for closed timeline\n");
}
static void test_alloc_merge_fence(void)
{
int in_fence[2];
int fence_merge;
int timeline[2];
timeline[0] = sw_sync_timeline_create();
timeline[1] = sw_sync_timeline_create();
in_fence[0] = sw_sync_timeline_create_fence(timeline[0], 1);
in_fence[1] = sw_sync_timeline_create_fence(timeline[1], 1);
fence_merge = sync_fence_merge(in_fence[1], in_fence[0]);
close(in_fence[0]);
close(in_fence[1]);
close(fence_merge);
close(timeline[0]);
close(timeline[1]);
}
static void test_sync_busy(void)
{
int fence;
int timeline;
int seqno;
timeline = sw_sync_timeline_create();
fence = sw_sync_timeline_create_fence(timeline, 5);
/* Make sure that fence has not been signaled yet */
igt_assert_f(sync_fence_wait(fence, 0) == -ETIME,
"Fence signaled early (timeline value 0, fence seqno 5)\n");
/* Advance timeline from 0 -> 1 */
sw_sync_timeline_inc(timeline, 1);
/* Make sure that fence has not been signaled yet */
igt_assert_f(sync_fence_wait(fence, 0) == -ETIME,
"Fence signaled early (timeline value 1, fence seqno 5)\n");
/* Advance timeline from 1 -> 5: signaling the fence (seqno 5)*/
sw_sync_timeline_inc(timeline, 4);
igt_assert_f(sync_fence_wait(fence, 0) == 0,
"Fence not signaled (timeline value 5, fence seqno 5)\n");
/* Go even further, and confirm wait still succeeds */
sw_sync_timeline_inc(timeline, 5);
igt_assert_f(sync_fence_wait(fence, 0) == 0,
"Fence not signaled (timeline value 10, fence seqno 5)\n");
seqno = 10;
for_each_prime_number(prime, 100) {
int fence_prime;
seqno += prime;
fence_prime = sw_sync_timeline_create_fence(timeline, seqno);
sw_sync_timeline_inc(timeline, prime);
igt_assert_f(sync_fence_wait(fence_prime, 0) == 0,
"Fence not signaled during test of prime timeline increments\n");
close(fence_prime);
}
close(fence);
close(timeline);
}
static void test_sync_busy_fork_unixsocket(void)
{
int fence;
int timeline;
int skip = 0;
int sv[2];
timeline = sw_sync_timeline_create();
fence = sw_sync_timeline_create_fence(timeline, 1);
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sv) != 0) {
skip = 1;
goto out;
}
switch (fork()) {
case 0:
{
/* Child process */
int socket = sv[1];
int socket_timeline;
struct msghdr msg = {0};
struct cmsghdr *cmsg;
unsigned char *data;
char m_buffer[256];
char c_buffer[256];
struct iovec io = { .iov_base = m_buffer, .iov_len = sizeof(m_buffer) };
close(sv[0]);
msg.msg_iov = &io;
msg.msg_iovlen = 1;
msg.msg_control = c_buffer;
msg.msg_controllen = sizeof(c_buffer);
if (recvmsg(socket, &msg, 0) < 0)
_Exit(1);
cmsg = CMSG_FIRSTHDR(&msg);
data = CMSG_DATA(cmsg);
socket_timeline = *((int *) data);
/* Advance timeline from 0 -> 1 */
sw_sync_timeline_inc(socket_timeline, 1);
_Exit(0);
break;
}
case -1:
{
/* Failed fork */
skip = 1;
break;
}
default:
{
/* Parent process */
int socket = sv[0];
struct cmsghdr *cmsg;
struct iovec io = { .iov_base = (char *)"ABC", .iov_len = 3 };
struct msghdr msg = { 0 };
char buf[CMSG_SPACE(sizeof(timeline))];
memset(buf, '\0', sizeof(buf));
close(sv[1]);
msg.msg_iov = &io;
msg.msg_iovlen = 1;
msg.msg_control = buf;
msg.msg_controllen = sizeof(buf);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(timeline));
*((int *) CMSG_DATA(cmsg)) = timeline;
msg.msg_controllen = cmsg->cmsg_len;
igt_assert_f(sync_fence_wait(fence, 0) == -ETIME,
"Fence signaled (it should not have been signalled yet)\n");
if (sendmsg(socket, &msg, 0) < 0) {
skip = 1;
goto out;
}
igt_assert_f(sync_fence_wait(fence, 2*1000) == 0,
"Fence not signaled (timeline value 1 fence seqno 1)\n");
break;
}
}
out:
close(fence);
close(timeline);
igt_require(!skip);
}
static void test_sync_busy_fork(void)
{
int fence;
int timeline;
int skip = 0;
timeline = sw_sync_timeline_create();
fence = sw_sync_timeline_create_fence(timeline, 1);
switch (fork()) {
case 0:
/* Child process */
usleep(1*1000*1000);
/* Advance timeline from 0 -> 1 */
sw_sync_timeline_inc(timeline, 1);
_Exit(0);
break;
case -1:
/* Failed fork */
skip = 1;
break;
default:
/* Parent process */
igt_assert_f(sync_fence_wait(fence, 0) == -ETIME,
"Fence signaled (it should not have been signalled yet)\n");
igt_assert_f(sync_fence_wait(fence, 2*1000) == 0,
"Fence not signaled (timeline value 1 fence seqno 1)\n");
break;
}
close(fence);
close(timeline);
igt_require(!skip);
}
static void test_sync_merge_invalid(void)
{
int in_fence;
int fence_invalid;
int fence_merge;
int timeline;
char tmppath[] = "/tmp/igt-XXXXXX";
int skip = 0;
timeline = sw_sync_timeline_create();
in_fence = sw_sync_timeline_create_fence(timeline, 1);
fence_invalid = -1;
fence_merge = sync_fence_merge(in_fence, fence_invalid);
igt_assert_f(fence_merge < 0, "Verify invalid fd (-1) handling");
fence_invalid = drm_open_driver(DRIVER_ANY);
fence_merge = sync_fence_merge(in_fence, fence_invalid);
igt_assert_f(fence_merge < 0, "Verify invalid fd (device fd) handling");
fence_invalid = mkstemp(tmppath);
if (fence_invalid == -1) {
skip = 1;
goto out;
}
unlink(tmppath);
fence_invalid = drm_open_driver(DRIVER_ANY);
fence_merge = sync_fence_merge(in_fence, fence_invalid);
close(fence_invalid);
igt_assert_f(fence_merge < 0, "Verify invalid fd (file fd) handling");
out:
close(in_fence);
close(fence_merge);
close(timeline);
igt_require(skip == 0);
}
static void test_sync_merge(void)
{
int in_fence[3];
int fence_merge;
int timeline;
int active, signaled;
timeline = sw_sync_timeline_create();
in_fence[0] = sw_sync_timeline_create_fence(timeline, 1);
in_fence[1] = sw_sync_timeline_create_fence(timeline, 2);
in_fence[2] = sw_sync_timeline_create_fence(timeline, 3);
fence_merge = sync_fence_merge(in_fence[0], in_fence[1]);
fence_merge = sync_fence_merge(in_fence[2], fence_merge);
/* confirm all fences have one active point (even d) */
active = sync_fence_count_status(in_fence[0],
SW_SYNC_FENCE_STATUS_ACTIVE);
igt_assert_f(active == 1, "in_fence[0] has too many active fences\n");
active = sync_fence_count_status(in_fence[1],
SW_SYNC_FENCE_STATUS_ACTIVE);
igt_assert_f(active == 1, "in_fence[1] has too many active fences\n");
active = sync_fence_count_status(in_fence[2],
SW_SYNC_FENCE_STATUS_ACTIVE);
igt_assert_f(active == 1, "in_fence[2] has too many active fences\n");
active = sync_fence_count_status(fence_merge,
SW_SYNC_FENCE_STATUS_ACTIVE);
igt_assert_f(active == 1, "fence_merge has too many active fences\n");
/* confirm that fence_merge is not signaled until the max of fence 0,1,2 */
sw_sync_timeline_inc(timeline, 1);
signaled = sync_fence_count_status(in_fence[0],
SW_SYNC_FENCE_STATUS_SIGNALED);
active = sync_fence_count_status(fence_merge,
SW_SYNC_FENCE_STATUS_ACTIVE);
igt_assert_f(signaled == 1, "in_fence[0] did not signal\n");
igt_assert_f(active == 1, "fence_merge signaled too early\n");
sw_sync_timeline_inc(timeline, 1);
signaled = sync_fence_count_status(in_fence[1],
SW_SYNC_FENCE_STATUS_SIGNALED);
active = sync_fence_count_status(fence_merge,
SW_SYNC_FENCE_STATUS_ACTIVE);
igt_assert_f(signaled == 1, "in_fence[1] did not signal\n");
igt_assert_f(active == 1, "fence_merge signaled too early\n");
sw_sync_timeline_inc(timeline, 1);
signaled = sync_fence_count_status(in_fence[2],
SW_SYNC_FENCE_STATUS_SIGNALED);
igt_assert_f(signaled == 1, "in_fence[2] did not signal\n");
signaled = sync_fence_count_status(fence_merge,
SW_SYNC_FENCE_STATUS_SIGNALED);
active = sync_fence_count_status(fence_merge,
SW_SYNC_FENCE_STATUS_ACTIVE);
igt_assert_f(active == 0 && signaled == 1,
"fence_merge did not signal\n");
close(in_fence[0]);
close(in_fence[1]);
close(in_fence[2]);
close(fence_merge);
close(timeline);
}
static void test_sync_merge_same(void)
{
int in_fence[2];
int timeline;
int signaled;
timeline = sw_sync_timeline_create();
in_fence[0] = sw_sync_timeline_create_fence(timeline, 1);
in_fence[1] = sync_fence_merge(in_fence[0], in_fence[0]);
signaled = sync_fence_count_status(in_fence[0],
SW_SYNC_FENCE_STATUS_SIGNALED);
igt_assert_f(signaled == 0, "Fence signaled too early\n");
sw_sync_timeline_inc(timeline, 1);
signaled = sync_fence_count_status(in_fence[0],
SW_SYNC_FENCE_STATUS_SIGNALED);
igt_assert_f(signaled == 1, "Fence did not signal\n");
close(in_fence[0]);
close(in_fence[1]);
close(timeline);
}
static void test_sync_multi_timeline_wait(void)
{
int timeline[3];
int in_fence[3];
int fence_merge;
int active, signaled;
timeline[0] = sw_sync_timeline_create();
timeline[1] = sw_sync_timeline_create();
timeline[2] = sw_sync_timeline_create();
in_fence[0] = sw_sync_timeline_create_fence(timeline[0], 5);
in_fence[1] = sw_sync_timeline_create_fence(timeline[1], 5);
in_fence[2] = sw_sync_timeline_create_fence(timeline[2], 5);
fence_merge = sync_fence_merge(in_fence[0], in_fence[1]);
fence_merge = sync_fence_merge(in_fence[2], fence_merge);
/* Confirm fence isn't signaled */
active = sync_fence_count_status(fence_merge,
SW_SYNC_FENCE_STATUS_ACTIVE);
igt_assert_f(active == 3, "Fence signaled too early\n");
igt_assert_f(sync_fence_wait(fence_merge, 0) == -ETIME,
"Failure waiting on fence until timeout\n");
sw_sync_timeline_inc(timeline[0], 5);
active = sync_fence_count_status(fence_merge,
SW_SYNC_FENCE_STATUS_ACTIVE);
signaled = sync_fence_count_status(fence_merge,
SW_SYNC_FENCE_STATUS_SIGNALED);
igt_assert_f(active == 2 && signaled == 1,
"Fence did not signal properly\n");
sw_sync_timeline_inc(timeline[1], 5);
active = sync_fence_count_status(fence_merge,
SW_SYNC_FENCE_STATUS_ACTIVE);
signaled = sync_fence_count_status(fence_merge,
SW_SYNC_FENCE_STATUS_SIGNALED);
igt_assert_f(active == 1 && signaled == 2,
"Fence did not signal properly\n");
sw_sync_timeline_inc(timeline[2], 5);
active = sync_fence_count_status(fence_merge,
SW_SYNC_FENCE_STATUS_ACTIVE);
signaled = sync_fence_count_status(fence_merge,
SW_SYNC_FENCE_STATUS_SIGNALED);
igt_assert_f(active == 0 && signaled == 3,
"Fence did not signal properly\n");
/* confirm you can successfully wait */
igt_assert_f(sync_fence_wait(fence_merge, 100) == 0,
"Failure waiting on signaled fence\n");
close(in_fence[0]);
close(in_fence[1]);
close(in_fence[2]);
close(fence_merge);
close(timeline[0]);
close(timeline[1]);
close(timeline[2]);
}
#define MULTI_CONSUMER_THREADS 8
#define MULTI_CONSUMER_ITERATIONS (1 << 14)
static void * test_sync_multi_consumer_thread(void *arg)
{
data_t *data = arg;
int thread_id = data->thread_id;
int timeline = data->timeline;
int i;
for (i = 0; i < MULTI_CONSUMER_ITERATIONS; i++) {
int next_point = i * MULTI_CONSUMER_THREADS + thread_id;
int fence = sw_sync_timeline_create_fence(timeline, next_point);
if (sync_fence_wait(fence, 1000) < 0)
return (void *) 1;
if (*(data->counter) != next_point)
return (void *) 1;
sem_post(data->sem);
close(fence);
}
return NULL;
}
static void test_sync_multi_consumer(void)
{
data_t data_arr[MULTI_CONSUMER_THREADS];
pthread_t thread_arr[MULTI_CONSUMER_THREADS];
sem_t sem;
int timeline;
volatile uint32_t counter = 0;
uintptr_t thread_ret = 0;
data_t data;
int i, ret;
sem_init(&sem, 0, 0);
timeline = sw_sync_timeline_create();
data.counter = &counter;
data.timeline = timeline;
data.sem = &sem;
/* Start sync threads. */
for (i = 0; i < MULTI_CONSUMER_THREADS; i++)
{
data_arr[i] = data;
data_arr[i].thread_id = i;
ret = pthread_create(&thread_arr[i], NULL,
test_sync_multi_consumer_thread,
(void *) &(data_arr[i]));
igt_assert_eq(ret, 0);
}
/* Produce 'content'. */
for (i = 0; i < MULTI_CONSUMER_THREADS * MULTI_CONSUMER_ITERATIONS; i++)
{
sem_wait(&sem);
counter++;
sw_sync_timeline_inc(timeline, 1);
}
/* Wait for threads to complete. */
for (i = 0; i < MULTI_CONSUMER_THREADS; i++)
{
uintptr_t local_thread_ret;
pthread_join(thread_arr[i], (void **)&local_thread_ret);
thread_ret |= local_thread_ret;
}
close(timeline);
sem_destroy(&sem);
igt_assert_f(counter == MULTI_CONSUMER_THREADS * MULTI_CONSUMER_ITERATIONS,
"Counter has unexpected value.\n");
igt_assert_f(thread_ret == 0, "A sync thread reported failure.\n");
}
#define MULTI_CONSUMER_PRODUCER_THREADS 8
#define MULTI_CONSUMER_PRODUCER_ITERATIONS (1 << 14)
static void * test_sync_multi_consumer_producer_thread(void *arg)
{
data_t *data = arg;
int thread_id = data->thread_id;
int timeline = data->timeline;
int i;
for (i = 0; i < MULTI_CONSUMER_PRODUCER_ITERATIONS; i++) {
int next_point = i * MULTI_CONSUMER_PRODUCER_THREADS + thread_id;
int fence = sw_sync_timeline_create_fence(timeline, next_point);
if (sync_fence_wait(fence, 1000) < 0)
return (void *) 1;
if (*(data->counter) != next_point)
return (void *) 1;
(*data->counter)++;
/* Kick off the next thread. */
sw_sync_timeline_inc(timeline, 1);
close(fence);
}
return NULL;
}
static void test_sync_multi_consumer_producer(void)
{
data_t data_arr[MULTI_CONSUMER_PRODUCER_THREADS];
pthread_t thread_arr[MULTI_CONSUMER_PRODUCER_THREADS];
int timeline;
volatile uint32_t counter = 0;
uintptr_t thread_ret = 0;
data_t data;
int i, ret;
timeline = sw_sync_timeline_create();
data.counter = &counter;
data.timeline = timeline;
/* Start consumer threads. */
for (i = 0; i < MULTI_CONSUMER_PRODUCER_THREADS; i++)
{
data_arr[i] = data;
data_arr[i].thread_id = i;
ret = pthread_create(&thread_arr[i], NULL,
test_sync_multi_consumer_producer_thread,
(void *) &(data_arr[i]));
igt_assert_eq(ret, 0);
}
/* Wait for threads to complete. */
for (i = 0; i < MULTI_CONSUMER_PRODUCER_THREADS; i++)
{
uintptr_t local_thread_ret;
pthread_join(thread_arr[i], (void **)&local_thread_ret);
thread_ret |= local_thread_ret;
}
close(timeline);
igt_assert_f(counter == MULTI_CONSUMER_PRODUCER_THREADS *
MULTI_CONSUMER_PRODUCER_ITERATIONS,
"Counter has unexpected value.\n");
igt_assert_f(thread_ret == 0, "A sync thread reported failure.\n");
}
static int test_mspc_wait_on_fence(int fence)
{
int error, active;
do {
error = sync_fence_count_status(fence,
SW_SYNC_FENCE_STATUS_ERROR);
igt_assert_f(error == 0, "Error occurred on fence\n");
active = sync_fence_count_status(fence,
SW_SYNC_FENCE_STATUS_ACTIVE);
} while (active);
return 0;
}
static struct {
int iterations;
int threads;
int counter;
int cons_timeline;
int *prod_timeline;
pthread_mutex_t lock;
} test_mpsc_data;
static int mpsc_producer_thread(void *d)
{
int id = (long)d;
int fence, i;
int *prod_timeline = test_mpsc_data.prod_timeline;
int cons_timeline = test_mpsc_data.cons_timeline;
int iterations = test_mpsc_data.iterations;
for (i = 0; i < iterations; i++) {
fence = sw_sync_timeline_create_fence(cons_timeline, i);
/* Wait for the consumer to finish. Use alternate
* means of waiting on the fence
*/
if ((iterations + id) % 8 != 0) {
igt_assert_f(sync_fence_wait(fence, -1) == 0,
"Failure waiting on fence\n");
} else {
igt_assert_f(test_mspc_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_mpsc_data.lock);
test_mpsc_data.counter++;
pthread_mutex_unlock(&test_mpsc_data.lock);
sw_sync_timeline_inc(prod_timeline[id], 1);
close(fence);
}
return 0;
}
static int mpsc_consumer_thread(void)
{
int fence, merged, tmp, it, i;
int *prod_timeline = test_mpsc_data.prod_timeline;
int cons_timeline = test_mpsc_data.cons_timeline;
int iterations = test_mpsc_data.iterations;
int n = test_mpsc_data.threads;
for (it = 1; it <= iterations; it++) {
fence = sw_sync_timeline_create_fence(prod_timeline[0], it);
for (i = 1; i < n; i++) {
tmp = sw_sync_timeline_create_fence(prod_timeline[i], it);
merged = sync_fence_merge(tmp, fence);
close(tmp);
close(fence);
fence = merged;
}
/* Make sure we see an increment from every producer thread.
* Vary the means by which we wait.
*/
if (iterations % 8 != 0) {
igt_assert_f(sync_fence_wait(fence, -1) == 0,
"Producers did not increment as expected\n");
} else {
igt_assert_f(test_mspc_wait_on_fence(fence) == 0,
"Failure waiting on fence\n");
}
igt_assert_f(test_mpsc_data.counter == n * it,
"Counter value mismatch\n");
/* Release the producer threads */
sw_sync_timeline_inc(cons_timeline, 1);
close(fence);
}
return 0;
}
/* 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.
*/
static void test_sync_multi_producer_single_consumer(void)
{
int iterations = 1 << 12;
int n = 5;
int prod_timeline[n];
int cons_timeline;
pthread_t threads[n];
long i;
cons_timeline = sw_sync_timeline_create();
for (i = 0; i < n; i++)
prod_timeline[i] = sw_sync_timeline_create();
test_mpsc_data.prod_timeline = prod_timeline;
test_mpsc_data.cons_timeline = cons_timeline;
test_mpsc_data.iterations = iterations;
test_mpsc_data.threads = n;
test_mpsc_data.counter = 0;
pthread_mutex_init(&test_mpsc_data.lock, NULL);
for (i = 0; i < n; i++) {
pthread_create(&threads[i], NULL, (void * (*)(void *))
mpsc_producer_thread,
(void *)i);
}
mpsc_consumer_thread();
for (i = 0; i < n; i++)
pthread_join(threads[i], NULL);
}
static void test_sync_expired_merge(void)
{
int iterations = 1 << 20;
int timeline;
int i;
int fence_expired, fence_merged;
timeline = sw_sync_timeline_create();
sw_sync_timeline_inc(timeline, 100);
fence_expired = sw_sync_timeline_create_fence(timeline, 1);
igt_assert_f(sync_fence_wait(fence_expired, 0) == 0,
"Failure waiting for expired fence\n");
fence_merged = sync_fence_merge(fence_expired, fence_expired);
close(fence_merged);
for (i = 0; i < iterations; i++) {
int fence = sync_fence_merge(fence_expired, fence_expired);
igt_assert_f(sync_fence_wait(fence, -1) == 0,
"Failure waiting on fence\n");
close(fence);
}
close(fence_expired);
}
static void test_sync_random_merge(void)
{
int i, size;
const int nbr_timeline = 32;
const int nbr_merge = 1024;
int fence_map[nbr_timeline];
int timeline_arr[nbr_timeline];
int fence, tmpfence, merged;
int timeline, timeline_offset, sync_pt;
srand(time(NULL));
for (i = 0; i < nbr_timeline; i++) {
timeline_arr[i] = sw_sync_timeline_create();
fence_map[i] = -1;
}
sync_pt = rand();
fence = sw_sync_timeline_create_fence(timeline_arr[0], sync_pt);
fence_map[0] = sync_pt;
/* Randomly create syncpoints out of a fixed set of timelines,
* and merge them together.
*/
for (i = 0; i < nbr_merge; i++) {
/* Generate syncpoint. */
timeline_offset = rand() % nbr_timeline;
timeline = timeline_arr[timeline_offset];
sync_pt = rand();
/* Keep track of the latest sync_pt in each timeline. */
if (fence_map[timeline_offset] == -1)
fence_map[timeline_offset] = sync_pt;
else if (fence_map[timeline_offset] < sync_pt)
fence_map[timeline_offset] = sync_pt;
/* Merge. */
tmpfence = sw_sync_timeline_create_fence(timeline, sync_pt);
merged = sync_fence_merge(tmpfence, fence);
close(tmpfence);
close(fence);
fence = merged;
}
size = 0;
for (i = 0; i < nbr_timeline; i++)
if (fence_map[i] != -1)
size++;
/* Trigger the merged fence. */
for (i = 0; i < nbr_timeline; i++) {
if (fence_map[i] != -1) {
igt_assert_f(sync_fence_wait(fence, 0) == -ETIME,
"Failure waiting on fence until timeout\n");
/* Increment the timeline to the last sync_pt */
sw_sync_timeline_inc(timeline_arr[i], fence_map[i]);
}
}
/* Check that the fence is triggered. */
igt_assert_f(sync_fence_wait(fence, 1) == 0,
"Failure triggering fence\n");
close(fence);
for (i = 0; i < nbr_timeline; i++)
close(timeline_arr[i]);
}
igt_main
{
igt_fixture
igt_require_sw_sync();
igt_subtest("alloc_timeline")
test_alloc_timeline();
igt_subtest("alloc_fence")
test_alloc_fence();
igt_subtest("alloc_fence_invalid_timeline")
test_alloc_fence_invalid_timeline();
igt_subtest("timeline_closed")
test_timeline_closed();
igt_subtest("timeline_closed_signaled")
test_timeline_closed_signaled();
igt_subtest("alloc_merge_fence")
test_alloc_merge_fence();
igt_subtest("sync_busy")
test_sync_busy();
igt_subtest("sync_busy_fork")
test_sync_busy_fork();
igt_subtest("sync_busy_fork_unixsocket")
test_sync_busy_fork_unixsocket();
igt_subtest("sync_merge_invalid")
test_sync_merge_invalid();
igt_subtest("sync_merge")
test_sync_merge();
igt_subtest("sync_merge_same")
test_sync_merge_same();
igt_subtest("sync_multi_timeline_wait")
test_sync_multi_timeline_wait();
igt_subtest("sync_multi_consumer")
test_sync_multi_consumer();
igt_subtest("sync_multi_consumer_producer")
test_sync_multi_consumer_producer();
igt_subtest("sync_multi_producer_single_consumer")
test_sync_multi_producer_single_consumer();
igt_subtest("sync_expired_merge")
test_sync_expired_merge();
igt_subtest("sync_random_merge")
test_sync_random_merge();
}