Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:32

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*! @file
0004  * @brief Common declarations of bdbuf tests.
0005  *
0006  * Copyright (C) 2010 OKTET Labs, St.-Petersburg, Russia
0007  * Author: Oleg Kravtsov <Oleg.Kravtsov@oktetlabs.ru>
0008  *
0009  * Redistribution and use in source and binary forms, with or without
0010  * modification, are permitted provided that the following conditions
0011  * are met:
0012  * 1. Redistributions of source code must retain the above copyright
0013  *    notice, this list of conditions and the following disclaimer.
0014  * 2. Redistributions in binary form must reproduce the above copyright
0015  *    notice, this list of conditions and the following disclaimer in the
0016  *    documentation and/or other materials provided with the distribution.
0017  *
0018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0019  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0020  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0021  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0022  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0023  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0024  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0025  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0026  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0027  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0028  * POSSIBILITY OF SUCH DAMAGE.
0029  */
0030 
0031 #ifndef BDBUF_TESTS_H
0032 #define BDBUF_TESTS_H
0033 
0034 #include <inttypes.h>
0035 #include <stdio.h>
0036 #include <string.h>
0037 #include <errno.h>
0038 #include <rtems/bspIo.h>
0039 #include <rtems/bdbuf.h>
0040 
0041 #ifdef __cplusplus
0042 extern "C" {
0043 #endif
0044 
0045 extern void run_bdbuf_tests(void);
0046 
0047 extern void bdbuf_test1_1_main(void);
0048 extern void bdbuf_test1_2_main(void);
0049 extern void bdbuf_test1_3_main(void);
0050 extern void bdbuf_test1_4_main(void);
0051 extern void bdbuf_test1_5_main(void);
0052 
0053 extern void bdbuf_test2_1_main(void);
0054 extern void bdbuf_test2_2_main(void);
0055 extern void bdbuf_test2_3_main(void);
0056 extern void bdbuf_test2_4_main(void);
0057 extern void bdbuf_test2_5_main(void);
0058 
0059 extern void bdbuf_test3_1_main(void);
0060 extern void bdbuf_test3_2_main(void);
0061 extern void bdbuf_test3_3_main(void);
0062 
0063 extern void bdbuf_test4_1_main(void);
0064 extern void bdbuf_test4_2_main(void);
0065 extern void bdbuf_test4_3_main(void);
0066 
0067 extern rtems_status_code test_disk_initialize(void);
0068 
0069 #define ARRAY_NUM(a_) (sizeof(a_) / sizeof(a_[0]))
0070 
0071 /**
0072  * Configuration parameters of Test disk device.
0073  */
0074 #define TEST_DISK_BLOCK_SIZE   512
0075 #define TEST_DISK_BLOCK_NUM    1024
0076 #define TEST_DISK_NAME         "/dev/testdisk"
0077 
0078 /** Type of messages between test disk driver and main test task */
0079 enum bdbuf_test_msg_type {
0080     /** Message sent by disk driver to main test task */
0081     BDBUF_TEST_MSG_TYPE_DRIVER_REQ,
0082     /**
0083      * Message sent main test task to disk driver
0084      * in reply to request.
0085      */
0086     BDBUF_TEST_MSG_TYPE_DRIVER_REPLY,
0087 };
0088 
0089 /**
0090  * Message used in communication between test disk driver
0091  * and main test task.
0092  * All R/W requests obtained by driver (from bdbuf library)
0093  * are directed to main test task. Then main test task
0094  * sends a reply after which test disk driver notifies
0095  * bdbuf library about operation complete event.
0096  */
0097 typedef struct bdbuf_test_msg {
0098     /** Message type */
0099     enum bdbuf_test_msg_type type;
0100 
0101     union {
0102         struct driver_req {
0103             const rtems_disk_device *dd;
0104             uint32_t  req;
0105             void     *argp;
0106         } driver_req;
0107         struct driver_reply {
0108             int               ret_val;
0109             int               ret_errno;
0110             rtems_status_code res_status;
0111             int               res_errno;
0112         } driver_reply;
0113     } val;
0114 } bdbuf_test_msg;
0115 
0116 
0117 typedef enum bdbuf_rest_thread_prio {
0118     BDBUF_TEST_THREAD_PRIO_NORMAL = 3,
0119     BDBUF_TEST_THREAD_PRIO_LOW = 7,
0120     BDBUF_TEST_THREAD_PRIO_HIGH = 5,
0121 } bdbuf_rest_thread_prio;
0122 
0123 
0124 typedef struct test_ctx {
0125     /**
0126      * Message queue used by main task to get messages from
0127      * disk device driver.
0128      */
0129     Objects_Id test_qid;
0130 
0131     /**
0132      * Object ID for disk driver queue.
0133      * Test task will send messages to this queue in reply
0134      * to messages received on @a test_qid.
0135      */
0136     Objects_Id test_drv_qid;
0137 
0138     /** Test name */
0139     const char *test_name;
0140 
0141     /**
0142      * Semaphore used for synchronization between test thread
0143      * and main test task.
0144      * Main test task blocks on one of these semaphores and an auxiliary thread
0145      * releases it in order to pass control to main task again.
0146      */
0147     rtems_id   test_sync_main[3];
0148 
0149     /**
0150      * This semaphore is used for synchornization between main test task
0151      * and the END of auxiliary threads.
0152      */
0153     rtems_id   test_end_main;
0154 
0155     /**
0156      * Semaphore used for synchronization between test thread
0157      * and main test task.
0158      * Thread #N blocks on this semaphore and the main task releases it
0159      * when it wants to pass control to the auxiliary thread #N.
0160      */
0161     rtems_id   test_sync[3];
0162 
0163     /** Task Id values of auxiliary threads */
0164     Objects_Id test_task[3];
0165 } test_ctx;
0166 
0167 extern test_ctx g_test_ctx;
0168 
0169 /** Device ID used for testing */
0170 extern rtems_disk_device *test_dd;
0171 
0172 /**
0173  * Create a message queue for test driver that is used for
0174  * receiving messages from test task.
0175  *
0176  * @param[out] id  RTEMS message queue identifier
0177  *
0178  * @return Status of the operation
0179  */
0180 extern rtems_status_code bdbuf_test_create_drv_rx_queue(Objects_Id *id);
0181 
0182 /**
0183  * Obtain a message queue for test driver that is used for
0184  * sending messages to test task.
0185  *
0186  * @param[out] id  RTEMS message queue identifier
0187  *
0188  * @return Status of the operation
0189  */
0190 extern rtems_status_code bdbuf_test_create_drv_tx_queue(Objects_Id *id);
0191 
0192 /**
0193  * Start a separate test task represented by function @p func
0194  * and associated with task index @p idx.
0195  *
0196  * @param[in] idx   Task index
0197  * @param[in] func  Test task function
0198  */
0199 extern rtems_status_code bdbuf_test_start_thread(unsigned int idx,
0200                                                  rtems_task_entry func);
0201 
0202 /**
0203  * Finalize test run.
0204  */
0205 extern rtems_status_code bdbuf_test_end(void);
0206 
0207 /** Test result variable */
0208 extern bool       good_test_result;
0209 
0210 #define BDBUF_TEST_BLOCK_TIMEOUT (2 * rtems_clock_get_ticks_per_second())
0211 
0212 #define SET_THREAD_PRIORITY(t_num_, prio_) \
0213     do {                                                        \
0214         rtems_task_priority old_prio;                           \
0215         rtems_status_code   rc_;                                \
0216                                                                 \
0217         rc_ = rtems_task_set_priority(                          \
0218                 g_test_ctx.test_task[(t_num_) - 1],             \
0219                 BDBUF_TEST_THREAD_PRIO_ ## prio_, &old_prio);   \
0220         if (rc_ != RTEMS_SUCCESSFUL)                            \
0221         {                                                       \
0222             printk("Failed to change priority of test thread #" \
0223                    #t_num_ " in test %s\n", g_test_ctx.test_name);         \
0224             return;                                             \
0225         }                                                       \
0226     } while (0)
0227 
0228 /**
0229  * Start thread number @p t_num_ with @p func_ function
0230  * as an entry point of the thread.
0231  *
0232  * @param t_num_  thread number.
0233  * @param func_   thread entry point.
0234  */
0235 #define START_THREAD(t_num_, func_) \
0236     do {                                                        \
0237         if (bdbuf_test_start_thread((t_num_) - 1, func_) !=     \
0238                 RTEMS_SUCCESSFUL)                               \
0239         {                                                       \
0240             return;                                             \
0241         }                                                       \
0242         printk("Thread #" #t_num_ " started\n");                \
0243     } while (0)
0244 
0245 /**
0246  * Wait for a message from device driver.
0247  *
0248  * @param[out] msg_  Pointer to a message data structure
0249  */
0250 #define WAIT_DRV_MSG(msg_) \
0251     do {                                                        \
0252         rtems_status_code rc_;                                  \
0253         size_t            msg_size_ = sizeof(*(msg_));          \
0254                                                                 \
0255         rc_ = rtems_message_queue_receive(g_test_ctx.test_qid,  \
0256                                           (msg_), &msg_size_,   \
0257                                           RTEMS_WAIT,           \
0258                                           RTEMS_NO_TIMEOUT);    \
0259         if (rc_ != RTEMS_SUCCESSFUL ||                          \
0260             msg_size_ != sizeof(*(msg_)))                       \
0261         {                                                       \
0262             printk("Error at %s:%d\n", __FILE__, __LINE__);     \
0263             return;                                             \
0264         }                                                       \
0265         if ((msg_)->type != BDBUF_TEST_MSG_TYPE_DRIVER_REQ)     \
0266         {                                                       \
0267             printk("Unexpected message received: %d\n",         \
0268                    (msg_)->type);                               \
0269             return;                                             \
0270         }                                                       \
0271     } while (0)
0272 
0273 #define WAIT_DRV_MSG_WR(msg_) \
0274   do {                                                                     \
0275         WAIT_DRV_MSG(msg_);                                                \
0276         if ((msg_)->val.driver_req.req != RTEMS_BLKIO_REQUEST ||           \
0277             (msg_)->val.driver_req.dd != test_dd ||                        \
0278             ((rtems_blkdev_request *)                                      \
0279                  ((msg_)->val.driver_req.argp))->req !=                    \
0280                  RTEMS_BLKDEV_REQ_WRITE)                                   \
0281         {                                                                  \
0282             printk("Unexpected message received by disk driver: "          \
0283                    "req - 0x%" PRIx32 " (0x%lx), dev - %p (%p)\n", \
0284                    (msg_)->val.driver_req.req, RTEMS_BLKIO_REQUEST,        \
0285                    (msg_)->val.driver_req.dd, test_dd);                    \
0286             return;                                                        \
0287         }                                                                  \
0288     } while (0)
0289 
0290 #define CHECK_NO_DRV_MSG() \
0291     do {                                                        \
0292         rtems_status_code rc_;                                  \
0293         bdbuf_test_msg    msg_;                                 \
0294         size_t            msg_size_ = sizeof(msg_);             \
0295                                                                 \
0296         rc_ = rtems_message_queue_receive(g_test_ctx.test_qid,  \
0297                   (&msg_), &msg_size_,                          \
0298                   RTEMS_WAIT,                                   \
0299                   BDBUF_TEST_BLOCK_TIMEOUT);                    \
0300         if (rc_ != RTEMS_TIMEOUT)                               \
0301         {                                                       \
0302             printk("Error at %s:%d\n", __FILE__, __LINE__);     \
0303             return;                                             \
0304         }                                                       \
0305     } while (0)
0306 
0307 extern bdbuf_test_msg test_drv_msg;
0308 
0309 /**
0310  * Send a message to device driver (in order to complete
0311  * blocked I/O operation).
0312  *
0313  * @param ret_val_     Return value to use when returning from
0314  *                     ioctl() function.
0315  * @param ret_errno_   errno value to set to errno variable.
0316  * @param res_status_  In case return value from the ioctl()
0317  *                     function is equal to 0, this value
0318  *                     is used as status code in asynchronous
0319  *                     notification.
0320  * @param res_errno_   In case return value from the ioctl()
0321  *                     function is equal to 0, this value
0322  *                     is used as error value in asynchronous
0323  *                     notification.
0324  *
0325  */
0326 #define SEND_DRV_MSG(ret_val_, ret_errno_, res_status_, res_errno_) \
0327     do {                                                                \
0328         rtems_status_code rc_;                                          \
0329                                                                         \
0330         memset(&test_drv_msg, 0, sizeof(test_drv_msg));                 \
0331         test_drv_msg.type = BDBUF_TEST_MSG_TYPE_DRIVER_REPLY;           \
0332         test_drv_msg.val.driver_reply.ret_val = (ret_val_);             \
0333         test_drv_msg.val.driver_reply.ret_errno = (ret_errno_);         \
0334         test_drv_msg.val.driver_reply.res_status = (res_status_);       \
0335         test_drv_msg.val.driver_reply.res_errno = (res_errno_);         \
0336                                                                         \
0337         rc_ = rtems_message_queue_send(g_test_ctx.test_drv_qid,         \
0338                                        &test_drv_msg,                   \
0339                                        sizeof(test_drv_msg));           \
0340         if (rc_ != RTEMS_SUCCESSFUL)                                    \
0341         {                                                               \
0342             printk("Error while sending a message to "                  \
0343                    "disk driver: %u\n", rc_);                           \
0344             return;                                                     \
0345         }                                                               \
0346     } while (0)
0347 
0348 /**
0349  * Block main test task until a thread passes back control
0350  * with CONTINUE_MAIN().
0351  *
0352  * @param t_num_  thread number from which the main thread
0353  *                is waiting for a sync.
0354  */
0355 #define WAIT_THREAD_SYNC(t_num_) \
0356     do {                                                                \
0357         rtems_status_code rc_;                                          \
0358                                                                         \
0359         rc_ = rtems_semaphore_obtain(                                   \
0360                 g_test_ctx.test_sync_main[(t_num_) - 1],                \
0361                 RTEMS_WAIT, RTEMS_NO_TIMEOUT);                          \
0362         if (rc_ != RTEMS_SUCCESSFUL)                                    \
0363         {                                                               \
0364             printk("Failed to get sync with a thread: %d\n", rc_);      \
0365             return;                                                     \
0366         }                                                               \
0367     } while (0)
0368 
0369 /**
0370  * Check that a particular thread is blocked.
0371  *
0372  * @param t_num_  thread number that we want to check for blocking
0373  */
0374 #define CHECK_THREAD_BLOCKED(t_num_) \
0375     do {                                                                \
0376         rtems_status_code rc_;                                          \
0377                                                                         \
0378         rc_ = rtems_semaphore_obtain(                                   \
0379                 g_test_ctx.test_sync_main[(t_num_) - 1],                \
0380                 RTEMS_WAIT, BDBUF_TEST_BLOCK_TIMEOUT);                  \
0381         if (rc_ != RTEMS_TIMEOUT)                                       \
0382         {                                                               \
0383             printk("Thread %d is not blocked at%s:%d\n",                \
0384                    t_num_, __FILE__, __LINE__);                         \
0385             return;                                                     \
0386         }                                                               \
0387     } while (0)
0388 
0389 /**
0390  * Main test task gives control to the particular thread.
0391  *
0392  * @param t_num_  thread number to which main test task wants
0393  *                to give control.
0394  */
0395 #define CONTINUE_THREAD(t_num_) \
0396     do {                                                        \
0397         rtems_status_code rc_;                                  \
0398                                                                 \
0399         rc_ = rtems_semaphore_release(                          \
0400                 g_test_ctx.test_sync[(t_num_) - 1]);            \
0401         if (rc_ != RTEMS_SUCCESSFUL)                            \
0402         {                                                       \
0403             printk("Failed to give control to thread #"         \
0404                    #t_num_ ": %d\n", rc_);                      \
0405             return;                                             \
0406         }                                                       \
0407     } while (0)
0408 
0409 /**
0410  * Passes control back to the main test task from a thread.
0411  *
0412  * @param t_num_ Current thread number
0413  */
0414 #define CONTINUE_MAIN(t_num_) \
0415     do {                                                        \
0416         rtems_status_code rc_;                                  \
0417                                                                 \
0418         rc_ = rtems_semaphore_release(                          \
0419                 g_test_ctx.test_sync_main[(t_num_) - 1]);       \
0420         if (rc_ != RTEMS_SUCCESSFUL)                            \
0421         {                                                       \
0422             printk("Failed to give control to "                 \
0423                    "main task: %d", rc_);                       \
0424             return;                                             \
0425         }                                                       \
0426         rc_ = rtems_semaphore_obtain(                           \
0427                 g_test_ctx.test_sync[(t_num_) - 1],             \
0428                 RTEMS_WAIT, RTEMS_NO_TIMEOUT);                  \
0429         if (rc_ != RTEMS_SUCCESSFUL)                            \
0430         {                                                       \
0431             printk("Failed to block on thread #"                \
0432                    #t_num_ ": %d\n", rc_);                      \
0433             return;                                             \
0434         }                                                       \
0435     } while (0)
0436 
0437 #define WAIT_MAIN_SYNC(t_num_) \
0438     do {                                                        \
0439         rtems_status_code rc_;                                  \
0440                                                                 \
0441         rc_ = rtems_semaphore_obtain(                           \
0442                 g_test_ctx.test_sync[(t_num_) - 1],             \
0443                 RTEMS_WAIT, RTEMS_NO_TIMEOUT);                  \
0444         if (rc_ != RTEMS_SUCCESSFUL)                            \
0445         {                                                       \
0446             printk("Failed to block on thread #"                \
0447                    #t_num_ ": %d\n", rc_);                      \
0448             return;                                             \
0449         }                                                       \
0450     } while (0)
0451 
0452 
0453 #define TEST_START(test_name_) \
0454     do {                                \
0455         good_test_result = true;        \
0456         g_test_ctx.test_name = test_name_; \
0457         printk("%s - STARTED\n",        \
0458                g_test_ctx.test_name);              \
0459     } while (0)
0460 
0461 #define TEST_CHECK_RESULT(step_) \
0462     do {                                        \
0463         if (!good_test_result)                  \
0464         {                                       \
0465             printk("TEST FAILED (Step %s)\n",   \
0466                    step_);                      \
0467             rtems_task_exit();                  \
0468         }                                       \
0469         else                                    \
0470         {                                       \
0471             printk("%s: Step %s - OK\n",        \
0472                    g_test_ctx.test_name, step_);           \
0473         }                                       \
0474     } while (0)
0475 
0476 #define TEST_STOP() \
0477     do {                                 \
0478         bdbuf_test_end();                \
0479                                          \
0480         if (good_test_result)            \
0481             printk("TEST PASSED\n");     \
0482         else                             \
0483             printk("TEST FAILED (END)"); \
0484     } while (0)
0485 
0486 #define THREAD_END() \
0487     do {                                                        \
0488         rtems_status_code rc_;                                  \
0489                                                                 \
0490         rc_ = rtems_semaphore_release(g_test_ctx.test_end_main);\
0491         if (rc_ != RTEMS_SUCCESSFUL)                            \
0492         {                                                       \
0493             printk("Failed to give control to "                 \
0494                    "main task: %d", rc_);                       \
0495             return;                                             \
0496         }                                                       \
0497         rtems_task_exit();                                      \
0498     } while (0)
0499 
0500 #define TEST_FAILED() \
0501     do {                                \
0502         good_test_result = false;       \
0503     } while (0)
0504 
0505 #define SLEEP() \
0506     rtems_task_wake_after(BDBUF_TEST_BLOCK_TIMEOUT)
0507 
0508 
0509 extern rtems_status_code
0510 bdbuf_test_start_aux_task(rtems_name name,
0511                           rtems_task_entry entry_point,
0512                           rtems_task_argument arg,
0513                           Objects_Id *id);
0514 #ifdef __cplusplus
0515 }
0516 #endif
0517 
0518 #endif /* BDBUF_TESTS_H */