source: rtems/testsuites/libtests/block06/init.c @ 90b301c

Last change on this file since 90b301c was 40284de, checked in by Sebastian Huber <sebastian.huber@…>, on 05/30/12 at 10:43:56

libblock: Remove const qualifier from bdbuf API

This allows addtion of per disk statistics for example.

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