forked from Imagelibrary/rtems
1791 lines
40 KiB
C
1791 lines
40 KiB
C
/*
|
|
* Copyright 2008 Chris Johns (chrisj@rtems.org)
|
|
*
|
|
* The license and distribution terms for this file may be
|
|
* found in the file LICENSE in this distribution or at
|
|
* http://www.rtems.org/license/LICENSE.
|
|
*/
|
|
|
|
/**
|
|
* BD Buffer test.
|
|
*
|
|
* Please add more tests
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <setjmp.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <inttypes.h>
|
|
#include <unistd.h>
|
|
|
|
#include <rtems.h>
|
|
#include <rtems/chain.h>
|
|
#include <rtems/error.h>
|
|
#include <rtems/bdbuf.h>
|
|
|
|
#include <bsp.h>
|
|
|
|
#include "tmacros.h"
|
|
|
|
const char rtems_test_name[] = "BLOCK 6";
|
|
|
|
/* forward declarations to avoid warnings */
|
|
static rtems_task Init(rtems_task_argument argument);
|
|
|
|
#define BDBUF_DISKS 2
|
|
#define BDBUF_SIZE 1024
|
|
|
|
#if 0
|
|
const rtems_bdbuf_config rtems_bdbuf_configuration =
|
|
{
|
|
5, /* max_read_ahead_blocks */
|
|
5, /* max_write_blocks */
|
|
15, /* swapout_priority */
|
|
250, /* swapout_period */
|
|
1000, /* swap_block_hold */
|
|
0, /* swapout_workers */
|
|
15, /* swapout_worker_priority */
|
|
1024 * 1024, /* size */
|
|
512, /* buffer_min */
|
|
4096 /* buffer_max */
|
|
};
|
|
#endif
|
|
|
|
/**
|
|
* The bdbuf disk driver base name.
|
|
*/
|
|
#define BDBUF_DISK_DEVICE_BASE_NAME "/dev/bddisk"
|
|
|
|
/**
|
|
* The actions the disk driver handles.
|
|
*/
|
|
typedef enum bdbuf_disk_action
|
|
{
|
|
BDBUF_DISK_NOOP,
|
|
BDBUF_DISK_WAIT,
|
|
BDBUF_DISK_SLEEP,
|
|
BDBUF_DISK_BLOCKS_INORDER
|
|
} bdbuf_disk_action;
|
|
|
|
/**
|
|
* The BDBUF Disk driver.
|
|
*/
|
|
typedef struct bdbuf_disk
|
|
{
|
|
const char* name;
|
|
uint32_t minor;
|
|
rtems_id lock;
|
|
uint32_t block_size;
|
|
uint32_t block_count;
|
|
bdbuf_disk_action driver_action;
|
|
const char* watcher_name;
|
|
rtems_id watcher;
|
|
int watch_count;
|
|
const char* waiting_name;
|
|
rtems_id waiting;
|
|
uint32_t driver_sleep;
|
|
rtems_disk_device* dd;
|
|
} bdbuf_disk;
|
|
|
|
/*
|
|
* A disk drive for each pool.
|
|
*/
|
|
static bdbuf_disk bdbuf_disks[BDBUF_DISKS];
|
|
|
|
/**
|
|
* Task control.
|
|
*/
|
|
typedef struct bdbuf_task_control
|
|
{
|
|
bool die;
|
|
const char* name;
|
|
rtems_id task;
|
|
rtems_id master;
|
|
int test;
|
|
bdbuf_disk *bdd;
|
|
bool passed;
|
|
} bdbuf_task_control;
|
|
|
|
#define BDBUF_TEST_TASKS (3)
|
|
|
|
#define BDBUF_TEST_STACK_SIZE (2 * RTEMS_MINIMUM_STACK_SIZE)
|
|
|
|
/**
|
|
* Seconds as milli-seconds.
|
|
*/
|
|
#define BDBUF_SECONDS(msec) ((msec) * 1000UL)
|
|
|
|
/**
|
|
* Print the status code description and return true if true.
|
|
*
|
|
* @param sc The RTEMS status code.
|
|
* @retval true The status code is successful.
|
|
* @retval false The status code is not successful.
|
|
*/
|
|
static bool
|
|
bdbuf_test_print_sc (rtems_status_code sc, bool newline)
|
|
{
|
|
if (newline)
|
|
printf ("%s\n", rtems_status_text (sc));
|
|
else
|
|
printf ("%s", rtems_status_text (sc));
|
|
return sc == RTEMS_SUCCESSFUL;
|
|
}
|
|
|
|
/**
|
|
* BDBuf disk device driver lock.
|
|
*/
|
|
static bool
|
|
bdbuf_disk_lock (bdbuf_disk* bdd)
|
|
{
|
|
rtems_status_code sc;
|
|
sc = rtems_semaphore_obtain (bdd->lock, RTEMS_WAIT, 0);
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
printf ("disk ioctl: lock failed: ");
|
|
bdbuf_test_print_sc (sc, true);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* BDBuf disk device driver unlock.
|
|
*/
|
|
static bool
|
|
bdbuf_disk_unlock (bdbuf_disk* bdd)
|
|
{
|
|
rtems_status_code sc;
|
|
sc = rtems_semaphore_release (bdd->lock);
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
printf ("disk ioctl: unlock failed: ");
|
|
bdbuf_test_print_sc (sc, true);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* BDBUf wait for the wait event.
|
|
*/
|
|
static rtems_status_code
|
|
bdbuf_wait (const char* who, unsigned long timeout)
|
|
{
|
|
rtems_status_code sc;
|
|
rtems_event_set out;
|
|
sc = rtems_event_receive (RTEMS_EVENT_0,
|
|
RTEMS_WAIT | RTEMS_EVENT_ANY,
|
|
RTEMS_MICROSECONDS_TO_TICKS (timeout * 1000),
|
|
&out);
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
printf ("%s: wait: receive failed: ", who);
|
|
bdbuf_test_print_sc (sc, true);
|
|
}
|
|
else if ((out & RTEMS_EVENT_0) == 0)
|
|
{
|
|
printf ("%s: wait: received wrong event: %08" PRIxrtems_event_set, who, out);
|
|
}
|
|
return sc;
|
|
}
|
|
|
|
/**
|
|
* BDBUf send wait event.
|
|
*/
|
|
static bool
|
|
bdbuf_send_wait_event (const char* task, const char* msg, rtems_id id)
|
|
{
|
|
printf ("%s: %s: %08" PRIxrtems_id ": ", task, msg, id);
|
|
return bdbuf_test_print_sc (rtems_event_send (id, RTEMS_EVENT_0), true);
|
|
}
|
|
|
|
/**
|
|
* BDBUf wait for the wait event.
|
|
*/
|
|
static rtems_status_code
|
|
bdbuf_watch (unsigned long timeout)
|
|
{
|
|
rtems_status_code sc;
|
|
rtems_event_set out;
|
|
sc = rtems_event_receive (RTEMS_EVENT_1,
|
|
RTEMS_WAIT | RTEMS_EVENT_ANY,
|
|
RTEMS_MICROSECONDS_TO_TICKS (timeout * 1000),
|
|
&out);
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
printf ("watch: receive failed: ");
|
|
bdbuf_test_print_sc (sc, true);
|
|
}
|
|
else if ((out & RTEMS_EVENT_1) == 0)
|
|
{
|
|
printf ("watch: received wrong event: %08" PRIxrtems_event_set, out);
|
|
}
|
|
return sc;
|
|
}
|
|
|
|
/**
|
|
* BDBUf send wait event.
|
|
*/
|
|
static bool
|
|
bdbuf_send_watch_event (const char* task, const char* msg, rtems_id id)
|
|
{
|
|
printf ("%s: %s: %08" PRIxrtems_id ": ", task, msg, id);
|
|
return bdbuf_test_print_sc (rtems_event_send (id, RTEMS_EVENT_1), true);
|
|
}
|
|
|
|
/**
|
|
* Set up a disk driver watch.
|
|
*/
|
|
static void
|
|
bdbuf_set_disk_driver_watch (bdbuf_task_control* tc, int count)
|
|
{
|
|
/*
|
|
* Set up a disk watch and wait for the write to happen.
|
|
*/
|
|
bdbuf_disk_lock (tc->bdd);
|
|
tc->bdd->watcher_name = tc->name;
|
|
tc->bdd->watcher = tc->task;
|
|
tc->bdd->watch_count = count;
|
|
bdbuf_disk_unlock (tc->bdd);
|
|
}
|
|
|
|
/**
|
|
* Clear the disk driver watch.
|
|
*/
|
|
static void
|
|
bdbuf_clear_disk_driver_watch (bdbuf_task_control* tc)
|
|
{
|
|
/*
|
|
* Set up a disk watch and wait for the write to happen.
|
|
*/
|
|
bdbuf_disk_lock (tc->bdd);
|
|
tc->bdd->watcher_name = 0;
|
|
tc->bdd->watcher = 0;
|
|
tc->bdd->watch_count = 0;
|
|
bdbuf_disk_unlock (tc->bdd);
|
|
}
|
|
|
|
/**
|
|
* Wait for the disk driver watch.
|
|
*/
|
|
static bool
|
|
bdbuf_disk_driver_watch_wait (bdbuf_task_control* tc, unsigned long msecs)
|
|
{
|
|
bool passed = true;
|
|
rtems_status_code sc = bdbuf_watch (msecs);
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
printf ("%s: driver watch: driver wait: ", tc->name);
|
|
passed = bdbuf_test_print_sc (sc, true);
|
|
}
|
|
bdbuf_clear_disk_driver_watch (tc);
|
|
return passed;
|
|
}
|
|
|
|
/**
|
|
* Set the disk driver action.
|
|
*/
|
|
static void
|
|
bdbuf_set_disk_driver_action (bdbuf_task_control* tc, bdbuf_disk_action action)
|
|
{
|
|
/*
|
|
* Set up a disk action.
|
|
*/
|
|
bdbuf_disk_lock (tc->bdd);
|
|
tc->bdd->driver_action = action;
|
|
bdbuf_disk_unlock (tc->bdd);
|
|
}
|
|
|
|
/**
|
|
* BDBUF Sleep.
|
|
*/
|
|
static bool
|
|
bdbuf_sleep (unsigned long msecs)
|
|
{
|
|
rtems_status_code sc;
|
|
sc = rtems_task_wake_after (RTEMS_MICROSECONDS_TO_TICKS (msecs * 1000));
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
printf ("sleep wake after failed: ");
|
|
bdbuf_test_print_sc (sc, true);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Initialise a task control.
|
|
*/
|
|
static void
|
|
bdbuf_task_control_init (int task,
|
|
bdbuf_task_control* tc,
|
|
rtems_id master)
|
|
{
|
|
char name[6];
|
|
sprintf (name, "bdt%d", task);
|
|
|
|
tc->die = false;
|
|
tc->name = strdup (name); /* leaks */
|
|
tc->task = 0;
|
|
tc->master = master;
|
|
tc->test = 0;
|
|
tc->bdd = NULL;
|
|
tc->passed = false;
|
|
}
|
|
|
|
static bool
|
|
bdbuf_disk_ioctl_watcher (bdbuf_disk* bdd, int update)
|
|
{
|
|
/*
|
|
* Always wake the watcher.
|
|
*/
|
|
if (bdd->watcher)
|
|
{
|
|
if (bdd->watch_count)
|
|
{
|
|
if (update > bdd->watch_count)
|
|
bdd->watch_count -= update;
|
|
else
|
|
bdd->watch_count = 0;
|
|
}
|
|
|
|
if (bdd->watch_count == 0)
|
|
{
|
|
bdbuf_send_watch_event (bdd->watcher_name,
|
|
"disk ioctl: wake watcher",
|
|
bdd->watcher);
|
|
bdd->watcher = 0;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
static bool
|
|
bdbuf_disk_ioctl_process (bdbuf_disk* bdd, rtems_blkdev_request* req)
|
|
{
|
|
bool result = true;
|
|
int b;
|
|
|
|
/*
|
|
* Perform the requested action.
|
|
*/
|
|
switch (bdd->driver_action)
|
|
{
|
|
case BDBUF_DISK_NOOP:
|
|
break;
|
|
|
|
case BDBUF_DISK_WAIT:
|
|
if (bdd->waiting)
|
|
printf ("disk ioctl: bad waiter: %s:%08" PRIxrtems_id "\n",
|
|
bdd->waiting_name, bdd->waiting);
|
|
bdd->waiting_name = "bdd";
|
|
|
|
bdd->waiting = rtems_task_self ();
|
|
|
|
if (bdbuf_disk_unlock (bdd))
|
|
result = bdbuf_wait (bdd->name, 0) == RTEMS_SUCCESSFUL;
|
|
else
|
|
result = false;
|
|
|
|
/*
|
|
* Ignore any error if one happens.
|
|
*/
|
|
bdbuf_disk_lock (bdd);
|
|
break;
|
|
|
|
case BDBUF_DISK_SLEEP:
|
|
printf ("disk ioctl: sleeping: %" PRId32 " msecs\n",
|
|
bdd->driver_sleep);
|
|
result = bdbuf_sleep (bdd->driver_sleep);
|
|
break;
|
|
|
|
case BDBUF_DISK_BLOCKS_INORDER:
|
|
printf ("disk ioctl: multi-block order check: count = %" PRId32 "\n",
|
|
req->bufnum);
|
|
for (b = 0; b < (req->bufnum - 1); b++)
|
|
if (req->bufs[b].block >= req->bufs[b + 1].block)
|
|
printf ("disk ioctl: out of order: index:%d "\
|
|
"(%" PRIdrtems_blkdev_bnum " >= %" PRIdrtems_blkdev_bnum "\n",
|
|
b, req->bufs[b].block, req->bufs[b + 1].block);
|
|
break;
|
|
|
|
default:
|
|
printf ("disk ioctl: invalid action: %d\n",
|
|
bdd->driver_action);
|
|
result = false;
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static bool
|
|
bdbuf_disk_ioctl_leave (bdbuf_disk* bdd, int buffer_count)
|
|
{
|
|
/*
|
|
* Handle the watcher.
|
|
*/
|
|
bdbuf_disk_ioctl_watcher (bdd, buffer_count);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* BDBuf disk IOCTL handler.
|
|
*
|
|
* @param dd Disk device.
|
|
* @param req IOCTL request code.
|
|
* @param argp IOCTL argument.
|
|
* @retval The IOCTL return value
|
|
*/
|
|
static int
|
|
bdbuf_disk_ioctl (rtems_disk_device *dd, uint32_t req, void* argp)
|
|
{
|
|
rtems_blkdev_request *r = argp;
|
|
bdbuf_disk *bdd = rtems_disk_get_driver_data (dd);
|
|
|
|
errno = 0;
|
|
|
|
if (!bdbuf_disk_lock (bdd))
|
|
{
|
|
errno = EIO;
|
|
}
|
|
else
|
|
{
|
|
switch (req)
|
|
{
|
|
case RTEMS_BLKIO_REQUEST:
|
|
switch (r->req)
|
|
{
|
|
case RTEMS_BLKDEV_REQ_READ:
|
|
if (!bdbuf_disk_ioctl_process (bdd, r))
|
|
rtems_blkdev_request_done(r, RTEMS_IO_ERROR);
|
|
else
|
|
{
|
|
rtems_blkdev_sg_buffer* sg = r->bufs;
|
|
uint32_t block = RTEMS_BLKDEV_START_BLOCK (r);
|
|
uint32_t b;
|
|
int32_t remains;
|
|
|
|
remains = r->bufnum * bdd->block_size;
|
|
|
|
for (b = 0; b < r->bufnum; b++, block++, sg++)
|
|
{
|
|
uint32_t length = sg->length;
|
|
|
|
if (sg->length != bdd->block_size)
|
|
if (length > bdd->block_size)
|
|
length = bdd->block_size;
|
|
|
|
memset (sg->buffer, block, length);
|
|
|
|
remains -= length;
|
|
}
|
|
|
|
rtems_blkdev_request_done (r, RTEMS_SUCCESSFUL);
|
|
}
|
|
bdbuf_disk_ioctl_leave (bdd, r->bufnum);
|
|
break;
|
|
|
|
case RTEMS_BLKDEV_REQ_WRITE:
|
|
if (!bdbuf_disk_ioctl_process (bdd, r))
|
|
rtems_blkdev_request_done(r, RTEMS_IO_ERROR);
|
|
else
|
|
rtems_blkdev_request_done(r, RTEMS_SUCCESSFUL);
|
|
bdbuf_disk_ioctl_leave (bdd, r->bufnum);
|
|
break;
|
|
|
|
default:
|
|
errno = EINVAL;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
rtems_blkdev_ioctl (dd, req, argp);
|
|
break;
|
|
}
|
|
|
|
if (!bdbuf_disk_unlock (bdd))
|
|
errno = EIO;
|
|
}
|
|
|
|
return errno == 0 ? 0 : -1;
|
|
}
|
|
|
|
static rtems_status_code
|
|
bdbuf_disk_initialize(void)
|
|
{
|
|
uint32_t minor;
|
|
|
|
printf ("register disks\n");
|
|
|
|
for (minor = 0; minor < BDBUF_DISKS; minor++)
|
|
{
|
|
char name[sizeof (BDBUF_DISK_DEVICE_BASE_NAME) + 10];
|
|
bdbuf_disk* bdd = &bdbuf_disks[minor];
|
|
rtems_status_code sc;
|
|
int fd;
|
|
int rv;
|
|
|
|
snprintf (name, sizeof (name),
|
|
BDBUF_DISK_DEVICE_BASE_NAME "%" PRIu32, minor);
|
|
|
|
bdd->name = strdup (name);
|
|
bdd->minor = minor;
|
|
|
|
printf ("disk init: %s\n", bdd->name);
|
|
printf ("disk lock: ");
|
|
|
|
sc = rtems_semaphore_create (rtems_build_name ('B', 'D', 'D', 'K'), 1,
|
|
RTEMS_PRIORITY | RTEMS_BINARY_SEMAPHORE |
|
|
RTEMS_INHERIT_PRIORITY, 0, &bdd->lock);
|
|
if (!bdbuf_test_print_sc (sc, true))
|
|
return RTEMS_IO_ERROR;
|
|
|
|
bdd->block_size = 512 * (minor + 1);
|
|
bdd->block_count = BDBUF_SIZE * (minor + 1);
|
|
|
|
sc = rtems_blkdev_create(name, bdd->block_size, bdd->block_count,
|
|
bdbuf_disk_ioctl, bdd);
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
printf ("disk init: create phys failed: ");
|
|
bdbuf_test_print_sc (sc, true);
|
|
return sc;
|
|
}
|
|
|
|
fd = open(name, O_RDWR);
|
|
rtems_test_assert(fd >= 0);
|
|
|
|
rv = rtems_disk_fd_get_disk_device(fd, &bdd->dd);
|
|
rtems_test_assert(rv == 0);
|
|
|
|
rv = close(fd);
|
|
rtems_test_assert(rv == 0);
|
|
}
|
|
|
|
return RTEMS_SUCCESSFUL;
|
|
}
|
|
|
|
static bool
|
|
bdbuf_tests_create_task (bdbuf_task_control* tc,
|
|
rtems_task_priority priority,
|
|
rtems_task_entry entry_point)
|
|
{
|
|
rtems_status_code sc;
|
|
|
|
printf ("creating task: %s: priority: %" PRIdrtems_task_priority ": ",
|
|
tc->name, priority);
|
|
|
|
sc = rtems_task_create (rtems_build_name (tc->name[0], tc->name[1],
|
|
tc->name[2], tc->name[3]),
|
|
priority,
|
|
BDBUF_TEST_STACK_SIZE,
|
|
RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
|
|
RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR,
|
|
&tc->task);
|
|
if (!bdbuf_test_print_sc (sc, true))
|
|
return false;
|
|
|
|
printf ("starting task: %s: ", tc->name);
|
|
|
|
sc = rtems_task_start (tc->task, entry_point, (rtems_task_argument) tc);
|
|
|
|
return bdbuf_test_print_sc (sc, true);
|
|
}
|
|
|
|
/**
|
|
* Get the block 0 buffer twice. The first time it is requested it
|
|
* will be taken from the empty list and returned to the LRU list.
|
|
* The second time it will be removed from the LRU list.
|
|
*/
|
|
static void
|
|
bdbuf_tests_task_0_test_1 (bdbuf_task_control* tc)
|
|
{
|
|
rtems_status_code sc;
|
|
bool passed;
|
|
int i;
|
|
rtems_bdbuf_buffer* bd;
|
|
|
|
/*
|
|
* Set task control's passed to false to handle a timeout.
|
|
*/
|
|
tc->passed = false;
|
|
passed = true;
|
|
|
|
for (i = 0; (i < 2) && passed; i++)
|
|
{
|
|
printf ("%s: rtems_bdbuf_get[0]: ", tc->name);
|
|
sc = rtems_bdbuf_get (tc->bdd->dd, 0, &bd);
|
|
if (!bdbuf_test_print_sc (sc, true))
|
|
{
|
|
passed = false;
|
|
break;
|
|
}
|
|
|
|
printf ("%s: rtems_bdbuf_release[0]: ", tc->name);
|
|
sc = rtems_bdbuf_release (bd);
|
|
if (!bdbuf_test_print_sc (sc, true))
|
|
{
|
|
passed = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
tc->passed = passed;
|
|
tc->test = 0;
|
|
}
|
|
|
|
/**
|
|
* Get the blocks 0 -> 4 and hold them. Wake the master to tell it was have the
|
|
* buffers then wait for the master to tell us to release a single buffer.
|
|
* Task 1 will be block waiting for each buffer. It is a higher priority.
|
|
*/
|
|
static void
|
|
bdbuf_tests_task_0_test_2 (bdbuf_task_control* tc)
|
|
{
|
|
rtems_status_code sc;
|
|
bool passed;
|
|
int i;
|
|
rtems_bdbuf_buffer* bd;
|
|
rtems_chain_control buffers;
|
|
|
|
/*
|
|
* Set task control's passed to false to handle a timeout.
|
|
*/
|
|
tc->passed = false;
|
|
passed = true;
|
|
|
|
/*
|
|
* Get the blocks 0 -> 4 and hold them.
|
|
*/
|
|
rtems_chain_initialize_empty (&buffers);
|
|
|
|
for (i = 0; (i < 5) && passed; i++)
|
|
{
|
|
printf ("%s: rtems_bdbuf_get[%d]: ", tc->name, i);
|
|
sc = rtems_bdbuf_get (tc->bdd->dd, i, &bd);
|
|
if (!bdbuf_test_print_sc (sc, true))
|
|
passed = false;
|
|
|
|
rtems_chain_append (&buffers, &bd->link);
|
|
}
|
|
|
|
/*
|
|
* Wake the master to tell it we have the buffers.
|
|
*/
|
|
bdbuf_send_wait_event (tc->name, "wake master", tc->master);
|
|
|
|
if (passed)
|
|
{
|
|
/*
|
|
* For each buffer we hold wait until the master wakes us
|
|
* and then return it. Task 2 will block waiting for this
|
|
* buffer. It is a higher priority task.
|
|
*/
|
|
for (i = 0; (i < 5) && passed; i++)
|
|
{
|
|
sc = bdbuf_wait (tc->name, BDBUF_SECONDS (5));
|
|
if (sc != RTEMS_SUCCESSFUL)
|
|
{
|
|
printf ("%s: wait failed: ", tc->name);
|
|
bdbuf_test_print_sc (sc, true);
|
|
passed = false;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
printf ("%s: rtems_bdbuf_release[%d]: unblocks task 1\n",
|
|
tc->name, i);
|
|
bd = (rtems_bdbuf_buffer*) rtems_chain_get (&buffers);
|
|
sc = rtems_bdbuf_release (bd);
|
|
printf ("%s: rtems_bdbuf_release[%d]: ", tc->name, i);
|
|
if (!bdbuf_test_print_sc (sc, true))
|
|
{
|
|
passed = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
tc->passed = passed;
|
|
tc->test = 0;
|
|
}
|
|
|
|
/**
|
|
* Read the block 5 from the disk modify it then release it modified.
|
|
*/
|
|
static void
|
|
bdbuf_tests_task_0_test_3 (bdbuf_task_control* tc)
|
|
{
|
|
rtems_status_code sc;
|
|
bool passed;
|
|
rtems_bdbuf_buffer* bd;
|
|
|
|
/*
|
|
* Set task control's passed to false to handle a timeout.
|
|
*/
|
|
tc->passed = false;
|
|
passed = true;
|
|
|
|
bdbuf_disk_lock (tc->bdd);
|
|
tc->bdd->driver_action = BDBUF_DISK_NOOP;
|
|
bdbuf_disk_unlock (tc->bdd);
|
|
|
|
/*
|
|
* Read the buffer and then release it.
|
|
*/
|
|
printf ("%s: rtems_bdbuf_read[5]: ", tc->name);
|
|
sc = rtems_bdbuf_read (tc->bdd->dd, 5, &bd);
|
|
if ((passed = bdbuf_test_print_sc (sc, true)))
|
|
{
|
|
printf ("%s: rtems_bdbuf_release_modified[5]: ", tc->name);
|
|
sc = rtems_bdbuf_release_modified (bd);
|
|
passed = bdbuf_test_print_sc (sc, true);
|
|
}
|
|
|
|
/*
|
|
* Read the buffer again and then just release. The buffer should
|
|
* be maintained as modified.
|
|
*/
|
|
printf ("%s: rtems_bdbuf_read[5]: ", tc->name);
|
|
sc = rtems_bdbuf_read (tc->bdd->dd, 5, &bd);
|
|
if ((passed = bdbuf_test_print_sc (sc, true)))
|
|
{
|
|
printf ("%s: rtems_bdbuf_release[5]: ", tc->name);
|
|
sc = rtems_bdbuf_release (bd);
|
|
passed = bdbuf_test_print_sc (sc, true);
|
|
}
|
|
|
|
/*
|
|
* Set up a disk watch and wait for the write to happen.
|
|
*/
|
|
bdbuf_set_disk_driver_watch (tc, 1);
|
|
passed = bdbuf_disk_driver_watch_wait (tc, BDBUF_SECONDS (5));
|
|
|
|
tc->passed = passed;
|
|
tc->test = 0;
|
|
}
|
|
|
|
static size_t
|
|
bdbuf_test_buffer_count (void)
|
|
{
|
|
return rtems_bdbuf_configuration.size / rtems_bdbuf_configuration.buffer_min;
|
|
}
|
|
|
|
/**
|
|
* Get all the blocks in the pool and hold them. Wake the master to tell it was
|
|
* have the buffers then wait for the master to tell us to release them.
|
|
*/
|
|
static void
|
|
bdbuf_tests_task_0_test_4 (bdbuf_task_control* tc)
|
|
{
|
|
rtems_status_code sc;
|
|
bool passed;
|
|
size_t i;
|
|
rtems_bdbuf_buffer* bd;
|
|
rtems_chain_control buffers;
|
|
size_t num = bdbuf_test_buffer_count ();
|
|
|
|
/*
|
|
* Set task control's passed to false to handle a timeout.
|
|
*/
|
|
tc->passed = false;
|
|
passed = true;
|
|
|
|
/*
|
|
* Clear any disk settings.
|
|
*/
|
|
bdbuf_clear_disk_driver_watch (tc);
|
|
bdbuf_set_disk_driver_action (tc, BDBUF_DISK_NOOP);
|
|
|
|
/*
|
|
* Get the blocks 0 -> 4 and hold them.
|
|
*/
|
|
rtems_chain_initialize_empty (&buffers);
|
|
|
|
for (i = 0; (i < num) && passed; i++)
|
|
{
|
|
printf ("%s: rtems_bdbuf_read[%zd]: ", tc->name, i);
|
|
sc = rtems_bdbuf_read (tc->bdd->dd, i, &bd);
|
|
if (!bdbuf_test_print_sc (sc, true))
|
|
passed = false;
|
|
|
|
rtems_chain_append (&buffers, &bd->link);
|
|
}
|
|
|
|
/*
|
|
* Wake the master to tell it we have the buffers.
|
|
*/
|
|
bdbuf_send_wait_event (tc->name, "wake master", tc->master);
|
|
|
|
if (passed)
|
|
{
|
|
bdbuf_sleep (250);
|
|
|
|
bdbuf_set_disk_driver_watch (tc, num / 2);
|
|
|
|
/*
|
|
* Release half the buffers, wait 500msecs then release the
|
|
* remainder. This tests the swap out timer on each buffer.
|
|
*/
|
|
printf ("%s: rtems_bdbuf_release_modified[0]: unblocks task 1\n",
|
|
tc->name);
|
|
bd = (rtems_bdbuf_buffer*) rtems_chain_get (&buffers);
|
|
sc = rtems_bdbuf_release_modified (bd);
|
|
printf ("%s: rtems_bdbuf_release_modified[0]: ", tc->name);
|
|
passed = bdbuf_test_print_sc (sc, true);
|
|
if (passed)
|
|
{
|
|
for (i = 1; (i < (num / 2)) && passed; i++)
|
|
{
|
|
printf ("%s: rtems_bdbuf_release_modified[%zd]: " \
|
|
"unblocks task 1\n", tc->name, i);
|
|
bd = (rtems_bdbuf_buffer*) rtems_chain_get (&buffers);
|
|
sc = rtems_bdbuf_release_modified (bd);
|
|
printf ("%s: rtems_bdbuf_release_modified[%zd]: ", tc->name, i);
|
|
passed = bdbuf_test_print_sc (sc, true);
|
|
if (!passed)
|
|
break;
|
|
}
|
|
|
|
if (passed)
|
|
{
|
|
passed = bdbuf_disk_driver_watch_wait (tc, BDBUF_SECONDS (5));
|
|
|
|
if (passed)
|
|
{
|
|
bdbuf_sleep (500);
|
|
|
|
bdbuf_set_disk_driver_watch (tc, num / 2);
|
|
|
|
for (i = 0; (i < (num / 2)) && passed; i++)
|
|
{
|
|
printf ("%s: rtems_bdbuf_release_modified[%zd]: ",
|
|
tc->name, i + (num / 2));
|
|
bd = (rtems_bdbuf_buffer*) rtems_chain_get (&buffers);
|
|
passed = bdbuf_test_print_sc (rtems_bdbuf_release_modified (bd),
|
|
true);
|
|
if (!passed)
|
|
break;
|
|
}
|
|
|
|
passed = bdbuf_disk_driver_watch_wait (tc, BDBUF_SECONDS (5));
|
|
|
|
if (passed)
|
|
{
|
|
if (!rtems_chain_is_empty (&buffers))
|
|
{
|
|
passed = false;
|
|
printf ("%s: buffer chain not empty\n", tc->name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
tc->passed = passed;
|
|
tc->test = 0;
|
|
}
|
|
|
|
static void
|
|
bdbuf_tests_task_0_test_5 (bdbuf_task_control* tc)
|
|
{
|
|
bdbuf_tests_task_0_test_4 (tc);
|
|
}
|
|
|
|
static void
|
|
bdbuf_tests_task_0_test_6 (bdbuf_task_control* tc)
|
|
{
|
|
rtems_status_code sc;
|
|
bool passed;
|
|
int i;
|
|
rtems_bdbuf_buffer* bd;
|
|
rtems_chain_control buffers;
|
|
|
|
/*
|
|
* Set task control's passed to false to handle a timeout.
|
|
*/
|
|
tc->passed = false;
|
|
passed = true;
|
|
|
|
/*
|
|
* Clear any disk settings.
|
|
*/
|
|
bdbuf_clear_disk_driver_watch (tc);
|
|
bdbuf_set_disk_driver_action (tc, BDBUF_DISK_NOOP);
|
|
|
|
/*
|
|
* Get the blocks 0 -> 4 and hold them.
|
|
*/
|
|
rtems_chain_initialize_empty (&buffers);
|
|
|
|
for (i = 0; (i < 5) && passed; i++)
|
|
{
|
|
printf ("%s: rtems_bdbuf_read[%d]: ", tc->name, i);
|
|
sc = rtems_bdbuf_get (tc->bdd->dd, i, &bd);
|
|
if (!bdbuf_test_print_sc (sc, true))
|
|
passed = false;
|
|
|
|
rtems_chain_append (&buffers, &bd->link);
|
|
}
|
|
|
|
for (i = 0; (i < 4) && passed; i++)
|
|
{
|
|
printf ("%s: rtems_bdbuf_release_modified[%d]: ",
|
|
tc->name, i);
|
|
bd = (rtems_bdbuf_buffer*) rtems_chain_get (&buffers);
|
|
passed = bdbuf_test_print_sc (rtems_bdbuf_release_modified (bd),
|
|
true);
|
|
}
|
|
|
|
if (passed)
|
|
{
|
|
printf ("%s: rtems_bdbuf_sync[%d]: ", tc->name, i);
|
|
bd = (rtems_bdbuf_buffer*) rtems_chain_get (&buffers);
|
|
|
|
passed = bdbuf_test_print_sc (rtems_bdbuf_sync (bd), true);
|
|
}
|
|
|
|
tc->passed = passed;
|
|
tc->test = 0;
|
|
}
|
|
|
|
static void
|
|
bdbuf_tests_task_0_test_7 (bdbuf_task_control* tc)
|
|
{
|
|
rtems_status_code sc;
|
|
bool passed;
|
|
int i;
|
|
rtems_bdbuf_buffer* bd;
|
|
rtems_chain_control buffers;
|
|
|
|
/*
|
|
* Set task control's passed to false to handle a timeout.
|
|
*/
|
|
tc->passed = false;
|
|
passed = true;
|
|
|
|
/*
|
|
* Clear any disk settings.
|
|
*/
|
|
bdbuf_clear_disk_driver_watch (tc);
|
|
bdbuf_set_disk_driver_action (tc, BDBUF_DISK_NOOP);
|
|
|
|
/*
|
|
* Get the blocks 0 -> 4 and hold them.
|
|
*/
|
|
rtems_chain_initialize_empty (&buffers);
|
|
|
|
for (i = 0; (i < 5) && passed; i++)
|
|
{
|
|
printf ("%s: rtems_bdbuf_read[%d]: ", tc->name, i);
|
|
sc = rtems_bdbuf_get (tc->bdd->dd, i, &bd);
|
|
if (!bdbuf_test_print_sc (sc, true))
|
|
passed = false;
|
|
|
|
rtems_chain_append (&buffers, &bd->link);
|
|
}
|
|
|
|
for (i = 0; (i < 5) && passed; i++)
|
|
{
|
|
printf ("%s: rtems_bdbuf_release_modified[%d]: ",
|
|
tc->name, i);
|
|
bd = (rtems_bdbuf_buffer*) rtems_chain_get (&buffers);
|
|
passed = bdbuf_test_print_sc (rtems_bdbuf_release_modified (bd),
|
|
true);
|
|
}
|
|
|
|
if (passed)
|
|
{
|
|
printf ("%s: rtems_bdbuf_syncdev[%" PRIu32 ": ",
|
|
tc->name,
|
|
tc->bdd->minor);
|
|
passed = bdbuf_test_print_sc (rtems_bdbuf_syncdev (tc->bdd->dd), true);
|
|
}
|
|
|
|
tc->passed = passed;
|
|
tc->test = 0;
|
|
}
|
|
|
|
static void
|
|
bdbuf_tests_task_0_test_8 (bdbuf_task_control* tc)
|
|
{
|
|
rtems_status_code sc;
|
|
bool passed;
|
|
int i;
|
|
rtems_bdbuf_buffer* bd;
|
|
rtems_chain_control buffers;
|
|
rtems_chain_node* node;
|
|
rtems_chain_node* pnode;
|
|
|
|
/*
|
|
* Set task control's passed to false to handle a timeout.
|
|
*/
|
|
tc->passed = false;
|
|
passed = true;
|
|
|
|
/*
|
|
* Clear any disk settings.
|
|
*/
|
|
bdbuf_clear_disk_driver_watch (tc);
|
|
bdbuf_set_disk_driver_action (tc, BDBUF_DISK_NOOP);
|
|
|
|
/*
|
|
* Get the blocks 0 -> 4 and hold them.
|
|
*/
|
|
rtems_chain_initialize_empty (&buffers);
|
|
|
|
for (i = 0; (i < 5) && passed; i++)
|
|
{
|
|
printf ("%s: rtems_bdbuf_read[%d]: ", tc->name, i);
|
|
sc = rtems_bdbuf_get (tc->bdd->dd, i, &bd);
|
|
if (!bdbuf_test_print_sc (sc, true))
|
|
passed = false;
|
|
|
|
rtems_chain_append (&buffers, &bd->link);
|
|
}
|
|
|
|
node = rtems_chain_tail (&buffers);
|
|
node = node->previous;
|
|
|
|
bd = (rtems_bdbuf_buffer*) node;
|
|
pnode = node->previous;
|
|
rtems_chain_extract (node);
|
|
node = pnode;
|
|
printf ("%s: rtems_bdbuf_release_modified[4]: ", tc->name);
|
|
passed = bdbuf_test_print_sc (rtems_bdbuf_release_modified (bd), true);
|
|
|
|
bd = (rtems_bdbuf_buffer*) node;
|
|
pnode = node->previous;
|
|
rtems_chain_extract (node);
|
|
node = pnode;
|
|
printf ("%s: rtems_bdbuf_release_modified[3]: ", tc->name);
|
|
passed = bdbuf_test_print_sc (rtems_bdbuf_release_modified (bd), true);
|
|
|
|
for (i = 0; (i < 3) && passed; i++)
|
|
{
|
|
printf ("%s: rtems_bdbuf_release_modified[%d]: ",
|
|
tc->name, i);
|
|
bd = (rtems_bdbuf_buffer*) rtems_chain_get (&buffers);
|
|
passed = bdbuf_test_print_sc (rtems_bdbuf_release_modified (bd),
|
|
true);
|
|
}
|
|
|
|
if (passed)
|
|
{
|
|
/*
|
|
* Check the block order.
|
|
*/
|
|
bdbuf_set_disk_driver_action (tc, BDBUF_DISK_BLOCKS_INORDER);
|
|
|
|
printf ("%s: rtems_bdbuf_syncdev[%" PRIu32 "]: checking order\n",
|
|
tc->name,
|
|
tc->bdd->minor);
|
|
sc = rtems_bdbuf_syncdev (tc->bdd->dd);
|
|
printf ("%s: rtems_bdbuf_syncdev[%" PRIu32 "]: ",
|
|
tc->name,
|
|
tc->bdd->minor);
|
|
passed = bdbuf_test_print_sc (sc, true);
|
|
}
|
|
|
|
tc->passed = passed;
|
|
tc->test = 0;
|
|
}
|
|
|
|
static void
|
|
bdbuf_tests_task_0 (rtems_task_argument arg)
|
|
{
|
|
bdbuf_task_control* tc = (bdbuf_task_control*) arg;
|
|
|
|
while (!tc->die)
|
|
{
|
|
switch (tc->test)
|
|
{
|
|
case 0:
|
|
/*
|
|
* Wait for the next test.
|
|
*/
|
|
bdbuf_wait (tc->name, 0);
|
|
break;
|
|
|
|
case 1:
|
|
bdbuf_tests_task_0_test_1 (tc);
|
|
break;
|
|
|
|
case 2:
|
|
bdbuf_tests_task_0_test_2 (tc);
|
|
break;
|
|
|
|
case 3:
|
|
bdbuf_tests_task_0_test_3 (tc);
|
|
break;
|
|
|
|
case 4:
|
|
bdbuf_tests_task_0_test_4 (tc);
|
|
break;
|
|
|
|
case 5:
|
|
bdbuf_tests_task_0_test_5 (tc);
|
|
break;
|
|
|
|
case 6:
|
|
bdbuf_tests_task_0_test_6 (tc);
|
|
break;
|
|
|
|
case 7:
|
|
bdbuf_tests_task_0_test_7 (tc);
|
|
break;
|
|
|
|
case 8:
|
|
bdbuf_tests_task_0_test_8 (tc);
|
|
break;
|
|
|
|
default:
|
|
/*
|
|
* Invalid test for this task. An error.
|
|
*/
|
|
printf ("%s: invalid test: %d\n", tc->name, tc->test);
|
|
tc->passed = false;
|
|
tc->test = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
printf ("%s: delete task\n", tc->name);
|
|
rtems_task_delete (RTEMS_SELF);
|
|
}
|
|
|
|
/**
|
|
* Get the blocks 0 -> 4 and release them. Task 0 should be holding
|
|
* each one.
|
|
*/
|
|
static void
|
|
bdbuf_tests_ranged_get_release (bdbuf_task_control* tc,
|
|
bool wake_master,
|
|
int lower,
|
|
int upper)
|
|
{
|
|
rtems_status_code sc;
|
|
bool passed;
|
|
int i;
|
|
rtems_bdbuf_buffer* bd;
|
|
|
|
/*
|
|
* Set task control's passed to false to handle a timeout.
|
|
*/
|
|
tc->passed = false;
|
|
passed = true;
|
|
|
|
for (i = lower; (i < upper) && passed; i++)
|
|
{
|
|
printf ("%s: rtems_bdbuf_get[%d]: blocking ...\n", tc->name, i);
|
|
sc = rtems_bdbuf_get (tc->bdd->dd, i, &bd);
|
|
printf ("%s: rtems_bdbuf_get[%d]: ", tc->name, i);
|
|
if (!bdbuf_test_print_sc (sc, true))
|
|
{
|
|
passed = false;
|
|
break;
|
|
}
|
|
|
|
printf ("%s: rtems_bdbuf_release[%d]: ", tc->name, i);
|
|
sc = rtems_bdbuf_release (bd);
|
|
if (!bdbuf_test_print_sc (sc, true))
|
|
{
|
|
passed = false;
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Wake the master to tell it we have finished.
|
|
*/
|
|
if (wake_master)
|
|
bdbuf_send_wait_event (tc->name, "wake master", tc->master);
|
|
}
|
|
|
|
tc->passed = passed;
|
|
tc->test = 0;
|
|
}
|
|
|
|
static void
|
|
bdbuf_tests_task_1 (rtems_task_argument arg)
|
|
{
|
|
bdbuf_task_control* tc = (bdbuf_task_control*) arg;
|
|
|
|
while (!tc->die)
|
|
{
|
|
switch (tc->test)
|
|
{
|
|
case 0:
|
|
/*
|
|
* Wait for the next test.
|
|
*/
|
|
bdbuf_wait (tc->name, 0);
|
|
break;
|
|
|
|
case 2:
|
|
bdbuf_tests_ranged_get_release (tc, false, 0, 5);
|
|
break;
|
|
|
|
case 4:
|
|
bdbuf_tests_ranged_get_release (tc, false, 0, 9);
|
|
break;
|
|
|
|
case 5:
|
|
bdbuf_tests_ranged_get_release (tc, false, 20, 25);
|
|
break;
|
|
|
|
default:
|
|
/*
|
|
* Invalid test for this task. An error.
|
|
*/
|
|
printf ("%s: invalid test: %d\n", tc->name, tc->test);
|
|
tc->passed = false;
|
|
tc->test = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
printf ("%s: delete task\n", tc->name);
|
|
rtems_task_delete (RTEMS_SELF);
|
|
}
|
|
|
|
/**
|
|
* Get the blocks 0 -> 4 and release them. Task 0 should be holding
|
|
* each one.
|
|
*/
|
|
static void
|
|
bdbuf_tests_task_2_test_2 (bdbuf_task_control* tc)
|
|
{
|
|
/*
|
|
* Use task 1's test 2. They are the same.
|
|
*/
|
|
bdbuf_tests_ranged_get_release (tc, true, 0, 5);
|
|
}
|
|
|
|
static void
|
|
bdbuf_tests_task_2 (rtems_task_argument arg)
|
|
{
|
|
bdbuf_task_control* tc = (bdbuf_task_control*) arg;
|
|
|
|
while (!tc->die)
|
|
{
|
|
switch (tc->test)
|
|
{
|
|
case 0:
|
|
/*
|
|
* Wait for the next test.
|
|
*/
|
|
bdbuf_wait (tc->name, 0);
|
|
break;
|
|
|
|
case 2:
|
|
bdbuf_tests_task_2_test_2 (tc);
|
|
break;
|
|
|
|
default:
|
|
/*
|
|
* Invalid test for this task. An error.
|
|
*/
|
|
printf ("%s: invalid test: %d\n", tc->name, tc->test);
|
|
tc->passed = false;
|
|
tc->test = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
printf ("%s: delete task\n", tc->name);
|
|
rtems_task_delete (RTEMS_SELF);
|
|
}
|
|
|
|
/**
|
|
* Table of task entry points.
|
|
*/
|
|
static rtems_task_entry bdbuf_test_tasks[] =
|
|
{
|
|
bdbuf_tests_task_0,
|
|
bdbuf_tests_task_1,
|
|
bdbuf_tests_task_2
|
|
};
|
|
|
|
#define BDBUF_TESTS_PRI_HIGH (30)
|
|
|
|
/**
|
|
* Wait for the all tests to finish. This is signalled by the test
|
|
* number becoming 0.
|
|
*/
|
|
static bool
|
|
bdbuf_tests_finished (bdbuf_task_control* tasks)
|
|
{
|
|
uint32_t time = 0;
|
|
bool finished = false;
|
|
|
|
while (time < (10 * 4))
|
|
{
|
|
int t;
|
|
|
|
finished = true;
|
|
|
|
for (t = 0; t < BDBUF_TEST_TASKS; t++)
|
|
if (tasks[t].test)
|
|
{
|
|
finished = false;
|
|
break;
|
|
}
|
|
|
|
if (finished)
|
|
break;
|
|
|
|
bdbuf_sleep (250);
|
|
time++;
|
|
}
|
|
|
|
if (!finished)
|
|
printf ("master: test timed out\n");
|
|
else
|
|
{
|
|
int t;
|
|
for (t = 0; t < BDBUF_TEST_TASKS; t++)
|
|
if (!tasks[0].passed)
|
|
{
|
|
finished = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return finished;
|
|
}
|
|
|
|
/**
|
|
* Test 1.
|
|
*
|
|
* # Get task 0 to get buffer 0 from the pool then release it twice.
|
|
*/
|
|
static bool
|
|
bdbuf_test_1 (bdbuf_task_control* tasks)
|
|
{
|
|
tasks[0].test = 1;
|
|
|
|
/*
|
|
* Use pool 0.
|
|
*/
|
|
tasks[0].bdd = &bdbuf_disks[0];
|
|
|
|
bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
|
|
|
|
return bdbuf_tests_finished (tasks);
|
|
}
|
|
|
|
/**
|
|
* Test 2.
|
|
*
|
|
* # Get task 0 to get buffers 0 -> 4 from the pool hold them. Then get
|
|
* task 1 and task 2 to get them with blocking. The 2 tasks tests the
|
|
* priority blocking on the buffer.
|
|
*/
|
|
static bool
|
|
bdbuf_test_2 (bdbuf_task_control* tasks)
|
|
{
|
|
int i;
|
|
|
|
tasks[0].test = 2;
|
|
tasks[1].test = 2;
|
|
tasks[2].test = 2;
|
|
|
|
/*
|
|
* Use pool 0.
|
|
*/
|
|
tasks[0].bdd = &bdbuf_disks[0];
|
|
tasks[1].bdd = &bdbuf_disks[0];
|
|
tasks[2].bdd = &bdbuf_disks[0];
|
|
|
|
/*
|
|
* Wake task 0 and wait for it to have all the buffers.
|
|
*/
|
|
bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
|
|
if (bdbuf_wait ("master", BDBUF_SECONDS (5)) != RTEMS_SUCCESSFUL)
|
|
return false;
|
|
|
|
/*
|
|
* Wake task 1.
|
|
*/
|
|
bdbuf_send_wait_event ("master", "wake task 1", tasks[1].task);
|
|
|
|
/*
|
|
* Wake task 2.
|
|
*/
|
|
bdbuf_send_wait_event ("master", "wake task 2", tasks[2].task);
|
|
|
|
for (i = 0; i < 5; i++)
|
|
{
|
|
/*
|
|
* Wake task 0 and watch task 2 then task 1 get the released buffer.
|
|
*/
|
|
bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
|
|
|
|
/*
|
|
* Wait until task 2 has the buffer.
|
|
*/
|
|
if (bdbuf_wait ("master", BDBUF_SECONDS (5)) != RTEMS_SUCCESSFUL)
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
* Wait for the tests to finish.
|
|
*/
|
|
return bdbuf_tests_finished (tasks);
|
|
}
|
|
|
|
/**
|
|
* Test 3.
|
|
*
|
|
* # Read a block from disk into the buffer, modify the block and release
|
|
* it modified. Use a block great then 4 because 0 -> 4 are in the cache.
|
|
*/
|
|
static bool
|
|
bdbuf_test_3 (bdbuf_task_control* tasks)
|
|
{
|
|
tasks[0].test = 3;
|
|
|
|
/*
|
|
* Use pool 0.
|
|
*/
|
|
tasks[0].bdd = &bdbuf_disks[0];
|
|
|
|
/*
|
|
* Wake task 0.
|
|
*/
|
|
bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
|
|
|
|
return bdbuf_tests_finished (tasks);
|
|
}
|
|
|
|
/**
|
|
* Test 4.
|
|
*
|
|
* # Read every buffer in the pool and hold. Then get task 1 to ask for another
|
|
* buffer that is being accessed. It will block waiting for it to appear.
|
|
*/
|
|
static bool
|
|
bdbuf_test_4 (bdbuf_task_control* tasks)
|
|
{
|
|
tasks[0].test = 4;
|
|
tasks[1].test = 4;
|
|
|
|
/*
|
|
* Use pool 0.
|
|
*/
|
|
tasks[0].bdd = &bdbuf_disks[0];
|
|
tasks[1].bdd = &bdbuf_disks[0];
|
|
|
|
/*
|
|
* Wake task 0.
|
|
*/
|
|
bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
|
|
|
|
/*
|
|
* Wait for the buffers in the pool to be taken.
|
|
*/
|
|
if (bdbuf_wait ("master", BDBUF_SECONDS (5)) != RTEMS_SUCCESSFUL)
|
|
return false;
|
|
|
|
bdbuf_sleep (100);
|
|
|
|
/*
|
|
* Wake task 1 to read another one and have to block.
|
|
*/
|
|
bdbuf_send_wait_event ("master", "wake task 1", tasks[1].task);
|
|
|
|
bdbuf_sleep (100);
|
|
|
|
/*
|
|
* Wake task 0 to release it buffers.
|
|
*/
|
|
bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
|
|
|
|
return bdbuf_tests_finished (tasks);
|
|
}
|
|
|
|
/**
|
|
* Test 5.
|
|
*
|
|
* # Read every buffer in the pool and hold. Then get task 1 to ask for a new
|
|
* buffer. It will block waiting for one to appear.
|
|
*/
|
|
static bool
|
|
bdbuf_test_5 (bdbuf_task_control* tasks)
|
|
{
|
|
tasks[0].test = 5;
|
|
tasks[1].test = 5;
|
|
|
|
/*
|
|
* Use pool 0.
|
|
*/
|
|
tasks[0].bdd = &bdbuf_disks[0];
|
|
tasks[1].bdd = &bdbuf_disks[0];
|
|
|
|
/*
|
|
* Wake task 0.
|
|
*/
|
|
bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
|
|
|
|
/*
|
|
* Wait for the buffers in the pool to be taken.
|
|
*/
|
|
if (bdbuf_wait ("master", BDBUF_SECONDS (5)) != RTEMS_SUCCESSFUL)
|
|
return false;
|
|
|
|
bdbuf_sleep (100);
|
|
|
|
/*
|
|
* Wake task 1 to read another one and have to block.
|
|
*/
|
|
bdbuf_send_wait_event ("master", "wake task 1", tasks[1].task);
|
|
|
|
bdbuf_sleep (100);
|
|
|
|
/*
|
|
* Wake task 0 to release it buffers.
|
|
*/
|
|
bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
|
|
|
|
return bdbuf_tests_finished (tasks);
|
|
}
|
|
|
|
/**
|
|
* Test 6.
|
|
*
|
|
* # Get 5 buffers, release modify 4 then sync the last.
|
|
*/
|
|
static bool
|
|
bdbuf_test_6 (bdbuf_task_control* tasks)
|
|
{
|
|
tasks[0].test = 6;
|
|
|
|
/*
|
|
* Use pool 0.
|
|
*/
|
|
tasks[0].bdd = &bdbuf_disks[0];
|
|
|
|
/*
|
|
* Wake task 0.
|
|
*/
|
|
bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
|
|
|
|
return bdbuf_tests_finished (tasks);
|
|
}
|
|
|
|
/**
|
|
* Test 7.
|
|
*
|
|
* # Get 5 buffers, release modify them all then sync the device.
|
|
*/
|
|
static bool
|
|
bdbuf_test_7 (bdbuf_task_control* tasks)
|
|
{
|
|
tasks[0].test = 7;
|
|
|
|
/*
|
|
* Use pool 0.
|
|
*/
|
|
tasks[0].bdd = &bdbuf_disks[0];
|
|
|
|
/*
|
|
* Wake task 0.
|
|
*/
|
|
bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
|
|
|
|
return bdbuf_tests_finished (tasks);
|
|
}
|
|
|
|
/**
|
|
* Test 8.
|
|
*
|
|
* # Get 5 buffers, release modify the last 2 then the reset from 0.
|
|
*/
|
|
static bool
|
|
bdbuf_test_8 (bdbuf_task_control* tasks)
|
|
{
|
|
tasks[0].test = 8;
|
|
|
|
/*
|
|
* Use pool 0.
|
|
*/
|
|
tasks[0].bdd = &bdbuf_disks[0];
|
|
|
|
/*
|
|
* Wake task 0.
|
|
*/
|
|
bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
|
|
|
|
return bdbuf_tests_finished (tasks);
|
|
}
|
|
|
|
/**
|
|
* A test.
|
|
*/
|
|
typedef bool (*bdbuf_test) (bdbuf_task_control* tasks);
|
|
|
|
/**
|
|
* A test name and function.
|
|
*/
|
|
typedef struct bdbuf_test_ident
|
|
{
|
|
const char* label;
|
|
bdbuf_test test;
|
|
} bdbuf_test_ident;
|
|
|
|
/**
|
|
* Table of tests.
|
|
*/
|
|
static bdbuf_test_ident bdbuf_tests[] =
|
|
{
|
|
{
|
|
"Task 0 get buffer 0 from pool 0",
|
|
bdbuf_test_1
|
|
},
|
|
{
|
|
"Task 0 get buffer 0 -> 4 from pool 0, task 2 and 1 block getting",
|
|
bdbuf_test_2
|
|
},
|
|
{
|
|
"Task 0 read buffer 5, modify and release modified",
|
|
bdbuf_test_3
|
|
},
|
|
{
|
|
"Task 0 read all buffers, task 1 blocks waiting for acessed buffer",
|
|
bdbuf_test_4
|
|
},
|
|
{
|
|
"Task 0 read all buffers, task 1 blocks waiting for new buffer",
|
|
bdbuf_test_5
|
|
},
|
|
{
|
|
"Task 0 release modified 4 buffers then syncs a 5th buffer",
|
|
bdbuf_test_6
|
|
},
|
|
{
|
|
"Task 0 release modified 5 buffers then sync the device",
|
|
bdbuf_test_7
|
|
},
|
|
{
|
|
"Task 0 releases modified 5 buffers is out or order sequence and the" \
|
|
" driver checks the buffers are in order",
|
|
bdbuf_test_8
|
|
}
|
|
};
|
|
|
|
#define BDBUF_TEST_NUM (sizeof (bdbuf_tests) / sizeof (bdbuf_test_ident))
|
|
|
|
/**
|
|
* Test the BD Buffering code.
|
|
*/
|
|
static void
|
|
bdbuf_tester (void)
|
|
{
|
|
bdbuf_task_control tasks[BDBUF_TEST_TASKS];
|
|
rtems_task_priority old_priority;
|
|
int t;
|
|
bool passed = true;
|
|
rtems_status_code sc;
|
|
|
|
sc = bdbuf_disk_initialize();
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
|
|
/*
|
|
* Change priority to a lower one.
|
|
*/
|
|
printf ("lower priority to %d: ", BDBUF_TESTS_PRI_HIGH + 1);
|
|
bdbuf_test_print_sc (rtems_task_set_priority (RTEMS_SELF,
|
|
BDBUF_TESTS_PRI_HIGH + 1,
|
|
&old_priority),
|
|
true);
|
|
|
|
/*
|
|
* Make sure the swapout task has run. The user could block
|
|
* the swapout task from running until later. This is not
|
|
* tested.
|
|
*/
|
|
bdbuf_sleep (100);
|
|
|
|
/*
|
|
* Start the test tasks used to test the threading parts
|
|
* of the bdbuf code.
|
|
*/
|
|
for (t = 0; t < BDBUF_TEST_TASKS; t++)
|
|
{
|
|
bdbuf_task_control_init (t, &tasks[t],
|
|
rtems_task_self ());
|
|
|
|
if (!bdbuf_tests_create_task (&tasks[t],
|
|
BDBUF_TESTS_PRI_HIGH - t,
|
|
bdbuf_test_tasks[t]))
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Let the test tasks run if they have not already done so.
|
|
*/
|
|
bdbuf_sleep (100);
|
|
|
|
/*
|
|
* Perform each test.
|
|
*/
|
|
for (t = 0; (t < BDBUF_TEST_NUM) && passed; t++)
|
|
{
|
|
printf ("test %d: %s\n", t + 1, bdbuf_tests[t].label);
|
|
passed = bdbuf_tests[t].test (tasks);
|
|
printf ("test %d: %s\n", t + 1, passed ? "passed" : "failed");
|
|
}
|
|
}
|
|
|
|
static rtems_task Init(rtems_task_argument argument)
|
|
{
|
|
TEST_BEGIN();
|
|
|
|
bdbuf_tester ();
|
|
|
|
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_LIBIO_MAXIMUM_FILE_DESCRIPTORS 4
|
|
|
|
#define CONFIGURE_BDBUF_TASK_STACK_SIZE BDBUF_TEST_STACK_SIZE
|
|
|
|
#define CONFIGURE_MAXIMUM_TASKS (1 + BDBUF_TEST_TASKS)
|
|
#define CONFIGURE_MAXIMUM_SEMAPHORES 2
|
|
|
|
#define CONFIGURE_EXTRA_TASK_STACKS \
|
|
(BDBUF_TEST_TASKS * BDBUF_TEST_STACK_SIZE)
|
|
|
|
#define CONFIGURE_INIT_TASK_STACK_SIZE BDBUF_TEST_STACK_SIZE
|
|
#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_FLOATING_POINT
|
|
#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
|
|
|
|
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
|
|
|
|
#include <rtems/confdefs.h>
|