diff options
author | Anton Staaf <robotboy@chromium.org> | 2015-02-18 14:43:52 -0800 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2015-02-24 00:27:50 +0000 |
commit | 1a0235e69ff197cb1add08ffaa38ba1470db8cbc (patch) | |
tree | 3ec35670076ace67898e9f9cc75fca44ddfd064f | |
parent | fc144e940ca89a020880645a823d5c2258aae8c4 (diff) | |
download | chrome-ec-1a0235e69ff197cb1add08ffaa38ba1470db8cbc.tar.gz |
Streams: Define a lower level abstraction for queue access
This adds a new pair of interfaces called producer and consumer
which are simpler (in that they don't hold onto the underlying
queue) than the stream interfaces. This makes it easier to
share a single queue between the endpoints that will manipulate
it. It was not possible to share a queue between two objects
that implemented the in_stream and out_stream interfaces.
This also adds a pair of adaptors that can convert a producer
or consumer into a stream of the correct type. These adaptors
will be used for existing code once the usb-stream and usart
drivers are converted over to use the producer/consumer
interfaces instead of the stream interfaces.
Signed-off-by: Anton Staaf <robotboy@chromium.org>
BRANCH=None
BUG=None
TEST=make buildall -j
Change-Id: I42b4b1ac15cca28e1adc6d3cea315f15e17a0b4d
Reviewed-on: https://chromium-review.googlesource.com/250941
Trybot-Ready: Anton Staaf <robotboy@chromium.org>
Tested-by: Anton Staaf <robotboy@chromium.org>
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Commit-Queue: Anton Staaf <robotboy@chromium.org>
-rw-r--r-- | common/build.mk | 4 | ||||
-rw-r--r-- | common/consumer.c | 40 | ||||
-rw-r--r-- | common/producer.c | 40 | ||||
-rw-r--r-- | common/stream_adaptor.c | 65 | ||||
-rw-r--r-- | include/consumer.h | 81 | ||||
-rw-r--r-- | include/producer.h | 75 | ||||
-rw-r--r-- | include/stream_adaptor.h | 80 |
7 files changed, 383 insertions, 2 deletions
diff --git a/common/build.mk b/common/build.mk index a6cb7bad8a..f713ea1b5d 100644 --- a/common/build.mk +++ b/common/build.mk @@ -7,7 +7,7 @@ # common-y=util.o -common-y+=version.o printf.o queue.o +common-y+=version.o printf.o queue.o producer.o consumer.o common-$(CONFIG_ADC)+=adc.o common-$(CONFIG_ALS)+=als.o @@ -75,7 +75,7 @@ common-$(CONFIG_SHA256)+=sha256.o common-$(CONFIG_SMBUS)+= smbus.o common-$(CONFIG_SOFTWARE_CLZ)+=clz.o common-$(CONFIG_SPI_FLASH)+=spi_flash.o -common-$(CONFIG_STREAM)+=in_stream.o out_stream.o +common-$(CONFIG_STREAM)+=in_stream.o out_stream.o stream_adaptor.o common-$(CONFIG_SWITCH)+=switch.o common-$(CONFIG_SW_CRC)+=crc.o common-$(CONFIG_TEMP_SENSOR)+=temp_sensor.o thermal.o throttle_ap.o diff --git a/common/consumer.c b/common/consumer.c new file mode 100644 index 0000000000..3d424479e4 --- /dev/null +++ b/common/consumer.c @@ -0,0 +1,40 @@ +/* Copyright (c) 2015 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Consumer methods + */ +#include "consumer.h" +#include "producer.h" + +void consumer_notify_directly(struct consumer const *consumer, size_t count) +{ + if (count && consumer->ops->written) + consumer->ops->written(consumer, count); +} + +size_t consumer_read_unit(struct consumer const *consumer, void *unit) +{ + size_t removed = queue_remove_unit(consumer->queue, unit); + + producer_notify_directly(consumer->producer, removed); + + return removed; +} + +size_t consumer_read_memcpy(struct consumer const *consumer, + void *units, + size_t count, + void *(*memcpy)(void *dest, + void const *src, + size_t n)) +{ + size_t removed = queue_remove_memcpy(consumer->queue, + units, + count, + memcpy); + + producer_notify_directly(consumer->producer, removed); + + return removed; +} diff --git a/common/producer.c b/common/producer.c new file mode 100644 index 0000000000..855eb4a651 --- /dev/null +++ b/common/producer.c @@ -0,0 +1,40 @@ +/* Copyright (c) 2015 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Producer methods + */ +#include "consumer.h" +#include "producer.h" + +void producer_notify_directly(struct producer const *producer, size_t count) +{ + if (count && producer->ops->read) + producer->ops->read(producer, count); +} + +size_t producer_write_unit(struct producer const *producer, void const *unit) +{ + size_t added = queue_add_unit(producer->queue, unit); + + consumer_notify_directly(producer->consumer, added); + + return added; +} + +size_t producer_write_memcpy(struct producer const *producer, + void const *units, + size_t count, + void *(*memcpy)(void *dest, + void const *src, + size_t n)) +{ + size_t added = queue_add_memcpy(producer->queue, + units, + count, + memcpy); + + consumer_notify_directly(producer->consumer, added); + + return added; +} diff --git a/common/stream_adaptor.c b/common/stream_adaptor.c new file mode 100644 index 0000000000..b8ede28e30 --- /dev/null +++ b/common/stream_adaptor.c @@ -0,0 +1,65 @@ +/* Copyright (c) 2015 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Stream adaptor implementation. + */ + +#include "producer.h" +#include "consumer.h" +#include "stream_adaptor.h" +#include "util.h" + +static size_t in_stream_from_producer_read(struct in_stream const *stream, + uint8_t *buffer, + size_t count) +{ + struct in_stream_from_producer const *adaptor = + DOWNCAST(stream, struct in_stream_from_producer, in); + + return consumer_read_memcpy(&adaptor->consumer, buffer, count, memcpy); +} + +static void in_stream_from_producer_written(struct consumer const *consumer, + size_t count) +{ + struct in_stream_from_producer const *adaptor = + DOWNCAST(consumer, struct in_stream_from_producer, consumer); + + in_stream_ready(&adaptor->in); +} + +struct in_stream_ops const in_stream_from_producer_in_stream_ops = { + .read = in_stream_from_producer_read, +}; + +struct consumer_ops const in_stream_from_producer_consumer_ops = { + .written = in_stream_from_producer_written, +}; + +static size_t out_stream_from_consumer_write(struct out_stream const *stream, + uint8_t const *buffer, + size_t count) +{ + struct out_stream_from_consumer const *adaptor = + DOWNCAST(stream, struct out_stream_from_consumer, out); + + return producer_write_memcpy(&adaptor->producer, buffer, count, memcpy); +} + +static void out_stream_from_consumer_read(struct producer const *producer, + size_t count) +{ + struct out_stream_from_consumer const *adaptor = + DOWNCAST(producer, struct out_stream_from_consumer, producer); + + out_stream_ready(&adaptor->out); +} + +struct out_stream_ops const out_stream_from_consumer_out_stream_ops = { + .write = out_stream_from_consumer_write, +}; + +struct producer_ops const out_stream_from_consumer_producer_ops = { + .read = out_stream_from_consumer_read, +}; diff --git a/include/consumer.h b/include/consumer.h new file mode 100644 index 0000000000..4a456de512 --- /dev/null +++ b/include/consumer.h @@ -0,0 +1,81 @@ +/* Copyright (c) 2015 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Consumer interface + * + * The consumer abstraction allows for code that wants to be able to read from + * a queue, and be notified of new additions to the queue, or of requests to + * flush (empty) the queue. + */ +#ifndef INCLUDE_CONSUMER_H +#define INCLUDE_CONSUMER_H + +#include "queue.h" + +#include <stddef.h> +#include <stdint.h> + +struct consumer; +struct producer; + +struct consumer_ops { + /* + * Inform the consumer that count units were written to the queue. + * This gives it the oportunity to read additional units from the queue + * or to wake up a task or interrupt to do the same. If a consumer has + * no need for this information it can set this to NULL. + */ + void (*written)(struct consumer const *consumer, size_t count); + + /* + * Flush (read) everything from the associated queue. This call blocks + * until the consumer has flushed the queue. + */ + void (*flush)(struct consumer const *consumer); +}; + +struct consumer { + /* + * A consumer references the producer at the other end of the queue. + * This allows the consumer to notify the producer when units are + * removed from the queue. + */ + struct producer const *producer; + + /* + * A consumer also references the queue that it is reading from. This + * and the producer reference above could be more flexibly replaced by + * a queue manager object that could handle multiple producer/consumers + * or alternate notification mechanisms. But that complexity is not + * yet warranted. + */ + struct queue const *queue; + + struct consumer_ops const *ops; +}; + +/* + * Notify the consumer by calling its written method directly, as opposed to + * from a deferred callback or another task. + */ +void consumer_notify_directly(struct consumer const *consumer, size_t count); + +/* + * Read a single unit from the queue and notify the associated producer. + * Return the number of units read. + */ +size_t consumer_read_unit(struct consumer const *consumer, void *unit); + +/* + * Read multiple units from the queue, using the provided memcpy like routine + * and notify the producer. Return the number of units read. + */ +size_t consumer_read_memcpy(struct consumer const *consumer, + void *units, + size_t count, + void *(*memcpy)(void *dest, + void const *src, + size_t n)); + +#endif /* INCLUDE_CONSUMER_H */ diff --git a/include/producer.h b/include/producer.h new file mode 100644 index 0000000000..d42e148ea6 --- /dev/null +++ b/include/producer.h @@ -0,0 +1,75 @@ +/* Copyright (c) 2015 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Producer interface + * + * The producer abstraction allows for code that wants to write into a queue and + * be notified when the queue is read from so that it can take action, such as + * adding new units to the queue. + */ +#ifndef INCLUDE_PRODUCER_H +#define INCLUDE_PRODUCER_H + +#include "queue.h" + +#include <stddef.h> +#include <stdint.h> + +struct consumer; +struct producer; + +struct producer_ops { + /* + * Inform the producer that count units were read from the queue. This + * gives it the oportunity to write additional units to the queue or to + * wake up a task or interrupt to do the same. If a producer has no + * need for this information it can set this to NULL. + */ + void (*read)(struct producer const *producer, size_t count); +}; + +struct producer { + /* + * A producer references the consumer at the other end of the queue. + * This allows the producer to notify the consumer when new units are + * added to the queue. + */ + struct consumer const *consumer; + + /* + * A producer also references the queue that it is writing into. This + * and the consumer reference above could be more flexibly replaced by + * a queue manager object that could handle multiple producer/consumers + * or alternate notification mechanisms. But that complexity is not + * yet warranted. + */ + struct queue const *queue; + + struct producer_ops const *ops; +}; + +/* + * Notify the producer by calling its read method directly, as opposed to from + * a deferred callback or another task. + */ +void producer_notify_directly(struct producer const *producer, size_t count); + +/* + * Write a single unit to the queue and notify the associated consumer. Return + * the number of units written. + */ +size_t producer_write_unit(struct producer const *producer, void const *unit); + +/* + * Write multiple units to the queue, using the provided memcpy like routine + * and notify the consumer. Return the number of units written. + */ +size_t producer_write_memcpy(struct producer const *producer, + void const *units, + size_t count, + void *(*memcpy)(void *dest, + void const *src, + size_t n)); + +#endif /* INCLUDE_PRODUCER_H */ diff --git a/include/stream_adaptor.h b/include/stream_adaptor.h new file mode 100644 index 0000000000..916ab6e78d --- /dev/null +++ b/include/stream_adaptor.h @@ -0,0 +1,80 @@ +/* Copyright (c) 2015 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ifndef INCLUDE_STREAM_ADAPTOR_H +#define INCLUDE_STREAM_ADAPTOR_H + +/* STM32 USART driver for Chrome EC */ + +#include "common.h" +#include "in_stream.h" +#include "out_stream.h" +#include "consumer.h" +#include "producer.h" + +/* + * +..........+ +..........+------+...........+ + * . .<------------->. | | . + * . Producer . +---------+ . Consumer | ISFP | In Stream . + * . .->| Queue |->. | | . + * +..........+ +---------+ +..........+------+...........+ + */ + +struct in_stream_from_producer { + struct consumer consumer; + struct in_stream in; +}; + +/* + * + */ +extern struct in_stream_ops const in_stream_from_producer_in_stream_ops; +extern struct consumer_ops const in_stream_from_producer_consumer_ops; + +#define IN_STREAM_FROM_PRODUCER(NAME, PRODUCER, QUEUE, READY) \ + struct in_stream_from_producer const NAME = { \ + .consumer = { \ + .producer = &PRODUCER, \ + .queue = &QUEUE, \ + .ops = &in_stream_from_producer_consumer_ops, \ + }, \ + .in = { \ + .ready = READY, \ + .ops = &in_stream_from_producer_in_stream_ops, \ + }, \ + }; + +/* + * +..........+ +..........+------+............+ + * . .<------------->. | | . + * . Consumer . +---------+ . Producer | OSFC | Out Stream . + * . .<-| Queue |<-. | | . + * +..........+ +---------+ +..........+------+............+ + */ + +struct out_stream_from_consumer { + struct producer producer; + struct out_stream out; +}; + +/* + * + */ +extern struct out_stream_ops const out_stream_from_consumer_out_stream_ops; +extern struct producer_ops const out_stream_from_consumer_producer_ops; + +#define OUT_STREAM_FROM_CONSUMER(NAME, CONSUMER, QUEUE, READY) \ + struct out_stream_from_consumer const NAME = { \ + .producer = { \ + .consumer = &CONSUMER, \ + .queue = &QUEUE, \ + .ops = &out_stream_from_consumer_producer_ops, \ + }, \ + .out = { \ + .ready = READY, \ + .ops = &out_stream_from_consumer_out_stream_ops, \ + }, \ + }; + +#endif /* INCLUDE_STREAM_ADAPTOR_H */ |