ovni/src/emu/chan.c

251 lines
4.8 KiB
C
Raw Normal View History

2023-01-12 19:16:52 +01:00
/* Copyright (c) 2021-2022 Barcelona Supercomputing Center (BSC)
2022-09-19 12:39:02 +02:00
* SPDX-License-Identifier: GPL-3.0-or-later */
2021-10-26 18:42:41 +02:00
2023-02-01 11:38:39 +01:00
//#define ENABLE_DEBUG
2023-01-27 18:51:18 +01:00
2023-01-12 19:16:52 +01:00
#include "chan.h"
#include "common.h"
#include <string.h>
2023-01-25 18:11:13 +01:00
#include <stdarg.h>
void
2023-01-25 12:01:01 +01:00
chan_init(struct chan *chan, enum chan_type type, const char *fmt, ...)
{
2023-01-25 12:01:01 +01:00
memset(chan, 0, sizeof(struct chan));
va_list ap;
va_start(ap, fmt);
int n = ARRAYLEN(chan->name);
int ret = vsnprintf(chan->name, n, fmt, ap);
if (ret >= n)
die("channel name too long\n");
va_end(ap);
2023-01-12 19:16:52 +01:00
chan->type = type;
}
void
2023-01-12 19:16:52 +01:00
chan_set_dirty_cb(struct chan *chan, chan_cb_t func, void *arg)
{
2023-01-12 19:16:52 +01:00
chan->dirty_cb = func;
chan->dirty_arg = arg;
2021-10-21 16:15:29 +02:00
}
2023-01-12 19:16:52 +01:00
enum chan_type
chan_get_type(struct chan *chan)
{
2023-01-12 19:16:52 +01:00
return chan->type;
}
2023-01-12 19:16:52 +01:00
static int
set_dirty(struct chan *chan)
2021-10-21 16:15:29 +02:00
{
2023-01-12 19:16:52 +01:00
if (chan->is_dirty) {
2023-01-10 18:30:51 +01:00
/* Already dirty and allowed, no need to do anything */
if (chan->prop[CHAN_DIRTY_WRITE])
2023-01-10 18:30:51 +01:00
return 0;
2023-01-27 18:51:18 +01:00
err("%s: already dirty\n", chan->name);
2023-01-12 19:16:52 +01:00
return -1;
}
2023-01-12 19:16:52 +01:00
chan->is_dirty = 1;
2023-01-12 19:16:52 +01:00
if (chan->dirty_cb != NULL) {
2023-01-31 18:23:41 +01:00
dbg("%s: calling dirty callback", chan->name);
2023-01-12 19:16:52 +01:00
if (chan->dirty_cb(chan, chan->dirty_arg) != 0) {
2023-01-27 18:51:18 +01:00
err("%s: dirty callback failed", chan->name);
2023-01-12 19:16:52 +01:00
return -1;
}
}
2021-10-21 16:15:29 +02:00
2023-01-12 19:16:52 +01:00
return 0;
2021-10-21 16:15:29 +02:00
}
2023-01-12 19:16:52 +01:00
static int
check_duplicates(struct chan *chan, struct value *v)
2021-10-21 16:15:29 +02:00
{
2023-01-12 19:16:52 +01:00
/* If duplicates are allowed just skip the check */
if (chan->prop[CHAN_DUPLICATES])
return 0;
2021-10-21 16:15:29 +02:00
2023-01-12 19:16:52 +01:00
if (value_is_equal(&chan->last_value, v)) {
2023-02-16 15:59:20 +01:00
char buf[128];
err("%s: same value as last_value %s",
chan->name, value_str(chan->last_value, buf));
2023-01-12 19:16:52 +01:00
return -1;
}
2023-01-12 19:16:52 +01:00
return 0;
}
2023-01-12 19:16:52 +01:00
int
chan_set(struct chan *chan, struct value value)
2021-10-21 16:15:29 +02:00
{
2023-01-12 19:16:52 +01:00
if (chan->type != CHAN_SINGLE) {
2023-01-27 18:51:18 +01:00
err("%s: cannot set on non-single channel", chan->name);
2023-01-12 19:16:52 +01:00
return -1;
}
if (chan->is_dirty && !chan->prop[CHAN_DIRTY_WRITE]) {
2023-01-27 18:51:18 +01:00
err("%s: cannot modify dirty channel", chan->name);
2023-01-12 19:16:52 +01:00
return -1;
}
2023-01-12 19:16:52 +01:00
if (check_duplicates(chan, &value) != 0) {
2023-02-16 15:59:20 +01:00
err("%s: cannot set duplicated value", chan->name);
2023-01-12 19:16:52 +01:00
return -1;
2021-10-21 16:15:29 +02:00
}
#ifdef ENABLE_DEBUG
2023-01-27 18:51:18 +01:00
char buf[128];
dbg("%s: sets value to %s", chan->name, value_str(value, buf));
#endif
2023-01-12 19:16:52 +01:00
chan->data.value = value;
2023-01-12 19:16:52 +01:00
if (set_dirty(chan) != 0) {
2023-01-27 18:51:18 +01:00
err("%s: set_dirty failed", chan->name);
2023-01-12 19:16:52 +01:00
return -1;
}
return 0;
2021-10-21 16:15:29 +02:00
}
2023-01-12 19:16:52 +01:00
/** Adds one value to the stack. Fails if the stack is full.
*
* @param ivalue The new integer value to be added on the stack.
*
* @return On success returns 0, otherwise returns -1.
*/
2021-10-21 16:15:29 +02:00
int
2023-01-12 19:16:52 +01:00
chan_push(struct chan *chan, struct value value)
2021-10-21 16:15:29 +02:00
{
2023-01-12 19:16:52 +01:00
if (chan->type != CHAN_STACK) {
2023-01-27 18:51:18 +01:00
err("%s: cannot push on non-stack channel", chan->name);
2023-01-12 19:16:52 +01:00
return -1;
2021-10-21 16:15:29 +02:00
}
if (chan->is_dirty && !chan->prop[CHAN_DIRTY_WRITE]) {
2023-01-27 18:51:18 +01:00
err("%s: cannot modify dirty channel", chan->name);
2023-01-12 19:16:52 +01:00
return -1;
2021-10-21 16:15:29 +02:00
}
2023-01-12 19:16:52 +01:00
if (check_duplicates(chan, &value) != 0) {
2023-01-27 18:51:18 +01:00
err("%s: cannot push a duplicated value", chan->name);
2023-01-12 19:16:52 +01:00
return -1;
}
2023-01-12 19:16:52 +01:00
struct chan_stack *stack = &chan->data.stack;
if (stack->n >= MAX_CHAN_STACK) {
2023-01-27 18:51:18 +01:00
err("%s: channel stack full", chan->name);
2023-01-10 18:30:51 +01:00
return -1;
}
2023-01-12 19:16:52 +01:00
stack->values[stack->n++] = value;
2021-10-21 16:15:29 +02:00
2023-01-12 19:16:52 +01:00
if (set_dirty(chan) != 0) {
2023-01-27 18:51:18 +01:00
err("%s: set_dirty failed", chan->name);
2023-01-12 19:16:52 +01:00
return -1;
}
2023-01-12 19:16:52 +01:00
return 0;
2021-10-21 16:15:29 +02:00
}
2023-01-12 19:16:52 +01:00
/** Remove one value from the stack. Fails if the top of the stack
* doesn't match the expected value.
*
* @param expected The expected value on the top of the stack.
*
* @return On success returns 0, otherwise returns -1.
*/
2021-10-21 16:15:29 +02:00
int
2023-01-12 19:16:52 +01:00
chan_pop(struct chan *chan, struct value evalue)
2021-10-21 16:15:29 +02:00
{
2023-01-12 19:16:52 +01:00
if (chan->type != CHAN_STACK) {
2023-01-27 18:51:18 +01:00
err("%s: cannot pop on non-stack channel", chan->name);
2023-01-12 19:16:52 +01:00
return -1;
}
2021-10-21 16:15:29 +02:00
if (chan->is_dirty && !chan->prop[CHAN_DIRTY_WRITE]) {
2023-01-27 18:51:18 +01:00
err("%s: cannot modify dirty channel", chan->name);
2023-01-12 19:16:52 +01:00
return -1;
2022-10-03 10:51:58 +02:00
}
2023-01-12 19:16:52 +01:00
struct chan_stack *stack = &chan->data.stack;
2022-10-03 10:51:58 +02:00
2023-01-12 19:16:52 +01:00
if (stack->n <= 0) {
2023-01-27 18:51:18 +01:00
err("%s: channel stack empty", chan->name);
2023-01-12 19:16:52 +01:00
return -1;
2022-10-03 10:51:58 +02:00
}
2023-01-12 19:16:52 +01:00
struct value *value = &stack->values[stack->n - 1];
if (!value_is_equal(value, &evalue)) {
2023-01-27 18:51:18 +01:00
err("%s: unexpected value %ld (expected %ld)",
2023-01-10 18:30:51 +01:00
chan->name, value->i, evalue.i);
2023-01-12 19:16:52 +01:00
return -1;
}
2023-01-12 19:16:52 +01:00
stack->n--;
2023-01-12 19:16:52 +01:00
if (set_dirty(chan) != 0) {
2023-01-27 18:51:18 +01:00
err("%s: set_dirty failed\n", chan->name);
2023-01-12 19:16:52 +01:00
return -1;
}
2023-01-12 19:16:52 +01:00
return 0;
}
static void
2023-01-12 19:16:52 +01:00
get_value(struct chan *chan, struct value *value)
2021-10-21 16:15:29 +02:00
{
2023-01-12 19:16:52 +01:00
if (chan->type == CHAN_SINGLE) {
*value = chan->data.value;
} else {
struct chan_stack *stack = &chan->data.stack;
if (stack->n > 0)
*value = stack->values[stack->n - 1];
else
*value = value_null();
2023-01-12 19:16:52 +01:00
}
2021-10-21 16:15:29 +02:00
}
2023-01-12 19:16:52 +01:00
/** Reads the current value of a channel */
int
chan_read(struct chan *chan, struct value *value)
2021-10-21 16:15:29 +02:00
{
get_value(chan, value);
2023-01-10 18:30:51 +01:00
return 0;
}
/** Remove the dirty state */
int
chan_flush(struct chan *chan)
{
if (!chan->is_dirty) {
2023-01-27 18:51:18 +01:00
err("%s: channel is not dirty", chan->name);
2023-01-12 19:16:52 +01:00
return -1;
2021-10-21 16:15:29 +02:00
}
get_value(chan, &chan->last_value);
2023-01-10 18:30:51 +01:00
chan->is_dirty = 0;
2023-01-12 19:16:52 +01:00
return 0;
2021-10-21 16:15:29 +02:00
}
2023-01-10 18:30:51 +01:00
void
chan_prop_set(struct chan *chan, enum chan_prop prop, int value)
{
chan->prop[prop] = value;
}
int
chan_prop_get(struct chan *chan, enum chan_prop prop)
2023-01-10 18:30:51 +01:00
{
return chan->prop[prop];
2023-01-10 18:30:51 +01:00
}