forked from Imagelibrary/rtems
548 lines
11 KiB
C
548 lines
11 KiB
C
/* SPDX-License-Identifier: BSD-2-Clause */
|
|
|
|
/**
|
|
* @file
|
|
*
|
|
* @ingroup test_bdbuf
|
|
*
|
|
* @brief Bdbuf test.
|
|
*/
|
|
|
|
/*
|
|
* Copyright (c) 2009, 2018 embedded brains GmbH. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <sys/stat.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdarg.h>
|
|
|
|
#include <rtems.h>
|
|
#include <rtems/bspIo.h>
|
|
#include <rtems/bdbuf.h>
|
|
#include <rtems/blkdev.h>
|
|
|
|
#include <tmacros.h>
|
|
|
|
const char rtems_test_name[] = "BLOCK 5";
|
|
|
|
/* forward declarations to avoid warnings */
|
|
static rtems_task Init(rtems_task_argument argument);
|
|
|
|
#define ASSERT_SC(sc) rtems_test_assert((sc) == RTEMS_SUCCESSFUL)
|
|
|
|
#define PRIORITY_INIT 1
|
|
|
|
#define PRIORITY_HIGH 2
|
|
|
|
#define PRIORITY_LOW_ALT 3
|
|
|
|
#define PRIORITY_SWAPOUT 4
|
|
|
|
#define PRIORITY_LOW 5
|
|
|
|
#define PRIORITY_RESUME 6
|
|
|
|
#define BLOCK_SIZE_A 1
|
|
|
|
#define BLOCK_COUNT_A 2
|
|
|
|
#define BLOCK_SIZE_B 2
|
|
|
|
#define BLOCK_COUNT_B 1
|
|
|
|
/* In case of trouble change this to 1 or 2 for more output */
|
|
static unsigned output_level = 0;
|
|
|
|
static rtems_disk_device *dd_a;
|
|
|
|
static rtems_disk_device *dd_b;
|
|
|
|
static rtems_id task_id_init;
|
|
|
|
static rtems_id task_id_low;
|
|
|
|
static rtems_id task_id_high;
|
|
|
|
static rtems_id task_id_resume;
|
|
|
|
static volatile bool finish_low;
|
|
|
|
static volatile bool finish_high;
|
|
|
|
static volatile enum resume_style {
|
|
RESUME_IMMEDIATE,
|
|
RESUME_FINISH
|
|
} resume;
|
|
|
|
static volatile enum trig_style {
|
|
SUSP = 0,
|
|
CONT
|
|
} trig;
|
|
|
|
static volatile enum get_type {
|
|
GET = 0,
|
|
READ
|
|
} trig_get, low_get, high_get;
|
|
|
|
static volatile enum blk_kind {
|
|
BLK_A0 = 0,
|
|
BLK_A1,
|
|
BLK_B0
|
|
} trig_blk, low_blk, high_blk;
|
|
|
|
static volatile enum rel_type {
|
|
REL = 0,
|
|
REL_MOD,
|
|
SYNC
|
|
} trig_rel, low_rel, high_rel;
|
|
|
|
static const char trig_style_desc [] = {
|
|
'S',
|
|
'C'
|
|
};
|
|
|
|
static const char get_type_desc [] = {
|
|
'G',
|
|
'R'
|
|
};
|
|
|
|
static const char *blk_kind_desc [] = {
|
|
"A0",
|
|
"A1",
|
|
"B0"
|
|
};
|
|
|
|
static const char rel_type_desc [] = {
|
|
'R',
|
|
'M',
|
|
'S'
|
|
};
|
|
|
|
static void print(unsigned level, const char *fmt, ...)
|
|
{
|
|
if (level <= output_level) {
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
vprintk(fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
}
|
|
|
|
static void set_task_prio(rtems_id task, rtems_task_priority prio)
|
|
{
|
|
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
|
rtems_task_priority cur = 0;
|
|
|
|
sc = rtems_task_set_priority(task, prio, &cur);
|
|
ASSERT_SC(sc);
|
|
}
|
|
|
|
static rtems_bdbuf_buffer *get(enum get_type type, enum blk_kind kind)
|
|
{
|
|
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
|
rtems_bdbuf_buffer *bd = NULL;
|
|
rtems_blkdev_bnum blk_index = 0;
|
|
rtems_status_code (*get_bd)(
|
|
rtems_disk_device *,
|
|
rtems_blkdev_bnum,
|
|
rtems_bdbuf_buffer **
|
|
) = NULL;
|
|
rtems_disk_device *dd = NULL;
|
|
size_t bds_per_group = 0;
|
|
|
|
switch (kind) {
|
|
case BLK_A0:
|
|
dd = dd_a;
|
|
blk_index = 0;
|
|
bds_per_group = 2;
|
|
break;
|
|
case BLK_A1:
|
|
dd = dd_a;
|
|
blk_index = 1;
|
|
bds_per_group = 2;
|
|
break;
|
|
case BLK_B0:
|
|
dd = dd_b;
|
|
blk_index = 0;
|
|
bds_per_group = 1;
|
|
break;
|
|
default:
|
|
rtems_test_assert(false);
|
|
break;
|
|
}
|
|
|
|
switch (type) {
|
|
case GET:
|
|
get_bd = rtems_bdbuf_get;
|
|
break;
|
|
case READ:
|
|
get_bd = rtems_bdbuf_read;
|
|
break;
|
|
default:
|
|
rtems_test_assert(false);
|
|
break;
|
|
}
|
|
|
|
sc = (*get_bd)(dd, blk_index, &bd);
|
|
rtems_test_assert(
|
|
sc == RTEMS_SUCCESSFUL
|
|
&& bd->dd == dd
|
|
&& bd->block == blk_index
|
|
&& bd->group->bds_per_group == bds_per_group
|
|
);
|
|
|
|
return bd;
|
|
}
|
|
|
|
static void rel(rtems_bdbuf_buffer *bd, enum rel_type type)
|
|
{
|
|
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
|
rtems_status_code (*rel_bd)(rtems_bdbuf_buffer *) = NULL;
|
|
|
|
switch (type) {
|
|
case REL:
|
|
rel_bd = rtems_bdbuf_release;
|
|
break;
|
|
case REL_MOD:
|
|
rel_bd = rtems_bdbuf_release_modified;
|
|
break;
|
|
case SYNC:
|
|
rel_bd = rtems_bdbuf_sync;
|
|
break;
|
|
default:
|
|
rtems_test_assert(false);
|
|
break;
|
|
}
|
|
|
|
sc = (*rel_bd)(bd);
|
|
ASSERT_SC(sc);
|
|
}
|
|
|
|
static void task_low(rtems_task_argument arg)
|
|
{
|
|
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
|
|
|
while (true) {
|
|
print(2, "LG\n");
|
|
rtems_bdbuf_buffer *bd = get(low_get, low_blk);
|
|
|
|
print(2, "LR\n");
|
|
rel(bd, low_rel);
|
|
|
|
finish_low = true;
|
|
|
|
sc = rtems_task_suspend(RTEMS_SELF);
|
|
ASSERT_SC(sc);
|
|
}
|
|
}
|
|
|
|
static void task_high(rtems_task_argument arg)
|
|
{
|
|
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
|
|
|
while (true) {
|
|
print(2, "HG\n");
|
|
rtems_bdbuf_buffer *bd = get(high_get, high_blk);
|
|
|
|
print(2, "HR\n");
|
|
rel(bd, high_rel);
|
|
|
|
finish_high = true;
|
|
|
|
sc = rtems_task_suspend(RTEMS_SELF);
|
|
ASSERT_SC(sc);
|
|
}
|
|
}
|
|
|
|
static void task_resume(rtems_task_argument arg)
|
|
{
|
|
while (true) {
|
|
bool do_resume = false;
|
|
|
|
switch (resume) {
|
|
case RESUME_IMMEDIATE:
|
|
print(2, "RI\n");
|
|
do_resume = true;
|
|
break;
|
|
case RESUME_FINISH:
|
|
print(2, "RF\n");
|
|
do_resume = finish_low && finish_high;
|
|
break;
|
|
default:
|
|
rtems_test_assert(false);
|
|
break;
|
|
}
|
|
|
|
if (do_resume) {
|
|
rtems_task_resume(task_id_init);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void execute_test(unsigned i)
|
|
{
|
|
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
|
rtems_bdbuf_buffer *bd = NULL;
|
|
bool suspend = false;
|
|
|
|
print(
|
|
1,
|
|
"[%05u]T(%c,%c,%s,%c)L(%c,%s,%c)H(%c,%s,%c)\n",
|
|
i,
|
|
trig_style_desc [trig],
|
|
get_type_desc [trig_get],
|
|
blk_kind_desc [trig_blk],
|
|
rel_type_desc [trig_rel],
|
|
get_type_desc [low_get],
|
|
blk_kind_desc [low_blk],
|
|
rel_type_desc [low_rel],
|
|
get_type_desc [high_get],
|
|
blk_kind_desc [high_blk],
|
|
rel_type_desc [high_rel]
|
|
);
|
|
|
|
set_task_prio(task_id_low, PRIORITY_LOW);
|
|
|
|
finish_low = false;
|
|
finish_high = false;
|
|
|
|
sc = rtems_task_resume(task_id_low);
|
|
ASSERT_SC(sc);
|
|
|
|
sc = rtems_task_resume(task_id_high);
|
|
ASSERT_SC(sc);
|
|
|
|
sc = rtems_bdbuf_get(dd_b, 0, &bd);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL && bd->dd == dd_b && bd->block == 0);
|
|
|
|
sc = rtems_bdbuf_release(bd);
|
|
ASSERT_SC(sc);
|
|
|
|
switch (trig) {
|
|
case SUSP:
|
|
suspend = true;
|
|
break;
|
|
case CONT:
|
|
suspend = false;
|
|
break;
|
|
default:
|
|
rtems_test_assert(false);
|
|
break;
|
|
}
|
|
|
|
print(2, "TG\n");
|
|
bd = get(trig_get, trig_blk);
|
|
|
|
if (suspend) {
|
|
print(2, "S\n");
|
|
resume = RESUME_IMMEDIATE;
|
|
sc = rtems_task_suspend(RTEMS_SELF);
|
|
ASSERT_SC(sc);
|
|
}
|
|
resume = RESUME_FINISH;
|
|
|
|
print(2, "TR\n");
|
|
rel(bd, trig_rel);
|
|
|
|
sc = rtems_task_suspend(RTEMS_SELF);
|
|
ASSERT_SC(sc);
|
|
|
|
print(2, "F\n");
|
|
|
|
sc = rtems_bdbuf_syncdev(dd_a);
|
|
ASSERT_SC(sc);
|
|
|
|
sc = rtems_bdbuf_syncdev(dd_b);
|
|
ASSERT_SC(sc);
|
|
}
|
|
|
|
static int disk_ioctl(rtems_disk_device *dd, uint32_t req, void *argp)
|
|
{
|
|
if (req == RTEMS_BLKIO_REQUEST) {
|
|
rtems_blkdev_request *r = argp;
|
|
|
|
set_task_prio(task_id_low, PRIORITY_LOW_ALT);
|
|
|
|
switch (r->req) {
|
|
case RTEMS_BLKDEV_REQ_READ:
|
|
case RTEMS_BLKDEV_REQ_WRITE:
|
|
rtems_blkdev_request_done(r, RTEMS_SUCCESSFUL);
|
|
return 0;
|
|
default:
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
} else {
|
|
return rtems_blkdev_ioctl(dd, req, argp);
|
|
}
|
|
}
|
|
|
|
static void disk_register(
|
|
const char *dev,
|
|
uint32_t block_size,
|
|
rtems_blkdev_bnum block_count,
|
|
rtems_disk_device **dd_ptr
|
|
)
|
|
{
|
|
rtems_status_code sc;
|
|
int rv;
|
|
int fd;
|
|
|
|
sc = rtems_blkdev_create(
|
|
dev,
|
|
block_size,
|
|
block_count,
|
|
disk_ioctl,
|
|
NULL
|
|
);
|
|
ASSERT_SC(sc);
|
|
|
|
fd = open(dev, O_RDWR);
|
|
rtems_test_assert(fd >= 0);
|
|
|
|
rv = rtems_disk_fd_get_disk_device(fd, dd_ptr);
|
|
rtems_test_assert(rv == 0);
|
|
|
|
rv = close(fd);
|
|
rtems_test_assert(rv == 0);
|
|
}
|
|
|
|
static rtems_task Init(rtems_task_argument argument)
|
|
{
|
|
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
|
unsigned i = 0;
|
|
|
|
TEST_BEGIN();
|
|
|
|
task_id_init = rtems_task_self();
|
|
|
|
disk_register("dd_b", BLOCK_SIZE_A, BLOCK_COUNT_A, &dd_a);
|
|
|
|
disk_register("dd_a", BLOCK_SIZE_B, BLOCK_COUNT_B, &dd_b);
|
|
|
|
sc = rtems_task_create(
|
|
rtems_build_name(' ', 'L', 'O', 'W'),
|
|
PRIORITY_LOW,
|
|
0,
|
|
RTEMS_DEFAULT_MODES,
|
|
RTEMS_DEFAULT_ATTRIBUTES,
|
|
&task_id_low
|
|
);
|
|
ASSERT_SC(sc);
|
|
|
|
sc = rtems_task_start(task_id_low, task_low, 0);
|
|
ASSERT_SC(sc);
|
|
|
|
sc = rtems_task_create(
|
|
rtems_build_name('H', 'I', 'G', 'H'),
|
|
PRIORITY_HIGH,
|
|
0,
|
|
RTEMS_DEFAULT_MODES,
|
|
RTEMS_DEFAULT_ATTRIBUTES,
|
|
&task_id_high
|
|
);
|
|
ASSERT_SC(sc);
|
|
|
|
sc = rtems_task_start(task_id_high, task_high, 0);
|
|
ASSERT_SC(sc);
|
|
|
|
sc = rtems_task_create(
|
|
rtems_build_name('R', 'E', 'S', 'U'),
|
|
PRIORITY_RESUME,
|
|
0,
|
|
RTEMS_DEFAULT_MODES,
|
|
RTEMS_DEFAULT_ATTRIBUTES,
|
|
&task_id_resume
|
|
);
|
|
ASSERT_SC(sc);
|
|
|
|
sc = rtems_task_start(task_id_resume, task_resume, 0);
|
|
ASSERT_SC(sc);
|
|
|
|
sc = rtems_task_suspend(task_id_low);
|
|
ASSERT_SC(sc);
|
|
|
|
sc = rtems_task_suspend(task_id_high);
|
|
ASSERT_SC(sc);
|
|
|
|
for (trig = SUSP; trig <= CONT; ++trig) {
|
|
for (trig_get = GET; trig_get <= READ; ++trig_get) {
|
|
for (low_get = GET; low_get <= READ; ++low_get) {
|
|
for (high_get = GET; high_get <= READ; ++high_get) {
|
|
for (trig_blk = BLK_A0; trig_blk <= BLK_B0; ++trig_blk) {
|
|
for (low_blk = BLK_A0; low_blk <= BLK_B0; ++low_blk) {
|
|
for (high_blk = BLK_A0; high_blk <= BLK_B0; ++high_blk) {
|
|
for (trig_rel = REL; trig_rel <= SYNC; ++trig_rel) {
|
|
for (low_rel = REL; low_rel <= SYNC; ++low_rel) {
|
|
for (high_rel = REL; high_rel <= SYNC; ++high_rel) {
|
|
execute_test(i);
|
|
++i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_END();
|
|
|
|
exit(0);
|
|
}
|
|
|
|
#define CONFIGURE_INIT
|
|
|
|
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
|
|
#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
|
|
#define CONFIGURE_APPLICATION_NEEDS_LIBBLOCK
|
|
|
|
#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 5
|
|
|
|
#define CONFIGURE_MAXIMUM_TASKS 4
|
|
|
|
#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
|
|
|
|
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
|
|
|
|
#define CONFIGURE_INIT_TASK_PRIORITY PRIORITY_INIT
|
|
#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_DEFAULT_ATTRIBUTES
|
|
#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES
|
|
|
|
#define CONFIGURE_SWAPOUT_TASK_PRIORITY PRIORITY_SWAPOUT
|
|
|
|
#define CONFIGURE_BDBUF_BUFFER_MIN_SIZE BLOCK_SIZE_A
|
|
#define CONFIGURE_BDBUF_BUFFER_MAX_SIZE BLOCK_SIZE_B
|
|
#define CONFIGURE_BDBUF_CACHE_MEMORY_SIZE BLOCK_SIZE_B
|
|
|
|
#include <rtems/confdefs.h>
|