forked from Imagelibrary/rtems
505 lines
20 KiB
C
505 lines
20 KiB
C
/*! @file
|
|
* @brief Common declarations of bdbuf tests.
|
|
*
|
|
* Copyright (C) 2010 OKTET Labs, St.-Petersburg, Russia
|
|
* Author: Oleg Kravtsov <Oleg.Kravtsov@oktetlabs.ru>
|
|
*
|
|
* The license and distribution terms for this file may be
|
|
* found in the file LICENSE in this distribution or at
|
|
* http://www.rtems.com/license/LICENSE.
|
|
*
|
|
* $Id$
|
|
*/
|
|
|
|
#ifndef BDBUF_TESTS_H
|
|
#define BDBUF_TESTS_H
|
|
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <rtems/diskdevs.h>
|
|
#include <rtems/bdbuf.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
extern void run_bdbuf_tests(void);
|
|
|
|
extern void bdbuf_test1_1_main(void);
|
|
extern void bdbuf_test1_2_main(void);
|
|
extern void bdbuf_test1_3_main(void);
|
|
extern void bdbuf_test1_4_main(void);
|
|
extern void bdbuf_test1_5_main(void);
|
|
|
|
extern void bdbuf_test2_1_main(void);
|
|
extern void bdbuf_test2_2_main(void);
|
|
extern void bdbuf_test2_3_main(void);
|
|
extern void bdbuf_test2_4_main(void);
|
|
extern void bdbuf_test2_5_main(void);
|
|
|
|
extern void bdbuf_test3_1_main(void);
|
|
extern void bdbuf_test3_2_main(void);
|
|
extern void bdbuf_test3_3_main(void);
|
|
|
|
extern void bdbuf_test4_1_main(void);
|
|
extern void bdbuf_test4_2_main(void);
|
|
extern void bdbuf_test4_3_main(void);
|
|
|
|
extern rtems_device_driver
|
|
test_disk_initialize(
|
|
rtems_device_major_number major,
|
|
rtems_device_minor_number minor,
|
|
void *arg);
|
|
|
|
#define ARRAY_NUM(a_) (sizeof(a_) / sizeof(a_[0]))
|
|
|
|
/**
|
|
* Configuration parameters of Test disk device.
|
|
*/
|
|
#define TEST_DISK_BLOCK_SIZE 512
|
|
#define TEST_DISK_BLOCK_NUM 1024
|
|
#define TEST_DISK_NAME "/dev/testdisk"
|
|
|
|
/** Type of messages between test disk driver and main test task */
|
|
enum bdbuf_test_msg_type {
|
|
/** Message sent by disk driver to main test task */
|
|
BDBUF_TEST_MSG_TYPE_DRIVER_REQ,
|
|
/**
|
|
* Message sent main test task to disk driver
|
|
* in reply to request.
|
|
*/
|
|
BDBUF_TEST_MSG_TYPE_DRIVER_REPLY,
|
|
};
|
|
|
|
/**
|
|
* Message used in communication between test disk driver
|
|
* and main test task.
|
|
* All R/W requests obtained by driver (from bdbuf library)
|
|
* are directed to main test task. Then main test task
|
|
* sends a reply after which test disk driver notifies
|
|
* bdbuf library about operation complete event.
|
|
*/
|
|
typedef struct bdbuf_test_msg {
|
|
/** Message type */
|
|
enum bdbuf_test_msg_type type;
|
|
|
|
union {
|
|
struct driver_req {
|
|
dev_t dev;
|
|
uint32_t req;
|
|
void *argp;
|
|
} driver_req;
|
|
struct driver_reply {
|
|
int ret_val;
|
|
int ret_errno;
|
|
rtems_status_code res_status;
|
|
int res_errno;
|
|
} driver_reply;
|
|
} val;
|
|
} bdbuf_test_msg;
|
|
|
|
|
|
typedef enum bdbuf_rest_thread_prio {
|
|
BDBUF_TEST_THREAD_PRIO_NORMAL = 3,
|
|
BDBUF_TEST_THREAD_PRIO_LOW = 7,
|
|
BDBUF_TEST_THREAD_PRIO_HIGH = 5,
|
|
} bdbuf_rest_thread_prio;
|
|
|
|
|
|
typedef struct test_ctx {
|
|
/**
|
|
* Message queue used by main task to get messages from
|
|
* disk device driver.
|
|
*/
|
|
Objects_Id test_qid;
|
|
|
|
/**
|
|
* Object ID for disk driver queue.
|
|
* Test task will send messages to this queue in reply
|
|
* to messages received on @a test_qid.
|
|
*/
|
|
Objects_Id test_drv_qid;
|
|
|
|
/** Test name */
|
|
const char *test_name;
|
|
|
|
/**
|
|
* Semaphore used for synchronization between test thread
|
|
* and main test task.
|
|
* Main test task blocks on one of these semaphores and an auxiliary thread
|
|
* releases it in order to pass control to main task again.
|
|
*/
|
|
rtems_id test_sync_main[3];
|
|
|
|
/**
|
|
* This semaphore is used for synchornization between main test task
|
|
* and the END of auxiliary threads.
|
|
*/
|
|
rtems_id test_end_main;
|
|
|
|
/**
|
|
* Semaphore used for synchronization between test thread
|
|
* and main test task.
|
|
* Thread #N blocks on this semaphore and the main task releases it
|
|
* when it wants to pass control to the auxiliary thread #N.
|
|
*/
|
|
rtems_id test_sync[3];
|
|
|
|
/** Task Id values of auxiliary threads */
|
|
Objects_Id test_task[3];
|
|
} test_ctx;
|
|
|
|
extern test_ctx g_test_ctx;
|
|
|
|
/** Device ID used for testing */
|
|
extern dev_t test_dev;
|
|
|
|
/**
|
|
* Create a message queue for test driver that is used for
|
|
* receiving messages from test task.
|
|
*
|
|
* @param[out] id RTEMS message queue identifier
|
|
*
|
|
* @return Status of the operation
|
|
*/
|
|
extern rtems_status_code bdbuf_test_create_drv_rx_queue(Objects_Id *id);
|
|
|
|
/**
|
|
* Obtain a message queue for test driver that is used for
|
|
* sending messages to test task.
|
|
*
|
|
* @param[out] id RTEMS message queue identifier
|
|
*
|
|
* @return Status of the operation
|
|
*/
|
|
extern rtems_status_code bdbuf_test_create_drv_tx_queue(Objects_Id *id);
|
|
|
|
/**
|
|
* Start a separate test task represented by function @p func
|
|
* and associated with task index @p idx.
|
|
*
|
|
* @param[in] idx Task index
|
|
* @param[in] func Test task function
|
|
*/
|
|
extern rtems_status_code bdbuf_test_start_thread(unsigned int idx,
|
|
rtems_task_entry func);
|
|
|
|
/**
|
|
* Finalize test run.
|
|
*/
|
|
extern rtems_status_code bdbuf_test_end(void);
|
|
|
|
/** Test result variable */
|
|
extern bool good_test_result;
|
|
|
|
#define BDBUF_TEST_BLOCK_TIMEOUT (2 * rtems_clock_get_ticks_per_second())
|
|
|
|
#define SET_THREAD_PRIORITY(t_num_, prio_) \
|
|
do { \
|
|
rtems_task_priority old_prio; \
|
|
rtems_status_code rc_; \
|
|
\
|
|
rc_ = rtems_task_set_priority( \
|
|
g_test_ctx.test_task[(t_num_) - 1], \
|
|
BDBUF_TEST_THREAD_PRIO_ ## prio_, &old_prio); \
|
|
if (rc_ != RTEMS_SUCCESSFUL) \
|
|
{ \
|
|
printk("Failed to change priority of test thread #" \
|
|
#t_num_ " in test %s\n", g_test_ctx.test_name); \
|
|
return; \
|
|
} \
|
|
} while (0)
|
|
|
|
/**
|
|
* Start thread number @p t_num_ with @p func_ function
|
|
* as an entry point of the thread.
|
|
*
|
|
* @param t_num_ thread number.
|
|
* @param func_ thread entry point.
|
|
*/
|
|
#define START_THREAD(t_num_, func_) \
|
|
do { \
|
|
if (bdbuf_test_start_thread((t_num_) - 1, func_) != \
|
|
RTEMS_SUCCESSFUL) \
|
|
{ \
|
|
return; \
|
|
} \
|
|
printk("Thread #" #t_num_ " started\n"); \
|
|
} while (0)
|
|
|
|
/**
|
|
* Wait for a message from device driver.
|
|
*
|
|
* @param[out] msg_ Pointer to a message data structure
|
|
*/
|
|
#define WAIT_DRV_MSG(msg_) \
|
|
do { \
|
|
rtems_status_code rc_; \
|
|
size_t msg_size_ = sizeof(*(msg_)); \
|
|
\
|
|
rc_ = rtems_message_queue_receive(g_test_ctx.test_qid, \
|
|
(msg_), &msg_size_, \
|
|
RTEMS_WAIT, \
|
|
RTEMS_NO_TIMEOUT); \
|
|
if (rc_ != RTEMS_SUCCESSFUL || \
|
|
msg_size_ != sizeof(*(msg_))) \
|
|
{ \
|
|
printk("Error at %s:%d\n", __FILE__, __LINE__); \
|
|
return; \
|
|
} \
|
|
if ((msg_)->type != BDBUF_TEST_MSG_TYPE_DRIVER_REQ) \
|
|
{ \
|
|
printk("Unexpected message received: %d\n", \
|
|
(msg_)->type); \
|
|
return; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define WAIT_DRV_MSG_WR(msg_) \
|
|
do { \
|
|
WAIT_DRV_MSG(msg_); \
|
|
if ((msg_)->val.driver_req.req != RTEMS_BLKIO_REQUEST || \
|
|
(msg_)->val.driver_req.dev != test_dev || \
|
|
((rtems_blkdev_request *) \
|
|
((msg_)->val.driver_req.argp))->req != \
|
|
RTEMS_BLKDEV_REQ_WRITE) \
|
|
{ \
|
|
printk("Unexpected message received by disk driver: " \
|
|
"req - 0x%x (0x%x), dev - %d (%d)\n", \
|
|
(msg_)->val.driver_req.req, RTEMS_BLKIO_REQUEST, \
|
|
(msg_)->val.driver_req.dev, test_dev); \
|
|
return; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define CHECK_NO_DRV_MSG() \
|
|
do { \
|
|
rtems_status_code rc_; \
|
|
bdbuf_test_msg msg_; \
|
|
size_t msg_size_ = sizeof(msg_); \
|
|
\
|
|
rc_ = rtems_message_queue_receive(g_test_ctx.test_qid, \
|
|
(&msg_), &msg_size_, \
|
|
RTEMS_WAIT, \
|
|
BDBUF_TEST_BLOCK_TIMEOUT); \
|
|
if (rc_ != RTEMS_TIMEOUT) \
|
|
{ \
|
|
printk("Error at %s:%d\n", __FILE__, __LINE__); \
|
|
return; \
|
|
} \
|
|
} while (0)
|
|
|
|
extern bdbuf_test_msg test_drv_msg;
|
|
|
|
/**
|
|
* Send a message to device driver (in order to complete
|
|
* blocked I/O operation).
|
|
*
|
|
* @param ret_val_ Return value to use when returning from
|
|
* ioctl() function.
|
|
* @param ret_errno_ errno value to set to errno variable.
|
|
* @param res_status_ In case return value from the ioctl()
|
|
* function is equal to 0, this value
|
|
* is used as status code in asynchronous
|
|
* notification.
|
|
* @param res_errno_ In case return value from the ioctl()
|
|
* function is equal to 0, this value
|
|
* is used as error value in asynchronous
|
|
* notification.
|
|
*
|
|
*/
|
|
#define SEND_DRV_MSG(ret_val_, ret_errno_, res_status_, res_errno_) \
|
|
do { \
|
|
rtems_status_code rc_; \
|
|
\
|
|
memset(&test_drv_msg, 0, sizeof(test_drv_msg)); \
|
|
test_drv_msg.type = BDBUF_TEST_MSG_TYPE_DRIVER_REPLY; \
|
|
test_drv_msg.val.driver_reply.ret_val = (ret_val_); \
|
|
test_drv_msg.val.driver_reply.ret_errno = (ret_errno_); \
|
|
test_drv_msg.val.driver_reply.res_status = (res_status_); \
|
|
test_drv_msg.val.driver_reply.res_errno = (res_errno_); \
|
|
\
|
|
rc_ = rtems_message_queue_send(g_test_ctx.test_drv_qid, \
|
|
&test_drv_msg, \
|
|
sizeof(test_drv_msg)); \
|
|
if (rc_ != RTEMS_SUCCESSFUL) \
|
|
{ \
|
|
printk("Error while sending a message to " \
|
|
"disk driver: %u\n", rc_); \
|
|
return; \
|
|
} \
|
|
} while (0)
|
|
|
|
/**
|
|
* Block main test task until a thread passes back control
|
|
* with CONTINUE_MAIN().
|
|
*
|
|
* @param t_num_ thread number from which the main thread
|
|
* is waiting for a sync.
|
|
*/
|
|
#define WAIT_THREAD_SYNC(t_num_) \
|
|
do { \
|
|
rtems_status_code rc_; \
|
|
\
|
|
rc_ = rtems_semaphore_obtain( \
|
|
g_test_ctx.test_sync_main[(t_num_) - 1], \
|
|
RTEMS_WAIT, RTEMS_NO_TIMEOUT); \
|
|
if (rc_ != RTEMS_SUCCESSFUL) \
|
|
{ \
|
|
printk("Failed to get sync with a thread: %d\n", rc_); \
|
|
return; \
|
|
} \
|
|
} while (0)
|
|
|
|
/**
|
|
* Check that a particular thread is blocked.
|
|
*
|
|
* @param t_num_ thread number that we want to check for blocking
|
|
*/
|
|
#define CHECK_THREAD_BLOCKED(t_num_) \
|
|
do { \
|
|
rtems_status_code rc_; \
|
|
\
|
|
rc_ = rtems_semaphore_obtain( \
|
|
g_test_ctx.test_sync_main[(t_num_) - 1], \
|
|
RTEMS_WAIT, BDBUF_TEST_BLOCK_TIMEOUT); \
|
|
if (rc_ != RTEMS_TIMEOUT) \
|
|
{ \
|
|
printk("Thread %d is not blocked at%s:%d\n", \
|
|
t_num_, __FILE__, __LINE__); \
|
|
return; \
|
|
} \
|
|
} while (0)
|
|
|
|
/**
|
|
* Main test task gives control to the particular thread.
|
|
*
|
|
* @param t_num_ thread number to which main test task wants
|
|
* to give control.
|
|
*/
|
|
#define CONTINUE_THREAD(t_num_) \
|
|
do { \
|
|
rtems_status_code rc_; \
|
|
\
|
|
rc_ = rtems_semaphore_release( \
|
|
g_test_ctx.test_sync[(t_num_) - 1]); \
|
|
if (rc_ != RTEMS_SUCCESSFUL) \
|
|
{ \
|
|
printk("Failed to give control to thread #" \
|
|
#t_num_ ": %d\n", rc_); \
|
|
return; \
|
|
} \
|
|
} while (0)
|
|
|
|
/**
|
|
* Passes control back to the main test task from a thread.
|
|
*
|
|
* @param t_num_ Current thread number
|
|
*/
|
|
#define CONTINUE_MAIN(t_num_) \
|
|
do { \
|
|
rtems_status_code rc_; \
|
|
\
|
|
rc_ = rtems_semaphore_release( \
|
|
g_test_ctx.test_sync_main[(t_num_) - 1]); \
|
|
if (rc_ != RTEMS_SUCCESSFUL) \
|
|
{ \
|
|
printk("Failed to give control to " \
|
|
"main task: %d", rc_); \
|
|
return; \
|
|
} \
|
|
rc_ = rtems_semaphore_obtain( \
|
|
g_test_ctx.test_sync[(t_num_) - 1], \
|
|
RTEMS_WAIT, RTEMS_NO_TIMEOUT); \
|
|
if (rc_ != RTEMS_SUCCESSFUL) \
|
|
{ \
|
|
printk("Failed to block on thread #" \
|
|
#t_num_ ": %d\n", rc_); \
|
|
return; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define WAIT_MAIN_SYNC(t_num_) \
|
|
do { \
|
|
rtems_status_code rc_; \
|
|
\
|
|
rc_ = rtems_semaphore_obtain( \
|
|
g_test_ctx.test_sync[(t_num_) - 1], \
|
|
RTEMS_WAIT, RTEMS_NO_TIMEOUT); \
|
|
if (rc_ != RTEMS_SUCCESSFUL) \
|
|
{ \
|
|
printk("Failed to block on thread #" \
|
|
#t_num_ ": %d\n", rc_); \
|
|
return; \
|
|
} \
|
|
} while (0)
|
|
|
|
|
|
#define TEST_START(test_name_) \
|
|
do { \
|
|
good_test_result = true; \
|
|
g_test_ctx.test_name = test_name_; \
|
|
printk("%s - STARTED\n", \
|
|
g_test_ctx.test_name); \
|
|
} while (0)
|
|
|
|
#define TEST_CHECK_RESULT(step_) \
|
|
do { \
|
|
if (!good_test_result) \
|
|
{ \
|
|
printk("TEST FAILED (Step %s)\n", \
|
|
step_); \
|
|
rtems_task_delete(RTEMS_SELF); \
|
|
} \
|
|
else \
|
|
{ \
|
|
printk("%s: Step %s - OK\n", \
|
|
g_test_ctx.test_name, step_); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define TEST_END() \
|
|
do { \
|
|
bdbuf_test_end(); \
|
|
\
|
|
if (good_test_result) \
|
|
printk("TEST PASSED\n"); \
|
|
else \
|
|
printk("TEST FAILED (END)"); \
|
|
} while (0)
|
|
|
|
#define THREAD_END() \
|
|
do { \
|
|
rtems_status_code rc_; \
|
|
\
|
|
rc_ = rtems_semaphore_release(g_test_ctx.test_end_main);\
|
|
if (rc_ != RTEMS_SUCCESSFUL) \
|
|
{ \
|
|
printk("Failed to give control to " \
|
|
"main task: %d", rc_); \
|
|
return; \
|
|
} \
|
|
rtems_task_delete(RTEMS_SELF); \
|
|
} while (0)
|
|
|
|
#define TEST_FAILED() \
|
|
do { \
|
|
good_test_result = false; \
|
|
} while (0)
|
|
|
|
#define SLEEP() \
|
|
rtems_task_wake_after(BDBUF_TEST_BLOCK_TIMEOUT)
|
|
|
|
|
|
extern rtems_status_code
|
|
bdbuf_test_start_aux_task(rtems_name name,
|
|
rtems_task_entry entry_point,
|
|
rtems_task_argument arg,
|
|
Objects_Id *id);
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* BDBUF_TESTS_H */
|
|
|