source: rtems/testsuites/libtests/block06/init.c @ ae88aa7

4.115
Last change on this file since ae88aa7 was ae88aa7, checked in by Sebastian Huber <sebastian.huber@…>, on 03/10/14 at 07:15:37

sapi: Use one SMP lock for all chains

This partially reverts commit 1215fd4d9426a59d568560e9a485628560363133.

In order to support profiling of SMP locks and provide a future
compatible SMP locks API it is necessary to add an SMP lock destroy
function. Since the commit above adds an SMP lock to each chain control
we would have to add a rtems_chain_destroy() function as well. This
complicates the chain usage dramatically. Thus revert the patch above.
A global SMP lock for all chains is used to implement the protected
chain operations.

Advantages:

  • The SAPI chain API is now identical on SMP and non-SMP configurations.
  • The size of the chain control is reduced and is then equal to the Score chains.
  • The protected chain operations work correctly on SMP.

Disadvantage:

  • Applications using many different chains and the protected operations may notice lock contention.

The chain control size drop is a huge benefit (SAPI chain controls are
66% larger than the Score chain controls). The only disadvantage is not
really a problem since these applications can use specific interrupt
locks and unprotected chain operations to avoid this issue.

  • Property mode set to 100644
File size: 42.5 KB
Line 
1/*
2 * Copyright 2008 Chris Johns (chrisj@rtems.org)
3 *
4 * The license and distribution terms for this file may be
5 * found in the file LICENSE in this distribution or at
6 * http://www.rtems.com/license/LICENSE.
7 */
8
9/**
10 * BD Buffer test.
11 *
12 * Please add more tests
13 */
14
15#ifdef HAVE_CONFIG_H
16#include "config.h"
17#endif
18
19#include <errno.h>
20#include <setjmp.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <inttypes.h>
27
28#include <rtems.h>
29#include <rtems/chain.h>
30#include <rtems/error.h>
31#include <rtems/bdbuf.h>
32
33#include <bsp.h>
34
35/* forward declarations to avoid warnings */
36static rtems_task Init(rtems_task_argument argument);
37
38#define BDBUF_DISKS 2
39#define BDBUF_SIZE  1024
40
41#if 0
42const rtems_bdbuf_config rtems_bdbuf_configuration =
43{
44  5,           /* max_read_ahead_blocks */
45  5,           /* max_write_blocks */
46  15,          /* swapout_priority */
47  250,         /* swapout_period */
48  1000,        /* swap_block_hold */
49  0,           /* swapout_workers */
50  15,          /* swapout_worker_priority */
51  1024 * 1024, /* size */
52  512,         /* buffer_min */
53  4096         /* buffer_max */
54};
55#endif
56
57/**
58 * Let the IO system allocation the next available major number.
59 */
60#define RTEMS_DRIVER_AUTO_MAJOR (0)
61
62/**
63 * The bdbuf disk driver base name.
64 */
65#define BDBUF_DISK_DEVICE_BASE_NAME "/dev/bddisk"
66
67/**
68 * The actions the disk driver handles.
69 */
70typedef enum bdbuf_disk_action
71{
72  BDBUF_DISK_NOOP,
73  BDBUF_DISK_WAIT,
74  BDBUF_DISK_SLEEP,
75  BDBUF_DISK_BLOCKS_INORDER
76} bdbuf_disk_action;
77
78/**
79 * The BDBUF Disk driver.
80 */
81typedef struct bdbuf_disk
82{
83  const char*       name;
84  rtems_id          lock;
85  uint32_t          block_size;
86  uint32_t          block_count;
87  bdbuf_disk_action driver_action;
88  const char*       watcher_name;
89  rtems_id          watcher;
90  int               watch_count;
91  const char*       waiting_name;
92  rtems_id          waiting;
93  uint32_t          driver_sleep;
94} bdbuf_disk;
95
96/*
97 * A disk drive for each pool.
98 */
99static bdbuf_disk bdbuf_disks[BDBUF_DISKS];
100
101/**
102 * Task control.
103 */
104typedef struct bdbuf_task_control
105{
106  bool                      die;
107  const char*               name;
108  rtems_id                  task;
109  rtems_id                  master;
110  int                       test;
111  rtems_device_major_number major;
112  rtems_device_minor_number minor;
113  bool                      passed;
114  rtems_disk_device        *dd;
115} bdbuf_task_control;
116
117#define BDBUF_TEST_TASKS (3)
118
119#define BDBUF_TEST_STACK_SIZE (2 * RTEMS_MINIMUM_STACK_SIZE)
120
121/**
122 * Seconds as milli-seconds.
123 */
124#define BDBUF_SECONDS(msec) ((msec) * 1000UL)
125
126/**
127 * Print a message to output and flush it.
128 *
129 * @param format The format string. See printf for details.
130 * @param ... The arguments for the format text.
131 * @return int The number of bytes written to the output.
132 */
133static int
134bdbuf_test_printf (const char *format, ...)
135{
136  int ret = 0;
137  va_list args;
138  va_start (args, format);
139  ret =  vfprintf (stdout, format, args);
140  fflush (stdout);
141  return ret;
142}
143
144/**
145 * Print the status code description and return true if true.
146 *
147 * @param sc The RTEMS status code.
148 * @retval true The status code is successful.
149 * @retval false The status code is not successful.
150 */
151static bool
152bdbuf_test_print_sc (rtems_status_code sc, bool newline)
153{
154  if (newline)
155    fprintf (stdout, "%s\n", rtems_status_text (sc));
156  else
157    fprintf (stdout, "%s", rtems_status_text (sc));
158  return sc == RTEMS_SUCCESSFUL;
159}
160
161/**
162 * BDBuf disk device driver lock.
163 */
164static bool
165bdbuf_disk_lock (bdbuf_disk* bdd)
166{
167  rtems_status_code sc;
168  sc = rtems_semaphore_obtain (bdd->lock, RTEMS_WAIT, 0);
169  if (sc != RTEMS_SUCCESSFUL)
170  {
171    bdbuf_test_printf ("disk ioctl: lock failed: ");
172    bdbuf_test_print_sc (sc, true);
173    return false;
174  }
175  return true;
176}
177
178/**
179 * BDBuf disk device driver unlock.
180 */
181static bool
182bdbuf_disk_unlock (bdbuf_disk* bdd)
183{
184  rtems_status_code sc;
185  sc = rtems_semaphore_release (bdd->lock);
186  if (sc != RTEMS_SUCCESSFUL)
187  {
188    bdbuf_test_printf ("disk ioctl: unlock failed: ");
189    bdbuf_test_print_sc (sc, true);
190    return false;
191  }
192  return true;
193}
194
195/**
196 * BDBUf wait for the wait event.
197 */
198static rtems_status_code
199bdbuf_wait (const char* who, unsigned long timeout)
200{
201  rtems_status_code sc;
202  rtems_event_set   out;
203  sc = rtems_event_receive (RTEMS_EVENT_0,
204                            RTEMS_WAIT | RTEMS_EVENT_ANY,
205                            RTEMS_MICROSECONDS_TO_TICKS (timeout * 1000),
206                            &out);
207  if (sc != RTEMS_SUCCESSFUL)
208  {
209    bdbuf_test_printf ("%s: wait: receive failed: ", who);
210    bdbuf_test_print_sc (sc, true);
211  }
212  else if ((out & RTEMS_EVENT_0) == 0)
213  {
214    bdbuf_test_printf ("%s: wait: received wrong event: %08x", who, out);
215  }
216  return sc;
217}
218
219/**
220 * BDBUf send wait event.
221 */
222static bool
223bdbuf_send_wait_event (const char* task, const char* msg, rtems_id id)
224{
225  bdbuf_test_printf ("%s: %s: %08x: ", task, msg, id);
226  return  bdbuf_test_print_sc (rtems_event_send (id, RTEMS_EVENT_0), true);
227}
228
229/**
230 * BDBUf wait for the wait event.
231 */
232static rtems_status_code
233bdbuf_watch (unsigned long timeout)
234{
235  rtems_status_code sc;
236  rtems_event_set   out;
237  sc = rtems_event_receive (RTEMS_EVENT_1,
238                            RTEMS_WAIT | RTEMS_EVENT_ANY,
239                            RTEMS_MICROSECONDS_TO_TICKS (timeout * 1000),
240                            &out);
241  if (sc != RTEMS_SUCCESSFUL)
242  {
243    bdbuf_test_printf ("watch: receive failed: ");
244    bdbuf_test_print_sc (sc, true);
245  }
246  else if ((out & RTEMS_EVENT_1) == 0)
247  {
248    bdbuf_test_printf ("watch: received wrong event: %08x", out);
249  }
250  return sc;
251}
252
253/**
254 * BDBUf send wait event.
255 */
256static bool
257bdbuf_send_watch_event (const char* task, const char* msg, rtems_id id)
258{
259  bdbuf_test_printf ("%s: %s: %08x: ", task, msg, id);
260  return  bdbuf_test_print_sc (rtems_event_send (id, RTEMS_EVENT_1), true);
261}
262
263/**
264 * Set up a disk driver watch.
265 */
266static void
267bdbuf_set_disk_driver_watch (bdbuf_task_control* tc, int count)
268{
269  /*
270   * Set up a disk watch and wait for the write to happen.
271   */
272  bdbuf_disk_lock (&bdbuf_disks[tc->minor]);
273  bdbuf_disks[tc->minor].watcher_name = tc->name;
274  bdbuf_disks[tc->minor].watcher = tc->task;
275  bdbuf_disks[tc->minor].watch_count = count;
276  bdbuf_disk_unlock (&bdbuf_disks[tc->minor]);
277}
278
279/**
280 * Clear the disk driver watch.
281 */
282static void
283bdbuf_clear_disk_driver_watch (bdbuf_task_control* tc)
284{
285  /*
286   * Set up a disk watch and wait for the write to happen.
287   */
288  bdbuf_disk_lock (&bdbuf_disks[tc->minor]);
289  bdbuf_disks[tc->minor].watcher_name = 0;
290  bdbuf_disks[tc->minor].watcher = 0;
291  bdbuf_disks[tc->minor].watch_count = 0;
292  bdbuf_disk_unlock (&bdbuf_disks[tc->minor]);
293}
294
295/**
296 * Wait for the disk driver watch.
297 */
298static bool
299bdbuf_disk_driver_watch_wait (bdbuf_task_control* tc, unsigned long msecs)
300{
301  bool              passed = true;
302  rtems_status_code sc = bdbuf_watch (msecs);
303  if (sc != RTEMS_SUCCESSFUL)
304  {
305    bdbuf_test_printf ("%s: driver watch: driver wait: ", tc->name);
306    passed = bdbuf_test_print_sc (sc, true);
307  }
308  bdbuf_clear_disk_driver_watch (tc);
309  return passed;
310}
311
312/**
313 * Set the disk driver action.
314 */
315static void
316bdbuf_set_disk_driver_action (bdbuf_task_control* tc, bdbuf_disk_action action)
317{
318  /*
319   * Set up a disk action.
320   */
321  bdbuf_disk_lock (&bdbuf_disks[tc->minor]);
322  bdbuf_disks[tc->minor].driver_action = action;
323  bdbuf_disk_unlock (&bdbuf_disks[tc->minor]);
324}
325
326/**
327 * BDBUF Sleep.
328 */
329static bool
330bdbuf_sleep (unsigned long msecs)
331{
332  rtems_status_code sc;
333  sc = rtems_task_wake_after (RTEMS_MICROSECONDS_TO_TICKS (msecs * 1000));
334  if (sc != RTEMS_SUCCESSFUL)
335  {
336    bdbuf_test_printf ("sleep wake after failed: ");
337    bdbuf_test_print_sc (sc, true);
338    return false;
339  }
340  return true;
341}
342
343/**
344 * Initialise a task control.
345 */
346static void
347bdbuf_task_control_init (int                       task,
348                         bdbuf_task_control*       tc,
349                         rtems_id                  master,
350                         rtems_device_major_number major,
351                         rtems_disk_device        *dd)
352{
353  char name[6];
354  sprintf (name, "bdt%d", task);
355
356  tc->die    = false;
357  tc->name   = strdup (name); /* leaks */
358  tc->task   = 0;
359  tc->master = master;
360  tc->test   = 0;
361  tc->major  = major;
362  tc->minor  = 0;
363  tc->passed = false;
364  tc->dd     = dd;
365}
366
367static bool
368bdbuf_disk_ioctl_watcher (bdbuf_disk* bdd, int update)
369{
370  /*
371   * Always wake the watcher.
372   */
373  if (bdd->watcher)
374  {
375    if (bdd->watch_count)
376    {
377      if (update > bdd->watch_count)
378        bdd->watch_count -= update;
379      else
380        bdd->watch_count = 0;
381    }
382
383    if (bdd->watch_count == 0)
384    {
385      bdbuf_send_watch_event (bdd->watcher_name,
386                              "disk ioctl: wake watcher",
387                              bdd->watcher);
388      bdd->watcher = 0;
389    }
390  }
391
392  return true;
393}
394
395
396static bool
397bdbuf_disk_ioctl_process (bdbuf_disk* bdd, rtems_blkdev_request* req)
398{
399  bool result = true;
400  int  b;
401
402  /*
403   * Perform the requested action.
404   */
405  switch (bdd->driver_action)
406  {
407    case BDBUF_DISK_NOOP:
408      break;
409
410    case BDBUF_DISK_WAIT:
411      if (bdd->waiting)
412        bdbuf_test_printf ("disk ioctl: bad waiter: %s:%08x\n",
413                           bdd->waiting_name, bdd->waiting);
414      bdd->waiting_name = "bdd";
415
416      bdd->waiting = rtems_task_self ();
417
418      if (bdbuf_disk_unlock (bdd))
419        result = bdbuf_wait (bdd->name, 0) == RTEMS_SUCCESSFUL;
420      else
421        result = false;
422
423      /*
424       * Ignore any error if one happens.
425       */
426      bdbuf_disk_lock (bdd);
427      break;
428
429    case BDBUF_DISK_SLEEP:
430      bdbuf_test_printf ("disk ioctl: sleeping: %d msecs\n",
431                         bdd->driver_sleep);
432      result = bdbuf_sleep (bdd->driver_sleep);
433      break;
434
435    case BDBUF_DISK_BLOCKS_INORDER:
436      bdbuf_test_printf ("disk ioctl: multi-block order check: count = %d\n",
437                         req->bufnum);
438      for (b = 0; b < (req->bufnum - 1); b++)
439        if (req->bufs[b].block >= req->bufs[b + 1].block)
440          bdbuf_test_printf ("disk ioctl: out of order: index:%d (%d >= %d\n",
441                             b, req->bufs[b].block, req->bufs[b + 1].block);
442      break;
443
444    default:
445      bdbuf_test_printf ("disk ioctl: invalid action: %d\n",
446                         bdd->driver_action);
447      result = false;
448      break;
449  }
450
451  return result;
452}
453
454static bool
455bdbuf_disk_ioctl_leave (bdbuf_disk* bdd, int buffer_count)
456{
457  /*
458   * Handle the watcher.
459   */
460  bdbuf_disk_ioctl_watcher (bdd, buffer_count);
461
462  return true;
463}
464
465/**
466 * BDBuf disk IOCTL handler.
467 *
468 * @param dd Disk device.
469 * @param req IOCTL request code.
470 * @param argp IOCTL argument.
471 * @retval The IOCTL return value
472 */
473static int
474bdbuf_disk_ioctl (rtems_disk_device *dd, uint32_t req, void* argp)
475{
476  rtems_blkdev_request *r = argp;
477  bdbuf_disk           *bdd = rtems_disk_get_driver_data (dd);
478
479  errno = 0;
480
481  if (!bdbuf_disk_lock (bdd))
482  {
483    errno = EIO;
484  }
485  else
486  {
487    switch (req)
488    {
489      case RTEMS_BLKIO_REQUEST:
490        switch (r->req)
491        {
492          case RTEMS_BLKDEV_REQ_READ:
493            if (!bdbuf_disk_ioctl_process (bdd, r))
494              rtems_blkdev_request_done(r, RTEMS_IO_ERROR);
495            else
496            {
497              rtems_blkdev_sg_buffer* sg = r->bufs;
498              uint32_t                block = RTEMS_BLKDEV_START_BLOCK (r);
499              uint32_t                b;
500              int32_t                 remains;
501
502              remains = r->bufnum * bdd->block_size;
503
504              for (b = 0; b < r->bufnum; b++, block++, sg++)
505              {
506                uint32_t length = sg->length;
507
508                if (sg->length != bdd->block_size)
509                  if (length > bdd->block_size)
510                    length = bdd->block_size;
511
512                memset (sg->buffer, block, length);
513
514                remains -= length;
515              }
516
517              rtems_blkdev_request_done (r, RTEMS_SUCCESSFUL);
518            }
519            bdbuf_disk_ioctl_leave (bdd, r->bufnum);
520            break;
521
522          case RTEMS_BLKDEV_REQ_WRITE:
523            if (!bdbuf_disk_ioctl_process (bdd, r))
524              rtems_blkdev_request_done(r, RTEMS_IO_ERROR);
525            else
526              rtems_blkdev_request_done(r, RTEMS_SUCCESSFUL);
527            bdbuf_disk_ioctl_leave (bdd, r->bufnum);
528            break;
529
530          default:
531            errno = EINVAL;
532            break;
533        }
534        break;
535
536      default:
537        errno = EINVAL;
538        break;
539    }
540
541    if (!bdbuf_disk_unlock (bdd))
542      errno = EIO;
543  }
544
545  return errno == 0 ? 0 : -1;
546}
547
548/**
549 * BDBuf disk device driver initialization.
550 *
551 * @param major Disk major device number.
552 * @param minor Minor device number, not applicable.
553 * @param arg Initialization argument, not applicable.
554 */
555static rtems_device_driver
556bdbuf_disk_initialize (rtems_device_major_number major,
557                       rtems_device_minor_number minor,
558                       void*                     arg)
559{
560  rtems_status_code sc;
561
562  bdbuf_test_printf ("disk io init: ");
563  sc = rtems_disk_io_initialize ();
564  if (!bdbuf_test_print_sc (sc, true))
565    return sc;
566
567  for (minor = 0; minor < BDBUF_DISKS; minor++)
568  {
569    char              name[sizeof (BDBUF_DISK_DEVICE_BASE_NAME) + 10];
570    bdbuf_disk*       bdd = &bdbuf_disks[minor];
571    rtems_status_code sc;
572
573    snprintf (name, sizeof (name),
574              BDBUF_DISK_DEVICE_BASE_NAME "%" PRIu32, minor);
575
576    bdd->name = strdup (name);
577
578    bdbuf_test_printf ("disk init: %s\n", bdd->name);
579    bdbuf_test_printf ("disk lock: ");
580
581    sc = rtems_semaphore_create (rtems_build_name ('B', 'D', 'D', 'K'), 1,
582                                 RTEMS_PRIORITY | RTEMS_BINARY_SEMAPHORE |
583                                 RTEMS_INHERIT_PRIORITY, 0, &bdd->lock);
584    if (!bdbuf_test_print_sc (sc, true))
585      return RTEMS_IO_ERROR;
586
587    bdd->block_size  = 512 * (minor + 1);
588    bdd->block_count = BDBUF_SIZE * (minor + 1);
589
590    sc = rtems_disk_create_phys(rtems_filesystem_make_dev_t (major, minor),
591                                bdd->block_size, bdd->block_count,
592                                bdbuf_disk_ioctl, bdd, name);
593    if (sc != RTEMS_SUCCESSFUL)
594    {
595      bdbuf_test_printf ("disk init: create phys failed: ");
596      bdbuf_test_print_sc (sc, true);
597      return sc;
598    }
599
600  }
601  return RTEMS_SUCCESSFUL;
602}
603
604/**
605 * Create the RAM Disk Driver entry.
606 */
607static rtems_driver_address_table bdbuf_disk_io_ops = {
608  initialization_entry: bdbuf_disk_initialize,
609  open_entry:           rtems_blkdev_generic_open,
610  close_entry:          rtems_blkdev_generic_close,
611  read_entry:           rtems_blkdev_generic_read,
612  write_entry:          rtems_blkdev_generic_write,
613  control_entry:        rtems_blkdev_generic_ioctl
614};
615
616/**
617 * Set up the disk.
618 */
619
620static bool
621bdbuf_tests_setup_disk (rtems_device_major_number *major,
622                        rtems_disk_device        **dd_ptr)
623{
624  rtems_status_code sc;
625  bool ok;
626
627  /*
628   * Register the disk driver.
629   */
630  bdbuf_test_printf ("register disk driver\n");
631
632  sc = rtems_io_register_driver (RTEMS_DRIVER_AUTO_MAJOR,
633                                 &bdbuf_disk_io_ops,
634                                 major);
635  ok = sc == RTEMS_SUCCESSFUL;
636
637  if (ok) {
638    *dd_ptr = rtems_disk_obtain (rtems_filesystem_make_dev_t (*major, 0));
639    ok = *dd_ptr != NULL;
640  }
641
642  return ok;
643}
644
645static bool
646bdbuf_tests_create_task (bdbuf_task_control* tc,
647                         rtems_task_priority priority,
648                         rtems_task_entry    entry_point)
649{
650  rtems_status_code sc;
651
652  bdbuf_test_printf ("creating task: %s: priority: %d: ",
653                     tc->name, priority);
654
655  sc = rtems_task_create (rtems_build_name (tc->name[0], tc->name[1],
656                                            tc->name[2], tc->name[3]),
657                          priority,
658                          BDBUF_TEST_STACK_SIZE,
659                          RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
660                          RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR,
661                          &tc->task);
662  if (!bdbuf_test_print_sc (sc, true))
663    return false;
664
665  bdbuf_test_printf ("starting task: %s: ", tc->name);
666
667  sc = rtems_task_start (tc->task, entry_point, (rtems_task_argument) tc);
668
669  return bdbuf_test_print_sc (sc, true);
670}
671
672/**
673 * Get the block 0 buffer twice. The first time it is requested it
674 * will be taken from the empty list and returned to the LRU list.
675 * The second time it will be removed from the LRU list.
676 */
677static void
678bdbuf_tests_task_0_test_1 (bdbuf_task_control* tc)
679{
680  rtems_status_code   sc;
681  bool                passed;
682  int                 i;
683  rtems_bdbuf_buffer* bd;
684
685  /*
686   * Set task control's passed to false to handle a timeout.
687   */
688  tc->passed = false;
689  passed = true;
690
691  for (i = 0; (i < 2) && passed; i++)
692  {
693    bdbuf_test_printf ("%s: rtems_bdbuf_get[0]: ", tc->name);
694    sc = rtems_bdbuf_get (tc->dd, 0, &bd);
695    if (!bdbuf_test_print_sc (sc, true))
696    {
697      passed = false;
698      break;
699    }
700
701    bdbuf_test_printf ("%s: rtems_bdbuf_release[0]: ", tc->name);
702    sc = rtems_bdbuf_release (bd);
703    if (!bdbuf_test_print_sc (sc, true))
704    {
705      passed = false;
706      break;
707    }
708  }
709
710  tc->passed = passed;
711  tc->test = 0;
712}
713
714/**
715 * Get the blocks 0 -> 4 and hold them. Wake the master to tell it was have the
716 * buffers then wait for the master to tell us to release a single buffer.
717 * Task 1 will be block waiting for each buffer. It is a higher priority.
718 */
719static void
720bdbuf_tests_task_0_test_2 (bdbuf_task_control* tc)
721{
722  rtems_status_code   sc;
723  bool                passed;
724  int                 i;
725  rtems_bdbuf_buffer* bd;
726  rtems_chain_control buffers;
727
728  /*
729   * Set task control's passed to false to handle a timeout.
730   */
731  tc->passed = false;
732  passed = true;
733
734  /*
735   * Get the blocks 0 -> 4 and hold them.
736   */
737  rtems_chain_initialize_empty (&buffers);
738
739  for (i = 0; (i < 5) && passed; i++)
740  {
741    bdbuf_test_printf ("%s: rtems_bdbuf_get[%d]: ", tc->name, i);
742    sc = rtems_bdbuf_get (tc->dd, i, &bd);
743    if (!bdbuf_test_print_sc (sc, true))
744      passed = false;
745
746    rtems_chain_append (&buffers, &bd->link);
747  }
748
749  /*
750   * Wake the master to tell it we have the buffers.
751   */
752  bdbuf_send_wait_event (tc->name, "wake master", tc->master);
753
754  if (passed)
755  {
756    /*
757     * For each buffer we hold wait until the master wakes us
758     * and then return it. Task 2 will block waiting for this
759     * buffer. It is a higher priority task.
760     */
761    for (i = 0; (i < 5) && passed; i++)
762    {
763      sc = bdbuf_wait (tc->name, BDBUF_SECONDS (5));
764      if (sc != RTEMS_SUCCESSFUL)
765      {
766        bdbuf_test_printf ("%s: wait failed: ", tc->name);
767        bdbuf_test_print_sc (sc, true);
768        passed = false;
769        break;
770      }
771      else
772      {
773        bdbuf_test_printf ("%s: rtems_bdbuf_release[%d]: unblocks task 1\n",
774                           tc->name, i);
775        bd = (rtems_bdbuf_buffer*) rtems_chain_get (&buffers);
776        sc = rtems_bdbuf_release (bd);
777        bdbuf_test_printf ("%s: rtems_bdbuf_release[%d]: ", tc->name, i);
778        if (!bdbuf_test_print_sc (sc, true))
779        {
780          passed = false;
781          break;
782        }
783      }
784    }
785  }
786
787  tc->passed = passed;
788  tc->test = 0;
789}
790
791/**
792 * Read the block 5 from the disk modify it then release it modified.
793 */
794static void
795bdbuf_tests_task_0_test_3 (bdbuf_task_control* tc)
796{
797  rtems_status_code   sc;
798  bool                passed;
799  rtems_bdbuf_buffer* bd;
800
801  /*
802   * Set task control's passed to false to handle a timeout.
803   */
804  tc->passed = false;
805  passed = true;
806
807  bdbuf_disk_lock (&bdbuf_disks[tc->minor]);
808  bdbuf_disks[tc->minor].driver_action = BDBUF_DISK_NOOP;
809  bdbuf_disk_unlock (&bdbuf_disks[tc->minor]);
810
811  /*
812   * Read the buffer and then release it.
813   */
814  bdbuf_test_printf ("%s: rtems_bdbuf_read[5]: ", tc->name);
815  sc = rtems_bdbuf_read (tc->dd, 5, &bd);
816  if ((passed = bdbuf_test_print_sc (sc, true)))
817  {
818    bdbuf_test_printf ("%s: rtems_bdbuf_release_modified[5]: ", tc->name);
819    sc = rtems_bdbuf_release_modified (bd);
820    passed = bdbuf_test_print_sc (sc, true);
821  }
822
823  /*
824   * Read the buffer again and then just release. The buffer should
825   * be maintained as modified.
826   */
827  bdbuf_test_printf ("%s: rtems_bdbuf_read[5]: ", tc->name);
828  sc = rtems_bdbuf_read (tc->dd, 5, &bd);
829  if ((passed = bdbuf_test_print_sc (sc, true)))
830  {
831    bdbuf_test_printf ("%s: rtems_bdbuf_release[5]: ", tc->name);
832    sc = rtems_bdbuf_release (bd);
833    passed = bdbuf_test_print_sc (sc, true);
834  }
835
836  /*
837   * Set up a disk watch and wait for the write to happen.
838   */
839  bdbuf_set_disk_driver_watch (tc, 1);
840  passed = bdbuf_disk_driver_watch_wait (tc, BDBUF_SECONDS (5));
841
842  tc->passed = passed;
843  tc->test = 0;
844}
845
846static size_t
847bdbuf_test_buffer_count (void)
848{
849  return rtems_bdbuf_configuration.size / rtems_bdbuf_configuration.buffer_min;
850}
851
852/**
853 * Get all the blocks in the pool and hold them. Wake the master to tell it was
854 * have the buffers then wait for the master to tell us to release them.
855 */
856static void
857bdbuf_tests_task_0_test_4 (bdbuf_task_control* tc)
858{
859  rtems_status_code   sc;
860  bool                passed;
861  size_t              i;
862  rtems_bdbuf_buffer* bd;
863  rtems_chain_control buffers;
864  size_t              num = bdbuf_test_buffer_count ();
865
866  /*
867   * Set task control's passed to false to handle a timeout.
868   */
869  tc->passed = false;
870  passed = true;
871
872  /*
873   * Clear any disk settings.
874   */
875  bdbuf_clear_disk_driver_watch (tc);
876  bdbuf_set_disk_driver_action (tc, BDBUF_DISK_NOOP);
877
878  /*
879   * Get the blocks 0 -> 4 and hold them.
880   */
881  rtems_chain_initialize_empty (&buffers);
882
883  for (i = 0; (i < num) && passed; i++)
884  {
885    bdbuf_test_printf ("%s: rtems_bdbuf_read[%d]: ", tc->name, i);
886    sc = rtems_bdbuf_read (tc->dd, i, &bd);
887    if (!bdbuf_test_print_sc (sc, true))
888      passed = false;
889
890    rtems_chain_append (&buffers, &bd->link);
891  }
892
893  /*
894   * Wake the master to tell it we have the buffers.
895   */
896  bdbuf_send_wait_event (tc->name, "wake master", tc->master);
897
898  if (passed)
899  {
900    bdbuf_sleep (250);
901
902    bdbuf_set_disk_driver_watch (tc, num / 2);
903
904    /*
905     * Release half the buffers, wait 500msecs then release the
906     * remainder. This tests the swap out timer on each buffer.
907     */
908    bdbuf_test_printf ("%s: rtems_bdbuf_release_modified[0]: unblocks task 1\n",
909                       tc->name);
910    bd = (rtems_bdbuf_buffer*) rtems_chain_get (&buffers);
911    sc = rtems_bdbuf_release_modified (bd);
912    bdbuf_test_printf ("%s: rtems_bdbuf_release_modified[0]: ", tc->name);
913    passed = bdbuf_test_print_sc (sc, true);
914    if (passed)
915    {
916      for (i = 1; (i < (num / 2)) && passed; i++)
917      {
918        bdbuf_test_printf ("%s: rtems_bdbuf_release_modified[%d]: " \
919                           "unblocks task 1\n", tc->name, i);
920        bd = (rtems_bdbuf_buffer*) rtems_chain_get (&buffers);
921        sc = rtems_bdbuf_release_modified (bd);
922        bdbuf_test_printf ("%s: rtems_bdbuf_release_modified[%d]: ",
923                           tc->name, i);
924        passed = bdbuf_test_print_sc (sc, true);
925        if (!passed)
926          break;
927      }
928
929      if (passed)
930      {
931        passed = bdbuf_disk_driver_watch_wait (tc, BDBUF_SECONDS (5));
932
933        if (passed)
934        {
935          bdbuf_sleep (500);
936
937          bdbuf_set_disk_driver_watch (tc, num / 2);
938
939          for (i = 0; (i < (num / 2)) && passed; i++)
940          {
941            bdbuf_test_printf ("%s: rtems_bdbuf_release_modified[%d]: ",
942                               tc->name, i + (num / 2));
943            bd = (rtems_bdbuf_buffer*) rtems_chain_get (&buffers);
944            passed = bdbuf_test_print_sc (rtems_bdbuf_release_modified (bd),
945                                          true);
946            if (!passed)
947              break;
948          }
949
950          passed = bdbuf_disk_driver_watch_wait (tc, BDBUF_SECONDS (5));
951
952          if (passed)
953          {
954            if (!rtems_chain_is_empty (&buffers))
955            {
956              passed = false;
957              bdbuf_test_printf ("%s: buffer chain not empty\n", tc->name);
958            }
959          }
960        }
961      }
962    }
963  }
964
965  tc->passed = passed;
966  tc->test = 0;
967}
968
969static void
970bdbuf_tests_task_0_test_5 (bdbuf_task_control* tc)
971{
972  bdbuf_tests_task_0_test_4 (tc);
973}
974
975static void
976bdbuf_tests_task_0_test_6 (bdbuf_task_control* tc)
977{
978  rtems_status_code   sc;
979  bool                passed;
980  int                 i;
981  rtems_bdbuf_buffer* bd;
982  rtems_chain_control buffers;
983
984  /*
985   * Set task control's passed to false to handle a timeout.
986   */
987  tc->passed = false;
988  passed = true;
989
990  /*
991   * Clear any disk settings.
992   */
993  bdbuf_clear_disk_driver_watch (tc);
994  bdbuf_set_disk_driver_action (tc, BDBUF_DISK_NOOP);
995
996  /*
997   * Get the blocks 0 -> 4 and hold them.
998   */
999  rtems_chain_initialize_empty (&buffers);
1000
1001  for (i = 0; (i < 5) && passed; i++)
1002  {
1003    bdbuf_test_printf ("%s: rtems_bdbuf_read[%d]: ", tc->name, i);
1004    sc = rtems_bdbuf_get (tc->dd, i, &bd);
1005    if (!bdbuf_test_print_sc (sc, true))
1006      passed = false;
1007
1008    rtems_chain_append (&buffers, &bd->link);
1009  }
1010
1011  for (i = 0; (i < 4) && passed; i++)
1012  {
1013    bdbuf_test_printf ("%s: rtems_bdbuf_release_modified[%d]: ",
1014                       tc->name, i);
1015    bd = (rtems_bdbuf_buffer*) rtems_chain_get (&buffers);
1016    passed = bdbuf_test_print_sc (rtems_bdbuf_release_modified (bd),
1017                                  true);
1018  }
1019
1020  if (passed)
1021  {
1022    bdbuf_test_printf ("%s: rtems_bdbuf_sync[%d]: ", tc->name, i);
1023    bd = (rtems_bdbuf_buffer*) rtems_chain_get (&buffers);
1024
1025    passed = bdbuf_test_print_sc (rtems_bdbuf_sync (bd), true);
1026  }
1027
1028  tc->passed = passed;
1029  tc->test = 0;
1030}
1031
1032static void
1033bdbuf_tests_task_0_test_7 (bdbuf_task_control* tc)
1034{
1035  rtems_status_code   sc;
1036  bool                passed;
1037  int                 i;
1038  rtems_bdbuf_buffer* bd;
1039  rtems_chain_control buffers;
1040
1041  /*
1042   * Set task control's passed to false to handle a timeout.
1043   */
1044  tc->passed = false;
1045  passed = true;
1046
1047  /*
1048   * Clear any disk settings.
1049   */
1050  bdbuf_clear_disk_driver_watch (tc);
1051  bdbuf_set_disk_driver_action (tc, BDBUF_DISK_NOOP);
1052
1053  /*
1054   * Get the blocks 0 -> 4 and hold them.
1055   */
1056  rtems_chain_initialize_empty (&buffers);
1057
1058  for (i = 0; (i < 5) && passed; i++)
1059  {
1060    bdbuf_test_printf ("%s: rtems_bdbuf_read[%d]: ", tc->name, i);
1061    sc = rtems_bdbuf_get (tc->dd, i, &bd);
1062    if (!bdbuf_test_print_sc (sc, true))
1063      passed = false;
1064
1065    rtems_chain_append (&buffers, &bd->link);
1066  }
1067
1068  for (i = 0; (i < 5) && passed; i++)
1069  {
1070    bdbuf_test_printf ("%s: rtems_bdbuf_release_modified[%d]: ",
1071                       tc->name, i);
1072    bd = (rtems_bdbuf_buffer*) rtems_chain_get (&buffers);
1073    passed = bdbuf_test_print_sc (rtems_bdbuf_release_modified (bd),
1074                                  true);
1075  }
1076
1077  if (passed)
1078  {
1079    bdbuf_test_printf ("%s: rtems_bdbuf_syncdev[%d:%d]: ",
1080                       tc->name, i,
1081                       tc->major,
1082                       tc->minor);
1083    passed = bdbuf_test_print_sc (rtems_bdbuf_syncdev (tc->dd), true);
1084  }
1085
1086  tc->passed = passed;
1087  tc->test = 0;
1088}
1089
1090static void
1091bdbuf_tests_task_0_test_8 (bdbuf_task_control* tc)
1092{
1093  rtems_status_code   sc;
1094  bool                passed;
1095  int                 i;
1096  rtems_bdbuf_buffer* bd;
1097  rtems_chain_control buffers;
1098  rtems_chain_node*   node;
1099  rtems_chain_node*   pnode;
1100
1101  /*
1102   * Set task control's passed to false to handle a timeout.
1103   */
1104  tc->passed = false;
1105  passed = true;
1106
1107  /*
1108   * Clear any disk settings.
1109   */
1110  bdbuf_clear_disk_driver_watch (tc);
1111  bdbuf_set_disk_driver_action (tc, BDBUF_DISK_NOOP);
1112
1113  /*
1114   * Get the blocks 0 -> 4 and hold them.
1115   */
1116  rtems_chain_initialize_empty (&buffers);
1117
1118  for (i = 0; (i < 5) && passed; i++)
1119  {
1120    bdbuf_test_printf ("%s: rtems_bdbuf_read[%d]: ", tc->name, i);
1121    sc = rtems_bdbuf_get (tc->dd, i, &bd);
1122    if (!bdbuf_test_print_sc (sc, true))
1123      passed = false;
1124
1125    rtems_chain_append (&buffers, &bd->link);
1126  }
1127
1128  node = rtems_chain_tail (&buffers);
1129  node = node->previous;
1130
1131  bd = (rtems_bdbuf_buffer*) node;
1132  pnode = node->previous;
1133  rtems_chain_extract (node);
1134  node = pnode;
1135  bdbuf_test_printf ("%s: rtems_bdbuf_release_modified[4]: ", tc->name);
1136  passed = bdbuf_test_print_sc (rtems_bdbuf_release_modified (bd), true);
1137
1138  bd = (rtems_bdbuf_buffer*) node;
1139  pnode = node->previous;
1140  rtems_chain_extract (node);
1141  node = pnode;
1142  bdbuf_test_printf ("%s: rtems_bdbuf_release_modified[3]: ", tc->name);
1143  passed = bdbuf_test_print_sc (rtems_bdbuf_release_modified (bd), true);
1144
1145  for (i = 0; (i < 3) && passed; i++)
1146  {
1147    bdbuf_test_printf ("%s: rtems_bdbuf_release_modified[%d]: ",
1148                       tc->name, i);
1149    bd = (rtems_bdbuf_buffer*) rtems_chain_get (&buffers);
1150    passed = bdbuf_test_print_sc (rtems_bdbuf_release_modified (bd),
1151                                  true);
1152  }
1153
1154  if (passed)
1155  {
1156    /*
1157     * Check the block order.
1158     */
1159    bdbuf_set_disk_driver_action (tc, BDBUF_DISK_BLOCKS_INORDER);
1160
1161    bdbuf_test_printf ("%s: rtems_bdbuf_syncdev[%d:%d]: checking order\n",
1162                       tc->name, i,
1163                       tc->major,
1164                       tc->minor);
1165    sc = rtems_bdbuf_syncdev (tc->dd);
1166    bdbuf_test_printf ("%s: rtems_bdbuf_syncdev[%d:%d]: ",
1167                       tc->name, i,
1168                       tc->major,
1169                       tc->minor);
1170    passed = bdbuf_test_print_sc (sc, true);
1171  }
1172
1173  tc->passed = passed;
1174  tc->test = 0;
1175}
1176
1177static void
1178bdbuf_tests_task_0 (rtems_task_argument arg)
1179{
1180  bdbuf_task_control* tc = (bdbuf_task_control*) arg;
1181
1182  while (!tc->die)
1183  {
1184    switch (tc->test)
1185    {
1186      case 0:
1187        /*
1188         * Wait for the next test.
1189         */
1190        bdbuf_wait (tc->name, 0);
1191        break;
1192
1193      case 1:
1194        bdbuf_tests_task_0_test_1 (tc);
1195        break;
1196
1197      case 2:
1198        bdbuf_tests_task_0_test_2 (tc);
1199        break;
1200
1201      case 3:
1202        bdbuf_tests_task_0_test_3 (tc);
1203        break;
1204
1205      case 4:
1206        bdbuf_tests_task_0_test_4 (tc);
1207        break;
1208
1209      case 5:
1210        bdbuf_tests_task_0_test_5 (tc);
1211        break;
1212
1213      case 6:
1214        bdbuf_tests_task_0_test_6 (tc);
1215        break;
1216
1217      case 7:
1218        bdbuf_tests_task_0_test_7 (tc);
1219        break;
1220
1221      case 8:
1222        bdbuf_tests_task_0_test_8 (tc);
1223        break;
1224
1225      default:
1226        /*
1227         * Invalid test for this task. An error.
1228         */
1229        bdbuf_test_printf ("%s: invalid test: %d\n", tc->name, tc->test);
1230        tc->passed = false;
1231        tc->test = 0;
1232        break;
1233    }
1234  }
1235
1236  bdbuf_test_printf ("%s: delete task\n", tc->name);
1237  rtems_task_delete (RTEMS_SELF);
1238}
1239
1240/**
1241 * Get the blocks 0 -> 4 and release them. Task 0 should be holding
1242 * each one.
1243 */
1244static void
1245bdbuf_tests_ranged_get_release (bdbuf_task_control* tc,
1246                                bool                wake_master,
1247                                int                 lower,
1248                                int                 upper)
1249{
1250  rtems_status_code   sc;
1251  bool                passed;
1252  int                 i;
1253  rtems_bdbuf_buffer* bd;
1254
1255  /*
1256   * Set task control's passed to false to handle a timeout.
1257   */
1258  tc->passed = false;
1259  passed = true;
1260
1261  for (i = lower; (i < upper) && passed; i++)
1262  {
1263    bdbuf_test_printf ("%s: rtems_bdbuf_get[%d]: blocking ...\n", tc->name, i);
1264    sc = rtems_bdbuf_get (tc->dd, i, &bd);
1265    bdbuf_test_printf ("%s: rtems_bdbuf_get[%d]: ", tc->name, i);
1266    if (!bdbuf_test_print_sc (sc, true))
1267    {
1268      passed = false;
1269      break;
1270    }
1271
1272    bdbuf_test_printf ("%s: rtems_bdbuf_release[%d]: ", tc->name, i);
1273    sc = rtems_bdbuf_release (bd);
1274    if (!bdbuf_test_print_sc (sc, true))
1275    {
1276      passed = false;
1277      break;
1278    }
1279
1280    /*
1281     * Wake the master to tell it we have finished.
1282     */
1283    if (wake_master)
1284      bdbuf_send_wait_event (tc->name, "wake master", tc->master);
1285  }
1286
1287  tc->passed = passed;
1288  tc->test = 0;
1289}
1290
1291static void
1292bdbuf_tests_task_1 (rtems_task_argument arg)
1293{
1294  bdbuf_task_control* tc = (bdbuf_task_control*) arg;
1295
1296  while (!tc->die)
1297  {
1298    switch (tc->test)
1299    {
1300      case 0:
1301        /*
1302         * Wait for the next test.
1303         */
1304        bdbuf_wait (tc->name, 0);
1305        break;
1306
1307      case 2:
1308        bdbuf_tests_ranged_get_release (tc, false, 0, 5);
1309        break;
1310
1311      case 4:
1312        bdbuf_tests_ranged_get_release (tc, false, 0, 9);
1313        break;
1314
1315      case 5:
1316        bdbuf_tests_ranged_get_release (tc, false, 20, 25);
1317        break;
1318
1319      default:
1320        /*
1321         * Invalid test for this task. An error.
1322         */
1323        bdbuf_test_printf ("%s: invalid test: %d\n", tc->name, tc->test);
1324        tc->passed = false;
1325        tc->test = 0;
1326        break;
1327    }
1328  }
1329
1330  bdbuf_test_printf ("%s: delete task\n", tc->name);
1331  rtems_task_delete (RTEMS_SELF);
1332}
1333
1334/**
1335 * Get the blocks 0 -> 4 and release them. Task 0 should be holding
1336 * each one.
1337 */
1338static void
1339bdbuf_tests_task_2_test_2 (bdbuf_task_control* tc)
1340{
1341  /*
1342   * Use task 1's test 2. They are the same.
1343   */
1344  bdbuf_tests_ranged_get_release (tc, true, 0, 5);
1345}
1346
1347static void
1348bdbuf_tests_task_2 (rtems_task_argument arg)
1349{
1350  bdbuf_task_control* tc = (bdbuf_task_control*) arg;
1351
1352  while (!tc->die)
1353  {
1354    switch (tc->test)
1355    {
1356      case 0:
1357        /*
1358         * Wait for the next test.
1359         */
1360        bdbuf_wait (tc->name, 0);
1361        break;
1362
1363      case 2:
1364        bdbuf_tests_task_2_test_2 (tc);
1365        break;
1366
1367      default:
1368        /*
1369         * Invalid test for this task. An error.
1370         */
1371        bdbuf_test_printf ("%s: invalid test: %d\n", tc->name, tc->test);
1372        tc->passed = false;
1373        tc->test = 0;
1374        break;
1375    }
1376  }
1377
1378  bdbuf_test_printf ("%s: delete task\n", tc->name);
1379  rtems_task_delete (RTEMS_SELF);
1380}
1381
1382/**
1383 * Table of task entry points.
1384 */
1385static rtems_task_entry bdbuf_test_tasks[] =
1386{
1387  bdbuf_tests_task_0,
1388  bdbuf_tests_task_1,
1389  bdbuf_tests_task_2
1390};
1391
1392#define BDBUF_TESTS_PRI_HIGH (30)
1393
1394/**
1395 * Wait for the all tests to finish. This is signalled by the test
1396 * number becoming 0.
1397 */
1398static bool
1399bdbuf_tests_finished (bdbuf_task_control* tasks)
1400{
1401  uint32_t time = 0;
1402  bool     finished = false;
1403
1404  while (time < (10 * 4))
1405  {
1406    int t;
1407
1408    finished = true;
1409
1410    for (t = 0; t < BDBUF_TEST_TASKS; t++)
1411      if (tasks[t].test)
1412      {
1413        finished = false;
1414        break;
1415      }
1416
1417    if (finished)
1418      break;
1419
1420    bdbuf_sleep (250);
1421    time++;
1422  }
1423
1424  if (!finished)
1425    bdbuf_test_printf ("master: test timed out\n");
1426  else
1427  {
1428    int t;
1429    for (t = 0; t < BDBUF_TEST_TASKS; t++)
1430      if (!tasks[0].passed)
1431      {
1432        finished = false;
1433        break;
1434      }
1435  }
1436
1437  return finished;
1438}
1439
1440/**
1441 * Test 1.
1442 *
1443 * # Get task 0 to get buffer 0 from the pool then release it twice.
1444 */
1445static bool
1446bdbuf_test_1 (bdbuf_task_control* tasks)
1447{
1448  tasks[0].test = 1;
1449
1450  /*
1451   * Use pool 0.
1452   */
1453  tasks[0].minor = 0;
1454
1455  bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
1456
1457  return bdbuf_tests_finished (tasks);
1458}
1459
1460/**
1461 * Test 2.
1462 *
1463 * # Get task 0 to get buffers 0 -> 4 from the pool hold them. Then get
1464 * task 1 and task 2 to get them with blocking. The 2 tasks tests the
1465 * priority blocking on the buffer.
1466 */
1467static bool
1468bdbuf_test_2 (bdbuf_task_control* tasks)
1469{
1470  int i;
1471
1472  tasks[0].test = 2;
1473  tasks[1].test = 2;
1474  tasks[2].test = 2;
1475
1476  /*
1477   * Use pool 0.
1478   */
1479  tasks[0].minor = 0;
1480  tasks[1].minor = 0;
1481  tasks[2].minor = 0;
1482
1483  /*
1484   * Wake task 0 and wait for it to have all the buffers.
1485   */
1486  bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
1487  if (bdbuf_wait ("master", BDBUF_SECONDS (5)) != RTEMS_SUCCESSFUL)
1488    return false;
1489
1490  /*
1491   * Wake task 1.
1492   */
1493  bdbuf_send_wait_event ("master", "wake task 1", tasks[1].task);
1494
1495  /*
1496   * Wake task 2.
1497   */
1498  bdbuf_send_wait_event ("master", "wake task 2", tasks[2].task);
1499
1500  for (i = 0; i < 5; i++)
1501  {
1502    /*
1503     * Wake task 0 and watch task 2 then task 1 get the released buffer.
1504     */
1505    bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
1506
1507    /*
1508     * Wait until task 2 has the buffer.
1509     */
1510    if (bdbuf_wait ("master", BDBUF_SECONDS (5)) != RTEMS_SUCCESSFUL)
1511      return false;
1512  }
1513
1514  /*
1515   * Wait for the tests to finish.
1516   */
1517  return bdbuf_tests_finished (tasks);
1518}
1519
1520/**
1521 * Test 3.
1522 *
1523 * # Read a block from disk into the buffer, modify the block and release
1524 * it modified. Use a block great then 4 because 0 -> 4 are in the cache.
1525 */
1526static bool
1527bdbuf_test_3 (bdbuf_task_control* tasks)
1528{
1529  tasks[0].test = 3;
1530
1531  /*
1532   * Use pool 0.
1533   */
1534  tasks[0].minor = 0;
1535
1536  /*
1537   * Wake task 0.
1538   */
1539  bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
1540
1541  return bdbuf_tests_finished (tasks);
1542}
1543
1544/**
1545 * Test 4.
1546 *
1547 * # Read every buffer in the pool and hold. Then get task 1 to ask for another
1548 *   buffer that is being accessed. It will block waiting for it to appear.
1549 */
1550static bool
1551bdbuf_test_4 (bdbuf_task_control* tasks)
1552{
1553  tasks[0].test = 4;
1554  tasks[1].test = 4;
1555
1556  /*
1557   * Use pool 0.
1558   */
1559  tasks[0].minor = 0;
1560  tasks[1].minor = 0;
1561
1562  /*
1563   * Wake task 0.
1564   */
1565  bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
1566
1567  /*
1568   * Wait for the buffers in the pool to be taken.
1569   */
1570  if (bdbuf_wait ("master", BDBUF_SECONDS (5)) != RTEMS_SUCCESSFUL)
1571    return false;
1572
1573  bdbuf_sleep (100);
1574
1575  /*
1576   * Wake task 1 to read another one and have to block.
1577   */
1578  bdbuf_send_wait_event ("master", "wake task 1", tasks[1].task);
1579
1580  bdbuf_sleep (100);
1581
1582  /*
1583   * Wake task 0 to release it buffers.
1584   */
1585  bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
1586
1587  return bdbuf_tests_finished (tasks);
1588}
1589
1590/**
1591 * Test 5.
1592 *
1593 * # Read every buffer in the pool and hold. Then get task 1 to ask for a new
1594 *   buffer. It will block waiting for one to appear.
1595 */
1596static bool
1597bdbuf_test_5 (bdbuf_task_control* tasks)
1598{
1599  tasks[0].test = 5;
1600  tasks[1].test = 5;
1601
1602  /*
1603   * Use pool 0.
1604   */
1605  tasks[0].minor = 0;
1606  tasks[1].minor = 0;
1607
1608  /*
1609   * Wake task 0.
1610   */
1611  bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
1612
1613  /*
1614   * Wait for the buffers in the pool to be taken.
1615   */
1616  if (bdbuf_wait ("master", BDBUF_SECONDS (5)) != RTEMS_SUCCESSFUL)
1617    return false;
1618
1619  bdbuf_sleep (100);
1620
1621  /*
1622   * Wake task 1 to read another one and have to block.
1623   */
1624  bdbuf_send_wait_event ("master", "wake task 1", tasks[1].task);
1625
1626  bdbuf_sleep (100);
1627
1628  /*
1629   * Wake task 0 to release it buffers.
1630   */
1631  bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
1632
1633  return bdbuf_tests_finished (tasks);
1634}
1635
1636/**
1637 * Test 6.
1638 *
1639 * # Get 5 buffers, release modify 4 then sync the last.
1640 */
1641static bool
1642bdbuf_test_6 (bdbuf_task_control* tasks)
1643{
1644  tasks[0].test = 6;
1645
1646  /*
1647   * Use pool 0.
1648   */
1649  tasks[0].minor = 0;
1650
1651  /*
1652   * Wake task 0.
1653   */
1654  bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
1655
1656  return bdbuf_tests_finished (tasks);
1657}
1658
1659/**
1660 * Test 7.
1661 *
1662 * # Get 5 buffers, release modify them all then sync the device.
1663 */
1664static bool
1665bdbuf_test_7 (bdbuf_task_control* tasks)
1666{
1667  tasks[0].test = 7;
1668
1669  /*
1670   * Use pool 0.
1671   */
1672  tasks[0].minor = 0;
1673
1674  /*
1675   * Wake task 0.
1676   */
1677  bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
1678
1679  return bdbuf_tests_finished (tasks);
1680}
1681
1682/**
1683 * Test 8.
1684 *
1685 * # Get 5 buffers, release modify the last 2 then the reset from 0.
1686 */
1687static bool
1688bdbuf_test_8 (bdbuf_task_control* tasks)
1689{
1690  tasks[0].test = 8;
1691
1692  /*
1693   * Use pool 0.
1694   */
1695  tasks[0].minor = 0;
1696
1697  /*
1698   * Wake task 0.
1699   */
1700  bdbuf_send_wait_event ("master", "wake task 0", tasks[0].task);
1701
1702  return bdbuf_tests_finished (tasks);
1703}
1704
1705/**
1706 * A test.
1707 */
1708typedef bool (*bdbuf_test) (bdbuf_task_control* tasks);
1709
1710/**
1711 * A test name and function.
1712 */
1713typedef struct bdbuf_test_ident
1714{
1715  const char* label;
1716  bdbuf_test  test;
1717} bdbuf_test_ident;
1718
1719/**
1720 * Table of tests.
1721 */
1722static bdbuf_test_ident bdbuf_tests[] =
1723{
1724  {
1725    "Task 0 get buffer 0 from pool 0",
1726    bdbuf_test_1
1727  },
1728  {
1729    "Task 0 get buffer 0 -> 4 from pool 0, task 2 and 1 block getting",
1730    bdbuf_test_2
1731  },
1732  {
1733    "Task 0 read buffer 5, modify and release modified",
1734    bdbuf_test_3
1735  },
1736  {
1737    "Task 0 read all buffers, task 1 blocks waiting for acessed buffer",
1738    bdbuf_test_4
1739  },
1740  {
1741    "Task 0 read all buffers, task 1 blocks waiting for new buffer",
1742    bdbuf_test_5
1743  },
1744  {
1745    "Task 0 release modified 4 buffers then syncs a 5th buffer",
1746    bdbuf_test_6
1747  },
1748  {
1749    "Task 0 release modified 5 buffers then sync the device",
1750    bdbuf_test_7
1751  },
1752  {
1753    "Task 0 releases modified 5 buffers is out or order sequence and the" \
1754    " driver checks the buffers are in order",
1755    bdbuf_test_8
1756  }
1757};
1758
1759#define BDBUF_TEST_NUM (sizeof (bdbuf_tests) / sizeof (bdbuf_test_ident))
1760
1761/**
1762 * Test the BD Buffering code.
1763 */
1764static void
1765bdbuf_tester (void)
1766{
1767  rtems_device_major_number major;
1768  bdbuf_task_control        tasks[BDBUF_TEST_TASKS];
1769  rtems_task_priority       old_priority;
1770  int                       t;
1771  bool                      passed = true;
1772  rtems_disk_device        *dd;
1773
1774  /*
1775   * Change priority to a lower one.
1776   */
1777  bdbuf_test_printf ("lower priority to %d: ", BDBUF_TESTS_PRI_HIGH + 1);
1778  bdbuf_test_print_sc (rtems_task_set_priority (RTEMS_SELF,
1779                                                BDBUF_TESTS_PRI_HIGH + 1,
1780                                                &old_priority),
1781                       true);
1782
1783  /*
1784   * This sets up the buffer pools.
1785   */
1786  if (!bdbuf_tests_setup_disk (&major, &dd))
1787  {
1788    bdbuf_test_printf ("disk set up failed\n");
1789    return;
1790  }
1791
1792  /*
1793   * Make sure the swapout task has run. The user could block
1794   * the swapout task from running until later. This is not
1795   * tested.
1796   */
1797  bdbuf_sleep (100);
1798
1799  /*
1800   * Start the test tasks used to test the threading parts
1801   * of the bdbuf code.
1802   */
1803  for (t = 0; t < BDBUF_TEST_TASKS; t++)
1804  {
1805    bdbuf_task_control_init (t, &tasks[t],
1806                             rtems_task_self (),
1807                             major,
1808                             dd);
1809
1810    if (!bdbuf_tests_create_task (&tasks[t],
1811                                  BDBUF_TESTS_PRI_HIGH - t,
1812                                  bdbuf_test_tasks[t]))
1813    return;
1814  }
1815
1816  /*
1817   * Let the test tasks run if they have not already done so.
1818   */
1819  bdbuf_sleep (100);
1820
1821  /*
1822   * Perform each test.
1823   */
1824  for (t = 0; (t < BDBUF_TEST_NUM) && passed; t++)
1825  {
1826    bdbuf_test_printf ("test %d: %s\n", t + 1, bdbuf_tests[t].label);
1827    passed = bdbuf_tests[t].test (tasks);
1828    bdbuf_test_printf ("test %d: %s\n", t + 1, passed ? "passed" : "failed");
1829  }
1830}
1831
1832static rtems_task Init(rtems_task_argument argument)
1833{
1834  printf ("\n\n*** TEST BLOCK 6 ***\n");
1835
1836  bdbuf_tester ();
1837
1838  printf ("*** END OF TEST BLOCK 6 ***\n");
1839
1840  exit (0);
1841}
1842
1843#define CONFIGURE_INIT
1844
1845#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
1846#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
1847#define CONFIGURE_APPLICATION_NEEDS_LIBBLOCK
1848
1849#define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM
1850
1851#define CONFIGURE_BDBUF_TASK_STACK_SIZE BDBUF_TEST_STACK_SIZE
1852
1853#define CONFIGURE_MAXIMUM_TASKS (1 + BDBUF_TEST_TASKS)
1854#define CONFIGURE_MAXIMUM_DRIVERS 3
1855#define CONFIGURE_MAXIMUM_SEMAPHORES 2
1856
1857#define CONFIGURE_EXTRA_TASK_STACKS \
1858  (BDBUF_TEST_TASKS * BDBUF_TEST_STACK_SIZE)
1859
1860#define CONFIGURE_INIT_TASK_STACK_SIZE BDBUF_TEST_STACK_SIZE
1861#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
1862
1863#include <rtems/confdefs.h>
Note: See TracBrowser for help on using the repository browser.