summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cpukit/ChangeLog9
-rw-r--r--cpukit/libblock/include/rtems/bdbuf.h67
-rw-r--r--cpukit/libblock/src/bdbuf.c376
-rw-r--r--testsuites/libtests/ChangeLog8
-rw-r--r--testsuites/libtests/Makefile.am2
-rw-r--r--testsuites/libtests/block05/Makefile.am2
-rw-r--r--testsuites/libtests/block05/block05.doc28
-rw-r--r--testsuites/libtests/block05/block05.pngbin0 -> 54778 bytes
-rw-r--r--testsuites/libtests/block10/Makefile.am27
-rw-r--r--testsuites/libtests/block10/block10.doc47
-rw-r--r--testsuites/libtests/block10/block10.pngbin0 -> 70224 bytes
-rw-r--r--testsuites/libtests/block10/block10.scn226
-rw-r--r--testsuites/libtests/block10/init.c481
-rw-r--r--testsuites/libtests/configure.ac1
14 files changed, 1134 insertions, 140 deletions
diff --git a/cpukit/ChangeLog b/cpukit/ChangeLog
index a6673f0a1d..722c8f3fae 100644
--- a/cpukit/ChangeLog
+++ b/cpukit/ChangeLog
@@ -1,5 +1,14 @@
2010-01-26 Sebastian Huber <sebastian.huber@embedded-brains.de>
+ * libblock/include/rtems/bdbuf.h: Documentation. New states
+ RTEMS_BDBUF_STATE_ACCESS_PURGED and RTEMS_BDBUF_STATE_TRANSFER_PURGED.
+ Declare rtems_bdbuf_purge_dev() and rtems_bdbuf_purge_major().
+ * libblock/src/bdbuf.c: Implemented ability to purge buffers from the
+ cache depending on the device identifier or major number. See test
+ "libtests/block10".
+
+2010-01-26 Sebastian Huber <sebastian.huber@embedded-brains.de>
+
* score/src/userextaddapiset.c: Removed file.
* score/Makefile.am: Update for removed file.
* sapi/include/rtems/extension.h, sapi/src/extensioncreate.c,
diff --git a/cpukit/libblock/include/rtems/bdbuf.h b/cpukit/libblock/include/rtems/bdbuf.h
index f4e87568da..66a9bbf59b 100644
--- a/cpukit/libblock/include/rtems/bdbuf.h
+++ b/cpukit/libblock/include/rtems/bdbuf.h
@@ -86,7 +86,9 @@ extern "C" {
* ac [label="ACCESS CACHED",style="filled",fillcolor="royalblue"];
* am [label="ACCESS MODIFIED",style="filled",fillcolor="royalblue"];
* ae [label="ACCESS EMPTY",style="filled",fillcolor="royalblue"];
+ * ap [label="ACCESS PURGED",style="filled",fillcolor="royalblue"];
* t [label="TRANSFER",style="filled",fillcolor="red"];
+ * tp [label="TRANSFER PURGED",style="filled",fillcolor="red"];
* s [label="SYNC",style="filled",fillcolor="red"];
* m [label="MODIFIED",style="filled",fillcolor="gold"];
* i [label="INITIAL"];
@@ -97,26 +99,33 @@ extern "C" {
* i -> f [label="Init"];
* f -> e [label="Buffer Recycle"];
* e -> ae [label="Get"];
- * e -> t [label="Read\nRead Ahead"];
- * c -> f [label="Reallocate\nBlock Size Changed"];
+ * e -> t [label="Read"];
+ * e -> f [label="Nobody Waits"];
* c -> ac [label="Get\nRead"];
- * c -> e [label="Buffer Recycle"];
+ * c -> e [label="Buffer Recycle\nPurge"];
+ * c -> f [label="Reallocate\nBlock Size Changed"];
* t -> c [label="Transfer Done",color="red",fontcolor="red"];
- * t -> e [label="Transfer Error With Waiter",color="red",fontcolor="red"];
- * t -> f [label="Transfer Error Without Waiter",color="red",fontcolor="red"];
+ * t -> e [label="Transfer Error",color="red",fontcolor="red"];
+ * t -> tp [label="Purge"];
+ * tp -> e [label="Transfer Done\nTransfer Error",color="red",fontcolor="red"];
* m -> t [label="Swapout"];
* m -> s [label="Block Size Changed"];
* m -> am [label="Get\nRead"];
+ * m -> e [label="Purge"];
* ac -> m [label="Release Modified",color="royalblue",fontcolor="royalblue"];
* ac -> s [label="Sync",color="royalblue",fontcolor="royalblue"];
* ac -> c [label="Release",color="royalblue",fontcolor="royalblue"];
+ * ac -> ap [label="Purge"];
* am -> m [label="Release\nRelease Modified",color="royalblue",fontcolor="royalblue"];
* am -> s [label="Sync",color="royalblue",fontcolor="royalblue"];
+ * am -> ap [label="Purge"];
* ae -> m [label="Release Modified",color="royalblue",fontcolor="royalblue"];
* ae -> s [label="Sync",color="royalblue",fontcolor="royalblue"];
- * ae -> e [label="Release With Waiter",color="royalblue",fontcolor="royalblue"];
- * ae -> f [label="Release Without Waiter",color="royalblue",fontcolor="royalblue"];
+ * ae -> e [label="Release",color="royalblue",fontcolor="royalblue"];
+ * ae -> ap [label="Purge"];
+ * ap -> e [label="Release\nRelease Modified\nSync",color="royalblue",fontcolor="royalblue"];
* s -> t [label="Swapout"];
+ * s -> e [label="Purge",color="red",fontcolor="red"];
* }
* @enddot
*
@@ -184,22 +193,26 @@ extern "C" {
* </tr>
* <tr>
* <td>EMPTY</td><td></td><td>X</td>
- * <td>X</td><td></td><td></td><td></td><td></td>
+ * <td></td><td></td><td></td><td></td><td></td>
* </tr>
* <tr>
* <td>CACHED</td><td>X</td><td>X</td>
* <td>X</td><td></td><td></td><td></td><td></td>
* </tr>
* <tr>
- * <td>ACCESS_CACHED</td><td>X</td><td>X</td>
+ * <td>ACCESS CACHED</td><td>X</td><td>X</td>
+ * <td></td><td></td><td></td><td>X</td><td>X</td>
+ * </tr>
+ * <tr>
+ * <td>ACCESS MODIFIED</td><td>X</td><td>X</td>
* <td></td><td></td><td></td><td>X</td><td>X</td>
* </tr>
* <tr>
- * <td>ACCESS_MODIFIED</td><td>X</td><td>X</td>
+ * <td>ACCESS EMPTY</td><td></td><td>X</td>
* <td></td><td></td><td></td><td>X</td><td>X</td>
* </tr>
* <tr>
- * <td>ACCESS_EMPTY</td><td></td><td>X</td>
+ * <td>ACCESS PURGED</td><td></td><td>X</td>
* <td></td><td></td><td></td><td>X</td><td>X</td>
* </tr>
* <tr>
@@ -214,6 +227,10 @@ extern "C" {
* <td>TRANSFER</td><td>X</td><td>X</td>
* <td></td><td></td><td></td><td>X</td><td>X</td>
* </tr>
+ * <tr>
+ * <td>TRANSFER PURGED</td><td></td><td>X</td>
+ * <td></td><td></td><td></td><td>X</td><td>X</td>
+ * </tr>
* </table>
*/
typedef enum
@@ -249,6 +266,11 @@ typedef enum
RTEMS_BDBUF_STATE_ACCESS_EMPTY,
/**
+ * @brief Accessed by upper layer with purged data.
+ */
+ RTEMS_BDBUF_STATE_ACCESS_PURGED,
+
+ /**
* @brief Modified by upper layer.
*/
RTEMS_BDBUF_STATE_MODIFIED,
@@ -261,7 +283,12 @@ typedef enum
/**
* @brief In transfer by block device driver.
*/
- RTEMS_BDBUF_STATE_TRANSFER
+ RTEMS_BDBUF_STATE_TRANSFER,
+
+ /**
+ * @brief In transfer by block device driver and purged.
+ */
+ RTEMS_BDBUF_STATE_TRANSFER_PURGED
} rtems_bdbuf_buf_state;
/**
@@ -542,6 +569,22 @@ rtems_bdbuf_sync (rtems_bdbuf_buffer* bd);
rtems_status_code
rtems_bdbuf_syncdev (dev_t dev);
+/**
+ * @brief Purges all buffers that matches the device identifier @a dev.
+ *
+ * This may result in loss of data.
+ */
+void
+rtems_bdbuf_purge_dev (dev_t dev);
+
+/**
+ * @brief Purges all buffers that matches the device major number @a major.
+ *
+ * This may result in loss of data.
+ */
+void
+rtems_bdbuf_purge_major (rtems_device_major_number major);
+
/** @} */
#ifdef __cplusplus
diff --git a/cpukit/libblock/src/bdbuf.c b/cpukit/libblock/src/bdbuf.c
index 056a7c8ec2..862591503f 100644
--- a/cpukit/libblock/src/bdbuf.c
+++ b/cpukit/libblock/src/bdbuf.c
@@ -144,6 +144,7 @@ typedef struct rtems_bdbuf_cache
#define RTEMS_BLKDEV_FATAL_ERROR(n) \
(((uint32_t)'B' << 24) | ((uint32_t)(n) & (uint32_t)0x00FFFFFF))
+#define RTEMS_BLKDEV_FATAL_BDBUF_STATE_11 RTEMS_BLKDEV_FATAL_ERROR(1)
#define RTEMS_BLKDEV_FATAL_BDBUF_STATE_4 RTEMS_BLKDEV_FATAL_ERROR(2)
#define RTEMS_BLKDEV_FATAL_BDBUF_STATE_5 RTEMS_BLKDEV_FATAL_ERROR(3)
#define RTEMS_BLKDEV_FATAL_BDBUF_STATE_6 RTEMS_BLKDEV_FATAL_ERROR(4)
@@ -1033,6 +1034,62 @@ rtems_bdbuf_has_buffer_waiters (void)
}
static void
+rtems_bdbuf_remove_from_tree (rtems_bdbuf_buffer *bd)
+{
+ if (rtems_bdbuf_avl_remove (&bdbuf_cache.tree, bd) != 0)
+ rtems_bdbuf_fatal (bd->state, RTEMS_BLKDEV_FATAL_BDBUF_TREE_RM);
+}
+
+static void
+rtems_bdbuf_remove_from_tree_and_lru_list (rtems_bdbuf_buffer *bd)
+{
+ switch (bd->state)
+ {
+ case RTEMS_BDBUF_STATE_FREE:
+ break;
+ case RTEMS_BDBUF_STATE_CACHED:
+ rtems_bdbuf_remove_from_tree (bd);
+ break;
+ default:
+ rtems_bdbuf_fatal (bd->state, RTEMS_BLKDEV_FATAL_BDBUF_STATE_10);
+ }
+
+ rtems_chain_extract (&bd->link);
+}
+
+static void
+rtems_bdbuf_make_free_and_add_to_lru_list (rtems_bdbuf_buffer *bd)
+{
+ rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_FREE);
+ rtems_chain_prepend (&bdbuf_cache.lru, &bd->link);
+}
+
+static void
+rtems_bdbuf_make_empty (rtems_bdbuf_buffer *bd)
+{
+ rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_EMPTY);
+}
+
+static void
+rtems_bdbuf_make_cached_and_add_to_lru_list (rtems_bdbuf_buffer *bd)
+{
+ rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_CACHED);
+ rtems_chain_append (&bdbuf_cache.lru, &bd->link);
+}
+
+static void
+rtems_bdbuf_discard_buffer (rtems_bdbuf_buffer *bd)
+{
+ rtems_bdbuf_make_empty (bd);
+
+ if (bd->waiters == 0)
+ {
+ rtems_bdbuf_remove_from_tree (bd);
+ rtems_bdbuf_make_free_and_add_to_lru_list (bd);
+ }
+}
+
+static void
rtems_bdbuf_add_to_modified_list_after_access (rtems_bdbuf_buffer *bd)
{
if (bdbuf_cache.sync_active && bdbuf_cache.sync_device == bd->dev)
@@ -1075,9 +1132,8 @@ rtems_bdbuf_add_to_modified_list_after_access (rtems_bdbuf_buffer *bd)
static void
rtems_bdbuf_add_to_lru_list_after_access (rtems_bdbuf_buffer *bd)
{
- rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_CACHED);
- rtems_chain_append (&bdbuf_cache.lru, &bd->link);
rtems_bdbuf_group_release (bd);
+ rtems_bdbuf_make_cached_and_add_to_lru_list (bd);
if (bd->waiters)
rtems_bdbuf_wake (&bdbuf_cache.access_waiters);
@@ -1085,17 +1141,6 @@ rtems_bdbuf_add_to_lru_list_after_access (rtems_bdbuf_buffer *bd)
rtems_bdbuf_wake (&bdbuf_cache.buffer_waiters);
}
-static void
-rtems_bdbuf_add_to_sync_list_after_access (rtems_bdbuf_buffer *bd)
-{
- rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_SYNC);
-
- rtems_chain_append (&bdbuf_cache.sync, &bd->link);
-
- if (bd->waiters)
- rtems_bdbuf_wake (&bdbuf_cache.access_waiters);
-}
-
/**
* Compute the number of BDs per group for a given buffer size.
*
@@ -1121,60 +1166,15 @@ rtems_bdbuf_bds_per_group (size_t size)
}
static void
-rtems_bdbuf_remove_from_tree (rtems_bdbuf_buffer *bd)
-{
- if (rtems_bdbuf_avl_remove (&bdbuf_cache.tree, bd) != 0)
- rtems_bdbuf_fatal (bd->state, RTEMS_BLKDEV_FATAL_BDBUF_TREE_RM);
-}
-
-static void
-rtems_bdbuf_remove_from_tree_and_lru_list (rtems_bdbuf_buffer *bd)
-{
- switch (bd->state)
- {
- case RTEMS_BDBUF_STATE_FREE:
- break;
- case RTEMS_BDBUF_STATE_CACHED:
- rtems_bdbuf_remove_from_tree (bd);
- break;
- default:
- rtems_bdbuf_fatal (bd->state, RTEMS_BLKDEV_FATAL_BDBUF_STATE_10);
- }
-
- rtems_chain_extract (&bd->link);
-}
-
-static void
-rtems_bdbuf_make_free_and_add_to_lru_list (rtems_bdbuf_buffer *bd)
-{
- rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_FREE);
- rtems_chain_prepend (&bdbuf_cache.lru, &bd->link);
-}
-
-static void
-rtems_bdbuf_make_empty_and_add_to_lru_list (rtems_bdbuf_buffer *bd)
-{
- rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_EMPTY);
- rtems_chain_append (&bdbuf_cache.lru, &bd->link);
-}
-
-static void
-rtems_bdbuf_release_empty_buffer (rtems_bdbuf_buffer *bd)
+rtems_bdbuf_discard_buffer_after_access (rtems_bdbuf_buffer *bd)
{
rtems_bdbuf_group_release (bd);
+ rtems_bdbuf_discard_buffer (bd);
if (bd->waiters)
- {
- rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_EMPTY);
- rtems_chain_append (&bdbuf_cache.lru, &bd->link);
rtems_bdbuf_wake (&bdbuf_cache.access_waiters);
- }
else
- {
- rtems_bdbuf_remove_from_tree (bd);
- rtems_bdbuf_make_free_and_add_to_lru_list (bd);
rtems_bdbuf_wake (&bdbuf_cache.buffer_waiters);
- }
}
/**
@@ -1220,9 +1220,9 @@ rtems_bdbuf_group_realloc (rtems_bdbuf_group* group, size_t new_bds_per_group)
}
static void
-rtems_bdbuf_recycle_buffer (rtems_bdbuf_buffer *bd,
- dev_t dev,
- rtems_blkdev_bnum block)
+rtems_bdbuf_setup_empty_buffer (rtems_bdbuf_buffer *bd,
+ dev_t dev,
+ rtems_blkdev_bnum block)
{
bd->dev = dev;
bd->block = block;
@@ -1233,7 +1233,7 @@ rtems_bdbuf_recycle_buffer (rtems_bdbuf_buffer *bd,
if (rtems_bdbuf_avl_insert (&bdbuf_cache.tree, bd) != 0)
rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_RECYCLE);
- rtems_bdbuf_make_empty_and_add_to_lru_list (bd);
+ rtems_bdbuf_make_empty (bd);
}
static rtems_bdbuf_buffer *
@@ -1246,7 +1246,7 @@ rtems_bdbuf_get_buffer_from_lru_list (dev_t dev,
while (!rtems_chain_is_tail (&bdbuf_cache.lru, node))
{
rtems_bdbuf_buffer *bd = (rtems_bdbuf_buffer *) node;
- rtems_bdbuf_buffer *recycle_bd = NULL;
+ rtems_bdbuf_buffer *empty_bd = NULL;
if (rtems_bdbuf_tracer)
printf ("bdbuf:next-bd: %tu (%td:%" PRId32 ") %zd -> %zd\n",
@@ -1263,17 +1263,17 @@ rtems_bdbuf_get_buffer_from_lru_list (dev_t dev,
{
rtems_bdbuf_remove_from_tree_and_lru_list (bd);
- recycle_bd = bd;
+ empty_bd = bd;
}
else if (bd->group->users == 0)
- recycle_bd = rtems_bdbuf_group_realloc (bd->group, bds_per_group);
+ empty_bd = rtems_bdbuf_group_realloc (bd->group, bds_per_group);
}
- if (recycle_bd != NULL)
+ if (empty_bd != NULL)
{
- rtems_bdbuf_recycle_buffer (recycle_bd, dev, block);
+ rtems_bdbuf_setup_empty_buffer (empty_bd, dev, block);
- return recycle_bd;
+ return empty_bd;
}
node = rtems_chain_next (node);
@@ -1529,10 +1529,12 @@ rtems_bdbuf_wait_for_access (rtems_bdbuf_buffer *bd)
case RTEMS_BDBUF_STATE_ACCESS_CACHED:
case RTEMS_BDBUF_STATE_ACCESS_EMPTY:
case RTEMS_BDBUF_STATE_ACCESS_MODIFIED:
+ case RTEMS_BDBUF_STATE_ACCESS_PURGED:
rtems_bdbuf_wait (bd, &bdbuf_cache.access_waiters);
break;
- case RTEMS_BDBUF_STATE_TRANSFER:
case RTEMS_BDBUF_STATE_SYNC:
+ case RTEMS_BDBUF_STATE_TRANSFER:
+ case RTEMS_BDBUF_STATE_TRANSFER_PURGED:
rtems_bdbuf_wait (bd, &bdbuf_cache.transfer_waiters);
break;
default:
@@ -1586,10 +1588,12 @@ rtems_bdbuf_wait_for_recycle (rtems_bdbuf_buffer *bd)
case RTEMS_BDBUF_STATE_ACCESS_CACHED:
case RTEMS_BDBUF_STATE_ACCESS_EMPTY:
case RTEMS_BDBUF_STATE_ACCESS_MODIFIED:
+ case RTEMS_BDBUF_STATE_ACCESS_PURGED:
rtems_bdbuf_wait (bd, &bdbuf_cache.access_waiters);
break;
- case RTEMS_BDBUF_STATE_TRANSFER:
case RTEMS_BDBUF_STATE_SYNC:
+ case RTEMS_BDBUF_STATE_TRANSFER:
+ case RTEMS_BDBUF_STATE_TRANSFER_PURGED:
rtems_bdbuf_wait (bd, &bdbuf_cache.transfer_waiters);
break;
default:
@@ -1611,9 +1615,11 @@ rtems_bdbuf_wait_for_sync_done (rtems_bdbuf_buffer *bd)
case RTEMS_BDBUF_STATE_ACCESS_CACHED:
case RTEMS_BDBUF_STATE_ACCESS_EMPTY:
case RTEMS_BDBUF_STATE_ACCESS_MODIFIED:
+ case RTEMS_BDBUF_STATE_ACCESS_PURGED:
return;
case RTEMS_BDBUF_STATE_SYNC:
case RTEMS_BDBUF_STATE_TRANSFER:
+ case RTEMS_BDBUF_STATE_TRANSFER_PURGED:
rtems_bdbuf_wait (bd, &bdbuf_cache.transfer_waiters);
break;
default:
@@ -1631,6 +1637,35 @@ rtems_bdbuf_wait_for_buffer (void)
rtems_bdbuf_anonymous_wait (&bdbuf_cache.buffer_waiters);
}
+static void
+rtems_bdbuf_sync_after_access (rtems_bdbuf_buffer *bd)
+{
+ rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_SYNC);
+
+ rtems_chain_append (&bdbuf_cache.sync, &bd->link);
+
+ if (bd->waiters)
+ rtems_bdbuf_wake (&bdbuf_cache.access_waiters);
+
+ rtems_bdbuf_wake_swapper ();
+ rtems_bdbuf_wait_for_sync_done (bd);
+
+ /*
+ * We may have created a cached or empty buffer which may be recycled.
+ */
+ if (bd->waiters == 0
+ && (bd->state == RTEMS_BDBUF_STATE_CACHED
+ || bd->state == RTEMS_BDBUF_STATE_EMPTY))
+ {
+ if (bd->state == RTEMS_BDBUF_STATE_EMPTY)
+ {
+ rtems_bdbuf_remove_from_tree (bd);
+ rtems_bdbuf_make_free_and_add_to_lru_list (bd);
+ }
+ rtems_bdbuf_wake (&bdbuf_cache.buffer_waiters);
+ }
+}
+
static rtems_bdbuf_buffer *
rtems_bdbuf_get_buffer_for_read_ahead (dev_t dev,
rtems_blkdev_bnum block,
@@ -1930,8 +1965,8 @@ rtems_bdbuf_execute_transfer_request (const rtems_disk_device *dd,
rtems_status_code sc = RTEMS_SUCCESSFUL;
int result = 0;
uint32_t transfer_index = 0;
- bool wake_transfer = false;
- bool wake_buffer = false;
+ bool wake_transfer_waiters = false;
+ bool wake_buffer_waiters = false;
if (cache_locked)
rtems_bdbuf_unlock_cache ();
@@ -1951,38 +1986,28 @@ rtems_bdbuf_execute_transfer_request (const rtems_disk_device *dd,
for (transfer_index = 0; transfer_index < req->bufnum; ++transfer_index)
{
rtems_bdbuf_buffer *bd = req->bufs [transfer_index].user;
- bool waiters = bd->waiters > 0;
+ bool waiters = bd->waiters;
if (waiters)
- wake_transfer = true;
+ wake_transfer_waiters = true;
else
- wake_buffer = true;
+ wake_buffer_waiters = true;
rtems_bdbuf_group_release (bd);
- if (sc == RTEMS_SUCCESSFUL)
- {
- rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_CACHED);
- rtems_chain_append (&bdbuf_cache.lru, &bd->link);
- }
- else if (waiters)
- {
- rtems_bdbuf_make_empty_and_add_to_lru_list (bd);
- }
+ if (sc == RTEMS_SUCCESSFUL && bd->state == RTEMS_BDBUF_STATE_TRANSFER)
+ rtems_bdbuf_make_cached_and_add_to_lru_list (bd);
else
- {
- rtems_bdbuf_remove_from_tree (bd);
- rtems_bdbuf_make_free_and_add_to_lru_list (bd);
- }
+ rtems_bdbuf_discard_buffer (bd);
if (rtems_bdbuf_tracer)
rtems_bdbuf_show_users ("transfer", bd);
}
- if (wake_transfer)
+ if (wake_transfer_waiters)
rtems_bdbuf_wake (&bdbuf_cache.transfer_waiters);
- if (wake_buffer)
+ if (wake_buffer_waiters)
rtems_bdbuf_wake (&bdbuf_cache.buffer_waiters);
if (!cache_locked)
@@ -2100,7 +2125,8 @@ rtems_bdbuf_release (rtems_bdbuf_buffer *bd)
rtems_bdbuf_add_to_lru_list_after_access (bd);
break;
case RTEMS_BDBUF_STATE_ACCESS_EMPTY:
- rtems_bdbuf_release_empty_buffer (bd);
+ case RTEMS_BDBUF_STATE_ACCESS_PURGED:
+ rtems_bdbuf_discard_buffer_after_access (bd);
break;
case RTEMS_BDBUF_STATE_ACCESS_MODIFIED:
rtems_bdbuf_add_to_modified_list_after_access (bd);
@@ -2134,6 +2160,9 @@ rtems_bdbuf_release_modified (rtems_bdbuf_buffer *bd)
case RTEMS_BDBUF_STATE_ACCESS_MODIFIED:
rtems_bdbuf_add_to_modified_list_after_access (bd);
break;
+ case RTEMS_BDBUF_STATE_ACCESS_PURGED:
+ rtems_bdbuf_discard_buffer_after_access (bd);
+ break;
default:
rtems_bdbuf_fatal (bd->state, RTEMS_BLKDEV_FATAL_BDBUF_STATE_6);
break;
@@ -2161,7 +2190,10 @@ rtems_bdbuf_sync (rtems_bdbuf_buffer *bd)
case RTEMS_BDBUF_STATE_ACCESS_CACHED:
case RTEMS_BDBUF_STATE_ACCESS_EMPTY:
case RTEMS_BDBUF_STATE_ACCESS_MODIFIED:
- rtems_bdbuf_add_to_sync_list_after_access (bd);
+ rtems_bdbuf_sync_after_access (bd);
+ break;
+ case RTEMS_BDBUF_STATE_ACCESS_PURGED:
+ rtems_bdbuf_discard_buffer_after_access (bd);
break;
default:
rtems_bdbuf_fatal (bd->state, RTEMS_BLKDEV_FATAL_BDBUF_STATE_5);
@@ -2171,25 +2203,6 @@ rtems_bdbuf_sync (rtems_bdbuf_buffer *bd)
if (rtems_bdbuf_tracer)
rtems_bdbuf_show_usage ();
- rtems_bdbuf_wake_swapper ();
- rtems_bdbuf_wait_for_sync_done (bd);
-
- /*
- * If no one intercepts the sync, we created a cached buffer which may be
- * recycled.
- */
- if (bd->waiters == 0
- && (bd->state == RTEMS_BDBUF_STATE_CACHED
- || bd->state == RTEMS_BDBUF_STATE_EMPTY))
- {
- if (bd->state == RTEMS_BDBUF_STATE_EMPTY)
- {
- rtems_bdbuf_remove_from_tree (bd);
- rtems_bdbuf_make_free_and_add_to_lru_list (bd);
- }
- rtems_bdbuf_wake (&bdbuf_cache.buffer_waiters);
- }
-
rtems_bdbuf_unlock_cache ();
return RTEMS_SUCCESSFUL;
@@ -2809,3 +2822,140 @@ rtems_bdbuf_swapout_task (rtems_task_argument arg)
rtems_task_delete (RTEMS_SELF);
}
+
+static void
+rtems_bdbuf_purge_list (rtems_chain_control *purge_list)
+{
+ bool wake_buffer_waiters = false;
+ rtems_chain_node *node = NULL;
+
+ while ((node = rtems_chain_get (purge_list)) != NULL)
+ {
+ rtems_bdbuf_buffer *bd = (rtems_bdbuf_buffer *) node;
+
+ if (bd->waiters == 0)
+ wake_buffer_waiters = true;
+
+ rtems_bdbuf_discard_buffer (bd);
+ }
+
+ if (wake_buffer_waiters)
+ rtems_bdbuf_wake (&bdbuf_cache.buffer_waiters);
+}
+
+typedef bool (*rtems_bdbuf_purge_compare)(dev_t a, dev_t b);
+
+static void
+rtems_bdbuf_gather_for_purge (rtems_chain_control *purge_list,
+ rtems_bdbuf_purge_compare compare,
+ dev_t dev)
+{
+ rtems_bdbuf_buffer *stack [RTEMS_BDBUF_AVL_MAX_HEIGHT];
+ rtems_bdbuf_buffer **prev = stack;
+ rtems_bdbuf_buffer *cur = bdbuf_cache.tree;
+
+ *prev = NULL;
+
+ while (cur != NULL)
+ {
+ if ((*compare) (cur->dev, dev))
+ {
+ switch (cur->state)
+ {
+ case RTEMS_BDBUF_STATE_FREE:
+ case RTEMS_BDBUF_STATE_EMPTY:
+ case RTEMS_BDBUF_STATE_ACCESS_PURGED:
+ case RTEMS_BDBUF_STATE_TRANSFER_PURGED:
+ break;
+ case RTEMS_BDBUF_STATE_SYNC:
+ rtems_bdbuf_wake (&bdbuf_cache.transfer_waiters);
+ /* Fall through */
+ case RTEMS_BDBUF_STATE_MODIFIED:
+ rtems_bdbuf_group_release (cur);
+ /* Fall through */
+ case RTEMS_BDBUF_STATE_CACHED:
+ rtems_chain_extract (&cur->link);
+ rtems_chain_append (purge_list, &cur->link);
+ break;
+ case RTEMS_BDBUF_STATE_TRANSFER:
+ rtems_bdbuf_set_state (cur, RTEMS_BDBUF_STATE_TRANSFER_PURGED);
+ break;
+ case RTEMS_BDBUF_STATE_ACCESS_CACHED:
+ case RTEMS_BDBUF_STATE_ACCESS_EMPTY:
+ case RTEMS_BDBUF_STATE_ACCESS_MODIFIED:
+ rtems_bdbuf_set_state (cur, RTEMS_BDBUF_STATE_ACCESS_PURGED);
+ break;
+ default:
+ rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_STATE_11);
+ }
+ }
+
+ if (cur->avl.left != NULL)
+ {
+ /* Left */
+ ++prev;
+ *prev = cur;
+ cur = cur->avl.left;
+ }
+ else if (cur->avl.right != NULL)
+ {
+ /* Right */
+ ++prev;
+ *prev = cur;
+ cur = cur->avl.right;
+ }
+ else
+ {
+ while (*prev != NULL && cur == (*prev)->avl.right)
+ {
+ /* Up */
+ cur = *prev;
+ --prev;
+ }
+ if (*prev != NULL)
+ /* Right */
+ cur = (*prev)->avl.right;
+ else
+ /* Finished */
+ cur = NULL;
+ }
+ }
+}
+
+static void
+rtems_bdbuf_purge (rtems_bdbuf_purge_compare compare, dev_t dev)
+{
+ rtems_chain_control purge_list;
+
+ rtems_chain_initialize_empty (&purge_list);
+ rtems_bdbuf_lock_cache ();
+ rtems_bdbuf_gather_for_purge (&purge_list, compare, dev);
+ rtems_bdbuf_purge_list (&purge_list);
+ rtems_bdbuf_unlock_cache ();
+}
+
+static bool
+rtems_bdbuf_purge_compare_dev (dev_t a, dev_t b)
+{
+ return a == b;
+}
+
+void
+rtems_bdbuf_purge_dev (dev_t dev)
+{
+ rtems_bdbuf_purge (rtems_bdbuf_purge_compare_dev, dev);
+}
+
+static bool
+rtems_bdbuf_purge_compare_major (dev_t a, dev_t b)
+{
+ return rtems_filesystem_dev_major_t (a) == rtems_filesystem_dev_major_t (b);
+}
+
+void
+rtems_bdbuf_purge_major (rtems_device_major_number major)
+{
+ dev_t dev = rtems_filesystem_make_dev_t (major, 0);
+
+ rtems_bdbuf_purge (rtems_bdbuf_purge_compare_major, dev);
+}
diff --git a/testsuites/libtests/ChangeLog b/testsuites/libtests/ChangeLog
index 5062f44164..23530b02c7 100644
--- a/testsuites/libtests/ChangeLog
+++ b/testsuites/libtests/ChangeLog
@@ -1,3 +1,11 @@
+2010-01-21 Sebastian Huber <Sebastian.Huber@embedded-brains.de>
+
+ * block05/block05.png, block10/block10.doc, block10/init.c,
+ block10/.cvsignore, block10/block10.scn, block10/block10.png,
+ block10/Makefile.am: New files.
+ * configure.ac, Makefile.am: Update for new files.
+ * block05/block05.doc: Update for new state transitions.
+
2010-01-20 Joel Sherrill <joel.sherrill@oarcorp.com>
* block08/.cvsignore, block09/.cvsignore: New files.
diff --git a/testsuites/libtests/Makefile.am b/testsuites/libtests/Makefile.am
index cc51b4970b..c3974f7c35 100644
--- a/testsuites/libtests/Makefile.am
+++ b/testsuites/libtests/Makefile.am
@@ -7,7 +7,7 @@ ACLOCAL_AMFLAGS = -I ../aclocal
SUBDIRS = bspcmdline01 cpuuse malloctest heapwalk putenvtest monitor \
monitor02 rtmonuse stackchk stackchk01 termios termios01 termios02 \
rtems++ tztest block01 block02 block03 block04 block05 block06 block07 \
- block08 block09 stringto01
+ block08 block09 block10 stringto01
SUBDIRS += POSIX
include $(top_srcdir)/../automake/subdirs.am
diff --git a/testsuites/libtests/block05/Makefile.am b/testsuites/libtests/block05/Makefile.am
index f8429cc116..01c6247142 100644
--- a/testsuites/libtests/block05/Makefile.am
+++ b/testsuites/libtests/block05/Makefile.am
@@ -7,7 +7,7 @@ MANAGERS = io semaphore event
rtems_tests_PROGRAMS = block05
block05_SOURCES = init.c
-dist_rtems_tests_DATA = block05.scn block05.doc
+dist_rtems_tests_DATA = block05.scn block05.doc block05.png
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
include $(top_srcdir)/../automake/compile.am
diff --git a/testsuites/libtests/block05/block05.doc b/testsuites/libtests/block05/block05.doc
index 819701f250..a1042f6c93 100644
--- a/testsuites/libtests/block05/block05.doc
+++ b/testsuites/libtests/block05/block05.doc
@@ -1,7 +1,7 @@
#
# $Id$
#
-# Copyright (c) 2009
+# Copyright (c) 2009, 2010
# embedded brains GmbH
# Obere Lagerstr. 30
# D-82178 Puchheim
@@ -31,15 +31,17 @@ concepts:
State changes count during this test:
- | PREVIOUS STATE
- | FR EM CA AC AM AE MO SY TR
-------+------------------------------------------------------------------
- | FR 7470 0 4050 0 0 11368 0 0 0
- | EM 15419 0 17389 0 0 523 0 0 0
- | CA 0 0 0 10301 0 0 0 0 33886
- | AC 0 0 22747 0 0 0 0 0 0
-NEW | AM 0 0 0 0 0 0 3424 0 0
-STATE | AE 0 20485 0 0 0 0 0 0 0
- | MO 0 0 0 6226 2280 4294 0 0 0
- | SY 0 0 0 6220 1144 4300 0 0 0
- | TR 0 12846 0 0 0 0 9376 11664 0
+ | PREVIOUS STATE
+ | FR EM CA AC AM AE AP MO SY TF TP
+---------+------------------------------------------------------------------
+ FR | 12240 11980 0 0 0 0 0 0 0 0 0
+ EM | 11981 0 21499 0 0 12503 0 0 0 0 0
+ CA | 0 0 0 9717 0 0 0 0 0 33978 0
+ AC | 0 0 22195 0 0 0 0 0 0 0 0
+NEW AM | 0 0 0 0 0 0 0 3340 0 0 0
+STATE AE | 0 21121 0 0 0 0 0 0 0 0 0
+ AP | 0 0 0 0 0 0 0 0 0 0 0
+ MO | 0 0 0 6242 2224 4306 0 0 0 0 0
+ SY | 0 0 0 6236 1116 4312 0 0 0 0 0
+ TF | 0 12882 0 0 0 0 0 9432 11664 0 0
+ TP | 0 0 0 0 0 0 0 0 0 0 0
diff --git a/testsuites/libtests/block05/block05.png b/testsuites/libtests/block05/block05.png
new file mode 100644
index 0000000000..f48098c6d0
--- /dev/null
+++ b/testsuites/libtests/block05/block05.png
Binary files differ
diff --git a/testsuites/libtests/block10/Makefile.am b/testsuites/libtests/block10/Makefile.am
new file mode 100644
index 0000000000..2df0bb48c5
--- /dev/null
+++ b/testsuites/libtests/block10/Makefile.am
@@ -0,0 +1,27 @@
+##
+## $Id$
+##
+
+MANAGERS = io semaphore event
+
+rtems_tests_PROGRAMS = block10
+block10_SOURCES = init.c
+
+dist_rtems_tests_DATA = block10.scn block10.doc block10.png
+
+include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
+include $(top_srcdir)/../automake/compile.am
+include $(top_srcdir)/../automake/leaf.am
+
+block10_LDADD = $(MANAGERS_NOT_WANTED:%=$(PROJECT_LIB)/no-%.rel)
+
+AM_CPPFLAGS += -I$(top_srcdir)/../support/include
+
+LINK_OBJS = $(block10_OBJECTS) $(block10_LDADD)
+LINK_LIBS = $(block10_LDLIBS)
+
+block10$(EXEEXT): $(block10_OBJECTS) $(block10_DEPENDENCIES)
+ @rm -f block10$(EXEEXT)
+ $(make-exe)
+
+include $(top_srcdir)/../automake/local.am
diff --git a/testsuites/libtests/block10/block10.doc b/testsuites/libtests/block10/block10.doc
new file mode 100644
index 0000000000..de1f9057e9
--- /dev/null
+++ b/testsuites/libtests/block10/block10.doc
@@ -0,0 +1,47 @@
+#
+# $Id$
+#
+# Copyright (c) 2010
+# embedded brains GmbH
+# Obere Lagerstr. 30
+# D-82178 Puchheim
+# Germany
+# <rtems@embedded-brains.de>
+#
+# The license and distribution terms for this file may be
+# found in the file LICENSE in this distribution or at
+# http://www.rtems.com/license/LICENSE.
+#
+
+This file describes the directives and concepts tested by this test set.
+
+test set name: block10
+
+directives:
+
+ rtems_bdbuf_get
+ rtems_bdbuf_read
+ rtems_bdbuf_release
+ rtems_bdbuf_release_modified
+ rtems_bdbuf_sync
+
+concepts:
+
++ Purge functions test in various states
+
+State changes count during this test:
+
+ | PREVIOUS STATE
+ | FR EM CA AC AM AE AP MO SY TF TP
+---------+---------------------------------
+ FR | 0 28 0 0 0 0 0 0 0 0 0
+ EM | 28 0 4 0 0 14 18 2 2 0 2
+ CA | 0 0 0 2 0 0 0 0 0 18 0
+ AC | 0 0 16 0 0 0 0 0 0 0 0
+NEW AM | 0 0 0 0 0 0 0 6 0 0 0
+STATE AE | 0 26 0 0 0 0 0 0 0 0 0
+ AP | 0 0 0 6 6 6 0 0 0 0 0
+ MO | 0 0 0 2 0 6 0 0 0 0 0
+ SY | 0 0 0 6 0 0 0 0 0 0 0
+ TF | 0 16 0 0 0 0 0 0 4 0 0
+ TP | 0 0 0 0 0 0 0 0 0 2 0
diff --git a/testsuites/libtests/block10/block10.png b/testsuites/libtests/block10/block10.png
new file mode 100644
index 0000000000..6ff93dadc1
--- /dev/null
+++ b/testsuites/libtests/block10/block10.png
Binary files differ
diff --git a/testsuites/libtests/block10/block10.scn b/testsuites/libtests/block10/block10.scn
new file mode 100644
index 0000000000..dc5ab15784
--- /dev/null
+++ b/testsuites/libtests/block10/block10.scn
@@ -0,0 +1,226 @@
+*** TEST BLOCK 10 ***
+test case [access]: get and release with waiter
+I: try get
+I: get
+W: try get
+I: purge
+I: release
+I: release done
+W: get
+W: release
+W: release done
+test case [access]: get and release without waiter
+I: try get
+I: get
+I: purge
+I: release
+I: release done
+test case [access]: get and release modified with waiter
+I: try get
+I: get
+W: try get
+I: purge
+I: release modified
+I: release modified done
+W: get
+W: release
+W: release done
+test case [access]: get and release modified without waiter
+I: try get
+I: get
+I: purge
+I: release modified
+I: release modified done
+test case [access]: get and sync with waiter
+I: try get
+I: get
+W: try get
+I: purge
+I: sync
+I: sync done
+W: get
+W: release
+W: release done
+test case [access]: get and sync without waiter
+I: try get
+I: get
+I: purge
+I: sync
+I: sync done
+test case [access]: access modified and release with waiter
+I: try get modified
+I: get modified
+W: try get
+I: purge
+I: release
+I: release done
+W: get
+W: release
+W: release done
+test case [access]: access modified and release without waiter
+I: try get modified
+I: get modified
+I: purge
+I: release
+I: release done
+test case [access]: access modified and release modified with waiter
+I: try get modified
+I: get modified
+W: try get
+I: purge
+I: release modified
+I: release modified done
+W: get
+W: release
+W: release done
+test case [access]: access modified and release modified without waiter
+I: try get modified
+I: get modified
+I: purge
+I: release modified
+I: release modified done
+test case [access]: access modified and sync with waiter
+I: try get modified
+I: get modified
+W: try get
+I: purge
+I: sync
+I: sync done
+W: get
+W: release
+W: release done
+test case [access]: access modified and sync without waiter
+I: try get modified
+I: get modified
+I: purge
+I: sync
+I: sync done
+test case [access]: read and release with waiter
+I: try read
+I: read
+W: try get
+I: purge
+I: release
+I: release done
+W: get
+W: release
+W: release done
+test case [access]: read and release without waiter
+I: try read
+I: read
+I: purge
+I: release
+I: release done
+test case [access]: read and release modified with waiter
+I: try read
+I: read
+W: try get
+I: purge
+I: release modified
+I: release modified done
+W: get
+W: release
+W: release done
+test case [access]: read and release modified without waiter
+I: try read
+I: read
+I: purge
+I: release modified
+I: release modified done
+test case [access]: read and sync with waiter
+I: try read
+I: read
+W: try get
+I: purge
+I: sync
+I: sync done
+W: get
+W: release
+W: release done
+test case [access]: read and sync without waiter
+I: try read
+I: read
+I: purge
+I: sync
+I: sync done
+test case [intermediate]: release with waiter
+I: try read
+I: read
+W: try get
+I: release
+I: release done
+I: purge
+W: get
+W: release
+W: release done
+test case [intermediate]: release without waiter
+I: try read
+I: read
+I: release
+I: release done
+I: purge
+test case [intermediate]: release modified with waiter
+I: try read
+I: read
+W: try get
+I: release modified
+I: release modified done
+I: purge
+W: get
+W: release
+W: release done
+test case [intermediate]: release modified without waiter
+I: try read
+I: read
+I: release modified
+I: release modified done
+I: purge
+test case [intermediate]: sync with waiter
+I: try read
+I: read
+W: try get
+I: sync
+I: sync done
+I: purge
+W: get
+W: release
+W: release done
+test case [intermediate]: sync without waiter
+I: try read
+I: read
+I: sync
+I: sync done
+I: purge
+test case [transfer]: sync with waiter
+I: try read
+I: read
+W: try get
+I: sync
+P: purge
+I: sync done
+W: get
+W: release
+W: release done
+test case [transfer]: sync without waiter
+I: try read
+I: read
+I: sync
+P: purge
+I: sync done
+test case [transfer]: transfer with waiter
+I: try read
+I: read
+W: try get
+I: sync
+P: purge
+I: sync done
+W: get
+W: release
+W: release done
+test case [transfer]: transfer without waiter
+I: try read
+I: read
+I: sync
+P: purge
+I: sync done
+*** END OF TEST BLOCK 10 ***
diff --git a/testsuites/libtests/block10/init.c b/testsuites/libtests/block10/init.c
new file mode 100644
index 0000000000..add29768e4
--- /dev/null
+++ b/testsuites/libtests/block10/init.c
@@ -0,0 +1,481 @@
+/**
+ * @file
+ *
+ * @ingroup test_bdbuf
+ *
+ * @brief Bdbuf test for purge.
+ */
+
+/*
+ * Copyright (c) 2010
+ * embedded brains GmbH
+ * Obere Lagerstr. 30
+ * D-82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <rtems.h>
+#include <rtems/bdbuf.h>
+#include <rtems/diskdevs.h>
+
+#define ASSERT_SC(sc) assert((sc) == RTEMS_SUCCESSFUL)
+
+#define PRIORITY_HIGH 1
+
+#define PRIORITY_INIT 2
+
+#define PRIORITY_MID 3
+
+#define PRIORITY_SWAPOUT 4
+
+#define PRIORITY_LOW 5
+
+#define PRIORITY_IDLE 6
+
+#define BLOCK_SIZE 1
+
+#define BLOCK_COUNT 1
+
+typedef rtems_bdbuf_buffer *(*access_func)(char task);
+
+typedef void (*release_func)(char task, rtems_bdbuf_buffer *bd);
+
+static dev_t dev;
+
+static rtems_id task_id_init;
+
+static rtems_id task_id_purger;
+
+static rtems_id task_id_waiter;
+
+static const rtems_driver_address_table disk_ops = {
+ .initialization_entry = NULL,
+ RTEMS_GENERIC_BLOCK_DEVICE_DRIVER_ENTRIES
+};
+
+static void set_task_prio(rtems_id task, rtems_task_priority prio)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ rtems_task_priority cur = 0;
+
+ sc = rtems_task_set_priority(task, prio, &cur);
+ ASSERT_SC(sc);
+}
+
+static void suspend(rtems_id task)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ sc = rtems_task_suspend(task);
+ ASSERT_SC(sc);
+}
+
+static void resume(rtems_id task)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ sc = rtems_task_resume(task);
+ ASSERT_SC(sc);
+}
+
+static int disk_ioctl(rtems_disk_device *dd, uint32_t req, void *arg)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ if (req == RTEMS_BLKIO_REQUEST) {
+ rtems_blkdev_request *r = arg;
+
+ if (r->req == RTEMS_BLKDEV_REQ_WRITE) {
+ set_task_prio(RTEMS_SELF, PRIORITY_IDLE);
+ set_task_prio(RTEMS_SELF, PRIORITY_SWAPOUT);
+ }
+
+ r->req_done(r->done_arg, sc);
+
+ return 0;
+ } else {
+ return rtems_blkdev_ioctl(dd, req, arg);
+ }
+}
+
+rtems_status_code disk_register(
+ uint32_t block_size,
+ rtems_blkdev_bnum block_count,
+ dev_t *dev_ptr
+)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ rtems_device_major_number major = 0;
+ dev_t dev = 0;
+
+ sc = rtems_io_register_driver(0, &disk_ops, &major);
+ ASSERT_SC(sc);
+
+ dev = rtems_filesystem_make_dev_t(major, 0);
+
+ sc = rtems_disk_create_phys(
+ dev,
+ block_size,
+ block_count,
+ disk_ioctl,
+ NULL,
+ NULL
+ );
+ ASSERT_SC(sc);
+
+ *dev_ptr = dev;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+static rtems_bdbuf_buffer *do_get(char task)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ rtems_bdbuf_buffer *bd = NULL;
+
+ printk("%c: try get\n", task);
+
+ sc = rtems_bdbuf_get(dev, 0, &bd);
+ ASSERT_SC(sc);
+
+ printk("%c: get\n", task);
+
+ return bd;
+}
+
+static rtems_bdbuf_buffer *do_get_mod(char task)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ rtems_bdbuf_buffer *bd = NULL;
+
+ printk("%c: try get modified\n", task);
+
+ sc = rtems_bdbuf_get(dev, 0, &bd);
+ ASSERT_SC(sc);
+
+ sc = rtems_bdbuf_release_modified(bd);
+ ASSERT_SC(sc);
+
+ sc = rtems_bdbuf_get(dev, 0, &bd);
+ ASSERT_SC(sc);
+
+ printk("%c: get modified\n", task);
+
+ return bd;
+}
+
+static rtems_bdbuf_buffer *do_read(char task)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ rtems_bdbuf_buffer *bd = NULL;
+
+ printk("%c: try read\n", task);
+
+ sc = rtems_bdbuf_read(dev, 0, &bd);
+ ASSERT_SC(sc);
+
+ printk("%c: read\n", task);
+
+ return bd;
+}
+
+static void do_rel(char task, rtems_bdbuf_buffer *bd)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ printk("%c: release\n", task);
+
+ sc = rtems_bdbuf_release(bd);
+ ASSERT_SC(sc);
+
+ printk("%c: release done\n", task);
+}
+
+void do_rel_mod(char task, rtems_bdbuf_buffer *bd)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ printk("%c: release modified\n", task);
+
+ sc = rtems_bdbuf_release_modified(bd);
+ ASSERT_SC(sc);
+
+ printk("%c: release modified done\n", task);
+}
+
+static void do_sync(char task, rtems_bdbuf_buffer *bd)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ printk("%c: sync\n", task);
+
+ sc = rtems_bdbuf_sync(bd);
+ ASSERT_SC(sc);
+
+ printk("%c: sync done\n", task);
+}
+
+static void purge(char task)
+{
+ printk("%c: purge\n", task);
+
+ rtems_bdbuf_purge_dev(dev);
+}
+
+static void task_purger(rtems_task_argument arg)
+{
+ while (true) {
+ suspend(RTEMS_SELF);
+
+ set_task_prio(RTEMS_SELF, PRIORITY_HIGH);
+
+ purge('P');
+ }
+
+ rtems_task_delete(RTEMS_SELF);
+}
+
+static void activate_purger(rtems_task_priority prio)
+{
+ set_task_prio(task_id_purger, prio);
+ resume(task_id_purger);
+}
+
+static void task_waiter(rtems_task_argument arg)
+{
+ while (true) {
+ rtems_bdbuf_buffer *bd = NULL;
+
+ suspend(RTEMS_SELF);
+
+ bd = do_get('W');
+
+ do_rel('W', bd);
+ }
+
+ rtems_task_delete(RTEMS_SELF);
+}
+
+static void create_waiter(void)
+{
+ resume(task_id_waiter);
+ set_task_prio(task_id_waiter, PRIORITY_IDLE);
+}
+
+static void restore_waiter(void)
+{
+ set_task_prio(task_id_waiter, PRIORITY_HIGH);
+}
+
+static void check_access(access_func ac, release_func rel, bool waiter)
+{
+ rtems_bdbuf_buffer *bd = (*ac)('I');
+
+ if (waiter) {
+ create_waiter();
+ }
+
+ purge('I');
+
+ (*rel)('I', bd);
+
+ if (waiter) {
+ restore_waiter();
+ }
+}
+
+static void check_intermediate(release_func rel, bool waiter)
+{
+ rtems_bdbuf_buffer *bd = do_read('I');
+
+ if (waiter) {
+ create_waiter();
+ }
+
+ (*rel)('I', bd);
+
+ purge('I');
+
+ if (waiter) {
+ restore_waiter();
+ }
+}
+
+static void check_transfer(rtems_task_priority prio, bool waiter)
+{
+ rtems_bdbuf_buffer *bd = do_read('I');
+
+ if (waiter) {
+ create_waiter();
+ }
+
+ activate_purger(prio);
+
+ do_sync('I', bd);
+
+ if (waiter) {
+ restore_waiter();
+ }
+}
+
+static const bool waiter_table [] = {
+ true,
+ false
+};
+
+static const access_func access_table [] = {
+ do_get,
+ do_get_mod,
+ do_read
+};
+
+static const release_func release_table [] = {
+ do_rel,
+ do_rel_mod,
+ do_sync
+};
+
+static const rtems_task_priority purger_table [] = {
+ PRIORITY_MID,
+ PRIORITY_LOW
+};
+
+#define ARRAY_COUNT(array) (sizeof(array) / sizeof(array [0]))
+
+#define WAITER_COUNT ARRAY_COUNT(waiter_table)
+
+#define ACCESS_COUNT ARRAY_COUNT(access_table)
+
+#define RELEASE_COUNT ARRAY_COUNT(release_table)
+
+#define PURGER_COUNT ARRAY_COUNT(purger_table)
+
+static const char *waiter_assoc_table [WAITER_COUNT] = {
+ "with waiter",
+ "without waiter"
+};
+
+static const char *access_assoc_table [ACCESS_COUNT] = {
+ "get",
+ "access modified",
+ "read"
+};
+
+static const char *release_assoc_table [RELEASE_COUNT] = {
+ "release",
+ "release modified",
+ "sync"
+};
+
+static const char *purger_assoc_table [PURGER_COUNT] = {
+ "sync",
+ "transfer"
+};
+
+static rtems_task Init(rtems_task_argument argument)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ size_t i_w = 0;
+ size_t i_ac = 0;
+ size_t i_rel = 0;
+ size_t i_p = 0;
+
+ printk("\n\n*** TEST BLOCK 10 ***\n");
+
+ task_id_init = rtems_task_self();
+
+ sc = rtems_disk_io_initialize();
+ ASSERT_SC(sc);
+
+ sc = disk_register(BLOCK_SIZE, BLOCK_COUNT, &dev);
+ ASSERT_SC(sc);
+
+ sc = rtems_task_create(
+ rtems_build_name('P', 'U', 'R', 'G'),
+ PRIORITY_HIGH,
+ 0,
+ RTEMS_DEFAULT_MODES,
+ RTEMS_DEFAULT_ATTRIBUTES,
+ &task_id_purger
+ );
+ ASSERT_SC(sc);
+
+ sc = rtems_task_start(task_id_purger, task_purger, 0);
+ ASSERT_SC(sc);
+
+ set_task_prio(task_id_purger, PRIORITY_LOW);
+
+ sc = rtems_task_create(
+ rtems_build_name('W', 'A', 'I', 'T'),
+ PRIORITY_HIGH,
+ 0,
+ RTEMS_DEFAULT_MODES,
+ RTEMS_DEFAULT_ATTRIBUTES,
+ &task_id_waiter
+ );
+ ASSERT_SC(sc);
+
+ sc = rtems_task_start(task_id_waiter, task_waiter, 0);
+ ASSERT_SC(sc);
+
+ for (i_ac = 0; i_ac < ACCESS_COUNT; ++i_ac) {
+ for (i_rel = 0; i_rel < RELEASE_COUNT; ++i_rel) {
+ for (i_w = 0; i_w < WAITER_COUNT; ++i_w) {
+ printk("test case [access]: %s and %s %s\n", access_assoc_table [i_ac], release_assoc_table [i_rel], waiter_assoc_table [i_w]);
+ check_access(access_table [i_ac], release_table [i_rel], waiter_table [i_w]);
+ }
+ }
+ }
+
+ for (i_rel = 0; i_rel < RELEASE_COUNT; ++i_rel) {
+ for (i_w = 0; i_w < WAITER_COUNT; ++i_w) {
+ printk("test case [intermediate]: %s %s\n", release_assoc_table [i_rel], waiter_assoc_table [i_w]);
+ check_intermediate(release_table [i_rel], waiter_table [i_w]);
+ }
+ }
+
+ for (i_p = 0; i_p < PURGER_COUNT; ++i_p) {
+ for (i_w = 0; i_w < WAITER_COUNT; ++i_w) {
+ printk("test case [transfer]: %s %s\n", purger_assoc_table [i_p], waiter_assoc_table [i_w]);
+ check_transfer(purger_table [i_p], waiter_table [i_w]);
+ }
+ }
+
+ printk("*** END OF TEST BLOCK 10 ***\n");
+
+ exit(0);
+}
+
+#define CONFIGURE_INIT
+
+#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_LIBBLOCK
+
+#define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM
+
+#define CONFIGURE_MAXIMUM_TASKS 5
+#define CONFIGURE_MAXIMUM_DRIVERS 4
+#define CONFIGURE_MAXIMUM_SEMAPHORES 5
+
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+
+#define CONFIGURE_INIT_TASK_PRIORITY PRIORITY_INIT
+#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_DEFAULT_ATTRIBUTES
+#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES
+
+#define CONFIGURE_SWAPOUT_TASK_PRIORITY PRIORITY_SWAPOUT
+
+#define CONFIGURE_BDBUF_BUFFER_MIN_SIZE BLOCK_SIZE
+#define CONFIGURE_BDBUF_BUFFER_MAX_SIZE BLOCK_SIZE
+#define CONFIGURE_BDBUF_CACHE_MEMORY_SIZE (BLOCK_SIZE * BLOCK_COUNT)
+
+#include <rtems/confdefs.h>
diff --git a/testsuites/libtests/configure.ac b/testsuites/libtests/configure.ac
index a93ba4ccda..d1d472c598 100644
--- a/testsuites/libtests/configure.ac
+++ b/testsuites/libtests/configure.ac
@@ -42,6 +42,7 @@ block06/Makefile
block07/Makefile
block08/Makefile
block09/Makefile
+block10/Makefile
bspcmdline01/Makefile
cpuuse/Makefile
heapwalk/Makefile