Allow dirty writes selectively
This commit is contained in:
parent
e1e0e9662d
commit
0944f84ac9
@ -106,7 +106,7 @@ bay_init(struct bay *bay)
|
|||||||
static int
|
static int
|
||||||
propagate_chan(struct bay_chan *bchan)
|
propagate_chan(struct bay_chan *bchan)
|
||||||
{
|
{
|
||||||
dbg("propagating dirty channel %p\n", (void *) bchan);
|
dbg("- propagating dirty channel %s\n", bchan->chan->name);
|
||||||
|
|
||||||
struct bay_cb *cur = NULL;
|
struct bay_cb *cur = NULL;
|
||||||
struct bay_cb *tmp = NULL;
|
struct bay_cb *tmp = NULL;
|
||||||
@ -123,7 +123,7 @@ propagate_chan(struct bay_chan *bchan)
|
|||||||
int
|
int
|
||||||
bay_propagate(struct bay *bay)
|
bay_propagate(struct bay *bay)
|
||||||
{
|
{
|
||||||
dbg("propagating channels\n");
|
dbg("-- propagating channels begins\n");
|
||||||
struct bay_chan *cur = NULL;
|
struct bay_chan *cur = NULL;
|
||||||
struct bay_chan *tmp = NULL;
|
struct bay_chan *tmp = NULL;
|
||||||
DL_FOREACH_SAFE(bay->dirty, cur, tmp) {
|
DL_FOREACH_SAFE(bay->dirty, cur, tmp) {
|
||||||
@ -134,8 +134,20 @@ bay_propagate(struct bay *bay)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Flush channels after running all the dirty callbacks, so we
|
||||||
|
* capture any potential double write when running the
|
||||||
|
* callbacks */
|
||||||
|
DL_FOREACH_SAFE(bay->dirty, cur, tmp) {
|
||||||
|
if (chan_flush(cur->chan) != 0) {
|
||||||
|
err("bay_propagate: chan_flush failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bay->dirty = NULL;
|
bay->dirty = NULL;
|
||||||
|
|
||||||
|
dbg("-- propagating channels ends\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +36,10 @@ static int
|
|||||||
set_dirty(struct chan *chan)
|
set_dirty(struct chan *chan)
|
||||||
{
|
{
|
||||||
if (chan->is_dirty) {
|
if (chan->is_dirty) {
|
||||||
|
/* Already dirty and allowed, no need to do anything */
|
||||||
|
if (chan->allow_dirty_write)
|
||||||
|
return 0;
|
||||||
|
|
||||||
err("channel %s already dirty\n", chan->name);
|
err("channel %s already dirty\n", chan->name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -44,7 +48,8 @@ set_dirty(struct chan *chan)
|
|||||||
|
|
||||||
if (chan->dirty_cb != NULL) {
|
if (chan->dirty_cb != NULL) {
|
||||||
if (chan->dirty_cb(chan, chan->dirty_arg) != 0) {
|
if (chan->dirty_cb(chan, chan->dirty_arg) != 0) {
|
||||||
err("dirty callback failed\n");
|
err("set_dirty %s: dirty callback failed\n",
|
||||||
|
chan->name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -60,7 +65,8 @@ check_duplicates(struct chan *chan, struct value *v)
|
|||||||
// return 0;
|
// return 0;
|
||||||
|
|
||||||
if (value_is_equal(&chan->last_value, v)) {
|
if (value_is_equal(&chan->last_value, v)) {
|
||||||
err("check_duplicates: same value as last_value\n");
|
err("check_duplicates %s: same value as last_value\n",
|
||||||
|
chan->name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,27 +77,30 @@ int
|
|||||||
chan_set(struct chan *chan, struct value value)
|
chan_set(struct chan *chan, struct value value)
|
||||||
{
|
{
|
||||||
if (chan->type != CHAN_SINGLE) {
|
if (chan->type != CHAN_SINGLE) {
|
||||||
err("chan_set: cannot set on non-single channel\n");
|
err("chan_set %s: cannot set on non-single channel\n",
|
||||||
|
chan->name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chan->is_dirty) {
|
if (chan->is_dirty && !chan->allow_dirty_write) {
|
||||||
err("chan_set: cannot modify dirty channel\n");
|
err("chan_set %s: cannot modify dirty channel\n",
|
||||||
|
chan->name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_duplicates(chan, &value) != 0) {
|
if (check_duplicates(chan, &value) != 0) {
|
||||||
err("chan_set: cannot set a duplicated value\n");
|
err("chan_set %s: cannot set a duplicated value\n",
|
||||||
|
chan->name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char buf[128];
|
char buf[128];
|
||||||
dbg("chan_set: channel %p sets value %s\n", (void *) chan,
|
dbg("chan_set %s: sets value to %s\n",
|
||||||
value_str(value, buf));
|
chan->name, value_str(value, buf));
|
||||||
chan->data.value = value;
|
chan->data.value = value;
|
||||||
|
|
||||||
if (set_dirty(chan) != 0) {
|
if (set_dirty(chan) != 0) {
|
||||||
err("chan_set: set_dirty failed\n");
|
err("chan_set %s: set_dirty failed\n", chan->name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,31 +117,34 @@ int
|
|||||||
chan_push(struct chan *chan, struct value value)
|
chan_push(struct chan *chan, struct value value)
|
||||||
{
|
{
|
||||||
if (chan->type != CHAN_STACK) {
|
if (chan->type != CHAN_STACK) {
|
||||||
err("chan_push: cannot push on non-stack channel\n");
|
err("chan_push %s: cannot push on non-stack channel\n",
|
||||||
|
chan->name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chan->is_dirty) {
|
if (chan->is_dirty && !chan->allow_dirty_write) {
|
||||||
err("chan_push: cannot modify dirty channel\n");
|
err("chan_push %s: cannot modify dirty channel\n",
|
||||||
|
chan->name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_duplicates(chan, &value) != 0) {
|
if (check_duplicates(chan, &value) != 0) {
|
||||||
err("chan_push: cannot push a duplicated value\n");
|
err("chan_push %s: cannot push a duplicated value\n",
|
||||||
|
chan->name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct chan_stack *stack = &chan->data.stack;
|
struct chan_stack *stack = &chan->data.stack;
|
||||||
|
|
||||||
if (stack->n >= MAX_CHAN_STACK) {
|
if (stack->n >= MAX_CHAN_STACK) {
|
||||||
err("chan_push: channel stack full\n");
|
err("chan_push %s: channel stack full\n", chan->name);
|
||||||
abort();
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
stack->values[stack->n++] = value;
|
stack->values[stack->n++] = value;
|
||||||
|
|
||||||
if (set_dirty(chan) != 0) {
|
if (set_dirty(chan) != 0) {
|
||||||
err("chan_set: set_dirty failed\n");
|
err("chan_push %s: set_dirty failed\n", chan->name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,34 +162,36 @@ int
|
|||||||
chan_pop(struct chan *chan, struct value evalue)
|
chan_pop(struct chan *chan, struct value evalue)
|
||||||
{
|
{
|
||||||
if (chan->type != CHAN_STACK) {
|
if (chan->type != CHAN_STACK) {
|
||||||
err("chan_pop: cannot pop on non-stack channel\n");
|
err("chan_pop %s: cannot pop on non-stack channel\n",
|
||||||
|
chan->name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chan->is_dirty) {
|
if (chan->is_dirty && !chan->allow_dirty_write) {
|
||||||
err("chan_pop: cannot modify dirty channel\n");
|
err("chan_pop %s: cannot modify dirty channel\n",
|
||||||
|
chan->name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct chan_stack *stack = &chan->data.stack;
|
struct chan_stack *stack = &chan->data.stack;
|
||||||
|
|
||||||
if (stack->n <= 0) {
|
if (stack->n <= 0) {
|
||||||
err("chan_pop: channel stack empty\n");
|
err("chan_pop %s: channel stack empty\n", chan->name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct value *value = &stack->values[stack->n - 1];
|
struct value *value = &stack->values[stack->n - 1];
|
||||||
|
|
||||||
if (!value_is_equal(value, &evalue)) {
|
if (!value_is_equal(value, &evalue)) {
|
||||||
err("chan_pop: unexpected value %ld (expected %ld)\n",
|
err("chan_pop %s: unexpected value %ld (expected %ld)\n",
|
||||||
value->i, evalue.i);
|
chan->name, value->i, evalue.i);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
stack->n--;
|
stack->n--;
|
||||||
|
|
||||||
if (set_dirty(chan) != 0) {
|
if (set_dirty(chan) != 0) {
|
||||||
err("chan_set: set_dirty failed\n");
|
err("chan_pop %s: set_dirty failed\n", chan->name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,7 +208,7 @@ get_value(struct chan *chan, struct value *value)
|
|||||||
|
|
||||||
struct chan_stack *stack = &chan->data.stack;
|
struct chan_stack *stack = &chan->data.stack;
|
||||||
if (stack->n <= 0) {
|
if (stack->n <= 0) {
|
||||||
err("get_value: channel stack empty\n");
|
err("get_value %s: channel stack empty\n", chan->name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,9 +222,29 @@ int
|
|||||||
chan_read(struct chan *chan, struct value *value)
|
chan_read(struct chan *chan, struct value *value)
|
||||||
{
|
{
|
||||||
if (get_value(chan, value) != 0) {
|
if (get_value(chan, value) != 0) {
|
||||||
err("chan_read: get_value failed\n");
|
err("chan_read %s: get_value failed\n", chan->name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Remove the dirty state */
|
||||||
|
int
|
||||||
|
chan_flush(struct chan *chan)
|
||||||
|
{
|
||||||
|
if (!chan->is_dirty) {
|
||||||
|
err("chan_flush %s: channel is not dirty\n", chan->name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
chan->is_dirty = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
chan_dirty_write(struct chan *chan, int allow)
|
||||||
|
{
|
||||||
|
chan->allow_dirty_write = allow;
|
||||||
|
}
|
||||||
|
@ -35,6 +35,7 @@ struct chan {
|
|||||||
enum chan_type type;
|
enum chan_type type;
|
||||||
union chan_data data;
|
union chan_data data;
|
||||||
int is_dirty;
|
int is_dirty;
|
||||||
|
int allow_dirty_write;
|
||||||
struct value err_value;
|
struct value err_value;
|
||||||
struct value last_value;
|
struct value last_value;
|
||||||
chan_cb_t dirty_cb;
|
chan_cb_t dirty_cb;
|
||||||
@ -51,6 +52,8 @@ int chan_push(struct chan *chan, struct value value);
|
|||||||
int chan_pop(struct chan *chan, struct value expected);
|
int chan_pop(struct chan *chan, struct value expected);
|
||||||
int chan_read(struct chan *chan, struct value *value);
|
int chan_read(struct chan *chan, struct value *value);
|
||||||
enum chan_type chan_get_type(struct chan *chan);
|
enum chan_type chan_get_type(struct chan *chan);
|
||||||
|
int chan_flush(struct chan *chan);
|
||||||
|
void chan_dirty_write(struct chan *chan, int allow);
|
||||||
|
|
||||||
/* Called when it becomes dirty */
|
/* Called when it becomes dirty */
|
||||||
void chan_set_dirty_cb(struct chan *chan, chan_cb_t func, void *arg);
|
void chan_set_dirty_cb(struct chan *chan, chan_cb_t func, void *arg);
|
||||||
|
@ -64,7 +64,8 @@ cb_select(struct chan *sel_chan, void *ptr)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
dbg("selecting mux input %p\n", (void *) input);
|
dbg("mux selects input key=%s chan=%s\n",
|
||||||
|
value_str(sel_value, buf), input->chan->name);
|
||||||
|
|
||||||
/* Set to null by default */
|
/* Set to null by default */
|
||||||
struct value out_value = value_null();
|
struct value out_value = value_null();
|
||||||
@ -102,8 +103,11 @@ cb_input(struct chan *in_chan, void *ptr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Nothing to do, the input is not selected */
|
/* Nothing to do, the input is not selected */
|
||||||
if (input == NULL || input->chan != in_chan)
|
if (input == NULL || input->chan != in_chan) {
|
||||||
|
dbg("mux: input channel %s changed but not selected\n",
|
||||||
|
in_chan->name);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
dbg("selected mux input %s changed\n", in_chan->name);
|
dbg("selected mux input %s changed\n", in_chan->name);
|
||||||
|
|
||||||
@ -135,6 +139,11 @@ mux_init(struct mux *mux,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The output channel must accept multiple writes in the same
|
||||||
|
* propagation phase, as we may write to the input and select
|
||||||
|
* channel at the same time. */
|
||||||
|
chan_dirty_write(output, 1);
|
||||||
|
|
||||||
memset(mux, 0, sizeof(struct mux_input));
|
memset(mux, 0, sizeof(struct mux_input));
|
||||||
mux->select = select;
|
mux->select = select;
|
||||||
mux->output = output;
|
mux->output = output;
|
||||||
|
@ -2,7 +2,46 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
static void
|
static void
|
||||||
check_single(void)
|
test_dirty(void)
|
||||||
|
{
|
||||||
|
struct chan chan;
|
||||||
|
chan_init(&chan, CHAN_SINGLE, "testchan");
|
||||||
|
|
||||||
|
if (chan_set(&chan, value_int64(1)) != 0)
|
||||||
|
die("chan_set failed\n");
|
||||||
|
|
||||||
|
/* Now channel is dirty */
|
||||||
|
|
||||||
|
if (chan_set(&chan, value_int64(2)) == 0)
|
||||||
|
die("chan_set didn't fail\n");
|
||||||
|
|
||||||
|
if (chan_flush(&chan) != 0)
|
||||||
|
die("chan_flush failed\n");
|
||||||
|
|
||||||
|
chan_dirty_write(&chan, 1);
|
||||||
|
|
||||||
|
if (chan_set(&chan, value_int64(3)) != 0)
|
||||||
|
die("chan_set failed\n");
|
||||||
|
|
||||||
|
/* Now is dirty, but it should allow multiple writes */
|
||||||
|
if (chan_set(&chan, value_int64(4)) != 0)
|
||||||
|
die("chan_set failed\n");
|
||||||
|
|
||||||
|
struct value value;
|
||||||
|
struct value four = value_int64(4);
|
||||||
|
|
||||||
|
if (chan_read(&chan, &value) != 0)
|
||||||
|
die("chan_read failed\n");
|
||||||
|
|
||||||
|
if (!value_is_equal(&value, &four))
|
||||||
|
die("chan_read returned unexpected value\n");
|
||||||
|
|
||||||
|
if (chan_flush(&chan) != 0)
|
||||||
|
die("chan_flush failed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_single(void)
|
||||||
{
|
{
|
||||||
struct chan chan;
|
struct chan chan;
|
||||||
struct value one = { .type = VALUE_INT64, .i = 1 };
|
struct value one = { .type = VALUE_INT64, .i = 1 };
|
||||||
@ -33,7 +72,7 @@ check_single(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//static void
|
//static void
|
||||||
//check_stack(void)
|
//test_stack(void)
|
||||||
//{
|
//{
|
||||||
// struct chan chan;
|
// struct chan chan;
|
||||||
//
|
//
|
||||||
@ -91,7 +130,8 @@ check_single(void)
|
|||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
check_single();
|
test_single();
|
||||||
//check_stack();
|
test_dirty();
|
||||||
|
//test_stack();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
154
test/unit/mux.c
154
test/unit/mux.c
@ -1,7 +1,7 @@
|
|||||||
#include "emu/mux.h"
|
#include "emu/mux.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
#define N 4
|
#define N 6
|
||||||
|
|
||||||
//static int
|
//static int
|
||||||
//select_active_thread(struct mux *mux,
|
//select_active_thread(struct mux *mux,
|
||||||
@ -39,6 +39,132 @@
|
|||||||
// return 0;
|
// return 0;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
static void
|
||||||
|
check_output(struct mux *mux, struct value expected)
|
||||||
|
{
|
||||||
|
struct value out_value = value_null();
|
||||||
|
if (chan_read(mux->output, &out_value) != 0)
|
||||||
|
die("chan_read() failed for output channel\n");
|
||||||
|
|
||||||
|
if (!value_is_equal(&out_value, &expected)) {
|
||||||
|
char buf1[128];
|
||||||
|
char buf2[128];
|
||||||
|
die("unexpected value found %s in output (expected %s)\n",
|
||||||
|
value_str(out_value, buf1),
|
||||||
|
value_str(expected, buf2));
|
||||||
|
}
|
||||||
|
|
||||||
|
err("----- output ok -----\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_select(struct mux *mux, int key)
|
||||||
|
{
|
||||||
|
if (chan_set(mux->select, value_int64(key)) != 0)
|
||||||
|
die("chan_set failed\n");
|
||||||
|
|
||||||
|
if (bay_propagate(mux->bay) != 0)
|
||||||
|
die("bay_propagate failed\n");
|
||||||
|
|
||||||
|
check_output(mux, value_int64(1000 + key));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_input(struct mux *mux, int key)
|
||||||
|
{
|
||||||
|
/* Set the select channel to the selected key */
|
||||||
|
test_select(mux, key);
|
||||||
|
|
||||||
|
int new_value = 2000 + key;
|
||||||
|
|
||||||
|
/* Then change that channel */
|
||||||
|
struct mux_input *mi = mux_find_input(mux, value_int64(key));
|
||||||
|
if (mi == NULL)
|
||||||
|
die("mux_find_input failed to locate input %d\n", key);
|
||||||
|
|
||||||
|
if (chan_set(mi->chan, value_int64(new_value)) != 0)
|
||||||
|
die("chan_set failed\n");
|
||||||
|
|
||||||
|
if (bay_propagate(mux->bay) != 0)
|
||||||
|
die("bay_propagate failed\n");
|
||||||
|
|
||||||
|
check_output(mux, value_int64(new_value));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_select_and_input(struct mux *mux, int key)
|
||||||
|
{
|
||||||
|
/* Set the select channel to the selected key, but don't
|
||||||
|
* propagate the changes yet */
|
||||||
|
if (chan_set(mux->select, value_int64(key)) != 0)
|
||||||
|
die("chan_set failed\n");
|
||||||
|
|
||||||
|
int new_value = 2000 + key;
|
||||||
|
|
||||||
|
/* Also change that channel */
|
||||||
|
struct mux_input *mi = mux_find_input(mux, value_int64(key));
|
||||||
|
if (mi == NULL)
|
||||||
|
die("mux_find_input failed to locate input %d\n", key);
|
||||||
|
|
||||||
|
if (chan_set(mi->chan, value_int64(new_value)) != 0)
|
||||||
|
die("chan_set failed\n");
|
||||||
|
|
||||||
|
/* Write twice to the output */
|
||||||
|
if (bay_propagate(mux->bay) != 0)
|
||||||
|
die("bay_propagate failed\n");
|
||||||
|
|
||||||
|
check_output(mux, value_int64(new_value));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_input_and_select(struct mux *mux, int key)
|
||||||
|
{
|
||||||
|
int new_value = 2000 + key;
|
||||||
|
|
||||||
|
/* First change the input */
|
||||||
|
struct mux_input *mi = mux_find_input(mux, value_int64(key));
|
||||||
|
if (mi == NULL)
|
||||||
|
die("mux_find_input failed to locate input %d\n", key);
|
||||||
|
|
||||||
|
if (chan_set(mi->chan, value_int64(new_value)) != 0)
|
||||||
|
die("chan_set failed\n");
|
||||||
|
|
||||||
|
/* Then change select */
|
||||||
|
if (chan_set(mux->select, value_int64(key)) != 0)
|
||||||
|
die("chan_set failed\n");
|
||||||
|
|
||||||
|
/* Write twice to the output */
|
||||||
|
if (bay_propagate(mux->bay) != 0)
|
||||||
|
die("bay_propagate failed\n");
|
||||||
|
|
||||||
|
check_output(mux, value_int64(new_value));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_mid_propagate(struct mux *mux, int key)
|
||||||
|
{
|
||||||
|
int new_value = 2000 + key;
|
||||||
|
|
||||||
|
struct mux_input *mi = mux_find_input(mux, value_int64(key));
|
||||||
|
if (mi == NULL)
|
||||||
|
die("mux_find_input failed to locate input %d\n", key);
|
||||||
|
|
||||||
|
if (chan_set(mi->chan, value_int64(new_value)) != 0)
|
||||||
|
die("chan_set failed\n");
|
||||||
|
|
||||||
|
if (bay_propagate(mux->bay) != 0)
|
||||||
|
die("bay_propagate failed\n");
|
||||||
|
|
||||||
|
if (chan_set(mux->select, value_int64(key)) != 0)
|
||||||
|
die("chan_set failed\n");
|
||||||
|
|
||||||
|
if (bay_propagate(mux->bay) != 0)
|
||||||
|
die("bay_propagate failed\n");
|
||||||
|
|
||||||
|
check_output(mux, value_int64(new_value));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(void)
|
main(void)
|
||||||
{
|
{
|
||||||
@ -81,27 +207,11 @@ main(void)
|
|||||||
if (bay_propagate(&bay) != 0)
|
if (bay_propagate(&bay) != 0)
|
||||||
die("bay_propagate failed\n");
|
die("bay_propagate failed\n");
|
||||||
|
|
||||||
|
test_select(&mux, 1);
|
||||||
/* Change select channel */
|
test_input(&mux, 2);
|
||||||
if (chan_set(&select, value_int64(2)) != 0)
|
test_select_and_input(&mux, 3);
|
||||||
die("chan_set failed\n");
|
test_input_and_select(&mux, 4);
|
||||||
|
test_mid_propagate(&mux, 5);
|
||||||
/* Propagate values and call the callbacks */
|
|
||||||
if (bay_propagate(&bay) != 0)
|
|
||||||
die("bay_propagate failed\n");
|
|
||||||
|
|
||||||
struct value out_value = value_null();
|
|
||||||
if (chan_read(&output, &out_value) != 0)
|
|
||||||
die("chan_read() failed for output channel\n");
|
|
||||||
|
|
||||||
struct value expected_value = value_int64(1002);
|
|
||||||
if (!value_is_equal(&out_value, &expected_value)) {
|
|
||||||
char buf1[128];
|
|
||||||
char buf2[128];
|
|
||||||
die("unexpected value found %s in output (expected %s)\n",
|
|
||||||
value_str(out_value, buf1),
|
|
||||||
value_str(expected_value, buf2));
|
|
||||||
}
|
|
||||||
|
|
||||||
err("OK\n");
|
err("OK\n");
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user