blob: 4c0167ee10fa36b2930cdf0badb2758f3dcdbfa3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013 Linaro
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Linaro <linaro-dev@lists.linaro.org>
*******************************************************************************/
/* sync framework test */
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#ifdef ANDROID
/* kernel headers on android */
#include <linux/sync.h>
#include <linux/sw_sync.h>
#else
/* set KDIR in Makefile to point to these headers */
#include "sync.h"
#include "sw_sync.h"
#endif /* ANDROID */
#define SW_SYNC_DEV "/dev/sw_sync"
/* current test run */
int testno = -1;
char testname[32];
/* fd of SW_SYNC_DEV */
int sw_fd;
#define RED "\x1B[31m"
#define GREEN "\x1B[32m"
#define NORMAL "\x1B[0m"
void fatal (int error, const char *fmt, ...)
{
va_list ap;
fprintf (stderr, "Test %d: ", testno);
va_start (ap, fmt);
vfprintf (stderr, fmt, ap);
if (error)
fprintf (stderr, " (error %d [%s])", error, strerror (error));
va_end (ap);
fprintf (stderr, "\n");
/* printf(RED); */
printf ("%d [sync_basic_%s]: test failed\n", testno, testname);
/* printf(NORMAL); */
exit (1);
}
void pass (const char *fmt, ...)
{
va_list ap;
fprintf (stderr, "Test %d: ", testno);
if (fmt == NULL)
fprintf (stderr, "Passed");
else {
va_start (ap, fmt);
vfprintf (stderr, fmt, ap);
va_end (ap);
}
fprintf (stderr, "\n");
/* printf(GREEN); */
printf ("%d [sync_basic_%s]: test passed\n", testno, testname);
/* printf(NORMAL); */
}
void create_and_delete_fence (void)
{
struct sw_sync_create_fence_data f;
int ret;
testno++;
strcpy (testname, __func__);
strncpy (f.name, "test fence 0", sizeof (f.name));
f.value = 0;
ret = ioctl (sw_fd, SW_SYNC_IOC_CREATE_FENCE, &f);
if (ret < 0)
fatal (errno, "can't create fence");
ret = close (f.fence);
if (ret < 0)
fatal (errno, "can't delete fence");
pass(NULL);
}
void create_fence_invalid (void)
{
struct sw_sync_create_fence_data *f = (void *)0xdeaddead;
int ret;
testno++;
strcpy (testname, __func__);
ret = ioctl (sw_fd, SW_SYNC_IOC_CREATE_FENCE, f);
if (ret >= 0 || errno != EFAULT)
fatal (0, "expect -1 and EFAULT, but got %d and %d", ret, errno);
pass(NULL);
}
#define TOOMANY 100000 /* should be larger than max fds per process */
void create_many_fences (void)
{
struct sw_sync_create_fence_data f;
static int fencefds[TOOMANY];
int ret, nr, i;
testno++;
strcpy (testname, __func__);
for (nr = 0; nr < TOOMANY; nr++) {
sprintf (f.name, "fence %d", nr);
f.value = nr;
ret = ioctl (sw_fd, SW_SYNC_IOC_CREATE_FENCE, &f);
if (ret < 0)
break;
else
fencefds[nr] = f.fence;
}
if (errno != EMFILE)
fatal (0, "expect EMFILE but got %d", errno);
for (i = 0; i < nr; i++) {
ret = close (fencefds[i]);
if (ret < 0)
fatal (errno, "error closing fence %d of %d", i, nr);
}
pass("%d fences were used", nr);
}
void fence_info (void)
{
struct sw_sync_create_fence_data f;
struct sync_fence_info_data *d;
int ret;
testno++;
strcpy (testname, __func__);
strncpy (f.name, "test fence 1", sizeof (f.name));
f.value = 0;
ret = ioctl (sw_fd, SW_SYNC_IOC_CREATE_FENCE, &f);
if (ret < 0)
fatal (errno, "can't create fence");
d = malloc (128);
if (!d)
abort ();
d->len = 128;
ret = ioctl (f.fence, SYNC_IOC_FENCE_INFO, d);
if (ret < 0)
fatal (errno, "can't get fence %d info", f.fence);
if (strcmp (d->name, "test fence 1"))
fatal (0, "invalid fence name");
if (d->status != 1)
fatal (0, "invalid fence status");
free (d);
ret = close (f.fence);
if (ret < 0)
fatal (errno, "can't delete fence");
pass(NULL);
}
void fence_info_invalid (void)
{
struct sync_fence_info_data *d;
int ret;
testno++;
strcpy (testname, __func__);
d = malloc (128);
if (!d)
abort ();
d->len = 128;
ret = ioctl (fileno (stdout), SYNC_IOC_FENCE_INFO, d);
if (ret >= 0 || errno != ENOTTY)
fatal (0, "expect -1 and ENOTTY, but got %d and %d", ret, errno);
free (d);
pass(NULL);
}
void fence_merge (void)
{
struct sw_sync_create_fence_data f1, f2;
struct sync_merge_data f3;
struct sync_fence_info_data *d;
int ret;
testno++;
strcpy (testname, __func__);
strncpy (f1.name, "test fence 1", sizeof (f1.name));
f1.value = 1;
ret = ioctl (sw_fd, SW_SYNC_IOC_CREATE_FENCE, &f1);
if (ret < 0)
fatal (errno, "can't create fence 1");
strncpy (f2.name, "test fence 2", sizeof (f2.name));
f2.value = 2;
ret = ioctl (sw_fd, SW_SYNC_IOC_CREATE_FENCE, &f2);
if (ret < 0)
fatal (errno, "can't create fence 2");
f3.fd2 = f2.fence;
strncpy (f3.name, "merged fence 1 + 2", sizeof (f3.name));
ret = ioctl (f1.fence, SYNC_IOC_MERGE, &f3);
if (ret < 0)
fatal (errno, "can't merge fences");
d = malloc (128);
if (!d)
abort ();
d->len = 128;
ret = ioctl (f3.fence, SYNC_IOC_FENCE_INFO, d);
if (ret < 0)
fatal (errno, "can't get information about merged fence");
if (strcmp (d->name, "merged fence 1 + 2"))
fatal (0, "invalid merged fence name");
free (d);
if (f1.fence == f2.fence ||
f2.fence == f3.fence ||
f3.fence == f1.fence)
fatal (0, "impossible fence fds: %d %d %d", f1.fence, f2.fence, f3.fence);
ret = close (f3.fence);
if (ret < 0)
fatal (errno, "can't close merged fence");
ret = close (f2.fence);
if (ret < 0)
fatal (errno, "can't close fence 2");
ret = close (f1.fence);
if (ret < 0)
fatal (errno, "can't close fence 1");
pass(NULL);
}
void fence_merge_itself (void)
{
struct sw_sync_create_fence_data f1;
struct sync_merge_data f2;
int ret;
testno++;
strcpy (testname, __func__);
strncpy (f1.name, "test fence 1", sizeof (f1.name));
f1.value = 1;
ret = ioctl (sw_fd, SW_SYNC_IOC_CREATE_FENCE, &f1);
if (ret < 0)
fatal (errno, "can't create fence 1");
f2.fd2 = f1.fence;
strncpy (f2.name, "copy of fence 1", sizeof (f2.name));
ret = ioctl (f1.fence, SYNC_IOC_MERGE, &f2);
if (ret < 0)
fatal (errno, "can't merge fence with itself");
ret = close (f2.fence);
if (ret < 0)
fatal (errno, "can't close copy fence");
ret = close (f1.fence);
if (ret < 0)
fatal (errno, "can't close fence 1");
pass(NULL);
}
void fence_merge_invalid (void)
{
struct sw_sync_create_fence_data f1;
struct sync_merge_data f2;
int ret;
testno++;
strcpy (testname, __func__);
strncpy (f1.name, "test fence 1", sizeof (f1.name));
f1.value = 1;
ret = ioctl (sw_fd, SW_SYNC_IOC_CREATE_FENCE, &f1);
if (ret < 0)
fatal (errno, "can't create fence 1");
f2.fd2 = fileno (stdout);
strncpy (f2.name, "impossible fence 2", sizeof (f2.name));
ret = ioctl (f1.fence, SYNC_IOC_MERGE, &f2);
if (ret >= 0 || errno != ENOENT)
fatal (0, "expect -1 and ENOENT, but got %d and %d", ret, errno);
ret = close (f1.fence);
if (ret < 0)
fatal (errno, "can't close fence 1");
pass(NULL);
}
int main (int argc, char *argv[])
{
/* 0 - just try to open */
testno++;
strcpy (testname, "try_open");
sw_fd = open (SW_SYNC_DEV, O_RDWR);
if (sw_fd < 0)
fatal (errno, "can't open '%s'", SW_SYNC_DEV);
pass(NULL);
/* 1 - create and delete just one fence */
create_and_delete_fence ();
/* 2 - try to create fence fron invalid data */
create_fence_invalid ();
/* 3 - try to create as much as possible */
create_many_fences ();
/* 4 - basic fence info */
fence_info ();
/* 5 - invalid fence info */
fence_info_invalid ();
/* 6 - basic merge */
fence_merge ();
/* 7 - merge with itself (e.g. copy) */
fence_merge_itself ();
/* 8 - merge with invalid fence */
fence_merge_invalid ();
close (sw_fd);
return 0;
}