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

4.115
Last change on this file since 796967c was 796967c, checked in by Sebastian Huber <sebastian.huber@…>, on 02/28/12 at 16:19:49

libblock: Change bdbuf API

The functions

o rtems_bdbuf_get(),
o rtems_bdbuf_read(),
o rtems_bdbuf_syncdev(), and
o rtems_bdbuf_purge_dev(),

use now the disk device instead of the device identifier. This makes
bdbuf independent of rtems_disk_obtain() and rtems_disk_release(). It
is the responsiblity of the file system to obtain the disk device. This
also reduces the overhead to get a buffer.

The key for the AVL tree uses now the disk device instead of the device
identifier. The pointer is interpreted as an unsigned integer. This
reduces the memory overhead and makes the comparison operation a bit
faster.

Removed function rtems_bdbuf_purge_major(). This function was too
destructive and could have unpredictable side effects.

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