+/**
+ * Create a new buffer pool.
+ *
+ * \param name The name of the new buffer pool.
+ *
+ * \param area The size in bytes of the pool area.
+ *
+ * \return An opaque pointer to the newly created buffer pool. It must be
+ * passed to btr_pool_free() after it is no longer used to deallocate all
+ * resources.
+ */
+struct btr_pool *btr_pool_new(const char *name, size_t area_size)
+{
+ struct btr_pool *btrp;
+
+ PARA_INFO_LOG("%s, %zu bytes\n", name, area_size);
+ btrp = para_malloc(sizeof(*btrp));
+ btrp->area_start = para_malloc(area_size);
+ btrp->area_end = btrp->area_start + area_size;
+ btrp->rhead = btrp->area_start;
+ btrp->whead = btrp->area_start;
+ btrp->name = para_strdup(name);
+ return btrp;
+}
+
+/**
+ * Dellocate resources used by a buffer pool.
+ *
+ * \param btrp A pointer obtained via btr_pool_new().
+ */
+void btr_pool_free(struct btr_pool *btrp)
+{
+ if (!btrp)
+ return;
+ free(btrp->area_start);
+ free(btrp->name);
+ free(btrp);
+}
+
+/**
+ * Return the size of the buffer pool area.
+ *
+ * \param btrp The buffer pool.
+ *
+ * \return The same value which was passed during creation time to
+ * btr_pool_new().
+ */
+size_t btr_pool_size(struct btr_pool *btrp)
+{
+ return btrp->area_end - btrp->area_start;
+}
+
+size_t btr_pool_filled(struct btr_pool *btrp)
+{
+ if (!btrp->whead)
+ return btr_pool_size(btrp);
+ if (btrp->rhead <= btrp->whead)
+ return btrp->whead - btrp->rhead;
+ return btr_pool_size(btrp) - (btrp->rhead - btrp->whead);
+}
+
+size_t btr_pool_unused(struct btr_pool *btrp)
+{
+ return btr_pool_size(btrp) - btr_pool_filled(btrp);
+}
+
+/*
+ * Return maximal size available for one read. This is
+ * smaller than the value returned by btr_pool_unused().
+ */
+size_t btr_pool_available(struct btr_pool *btrp)
+{
+ if (!btrp->whead)
+ return 0;
+ if (btrp->rhead <= btrp->whead)
+ return btrp->area_end - btrp->whead;
+ return btrp->rhead - btrp->whead;
+}
+
+size_t btr_pool_get_buffer(struct btr_pool *btrp, char **result)
+{
+ if (result)
+ *result = btrp->whead;
+ return btr_pool_available(btrp);
+}
+
+void btr_pool_allocate(struct btr_pool *btrp, size_t size)
+{
+ char *end;
+
+ if (size == 0)
+ return;
+ assert(size <= btr_pool_available(btrp));
+ end = btrp->whead + size;
+ assert(end <= btrp->area_end);
+
+ if (end == btrp->area_end) {
+ PARA_DEBUG_LOG("%s: end of pool area reached\n", btrp->name);
+ end = btrp->area_start;
+ }
+ if (end == btrp->rhead) {
+ PARA_DEBUG_LOG("%s btrp buffer full\n", btrp->name);
+ end = NULL; /* buffer full */
+ }
+ btrp->whead = end;
+}
+
+static void btr_pool_deallocate(struct btr_pool *btrp, size_t size)
+{
+ char *end = btrp->rhead + size;
+
+ if (size == 0)
+ return;
+ assert(end <= btrp->area_end);
+ assert(size <= btr_pool_filled(btrp));
+ if (end == btrp->area_end)
+ end = btrp->area_start;
+ if (!btrp->whead)
+ btrp->whead = btrp->rhead;
+ btrp->rhead = end;
+ if (btrp->rhead == btrp->whead)
+ btrp->rhead = btrp->whead = btrp->area_start;
+}
+