Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  * Copyright 2008 Chris Johns (chrisj@rtems.org)
0005  *
0006  * Redistribution and use in source and binary forms, with or without
0007  * modification, are permitted provided that the following conditions
0008  * are met:
0009  * 1. Redistributions of source code must retain the above copyright
0010  *    notice, this list of conditions and the following disclaimer.
0011  * 2. Redistributions in binary form must reproduce the above copyright
0012  *    notice, this list of conditions and the following disclaimer in the
0013  *    documentation and/or other materials provided with the distribution.
0014  *
0015  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0016  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0017  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0018  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0019  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0020  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0021  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0023  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0024  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0025  * POSSIBILITY OF SUCH DAMAGE.
0026  */
0027 
0028 /**
0029  * BD Buffer test.
0030  *
0031  * Please add more tests
0032  */
0033 
0034 #ifdef HAVE_CONFIG_H
0035 #include "config.h"
0036 #endif
0037 
0038 #include <errno.h>
0039 #include <fcntl.h>
0040 #include <setjmp.h>
0041 #include <stdio.h>
0042 #include <stdlib.h>
0043 #include <string.h>
0044 #include <sys/types.h>
0045 #include <sys/stat.h>
0046 #include <inttypes.h>
0047 #include <unistd.h>
0048 
0049 #include <rtems.h>
0050 #include <rtems/chain.h>
0051 #include <rtems/error.h>
0052 #include <rtems/bdbuf.h>
0053 
0054 #include <bsp.h>
0055 
0056 #include "tmacros.h"
0057 
0058 const char rtems_test_name[] = "BLOCK 6";
0059 
0060 /* forward declarations to avoid warnings */
0061 static rtems_task Init(rtems_task_argument argument);
0062 
0063 #define BDBUF_DISKS 2
0064 #define BDBUF_SIZE  1024
0065 
0066 #if 0
0067 const rtems_bdbuf_config rtems_bdbuf_configuration =
0068 {
0069   5,           /* max_read_ahead_blocks */
0070   5,           /* max_write_blocks */
0071   15,          /* swapout_priority */
0072   250,         /* swapout_period */
0073   1000,        /* swap_block_hold */
0074   0,           /* swapout_workers */
0075   15,          /* swapout_worker_priority */
0076   1024 * 1024, /* size */
0077   512,         /* buffer_min */
0078   4096         /* buffer_max */
0079 };
0080 #endif
0081 
0082 /**
0083  * The bdbuf disk driver base name.
0084  */
0085 #define BDBUF_DISK_DEVICE_BASE_NAME "/dev/bddisk"
0086 
0087 /**
0088  * The actions the disk driver handles.
0089  */
0090 typedef enum bdbuf_disk_action
0091 {
0092   BDBUF_DISK_NOOP,
0093   BDBUF_DISK_WAIT,
0094   BDBUF_DISK_SLEEP,
0095   BDBUF_DISK_BLOCKS_INORDER
0096 } bdbuf_disk_action;
0097 
0098 /**
0099  * The BDBUF Disk driver.
0100  */
0101 typedef struct bdbuf_disk
0102 {
0103   const char*        name;
0104   uint32_t           minor;
0105   rtems_id           lock;
0106   uint32_t           block_size;
0107   uint32_t           block_count;
0108   bdbuf_disk_action  driver_action;
0109   const char*        watcher_name;
0110   rtems_id           watcher;
0111   int                watch_count;
0112   const char*        waiting_name;
0113   rtems_id           waiting;
0114   uint32_t           driver_sleep;
0115   rtems_disk_device* dd;
0116 } bdbuf_disk;
0117 
0118 /*
0119  * A disk drive for each pool.
0120  */
0121 static bdbuf_disk bdbuf_disks[BDBUF_DISKS];
0122 
0123 /**
0124  * Task control.
0125  */
0126 typedef struct bdbuf_task_control
0127 {
0128   bool                      die;
0129   const char*               name;
0130   rtems_id                  task;
0131   rtems_id                  master;
0132   int                       test;
0133   bdbuf_disk               *bdd;
0134   bool                      passed;
0135 } bdbuf_task_control;
0136 
0137 #define BDBUF_TEST_TASKS (3)
0138 
0139 #define BDBUF_TEST_STACK_SIZE (2 * RTEMS_MINIMUM_STACK_SIZE)
0140 
0141 /**
0142  * Seconds as milli-seconds.
0143  */
0144 #define BDBUF_SECONDS(msec) ((msec) * 1000UL)
0145 
0146 /**
0147  * Print the status code description and return true if true.
0148  *
0149  * @param sc The RTEMS status code.
0150  * @retval true The status code is successful.
0151  * @retval false The status code is not successful.
0152  */
0153 static bool
0154 bdbuf_test_print_sc (rtems_status_code sc, bool newline)
0155 {
0156   if (newline)
0157     printf ("%s\n", rtems_status_text (sc));
0158   else
0159     printf ("%s", rtems_status_text (sc));
0160   return sc == RTEMS_SUCCESSFUL;
0161 }
0162 
0163 /**
0164  * BDBuf disk device driver lock.
0165  */
0166 static bool
0167 bdbuf_disk_lock (bdbuf_disk* bdd)
0168 {
0169   rtems_status_code sc;
0170   sc = rtems_semaphore_obtain (bdd->lock, RTEMS_WAIT, 0);
0171   if (sc != RTEMS_SUCCESSFUL)
0172   {
0173     printf ("disk ioctl: lock failed: ");
0174     bdbuf_test_print_sc (sc, true);
0175     return false;
0176   }
0177   return true;
0178 }
0179 
0180 /**
0181  * BDBuf disk device driver unlock.
0182  */
0183 static bool
0184 bdbuf_disk_unlock (bdbuf_disk* bdd)
0185 {
0186   rtems_status_code sc;
0187   sc = rtems_semaphore_release (bdd->lock);
0188   if (sc != RTEMS_SUCCESSFUL)
0189   {
0190     printf ("disk ioctl: unlock failed: ");
0191     bdbuf_test_print_sc (sc, true);
0192     return false;
0193   }
0194   return true;
0195 }
0196 
0197 /**
0198  * BDBUf wait for the wait event.
0199  */
0200 static rtems_status_code
0201 bdbuf_wait (const char* who, unsigned long timeout)
0202 {
0203   rtems_status_code sc;
0204   rtems_event_set   out;
0205   sc = rtems_event_receive (RTEMS_EVENT_0,
0206                             RTEMS_WAIT | RTEMS_EVENT_ANY,
0207                             RTEMS_MICROSECONDS_TO_TICKS (timeout * 1000),
0208                             &out);
0209   if (sc != RTEMS_SUCCESSFUL)
0210   {
0211     printf ("%s: wait: receive failed: ", who);
0212     bdbuf_test_print_sc (sc, true);
0213   }
0214   else if ((out & RTEMS_EVENT_0) == 0)
0215   {
0216     printf ("%s: wait: received wrong event: %08" PRIxrtems_event_set, who, out);
0217   }
0218   return sc;
0219 }
0220 
0221 /**
0222  * BDBUf send wait event.
0223  */
0224 static bool
0225 bdbuf_send_wait_event (const char* task, const char* msg, rtems_id id)
0226 {
0227   printf ("%s: %s: %08" PRIxrtems_id ": ", task, msg, id);
0228   return  bdbuf_test_print_sc (rtems_event_send (id, RTEMS_EVENT_0), true);
0229 }
0230 
0231 /**
0232  * BDBUf wait for the wait event.
0233  */
0234 static rtems_status_code
0235 bdbuf_watch (unsigned long timeout)
0236 {
0237   rtems_status_code sc;
0238   rtems_event_set   out;
0239   sc = rtems_event_receive (RTEMS_EVENT_1,
0240                             RTEMS_WAIT | RTEMS_EVENT_ANY,
0241                             RTEMS_MICROSECONDS_TO_TICKS (timeout * 1000),
0242                             &out);
0243   if (sc != RTEMS_SUCCESSFUL)
0244   {
0245     printf ("watch: receive failed: ");
0246     bdbuf_test_print_sc (sc, true);
0247   }
0248   else if ((out & RTEMS_EVENT_1) == 0)
0249   {
0250     printf ("watch: received wrong event: %08" PRIxrtems_event_set, out);
0251   }
0252   return sc;
0253 }
0254 
0255 /**
0256  * BDBUf send wait event.
0257  */
0258 static bool
0259 bdbuf_send_watch_event (const char* task, const char* msg, rtems_id id)
0260 {
0261   printf ("%s: %s: %08" PRIxrtems_id ": ", task, msg, id);
0262   return  bdbuf_test_print_sc (rtems_event_send (id, RTEMS_EVENT_1), true);
0263 }
0264 
0265 /**
0266  * Set up a disk driver watch.
0267  */
0268 static void
0269 bdbuf_set_disk_driver_watch (bdbuf_task_control* tc, int count)
0270 {
0271   /*
0272    * Set up a disk watch and wait for the write to happen.
0273    */
0274   bdbuf_disk_lock (tc->bdd);
0275   tc->bdd->watcher_name = tc->name;
0276   tc->bdd->watcher = tc->task;
0277   tc->bdd->watch_count = count;
0278   bdbuf_disk_unlock (tc->bdd);
0279 }
0280 
0281 /**
0282  * Clear the disk driver watch.
0283  */
0284 static void
0285 bdbuf_clear_disk_driver_watch (bdbuf_task_control* tc)
0286 {
0287   /*
0288    * Set up a disk watch and wait for the write to happen.
0289    */
0290   bdbuf_disk_lock (tc->bdd);
0291   tc->bdd->watcher_name = 0;
0292   tc->bdd->watcher = 0;
0293   tc->bdd->watch_count = 0;
0294   bdbuf_disk_unlock (tc->bdd);
0295 }
0296 
0297 /**
0298  * Wait for the disk driver watch.
0299  */
0300 static bool
0301 bdbuf_disk_driver_watch_wait (bdbuf_task_control* tc, unsigned long msecs)
0302 {
0303   bool              passed = true;
0304   rtems_status_code sc = bdbuf_watch (msecs);
0305   if (sc != RTEMS_SUCCESSFUL)
0306   {
0307     printf ("%s: driver watch: driver wait: ", tc->name);
0308     passed = bdbuf_test_print_sc (sc, true);
0309   }
0310   bdbuf_clear_disk_driver_watch (tc);
0311   return passed;
0312 }
0313 
0314 /**
0315  * Set the disk driver action.
0316  */
0317 static void
0318 bdbuf_set_disk_driver_action (bdbuf_task_control* tc, bdbuf_disk_action action)
0319 {
0320   /*
0321    * Set up a disk action.
0322    */
0323   bdbuf_disk_lock (tc->bdd);
0324   tc->bdd->driver_action = action;
0325   bdbuf_disk_unlock (tc->bdd);
0326 }
0327 
0328 /**
0329  * BDBUF Sleep.
0330  */
0331 static bool
0332 bdbuf_sleep (unsigned long msecs)
0333 {
0334   rtems_status_code sc;
0335   sc = rtems_task_wake_after (RTEMS_MICROSECONDS_TO_TICKS (msecs * 1000));
0336   if (sc != RTEMS_SUCCESSFUL)
0337   {
0338     printf ("sleep wake after failed: ");
0339     bdbuf_test_print_sc (sc, true);
0340     return false;
0341   }
0342   return true;
0343 }
0344 
0345 /**
0346  * Initialise a task control.
0347  */
0348 static void
0349 bdbuf_task_control_init (int                       task,
0350                          bdbuf_task_control*       tc,
0351                          rtems_id                  master)
0352 {
0353   char name[6];
0354   sprintf (name, "bdt%d", task);
0355 
0356   tc->die    = false;
0357   tc->name   = strdup (name); /* leaks */
0358   tc->task   = 0;
0359   tc->master = master;
0360   tc->test   = 0;
0361   tc->bdd    = NULL;
0362   tc->passed = false;
0363 }
0364 
0365 static bool
0366 bdbuf_disk_ioctl_watcher (bdbuf_disk* bdd, int update)
0367 {
0368   /*
0369    * Always wake the watcher.
0370    */
0371   if (bdd->watcher)
0372   {
0373     if (bdd->watch_count)
0374     {
0375       if (update > bdd->watch_count)
0376         bdd->watch_count -= update;
0377       else
0378         bdd->watch_count = 0;
0379     }
0380 
0381     if (bdd->watch_count == 0)
0382     {
0383       bdbuf_send_watch_event (bdd->watcher_name,
0384                               "disk ioctl: wake watcher",
0385                               bdd->watcher);
0386       bdd->watcher = 0;
0387     }
0388   }
0389 
0390   return true;
0391 }
0392 
0393 
0394 static bool
0395 bdbuf_disk_ioctl_process (bdbuf_disk* bdd, rtems_blkdev_request* req)
0396 {
0397   bool result = true;
0398   int  b;
0399 
0400   /*
0401    * Perform the requested action.
0402    */
0403   switch (bdd->driver_action)
0404   {
0405     case BDBUF_DISK_NOOP:
0406       break;
0407 
0408     case BDBUF_DISK_WAIT:
0409       if (bdd->waiting)
0410         printf ("disk ioctl: bad waiter: %s:%08" PRIxrtems_id "\n",
0411                            bdd->waiting_name, bdd->waiting);
0412       bdd->waiting_name = "bdd";
0413 
0414       bdd->waiting = rtems_task_self ();
0415 
0416       if (bdbuf_disk_unlock (bdd))
0417         result = bdbuf_wait (bdd->name, 0) == RTEMS_SUCCESSFUL;
0418       else
0419         result = false;
0420 
0421       /*
0422        * Ignore any error if one happens.
0423        */
0424       bdbuf_disk_lock (bdd);
0425       break;
0426 
0427     case BDBUF_DISK_SLEEP:
0428       printf ("disk ioctl: sleeping: %" PRId32 " msecs\n",
0429                          bdd->driver_sleep);
0430       result = bdbuf_sleep (bdd->driver_sleep);
0431       break;
0432 
0433     case BDBUF_DISK_BLOCKS_INORDER:
0434       printf ("disk ioctl: multi-block order check: count = %" PRId32 "\n",
0435               req->bufnum);
0436       for (b = 0; b < (req->bufnum - 1); b++)
0437         if (req->bufs[b].block >= req->bufs[b + 1].block)
0438           printf ("disk ioctl: out of order: index:%d "\
0439                   "(%" PRIdrtems_blkdev_bnum " >= %" PRIdrtems_blkdev_bnum "\n",
0440                   b, req->bufs[b].block, req->bufs[b + 1].block);
0441       break;
0442 
0443     default:
0444       printf ("disk ioctl: invalid action: %d\n",
0445                          bdd->driver_action);
0446       result = false;
0447       break;
0448   }
0449 
0450   return result;
0451 }
0452 
0453 static bool
0454 bdbuf_disk_ioctl_leave (bdbuf_disk* bdd, int buffer_count)
0455 {
0456   /*
0457    * Handle the watcher.
0458    */
0459   bdbuf_disk_ioctl_watcher (bdd, buffer_count);
0460 
0461   return true;
0462 }
0463 
0464 /**
0465  * BDBuf disk IOCTL handler.
0466  *
0467  * @param dd Disk device.
0468  * @param req IOCTL request code.
0469  * @param argp IOCTL argument.
0470  * @retval The IOCTL return value
0471  */
0472 static int
0473 bdbuf_disk_ioctl (rtems_disk_device *dd, uint32_t req, void* argp)
0474 {
0475   rtems_blkdev_request *r = argp;
0476   bdbuf_disk           *bdd = rtems_disk_get_driver_data (dd);
0477 
0478   errno = 0;
0479 
0480   if (!bdbuf_disk_lock (bdd))
0481   {
0482     errno = EIO;
0483   }
0484   else
0485   {
0486     switch (req)
0487     {
0488       case RTEMS_BLKIO_REQUEST:
0489         switch (r->req)
0490         {
0491           case RTEMS_BLKDEV_REQ_READ:
0492             if (!bdbuf_disk_ioctl_process (bdd, r))
0493               rtems_blkdev_request_done(r, RTEMS_IO_ERROR);
0494             else
0495             {
0496               rtems_blkdev_sg_buffer* sg = r->bufs;
0497               uint32_t                block = RTEMS_BLKDEV_START_BLOCK (r);
0498               uint32_t                b;
0499               int32_t                 remains;
0500 
0501               remains = r->bufnum * bdd->block_size;
0502 
0503               for (b = 0; b < r->bufnum; b++, block++, sg++)
0504               {
0505                 uint32_t length = sg->length;
0506 
0507                 if (sg->length != bdd->block_size)
0508                   if (length > bdd->block_size)
0509                     length = bdd->block_size;
0510 
0511                 memset (sg->buffer, block, length);
0512 
0513                 remains -= length;
0514               }
0515 
0516               rtems_blkdev_request_done (r, RTEMS_SUCCESSFUL);
0517             }
0518             bdbuf_disk_ioctl_leave (bdd, r->bufnum);
0519             break;
0520 
0521           case RTEMS_BLKDEV_REQ_WRITE:
0522             if (!bdbuf_disk_ioctl_process (bdd, r))
0523               rtems_blkdev_request_done(r, RTEMS_IO_ERROR);
0524             else
0525               rtems_blkdev_request_done(r, RTEMS_SUCCESSFUL);
0526             bdbuf_disk_ioctl_leave (bdd, r->bufnum);
0527             break;
0528 
0529           default:
0530             errno = EINVAL;
0531             break;
0532         }
0533         break;
0534 
0535       default:
0536         rtems_blkdev_ioctl (dd, req, argp);
0537         break;
0538     }
0539 
0540     if (!bdbuf_disk_unlock (bdd))
0541       errno = EIO;
0542   }
0543 
0544   return errno == 0 ? 0 : -1;
0545 }
0546 
0547 static rtems_status_code
0548 bdbuf_disk_initialize(void)
0549 {
0550   uint32_t minor;
0551 
0552   printf ("register disks\n");
0553 
0554   for (minor = 0; minor < BDBUF_DISKS; minor++)
0555   {
0556     char              name[sizeof (BDBUF_DISK_DEVICE_BASE_NAME) + 10];
0557     bdbuf_disk*       bdd = &bdbuf_disks[minor];
0558     rtems_status_code sc;
0559     int               fd;
0560     int               rv;
0561 
0562     snprintf (name, sizeof (name),
0563               BDBUF_DISK_DEVICE_BASE_NAME "%" PRIu32, minor);
0564 
0565     bdd->name = strdup (name);
0566     bdd->minor = minor;
0567 
0568     printf ("disk init: %s\n", bdd->name);
0569     printf ("disk lock: ");
0570 
0571     sc = rtems_semaphore_create (rtems_build_name ('B', 'D', 'D', 'K'), 1,
0572                                  RTEMS_PRIORITY | RTEMS_BINARY_SEMAPHORE |
0573                                  RTEMS_INHERIT_PRIORITY, 0, &bdd->lock);
0574     if (!bdbuf_test_print_sc (sc, true))
0575       return RTEMS_IO_ERROR;
0576 
0577     bdd->block_size  = 512 * (minor + 1);
0578     bdd->block_count = BDBUF_SIZE * (minor + 1);
0579 
0580     sc = rtems_blkdev_create(name, bdd->block_size, bdd->block_count,
0581                              bdbuf_disk_ioctl, bdd);
0582     if (sc != RTEMS_SUCCESSFUL)
0583     {
0584       printf ("disk init: create phys failed: ");
0585       bdbuf_test_print_sc (sc, true);
0586       return sc;
0587     }
0588 
0589     fd = open(name, O_RDWR);
0590     rtems_test_assert(fd >= 0);
0591 
0592     rv = rtems_disk_fd_get_disk_device(fd, &bdd->dd);
0593     rtems_test_assert(rv == 0);
0594 
0595     rv = close(fd);
0596     rtems_test_assert(rv == 0);
0597   }
0598 
0599   return RTEMS_SUCCESSFUL;
0600 }
0601 
0602 static bool
0603 bdbuf_tests_create_task (bdbuf_task_control* tc,
0604                          rtems_task_priority priority,
0605                          rtems_task_entry    entry_point)
0606 {
0607   rtems_status_code sc;
0608 
0609   printf ("creating task: %s: priority: %" PRIdrtems_task_priority ": ",
0610                      tc->name, priority);
0611 
0612   sc = rtems_task_create (rtems_build_name (tc->name[0], tc->name[1],
0613                                             tc->name[2], tc->name[3]),
0614                           priority,
0615                           BDBUF_TEST_STACK_SIZE,
0616                           RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
0617                           RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR,
0618                           &tc->task);
0619   if (!bdbuf_test_print_sc (sc, true))
0620     return false;
0621 
0622   printf ("starting task: %s: ", tc->name);
0623 
0624   sc = rtems_task_start (tc->task, entry_point, (rtems_task_argument) tc);
0625 
0626   return bdbuf_test_print_sc (sc, true);
0627 }
0628 
0629 /**
0630  * Get the block 0 buffer twice. The first time it is requested it
0631  * will be taken from the empty list and returned to the LRU list.
0632  * The second time it will be removed from the LRU list.
0633  */
0634 static void
0635 bdbuf_tests_task_0_test_1 (bdbuf_task_control* tc)
0636 {
0637   rtems_status_code   sc;
0638   bool                passed;
0639   int                 i;
0640   rtems_bdbuf_buffer* bd;
0641 
0642   /*
0643    * Set task control's passed to false to handle a timeout.
0644    */
0645   tc->passed = false;
0646   passed = true;
0647 
0648   for (i = 0; (i < 2) && passed; i++)
0649   {
0650     printf ("%s: rtems_bdbuf_get[0]: ", tc->name);
0651     sc = rtems_bdbuf_get (tc->bdd->dd, 0, &bd);
0652     if (!bdbuf_test_print_sc (sc, true))
0653     {
0654       passed = false;
0655       break;
0656     }
0657 
0658     printf ("%s: rtems_bdbuf_release[0]: ", tc->name);
0659     sc = rtems_bdbuf_release (bd);
0660     if (!bdbuf_test_print_sc (sc, true))
0661     {
0662       passed = false;
0663       break;
0664     }
0665   }
0666 
0667   tc->passed = passed;
0668   tc->test = 0;
0669 }
0670 
0671 /**
0672  * Get the blocks 0 -> 4 and hold them. Wake the master to tell it was have the
0673  * buffers then wait for the master to tell us to release a single buffer.
0674  * Task 1 will be block waiting for each buffer. It is a higher priority.
0675  */
0676 static void
0677 bdbuf_tests_task_0_test_2 (bdbuf_task_control* tc)
0678 {
0679   rtems_status_code   sc;
0680   bool                passed;
0681   int                 i;
0682   rtems_bdbuf_buffer* bd;
0683   rtems_chain_control buffers;
0684 
0685   /*
0686    * Set task control's passed to false to handle a timeout.
0687    */
0688   tc->passed = false;
0689   passed = true;
0690 
0691   /*
0692    * Get the blocks 0 -> 4 and hold them.
0693    */
0694   rtems_chain_initialize_empty (&buffers);
0695 
0696   for (i = 0; (i < 5) && passed; i++)
0697   {
0698     printf ("%s: rtems_bdbuf_get[%d]: ", tc->name, i);
0699     sc = rtems_bdbuf_get (tc->bdd->dd, i, &bd);
0700     if (!bdbuf_test_print_sc (sc, true))
0701       passed = false;
0702 
0703     rtems_chain_append (&buffers, &bd->link);
0704   }
0705 
0706   /*
0707    * Wake the master to tell it we have the buffers.
0708    */
0709   bdbuf_send_wait_event (tc->name, "wake master", tc->master);
0710 
0711   if (passed)
0712   {
0713     /*
0714      * For each buffer we hold wait until the master wakes us
0715      * and then return it. Task 2 will block waiting for this
0716      * buffer. It is a higher priority task.
0717      */
0718     for (i = 0; (i < 5) && passed; i++)
0719     {
0720       sc = bdbuf_wait (tc->name, BDBUF_SECONDS (5));
0721       if (sc != RTEMS_SUCCESSFUL)
0722       {
0723         printf ("%s: wait failed: ", tc->name);
0724         bdbuf_test_print_sc (sc, true);
0725         passed = false;
0726         break;
0727       }
0728       else
0729       {
0730         printf ("%s: rtems_bdbuf_release[%d]: unblocks task 1\n",
0731                            tc->name, i);
0732         bd = (rtems_bdbuf_buffer*) rtems_chain_get (&buffers);
0733         sc = rtems_bdbuf_release (bd);
0734         printf ("%s: rtems_bdbuf_release[%d]: ", tc->name, i);
0735         if (!bdbuf_test_print_sc (sc, true))
0736         {
0737           passed = false;
0738           break;
0739         }
0740       }
0741     }
0742   }
0743 
0744   tc->passed = passed;
0745   tc->test = 0;
0746 }
0747 
0748 /**
0749  * Read the block 5 from the disk modify it then release it modified.
0750  */
0751 static void
0752 bdbuf_tests_task_0_test_3 (bdbuf_task_control* tc)
0753 {
0754   rtems_status_code   sc;
0755   bool                passed;
0756   rtems_bdbuf_buffer* bd;
0757 
0758   /*
0759    * Set task control's passed to false to handle a timeout.
0760    */
0761   tc->passed = false;
0762   passed = true;
0763 
0764   bdbuf_disk_lock (tc->bdd);
0765   tc->bdd->driver_action = BDBUF_DISK_NOOP;
0766   bdbuf_disk_unlock (tc->bdd);
0767 
0768   /*
0769    * Read the buffer and then release it.
0770    */
0771   printf ("%s: rtems_bdbuf_read[5]: ", tc->name);
0772   sc = rtems_bdbuf_read (tc->bdd->dd, 5, &bd);
0773   if ((passed = bdbuf_test_print_sc (sc, true)))
0774   {
0775     printf ("%s: rtems_bdbuf_release_modified[5]: ", tc->name);
0776     sc = rtems_bdbuf_release_modified (bd);
0777     passed = bdbuf_test_print_sc (sc, true);
0778   }
0779 
0780   /*
0781    * Read the buffer again and then just release. The buffer should
0782    * be maintained as modified.
0783    */
0784   printf ("%s: rtems_bdbuf_read[5]: ", tc->name);
0785   sc = rtems_bdbuf_read (tc->bdd->dd, 5, &bd);
0786   if ((passed = bdbuf_test_print_sc (sc, true)))
0787   {
0788     printf ("%s: rtems_bdbuf_release[5]: ", tc->name);
0789     sc = rtems_bdbuf_release (bd);
0790     passed = bdbuf_test_print_sc (sc, true);
0791   }
0792 
0793   /*
0794    * Set up a disk watch and wait for the write to happen.
0795    */
0796   bdbuf_set_disk_driver_watch (tc, 1);
0797   passed = bdbuf_disk_driver_watch_wait (tc, BDBUF_SECONDS (5));
0798 
0799   tc->passed = passed;
0800   tc->test = 0;
0801 }
0802 
0803 static size_t
0804 bdbuf_test_buffer_count (void)
0805 {
0806   return rtems_bdbuf_configuration.size / rtems_bdbuf_configuration.buffer_min;
0807 }
0808 
0809 /**
0810  * Get all the blocks in the pool and hold them. Wake the master to tell it was
0811  * have the buffers then wait for the master to tell us to release them.
0812  */
0813 static void
0814 bdbuf_tests_task_0_test_4 (bdbuf_task_control* tc)
0815 {
0816   rtems_status_code   sc;
0817   bool                passed;
0818   size_t              i;
0819   rtems_bdbuf_buffer* bd;
0820   rtems_chain_control buffers;
0821   size_t              num = bdbuf_test_buffer_count ();
0822 
0823   /*
0824    * Set task control's passed to false to handle a timeout.
0825    */
0826   tc->passed = false;
0827   passed = true;
0828 
0829   /*
0830    * Clear any disk settings.
0831    */
0832   bdbuf_clear_disk_driver_watch (tc);
0833   bdbuf_set_disk_driver_action (tc, BDBUF_DISK_NOOP);
0834 
0835   /*
0836    * Get the blocks 0 -> 4 and hold them.
0837    */
0838   rtems_chain_initialize_empty (&buffers);
0839 
0840   for (i = 0; (i < num) && passed; i++)
0841   {
0842     printf ("%s: rtems_bdbuf_read[%zd]: ", tc->name, i);
0843     sc = rtems_bdbuf_read (tc->bdd->dd, i, &bd);
0844     if (!bdbuf_test_print_sc (sc, true))
0845       passed = false;
0846 
0847     rtems_chain_append (&buffers, &bd->link);
0848   }
0849 
0850   /*
0851    * Wake the master to tell it we have the buffers.
0852    */
0853   bdbuf_send_wait_event (tc->name, "wake master", tc->master);
0854 
0855   if (passed)
0856   {
0857     bdbuf_sleep (250);
0858 
0859     bdbuf_set_disk_driver_watch (tc, num / 2);
0860 
0861     /*
0862      * Release half the buffers, wait 500msecs then release the
0863      * remainder. This tests the swap out timer on each buffer.
0864      */
0865     printf ("%s: rtems_bdbuf_release_modified[0]: unblocks task 1\n",
0866                        tc->name);
0867     bd = (rtems_bdbuf_buffer*) rtems_chain_get (&buffers);
0868     sc = rtems_bdbuf_release_modified (bd);
0869     printf ("%s: rtems_bdbuf_release_modified[0]: ", tc->name);
0870     passed = bdbuf_test_print_sc (sc, true);
0871     if (passed)
0872     {
0873       for (i = 1; (i < (num / 2)) && passed; i++)
0874       {
0875         printf ("%s: rtems_bdbuf_release_modified[%zd]: " \
0876                            "unblocks task 1\n", tc->name, i);
0877         bd = (rtems_bdbuf_buffer*) rtems_chain_get (&buffers);
0878         sc = rtems_bdbuf_release_modified (bd);
0879         printf ("%s: rtems_bdbuf_release_modified[%zd]: ", tc->name, i);
0880         passed = bdbuf_test_print_sc (sc, true);
0881         if (!passed)
0882           break;
0883       }
0884 
0885       if (passed)
0886       {
0887         passed = bdbuf_disk_driver_watch_wait (tc, BDBUF_SECONDS (5));
0888 
0889         if (passed)
0890         {
0891           bdbuf_sleep (500);
0892 
0893           bdbuf_set_disk_driver_watch (tc, num / 2);
0894 
0895           for (i = 0; (i < (num / 2)) && passed; i++)
0896           {
0897             printf ("%s: rtems_bdbuf_release_modified[%zd]: ",
0898                                tc->name, i + (num / 2));
0899             bd = (rtems_bdbuf_buffer*) rtems_chain_get (&buffers);
0900             passed = bdbuf_test_print_sc (rtems_bdbuf_release_modified (bd),
0901                                           true);
0902             if (!passed)
0903               break;
0904           }
0905 
0906           passed = bdbuf_disk_driver_watch_wait (tc, BDBUF_SECONDS (5));
0907 
0908           if (passed)
0909           {
0910             if (!rtems_chain_is_empty (&buffers))
0911             {
0912               passed = false;
0913               printf ("%s: buffer chain not empty\n", tc->name);
0914             }
0915           }
0916         }
0917       }
0918     }
0919   }
0920 
0921   tc->passed = passed;
0922   tc->test = 0;
0923 }
0924 
0925 static void
0926 bdbuf_tests_task_0_test_5 (bdbuf_task_control* tc)
0927 {
0928   bdbuf_tests_task_0_test_4 (tc);
0929 }
0930 
0931 static void
0932 bdbuf_tests_task_0_test_6 (bdbuf_task_control* tc)
0933 {
0934   rtems_status_code   sc;
0935   bool                passed;
0936   int                 i;
0937   rtems_bdbuf_buffer* bd;
0938   rtems_chain_control buffers;
0939 
0940   /*
0941    * Set task control's passed to false to handle a timeout.
0942    */
0943   tc->passed = false;
0944   passed = true;
0945 
0946   /*
0947    * Clear any disk settings.
0948    */
0949   bdbuf_clear_disk_driver_watch (tc);
0950   bdbuf_set_disk_driver_action (tc, BDBUF_DISK_NOOP);
0951 
0952   /*
0953    * Get the blocks 0 -> 4 and hold them.
0954    */
0955   rtems_chain_initialize_empty (&buffers);
0956 
0957   for (i = 0; (i < 5) && passed; i++)
0958   {
0959     printf ("%s: rtems_bdbuf_read[%d]: ", tc->name, i);
0960     sc = rtems_bdbuf_get (tc->bdd->dd, i, &bd);
0961     if (!bdbuf_test_print_sc (sc, true))
0962       passed = false;
0963 
0964     rtems_chain_append (&buffers, &bd->link);
0965   }
0966 
0967   for (i = 0; (i < 4) && passed; i++)
0968   {
0969     printf ("%s: rtems_bdbuf_release_modified[%d]: ",
0970                        tc->name, i);
0971     bd = (rtems_bdbuf_buffer*) rtems_chain_get (&buffers);
0972     passed = bdbuf_test_print_sc (rtems_bdbuf_release_modified (bd),
0973                                   true);
0974   }
0975 
0976   if (passed)
0977   {
0978     printf ("%s: rtems_bdbuf_sync[%d]: ", tc->name, i);
0979     bd = (rtems_bdbuf_buffer*) rtems_chain_get (&buffers);
0980 
0981     passed = bdbuf_test_print_sc (rtems_bdbuf_sync (bd), true);
0982   }
0983 
0984   tc->passed = passed;
0985   tc->test = 0;
0986 }
0987 
0988 static void
0989 bdbuf_tests_task_0_test_7 (bdbuf_task_control* tc)
0990 {
0991   rtems_status_code   sc;
0992   bool                passed;
0993   int                 i;
0994   rtems_bdbuf_buffer* bd;
0995   rtems_chain_control buffers;
0996 
0997   /*
0998    * Set task control's passed to false to handle a timeout.
0999    */
1000   tc->passed = false;
1001   passed = true;
1002 
1003   /*
1004    * Clear any disk settings.
1005    */
1006   bdbuf_clear_disk_driver_watch (tc);
1007   bdbuf_set_disk_driver_action (tc, BDBUF_DISK_NOOP);
1008 
1009   /*
1010    * Get the blocks 0 -> 4 and hold them.
1011    */
1012   rtems_chain_initialize_empty (&buffers);
1013 
1014   for (i = 0; (i < 5) && passed; i++)
1015   {
1016     printf ("%s: rtems_bdbuf_read[%d]: ", tc->name, i);
1017     sc = rtems_bdbuf_get (tc->bdd->dd, i, &bd);
1018     if (!bdbuf_test_print_sc (sc, true))
1019       passed = false;
1020 
1021     rtems_chain_append (&buffers, &bd->link);
1022   }
1023 
1024   for (i = 0; (i < 5) && passed; i++)
1025   {
1026     printf ("%s: rtems_bdbuf_release_modified[%d]: ",
1027                        tc->name, i);
1028     bd = (rtems_bdbuf_buffer*) rtems_chain_get (&buffers);
1029     passed = bdbuf_test_print_sc (rtems_bdbuf_release_modified (bd),
1030                                   true);
1031   }
1032 
1033   if (passed)
1034   {
1035     printf ("%s: rtems_bdbuf_syncdev[%" PRIu32 ": ",
1036                        tc->name,
1037                        tc->bdd->minor);
1038     passed = bdbuf_test_print_sc (rtems_bdbuf_syncdev (tc->bdd->dd), true);
1039   }
1040 
1041   tc->passed = passed;
1042   tc->test = 0;
1043 }
1044 
1045 static void
1046 bdbuf_tests_task_0_test_8 (bdbuf_task_control* tc)
1047 {
1048   rtems_status_code   sc;
1049   bool                passed;
1050   int                 i;
1051   rtems_bdbuf_buffer* bd;
1052   rtems_chain_control buffers;
1053   rtems_chain_node*   node;
1054   rtems_chain_node*   pnode;
1055 
1056   /*
1057    * Set task control's passed to false to handle a timeout.
1058    */
1059   tc->passed = false;
1060   passed = true;
1061 
1062   /*
1063    * Clear any disk settings.
1064    */
1065   bdbuf_clear_disk_driver_watch (tc);
1066   bdbuf_set_disk_driver_action (tc, BDBUF_DISK_NOOP);
1067 
1068   /*
1069    * Get the blocks 0 -> 4 and hold them.
1070    */
1071   rtems_chain_initialize_empty (&buffers);
1072 
1073   for (i = 0; (i < 5) && passed; i++)
1074   {
1075     printf ("%s: rtems_bdbuf_read[%d]: ", tc->name, i);
1076     sc = rtems_bdbuf_get (tc->bdd->dd, i, &bd);
1077     if (!bdbuf_test_print_sc (sc, true))
1078       passed = false;
1079 
1080     rtems_chain_append (&buffers, &bd->link);
1081   }
1082 
1083   node = rtems_chain_tail (&buffers);
1084   node = node->previous;
1085 
1086   bd = (rtems_bdbuf_buffer*) node;
1087   pnode = node->previous;
1088   rtems_chain_extract (node);
1089   node = pnode;
1090   printf ("%s: rtems_bdbuf_release_modified[4]: ", tc->name);
1091   passed = bdbuf_test_print_sc (rtems_bdbuf_release_modified (bd), true);
1092 
1093   bd = (rtems_bdbuf_buffer*) node;
1094   pnode = node->previous;
1095   rtems_chain_extract (node);
1096   node = pnode;
1097   printf ("%s: rtems_bdbuf_release_modified[3]: ", tc->name);
1098   passed = bdbuf_test_print_sc (rtems_bdbuf_release_modified (bd), true);
1099 
1100   for (i = 0; (i < 3) && passed; i++)
1101   {
1102     printf ("%s: rtems_bdbuf_release_modified[%d]: ",
1103                        tc->name, i);
1104     bd = (rtems_bdbuf_buffer*) rtems_chain_get (&buffers);
1105     passed = bdbuf_test_print_sc (rtems_bdbuf_release_modified (bd),
1106                                   true);
1107   }
1108 
1109   if (passed)
1110   {
1111     /*
1112      * Check the block order.
1113      */
1114     bdbuf_set_disk_driver_action (tc, BDBUF_DISK_BLOCKS_INORDER);
1115 
1116     printf ("%s: rtems_bdbuf_syncdev[%" PRIu32 "]: checking order\n",
1117                        tc->name,
1118                        tc->bdd->minor);
1119     sc = rtems_bdbuf_syncdev (tc->bdd->dd);
1120     printf ("%s: rtems_bdbuf_syncdev[%" PRIu32 "]: ",
1121                        tc->name,
1122                        tc->bdd->minor);
1123     passed = bdbuf_test_print_sc (sc, true);
1124   }
1125 
1126   tc->passed = passed;
1127   tc->test = 0;
1128 }
1129 
1130 static void
1131 bdbuf_tests_task_0 (rtems_task_argument arg)
1132 {
1133   bdbuf_task_control* tc = (bdbuf_task_control*) arg;
1134 
1135   while (!tc->die)
1136   {
1137     switch (tc->test)
1138     {
1139       case 0:
1140         /*
1141          * Wait for the next test.
1142          */
1143         bdbuf_wait (tc->name, 0);
1144         break;
1145 
1146       case 1:
1147         bdbuf_tests_task_0_test_1 (tc);
1148         break;
1149 
1150       case 2:
1151         bdbuf_tests_task_0_test_2 (tc);
1152         break;
1153 
1154       case 3:
1155         bdbuf_tests_task_0_test_3 (tc);
1156         break;
1157 
1158       case 4:
1159         bdbuf_tests_task_0_test_4 (tc);
1160         break;
1161 
1162       case 5:
1163         bdbuf_tests_task_0_test_5 (tc);
1164         break;
1165 
1166       case 6:
1167         bdbuf_tests_task_0_test_6 (tc);
1168         break;
1169 
1170       case 7:
1171         bdbuf_tests_task_0_test_7 (tc);
1172         break;
1173 
1174       case 8:
1175         bdbuf_tests_task_0_test_8 (tc);
1176         break;
1177 
1178       default:
1179         /*
1180          * Invalid test for this task. An error.
1181          */
1182         printf ("%s: invalid test: %d\n", tc->name, tc->test);
1183         tc->passed = false;
1184         tc->test = 0;
1185         break;
1186     }
1187   }
1188 
1189   printf ("%s: delete task\n", tc->name);
1190   rtems_task_exit();
1191 }
1192 
1193 /**
1194  * Get the blocks 0 -> 4 and release them. Task 0 should be holding
1195  * each one.
1196  */
1197 static void
1198 bdbuf_tests_ranged_get_release (bdbuf_task_control* tc,
1199                                 bool                wake_master,
1200                                 int                 lower,
1201                                 int                 upper)
1202 {
1203   rtems_status_code   sc;
1204   bool                passed;
1205   int                 i;
1206   rtems_bdbuf_buffer* bd;
1207 
1208   /*
1209    * Set task control's passed to false to handle a timeout.
1210    */
1211   tc->passed = false;
1212   passed = true;
1213 
1214   for (i = lower; (i < upper) && passed; i++)
1215   {
1216     printf ("%s: rtems_bdbuf_get[%d]: blocking ...\n", tc->name, i);
1217     sc = rtems_bdbuf_get (tc->bdd->dd, i, &bd);
1218     printf ("%s: rtems_bdbuf_get[%d]: ", tc->name, i);
1219     if (!bdbuf_test_print_sc (sc, true))
1220     {
1221       passed = false;
1222       break;
1223     }
1224 
1225     printf ("%s: rtems_bdbuf_release[%d]: ", tc->name, i);
1226     sc = rtems_bdbuf_release (bd);
1227     if (!bdbuf_test_print_sc (sc, true))
1228     {
1229       passed = false;
1230       break;
1231     }
1232 
1233     /*
1234      * Wake the master to tell it we have finished.
1235      */
1236     if (wake_master)
1237       bdbuf_send_wait_event (tc->name, "wake master", tc->master);
1238   }
1239 
1240   tc->passed = passed;
1241   tc->test = 0;
1242 }
1243 
1244 static void
1245 bdbuf_tests_task_1 (rtems_task_argument arg)
1246 {
1247   bdbuf_task_control* tc = (bdbuf_task_control*) arg;
1248 
1249   while (!tc->die)
1250   {
1251     switch (tc->test)
1252     {
1253       case 0:
1254         /*
1255          * Wait for the next test.
1256          */
1257         bdbuf_wait (tc->name, 0);
1258         break;
1259 
1260       case 2:
1261         bdbuf_tests_ranged_get_release (tc, false, 0, 5);
1262         break;
1263 
1264       case 4:
1265         bdbuf_tests_ranged_get_release (tc, false, 0, 9);
1266         break;
1267 
1268       case 5:
1269         bdbuf_tests_ranged_get_release (tc, false, 20, 25);
1270         break;
1271 
1272       default:
1273         /*
1274          * Invalid test for this task. An error.
1275          */
1276         printf ("%s: invalid test: %d\n", tc->name, tc->test);
1277         tc->passed = false;
1278         tc->test = 0;
1279         break;
1280     }
1281   }
1282 
1283   printf ("%s: delete task\n", tc->name);
1284   rtems_task_exit();
1285 }
1286 
1287 /**
1288  * Get the blocks 0 -> 4 and release them. Task 0 should be holding
1289  * each one.
1290  */
1291 static void
1292 bdbuf_tests_task_2_test_2 (bdbuf_task_control* tc)
1293 {
1294   /*
1295    * Use task 1's test 2. They are the same.
1296    */
1297   bdbuf_tests_ranged_get_release (tc, true, 0, 5);
1298 }
1299 
1300 static void
1301 bdbuf_tests_task_2 (rtems_task_argument arg)
1302 {
1303   bdbuf_task_control* tc = (bdbuf_task_control*) arg;
1304 
1305   while (!tc->die)
1306   {
1307     switch (tc->test)
1308     {
1309       case 0:
1310         /*
1311          * Wait for the next test.
1312          */
1313         bdbuf_wait (tc->name, 0);
1314         break;
1315 
1316       case 2:
1317         bdbuf_tests_task_2_test_2 (tc);
1318         break;
1319 
1320       default:
1321         /*
1322          * Invalid test for this task. An error.
1323          */
1324         printf ("%s: invalid test: %d\n", tc->name, tc->test);
1325         tc->passed = false;
1326         tc->test = 0;
1327         break;
1328     }
1329   }
1330 
1331   printf ("%s: delete task\n", tc->name);
1332   rtems_task_exit();
1333 }
1334 
1335 /**
1336  * Table of task entry points.
1337  */
1338 static rtems_task_entry bdbuf_test_tasks[] =
1339 {
1340   bdbuf_tests_task_0,
1341   bdbuf_tests_task_1,
1342   bdbuf_tests_task_2
1343 };
1344 
1345 #define BDBUF_TESTS_PRI_HIGH (30)
1346 
1347 /**
1348  * Wait for the all tests to finish. This is signalled by the test
1349  * number becoming 0.
1350  */
1351 static bool
1352 bdbuf_tests_finished (bdbuf_task_control* tasks)
1353 {
1354   uint32_t time = 0;
1355   bool     finished = false;
1356 
1357   while (time < (10 * 4))
1358   {
1359     int t;
1360 
1361     finished = true;
1362 
1363     for (t = 0; t < BDBUF_TEST_TASKS; t++)
1364       if (tasks[t].test)
1365       {
1366         finished = false;
1367         break;
1368       }
1369 
1370     if (finished)
1371       break;
1372 
1373     bdbuf_sleep (250);
1374     time++;
1375   }
1376 
1377   if (!finished)
1378     printf ("master: test timed out\n");
1379   else
1380   {
1381     int t;
1382     for (t = 0; t < BDBUF_TEST_TASKS; t++)
1383       if (!tasks[0].passed)
1384       {
1385         finished = false;
1386         break;
1387       }
1388   }
1389 
1390   return finished;
1391 }
1392 
1393 /**
1394  * Test 1.
1395  *
1396  * # Get task 0 to get buffer 0 from the pool then release it twice.
1397  */
1398 static bool
1399 bdbuf_test_1 (bdbuf_task_control* tasks)
1400 {
1401   tasks[0].test = 1;
1402 
1403   /*
1404    * Use pool 0.
1405    */
1406   tasks[0].bdd = &bdbuf_disks[0];
1407 
1408   bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
1409 
1410   return bdbuf_tests_finished (tasks);
1411 }
1412 
1413 /**
1414  * Test 2.
1415  *
1416  * # Get task 0 to get buffers 0 -> 4 from the pool hold them. Then get
1417  * task 1 and task 2 to get them with blocking. The 2 tasks tests the
1418  * priority blocking on the buffer.
1419  */
1420 static bool
1421 bdbuf_test_2 (bdbuf_task_control* tasks)
1422 {
1423   int i;
1424 
1425   tasks[0].test = 2;
1426   tasks[1].test = 2;
1427   tasks[2].test = 2;
1428 
1429   /*
1430    * Use pool 0.
1431    */
1432   tasks[0].bdd = &bdbuf_disks[0];
1433   tasks[1].bdd = &bdbuf_disks[0];
1434   tasks[2].bdd = &bdbuf_disks[0];
1435 
1436   /*
1437    * Wake task 0 and wait for it to have all the buffers.
1438    */
1439   bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
1440   if (bdbuf_wait ("master", BDBUF_SECONDS (5)) != RTEMS_SUCCESSFUL)
1441     return false;
1442 
1443   /*
1444    * Wake task 1.
1445    */
1446   bdbuf_send_wait_event ("master", "wake task 1", tasks[1].task);
1447 
1448   /*
1449    * Wake task 2.
1450    */
1451   bdbuf_send_wait_event ("master", "wake task 2", tasks[2].task);
1452 
1453   for (i = 0; i < 5; i++)
1454   {
1455     /*
1456      * Wake task 0 and watch task 2 then task 1 get the released buffer.
1457      */
1458     bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
1459 
1460     /*
1461      * Wait until task 2 has the buffer.
1462      */
1463     if (bdbuf_wait ("master", BDBUF_SECONDS (5)) != RTEMS_SUCCESSFUL)
1464       return false;
1465   }
1466 
1467   /*
1468    * Wait for the tests to finish.
1469    */
1470   return bdbuf_tests_finished (tasks);
1471 }
1472 
1473 /**
1474  * Test 3.
1475  *
1476  * # Read a block from disk into the buffer, modify the block and release
1477  * it modified. Use a block great then 4 because 0 -> 4 are in the cache.
1478  */
1479 static bool
1480 bdbuf_test_3 (bdbuf_task_control* tasks)
1481 {
1482   tasks[0].test = 3;
1483 
1484   /*
1485    * Use pool 0.
1486    */
1487   tasks[0].bdd = &bdbuf_disks[0];
1488 
1489   /*
1490    * Wake task 0.
1491    */
1492   bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
1493 
1494   return bdbuf_tests_finished (tasks);
1495 }
1496 
1497 /**
1498  * Test 4.
1499  *
1500  * # Read every buffer in the pool and hold. Then get task 1 to ask for another
1501  *   buffer that is being accessed. It will block waiting for it to appear.
1502  */
1503 static bool
1504 bdbuf_test_4 (bdbuf_task_control* tasks)
1505 {
1506   tasks[0].test = 4;
1507   tasks[1].test = 4;
1508 
1509   /*
1510    * Use pool 0.
1511    */
1512   tasks[0].bdd = &bdbuf_disks[0];
1513   tasks[1].bdd = &bdbuf_disks[0];
1514 
1515   /*
1516    * Wake task 0.
1517    */
1518   bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
1519 
1520   /*
1521    * Wait for the buffers in the pool to be taken.
1522    */
1523   if (bdbuf_wait ("master", BDBUF_SECONDS (5)) != RTEMS_SUCCESSFUL)
1524     return false;
1525 
1526   bdbuf_sleep (100);
1527 
1528   /*
1529    * Wake task 1 to read another one and have to block.
1530    */
1531   bdbuf_send_wait_event ("master", "wake task 1", tasks[1].task);
1532 
1533   bdbuf_sleep (100);
1534 
1535   /*
1536    * Wake task 0 to release it buffers.
1537    */
1538   bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
1539 
1540   return bdbuf_tests_finished (tasks);
1541 }
1542 
1543 /**
1544  * Test 5.
1545  *
1546  * # Read every buffer in the pool and hold. Then get task 1 to ask for a new
1547  *   buffer. It will block waiting for one to appear.
1548  */
1549 static bool
1550 bdbuf_test_5 (bdbuf_task_control* tasks)
1551 {
1552   tasks[0].test = 5;
1553   tasks[1].test = 5;
1554 
1555   /*
1556    * Use pool 0.
1557    */
1558   tasks[0].bdd = &bdbuf_disks[0];
1559   tasks[1].bdd = &bdbuf_disks[0];
1560 
1561   /*
1562    * Wake task 0.
1563    */
1564   bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
1565 
1566   /*
1567    * Wait for the buffers in the pool to be taken.
1568    */
1569   if (bdbuf_wait ("master", BDBUF_SECONDS (5)) != RTEMS_SUCCESSFUL)
1570     return false;
1571 
1572   bdbuf_sleep (100);
1573 
1574   /*
1575    * Wake task 1 to read another one and have to block.
1576    */
1577   bdbuf_send_wait_event ("master", "wake task 1", tasks[1].task);
1578 
1579   bdbuf_sleep (100);
1580 
1581   /*
1582    * Wake task 0 to release it buffers.
1583    */
1584   bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
1585 
1586   return bdbuf_tests_finished (tasks);
1587 }
1588 
1589 /**
1590  * Test 6.
1591  *
1592  * # Get 5 buffers, release modify 4 then sync the last.
1593  */
1594 static bool
1595 bdbuf_test_6 (bdbuf_task_control* tasks)
1596 {
1597   tasks[0].test = 6;
1598 
1599   /*
1600    * Use pool 0.
1601    */
1602   tasks[0].bdd = &bdbuf_disks[0];
1603 
1604   /*
1605    * Wake task 0.
1606    */
1607   bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
1608 
1609   return bdbuf_tests_finished (tasks);
1610 }
1611 
1612 /**
1613  * Test 7.
1614  *
1615  * # Get 5 buffers, release modify them all then sync the device.
1616  */
1617 static bool
1618 bdbuf_test_7 (bdbuf_task_control* tasks)
1619 {
1620   tasks[0].test = 7;
1621 
1622   /*
1623    * Use pool 0.
1624    */
1625   tasks[0].bdd = &bdbuf_disks[0];
1626 
1627   /*
1628    * Wake task 0.
1629    */
1630   bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
1631 
1632   return bdbuf_tests_finished (tasks);
1633 }
1634 
1635 /**
1636  * Test 8.
1637  *
1638  * # Get 5 buffers, release modify the last 2 then the reset from 0.
1639  */
1640 static bool
1641 bdbuf_test_8 (bdbuf_task_control* tasks)
1642 {
1643   tasks[0].test = 8;
1644 
1645   /*
1646    * Use pool 0.
1647    */
1648   tasks[0].bdd = &bdbuf_disks[0];
1649 
1650   /*
1651    * Wake task 0.
1652    */
1653   bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
1654 
1655   return bdbuf_tests_finished (tasks);
1656 }
1657 
1658 /**
1659  * A test.
1660  */
1661 typedef bool (*bdbuf_test) (bdbuf_task_control* tasks);
1662 
1663 /**
1664  * A test name and function.
1665  */
1666 typedef struct bdbuf_test_ident
1667 {
1668   const char* label;
1669   bdbuf_test  test;
1670 } bdbuf_test_ident;
1671 
1672 /**
1673  * Table of tests.
1674  */
1675 static bdbuf_test_ident bdbuf_tests[] =
1676 {
1677   {
1678     "Task 0 get buffer 0 from pool 0",
1679     bdbuf_test_1
1680   },
1681   {
1682     "Task 0 get buffer 0 -> 4 from pool 0, task 2 and 1 block getting",
1683     bdbuf_test_2
1684   },
1685   {
1686     "Task 0 read buffer 5, modify and release modified",
1687     bdbuf_test_3
1688   },
1689   {
1690     "Task 0 read all buffers, task 1 blocks waiting for acessed buffer",
1691     bdbuf_test_4
1692   },
1693   {
1694     "Task 0 read all buffers, task 1 blocks waiting for new buffer",
1695     bdbuf_test_5
1696   },
1697   {
1698     "Task 0 release modified 4 buffers then syncs a 5th buffer",
1699     bdbuf_test_6
1700   },
1701   {
1702     "Task 0 release modified 5 buffers then sync the device",
1703     bdbuf_test_7
1704   },
1705   {
1706     "Task 0 releases modified 5 buffers is out or order sequence and the" \
1707     " driver checks the buffers are in order",
1708     bdbuf_test_8
1709   }
1710 };
1711 
1712 #define BDBUF_TEST_NUM (sizeof (bdbuf_tests) / sizeof (bdbuf_test_ident))
1713 
1714 /**
1715  * Test the BD Buffering code.
1716  */
1717 static void
1718 bdbuf_tester (void)
1719 {
1720   bdbuf_task_control        tasks[BDBUF_TEST_TASKS];
1721   rtems_task_priority       old_priority;
1722   int                       t;
1723   bool                      passed = true;
1724   rtems_status_code         sc;
1725 
1726   sc = bdbuf_disk_initialize();
1727   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
1728 
1729   /*
1730    * Change priority to a lower one.
1731    */
1732   printf ("lower priority to %d: ", BDBUF_TESTS_PRI_HIGH + 1);
1733   bdbuf_test_print_sc (rtems_task_set_priority (RTEMS_SELF,
1734                                                 BDBUF_TESTS_PRI_HIGH + 1,
1735                                                 &old_priority),
1736                        true);
1737 
1738   /*
1739    * Make sure the swapout task has run. The user could block
1740    * the swapout task from running until later. This is not
1741    * tested.
1742    */
1743   bdbuf_sleep (100);
1744 
1745   /*
1746    * Start the test tasks used to test the threading parts
1747    * of the bdbuf code.
1748    */
1749   for (t = 0; t < BDBUF_TEST_TASKS; t++)
1750   {
1751     bdbuf_task_control_init (t, &tasks[t],
1752                              rtems_task_self ());
1753 
1754     if (!bdbuf_tests_create_task (&tasks[t],
1755                                   BDBUF_TESTS_PRI_HIGH - t,
1756                                   bdbuf_test_tasks[t]))
1757     return;
1758   }
1759 
1760   /*
1761    * Let the test tasks run if they have not already done so.
1762    */
1763   bdbuf_sleep (100);
1764 
1765   /*
1766    * Perform each test.
1767    */
1768   for (t = 0; (t < BDBUF_TEST_NUM) && passed; t++)
1769   {
1770     printf ("test %d: %s\n", t + 1, bdbuf_tests[t].label);
1771     passed = bdbuf_tests[t].test (tasks);
1772     printf ("test %d: %s\n", t + 1, passed ? "passed" : "failed");
1773   }
1774 }
1775 
1776 static rtems_task Init(rtems_task_argument argument)
1777 {
1778   TEST_BEGIN();
1779 
1780   bdbuf_tester ();
1781 
1782   TEST_END();
1783 
1784   exit (0);
1785 }
1786 
1787 #define CONFIGURE_INIT
1788 
1789 #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
1790 #define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
1791 #define CONFIGURE_APPLICATION_NEEDS_LIBBLOCK
1792 
1793 #define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 4
1794 
1795 #define CONFIGURE_BDBUF_TASK_STACK_SIZE BDBUF_TEST_STACK_SIZE
1796 
1797 #define CONFIGURE_MAXIMUM_TASKS (1 + BDBUF_TEST_TASKS)
1798 #define CONFIGURE_MAXIMUM_SEMAPHORES 2
1799 
1800 #define CONFIGURE_EXTRA_TASK_STACKS \
1801   (BDBUF_TEST_TASKS * BDBUF_TEST_STACK_SIZE)
1802 
1803 #define CONFIGURE_INIT_TASK_STACK_SIZE BDBUF_TEST_STACK_SIZE
1804 #define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_FLOATING_POINT
1805 #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
1806 
1807 #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
1808 
1809 #include <rtems/confdefs.h>