aos/lib/devif/backends/debug/devif_backend_debug.c
Daniel Schwyn 6d444bf552 Main handout
Signed-off-by: Daniel Schwyn <daniel.schwyn@inf.ethz.ch>
2022-03-03 14:57:51 +01:00

957 lines
30 KiB
C

/*
* Copyright (c) 2007, 2008, 2009, 2010, 2011, 2012, ETH Zurich.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
* ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <aos/aos.h>
#include <devif/queue_interface.h>
#include <devif/queue_interface_backend.h>
#include <devif/backends/debug.h>
#include "debug.h"
//#define DQ_ENABLE_HIST
#define HIST_SIZE 128
#define MAX_STR_SIZE 128
/*
* This is a debugging interface for the device queue interface that
* can be used with any existing queue. It can be stacked on top
* to check for non valid buffer enqueues/deqeues that might happen.
* A not valid enqueue of a buffer is when the endpoint that enqueues
* the buffer does not own the buffer.
*
* We keep track of the owned buffers as a list of regions which each
* contains a list of memory chunks.
* Each chunk specifies a offset within the region and its length.
*
* When a region is registered, we add one memory chunk that describes
* the whole region i.e. offset=0 length= length of region
*
* If a a buffer is enqueued, it has to be contained in one of these
* memory chunks. The memory chunk is then altered according how
* the buffer is contained in the chunk. If it is at the beginning or
* end of the chunk, the offset/length of the chunk is changed accordingly
* If the buffer is in the middle of the chunk, we split the memory chunk
* into two new memory chunks that do not contain the buffer.
*
* If a buffer is dequeued the buffer is added to the existing memory
* chunks if possible, otherwise a new memory chunk is added to the
* list of chunks. If a buffer is dequeued that is in between two
* memory chunks, the memory chunks are merged to one big chunk.
* We might fail to find the region id in our list of regions. In this
* case we add the region with the deqeued offset+length as a size.
* We can be sure that this region exists since the devq library itself
* does these checks if the region is known to the endpoint. This simply
* means the debugging queue on top of the other queue does not have a
* consistant view of the registered regions (but the queue below does)
*
* When a region is deregistered, the list of chunks has to only
* contain a single chunk that descirbes the whole region. Otherwise
* the call will fail since some of the buffers are still in use.
*
*/
struct memory_ele {
genoffset_t offset;
genoffset_t length;
struct memory_ele* next;
struct memory_ele* prev;
};
struct memory_list {
regionid_t rid;
genoffset_t length;
// is a region that we did not register ourselves
bool not_consistent;
struct memory_ele* buffers;
struct memory_list* next; // next in list of lists
};
struct operation {
char str[MAX_STR_SIZE];
genoffset_t offset;
genoffset_t length;
};
struct debug_q {
struct devq my_q;
struct devq* q;
struct memory_list* regions; // list of lists
struct slab_allocator alloc;
struct slab_allocator alloc_list;
uint16_t hist_head;
struct operation history[HIST_SIZE];
};
static void dump_list(struct memory_list* region)
{
struct memory_ele* ele = region->buffers;
int index = 0;
printf("================================================ \n");
while (ele != NULL) {
printf("Idx=%d offset=%lu length=%lu", index, ele->offset,
ele->length);
if (ele->prev != NULL) {
printf(" prev->offset=%lu prev->length=%lu", ele->prev->offset,
ele->prev->length);
}
printf(" \n");
ele = ele->next;
index++;
}
printf("================================================ \n");
}
// checks if there are elements in the list that should be merged
/*
static void check_consistency(struct memory_list* region)
{
struct memory_ele* ele = region->buffers;
while (ele->next != NULL) {
if (ele->offset + ele->length == ele->next->offset) {
printf("offset=%lu length=%lu \n", ele->offset, ele->length);
dump_list(region);
USER_PANIC("Found entry that should be merged \n");
}
ele = ele->next;
}
}
*/
#ifdef DQ_ENABLE_HIST
static void add_to_history(struct debug_q* q, genoffset_t offset,
genoffset_t length, char* s)
{
q->history[q->hist_head].offset = offset;
q->history[q->hist_head].length = length;
strncpy(q->history[q->hist_head].str, s, MAX_STR_SIZE);
q->hist_head = (q->hist_head + 1) % HIST_SIZE;
}
static void dump_history(struct debug_q* q)
{
for (int i = 0; i < HIST_SIZE; i++) {
printf("offset=%lu length=%lu %s\n", q->history[q->hist_head].offset,
q->history[q->hist_head].length, q->history[q->hist_head].str);
q->hist_head = (q->hist_head + 1) % HIST_SIZE;
}
}
#endif
/*
static bool in_list(struct memory_list* region, genoffset_t offset,
genoffset_t length)
{
struct memory_ele* ele = region->buffers;
while (ele != NULL) {
if (offset >= ele->offset &&
offset + length <= ele->offset+ele->length) {
return true;
}
ele = ele->next;
}
return false;
}
*/
static errval_t debug_register(struct devq* q, struct capref cap,
regionid_t rid)
{
errval_t err;
struct debug_q* que = (struct debug_q*) q;
DEBUG("Register \n");
struct frame_identity id;
err = frame_identify(cap, &id);
if (err_is_fail(err)) {
return err;
}
// queue of regions is empty
if (que->regions == NULL) {
// add the reigon
err = que->q->f.reg(que->q, cap, rid);
if (err_is_fail(err)) {
return err;
}
que->regions = slab_alloc(&que->alloc_list);
assert(que->regions != NULL);
que->regions->rid = rid;
que->regions->length = id.bytes;
que->regions->not_consistent = false;
que->regions->next = NULL;
// add the whole regions as a buffer
que->regions->buffers = slab_alloc(&que->alloc);
assert(que->regions->buffers != NULL);
memset(que->regions->buffers, 0, sizeof(que->regions->buffers));
que->regions->buffers->offset = 0;
que->regions->buffers->length = id.bytes;
que->regions->buffers->next = NULL;
DEBUG("Register rid=%"PRIu32" size=%"PRIu64" \n", rid,
id.bytes);
return SYS_ERR_OK;
}
struct memory_list* ele = que->regions;
while (ele->next != NULL) {
ele = ele->next;
}
err = que->q->f.reg(que->q, cap, rid);
if (err_is_fail(err)) {
return err;
}
// add the reigon
ele->next = slab_alloc(&que->alloc_list);
assert(ele->next != NULL);
ele = ele->next;
ele->rid = rid;
ele->next = NULL;
ele->length = id.bytes;
ele->not_consistent = false;
// add the whole regions as a buffer
ele->buffers = slab_alloc(&que->alloc);
assert(ele->buffers != NULL);
memset(ele->buffers, 0, sizeof(ele->buffers));
ele->buffers->offset = 0;
ele->buffers->length = id.bytes;
ele->buffers->next = NULL;
DEBUG("Register rid=%"PRIu32" size=%"PRIu64" \n", rid,
id.bytes);
return SYS_ERR_OK;
}
static errval_t debug_deregister(struct devq* q, regionid_t rid)
{
DEBUG("Deregister \n");
struct debug_q* que = (struct debug_q*) q;
errval_t err;
struct memory_list* ele = que->regions;
if (ele == NULL) {
return DEVQ_ERR_INVALID_REGION_ID;
}
// remove head
if (ele->rid == rid) {
// there should only be a single element in the list
// i.e. the whole region
if (ele->buffers->offset == 0 &&
ele->buffers->length == ele->length &&
ele->buffers->next == NULL) {
err = que->q->f.dereg(que->q, rid);
if (err_is_fail(err)) {
return err;
}
que->regions = ele->next;
DEBUG("removed region rid=%"PRIu32" size=%"PRIu64" \n", rid,
ele->length);
slab_free(&que->alloc, ele->buffers);
slab_free(&que->alloc_list, ele);
return SYS_ERR_OK;
} else {
DEBUG("Destroy error rid=%d offset=%"PRIu64" length=%"PRIu64" "
"should be offset=0 length=%"PRIu64"\n",
ele->rid, ele->buffers->offset,
ele->buffers->length, ele->length);
dump_list(ele);
return DEVQ_ERR_REGION_DESTROY;
}
}
while (ele->next != NULL) {
if (ele->next->rid == rid) {
if (ele->next->buffers->offset == 0 &&
ele->next->buffers->length == ele->next->length &&
ele->next->buffers->next == NULL) {
err = que->q->f.dereg(que->q, rid);
if (err_is_fail(err)) {
return err;
}
// remove from queue
struct memory_list* next = ele->next;
ele->next = ele->next->next;
DEBUG("removed region rid=%"PRIu32" size=%"PRIu64" \n", rid,
next->length);
slab_free(&que->alloc, next->buffers);
slab_free(&que->alloc_list, next);
return SYS_ERR_OK;
} else {
DEBUG("Destroy error rid=%d offset=%"PRIu64" length=%"PRIu64" "
"should be offset=0 length=%"PRIu64"\n",
ele->next->rid, ele->next->buffers->offset,
ele->next->buffers->length, ele->next->length);
dump_list(ele);
return DEVQ_ERR_REGION_DESTROY;
}
} else {
ele = ele->next;
}
}
return DEVQ_ERR_INVALID_REGION_ID;
}
static errval_t debug_control(struct devq* q, uint64_t cmd, uint64_t value,
uint64_t* result)
{
DEBUG("control \n");
struct debug_q* que = (struct debug_q*) q;
return que->q->f.ctrl(que->q, cmd, value, result);
}
static errval_t debug_notify(struct devq* q)
{
DEBUG("notify \n");
struct debug_q* que = (struct debug_q*) q;
return que->q->f.notify(que->q);
}
// is b1 in bounds of b2?
static bool buffer_in_bounds(genoffset_t offset_b1, genoffset_t len_b1,
genoffset_t offset_b2, genoffset_t len_b2)
{
return (offset_b1 >= offset_b2) && (len_b1 <= len_b2) &&
((offset_b1 + len_b1) <= offset_b2 + len_b2);
}
// assumes that the buffer described by offset and length is contained
// in the buffer that is given as a struct
static void remove_split_buffer(struct debug_q* que,
struct memory_list* region,
struct memory_ele* buffer,
genoffset_t offset,
genoffset_t length)
{
// split the buffer
// insert half before the buffer
DEBUG("enqueue offset=%"PRIu64" length=%"PRIu64" buf->offset=%lu "
"buf->length %lu \n",
offset, length, buffer->offset, buffer->length);
// check if buffer at beginning of region
if (buffer->offset == offset) {
buffer->offset += length;
buffer->length -= length;
if (buffer->length == 0) {
#ifdef DQ_ENABLE_HIST
add_to_history(que, offset, length, "enq cut of beginning remove");
#endif
DEBUG("enqueue remove buffer from list\n");
// remove
if (buffer->prev != NULL) {
buffer->prev->next = buffer->next;
} else {
region->buffers = buffer->next;
}
if (buffer->next != NULL) {
buffer->next->prev = buffer->prev;
}
slab_free(&que->alloc, buffer);
} else {
#ifdef DQ_ENABLE_HIST
add_to_history(que, offset, length, "enq cut of beginning");
#endif
}
DEBUG("enqueue first cut off begining results in offset=%"PRIu64" "
"length=%"PRIu64"\n",
buffer->offset, buffer->length);
return;
}
// check if buffer at end of region
if ((buffer->offset+buffer->length) == (offset+length)) {
buffer->length -= length;
if (buffer->length == 0) {
#ifdef DQ_ENABLE_HIST
add_to_history(que, offset, length, "enq cut of end remove");
#endif
// remove
if (buffer->prev != NULL) {
buffer->prev = buffer->next;
}
if (buffer->next != NULL) {
buffer->next->prev = buffer->prev;
}
slab_free(&que->alloc, buffer);
} else {
#ifdef DQ_ENABLE_HIST
add_to_history(que, offset, length, "enq cut of end");
#endif
}
DEBUG("enqueue first cut off end results in offset=%"PRIu64" "
"length=%"PRIu64"\n",
buffer->offset, buffer->length);
return;
}
// now if this did not work need to split buffer that contains the
// enqueued buffer into two buffers (might also result only in one)
// inset half before buffer
genoffset_t old_len = buffer->length;
buffer->length = offset - buffer->offset;
struct memory_ele* after = NULL;
after = slab_alloc(&que->alloc);
assert(after != NULL);
memset(after, 0, sizeof(after));
after->offset = buffer->offset + buffer->length + length;
after->length = old_len - buffer->length - length;
// insert after buffer
after->prev = buffer;
after->next = buffer->next;
if (buffer->next != NULL) {
buffer->next->prev = after;
}
buffer->next = after;
#ifdef DQ_ENABLE_HIST
add_to_history(que, offset, length, "enq split buffer");
#endif
DEBUG("Split buffer length=%lu to "
"offset=%"PRIu64" length=%"PRIu64" and "
"offset=%lu length=%lu \n",
old_len,
buffer->offset, buffer->length,
after->offset, after->length);
}
/*
* Inserts a buffer either before or after an existing buffer into the queue
* Checks for merges of prev/next buffer in the queue
*/
static void insert_merge_buffer(struct debug_q* que,
struct memory_list* region,
struct memory_ele* buffer,
genoffset_t offset,
genoffset_t length)
{
assert(buffer != NULL);
assert(region != NULL);
if (offset >= buffer->offset+buffer->length) {// insert after
// buffer is on lower boundary
//
if (buffer->offset+length == offset) {
buffer->length += length;
DEBUG("dequeue merge after "
"offset=%"PRIu64" length=%"PRIu64" to offset=%"PRIu64" "
"length=%"PRIu64"\n",
offset, length, buffer->offset, buffer->length);
// check other boundary for merge
if (buffer->next != NULL &&
(buffer->offset + buffer->length == buffer->next->offset)) {
buffer->length += buffer->next->length;
struct memory_ele* next = buffer->next;
if (buffer->next->next != NULL) {
buffer->next = buffer->next->next;
buffer->next->next->prev = buffer;
}
DEBUG("dequeue merge after more offset=%"PRIu64" "
"length=%"PRIu64" to offset=%"PRIu64" length=%"PRIu64" \n ",
next->offset, next->length,
buffer->offset, buffer->length);
#ifdef DQ_ENABLE_HIST
add_to_history(que, offset, length, "deq insert after"
" on lower boundary and merge");
#endif
slab_free(&que->alloc, next);
} else {
#ifdef DQ_ENABLE_HIST
add_to_history(que, offset, length, "deq insert after on lower boundary");
#endif
}
} else {
// check higher boundary
if (buffer->next != NULL &&
buffer->next->offset == offset+length) {
buffer->next->offset = offset;
buffer->next->length += length;
DEBUG("dequeue merge after more offset=%"PRIu64" "
"length=%"PRIu64" to offset=%"PRIu64" length=%"PRIu64" \n ",
offset, length,
buffer->next->offset, buffer->next->length);
#ifdef DQ_ENABLE_HIST
add_to_history(que, offset, length, "deq insert after"
" on higer boundary");
#endif
} else {
// buffer->next can be null and the newly inserted buffer
// is the inserted at the end -> check boundary
if (buffer->next == NULL &&
buffer->offset + buffer->length == offset) {
buffer->length += length;
#ifdef DQ_ENABLE_HIST
add_to_history(que, offset, length, "deq insert after"
" on higer boundary end");
#endif
DEBUG("dequeue insert after merged offset=%"PRIu64" "
"length=%"PRIu64" "
"to offset=%"PRIu64" length=%"PRIu64" \n",
offset, length, buffer->offset, buffer->length);
} else {
// insert in between
struct memory_ele* ele = slab_alloc(&que->alloc);
assert(ele != NULL);
ele->offset = offset;
ele->length = length;
ele->next = buffer->next;
ele->prev = buffer;
if (buffer->next != NULL) {
buffer->next->prev = ele;
}
buffer->next = ele;
#ifdef DQ_ENABLE_HIST
add_to_history(que, offset, length, "deq insert after"
" in between");
#endif
DEBUG("dequeue insert after offset=%"PRIu64" length=%"PRIu64" "
"after offset=%"PRIu64" length=%"PRIu64" \n",
offset, length, buffer->offset, buffer->length);
}
}
}
} else { // insert before buffer
// buffer is on lower boundary
if (buffer->offset == offset+length) {
buffer->length += length;
buffer->offset = offset;
// check other boundary
if (buffer->prev != NULL &&
(buffer->prev->offset+ buffer->prev->length ==
buffer->offset)) {
struct memory_ele* prev = buffer->prev;
prev->length += buffer->length;
prev->next = buffer->next;
if (buffer->next != NULL) {
buffer->next->prev = prev;
}
slab_free(&que->alloc, buffer);
#ifdef DQ_ENABLE_HIST
add_to_history(que, offset, length, "deq insert buffer"
" before lower boundary merge");
#endif
DEBUG("dequeue merge before more offset=%"PRIu64" "
"length=%"PRIu64" to offset=%"PRIu64" length=%"PRIu64" \n ",
offset, length, prev->offset, prev->length);
} else {
#ifdef DQ_ENABLE_HIST
add_to_history(que, offset, length, "deq insert buffer"
" before lower boundary");
#endif
}
} else {
// check lower boundary
if (buffer->prev != NULL &&
(buffer->prev->offset+ buffer->prev->length ==
offset)) {
if (length == 0) {
printf("Length is 0 \n");
buffer->prev->length += 2048;
}
buffer->prev->length += length;
#ifdef DQ_ENABLE_HIST
add_to_history(que, offset, length, "deq insert buffer"
" before prev lower boundary merge");
#endif
DEBUG("dequeue merge before more offset=%"PRIu64" "
"length=%"PRIu64" to offset=%"PRIu64" length=%"PRIu64" \n ",
offset, length, buffer->prev->offset, buffer->prev->length);
} else { // insert in between
// insert in between
struct memory_ele* ele = slab_alloc(&que->alloc);
assert(ele != NULL);
memset(ele, 0, sizeof(ele));
ele->offset = offset;
ele->length = length;
ele->next = buffer;
ele->prev = buffer->prev;
if (buffer->prev != NULL) {
buffer->prev->next = ele;
} else {
region->buffers = ele;
}
buffer->prev = ele;
#ifdef DQ_ENABLE_HIST
add_to_history(que, offset, length, "deq insert buffer"
" before in between");
#endif
DEBUG("dequeue insert before offset=%"PRIu64" length=%"PRIu64" "
"next is offset=%"PRIu64" length=%"PRIu64" \n",
offset, length,
buffer->offset, buffer->length);
}
}
}
}
static errval_t find_region(struct debug_q* que, struct memory_list** list,
regionid_t rid)
{
// find region
struct memory_list* region = que->regions;
while (region != NULL) {
if (region->rid == rid) {
break;
}
region = region->next;
}
// check if we found the region
if (region == NULL) {
return DEVQ_ERR_INVALID_REGION_ID;
}
*list = region;
return SYS_ERR_OK;
}
static errval_t debug_enqueue(struct devq* q, regionid_t rid,
genoffset_t offset, genoffset_t length,
genoffset_t valid_data, genoffset_t valid_length,
uint64_t flags)
{
assert(length > 0);
DEBUG("enqueue offset %"PRIu64" \n", offset);
errval_t err;
struct debug_q* que = (struct debug_q*) q;
// find region
struct memory_list* region = NULL;
err = find_region(que, &region, rid);
if (err_is_fail(err)){
return err;
}
//check_consistency(region);
// find the buffer
struct memory_ele* buffer = region->buffers;
if (region->buffers == NULL) {
return DEVQ_ERR_BUFFER_ALREADY_IN_USE;
}
// the only buffer
if (buffer->next == NULL) {
if (buffer_in_bounds(offset, length,
buffer->offset, buffer->length)) {
err = que->q->f.enq(que->q, rid, offset, length, valid_data,
valid_length, flags);
if (err_is_fail(err)) {
return err;
}
remove_split_buffer(que, region, buffer, offset, length);
return SYS_ERR_OK;
} else {
printf("Bounds check failed only buffer offset=%lu length=%lu "
" buf->offset=%lu buf->len=%lu\n", offset, length,
buffer->offset, buffer->length);
#ifdef DQ_ENABLE_HIST
dump_history(que);
#endif
dump_list(region);
return DEVQ_ERR_INVALID_BUFFER_ARGS;
}
}
// more than one buffer
while (buffer != NULL) {
if (buffer_in_bounds(offset, length,
buffer->offset, buffer->length)){
err = que->q->f.enq(que->q, rid, offset, length, valid_data,
valid_length, flags);
if (err_is_fail(err)) {
return err;
}
remove_split_buffer(que, region, buffer, offset, length);
return SYS_ERR_OK;
}
buffer = buffer->next;
}
printf("Did not find region offset=%ld length=%ld \n", offset, length);
#ifdef DQ_ENABLE_HIST
dump_history(que);
#endif
dump_list(region);
return DEVQ_ERR_INVALID_BUFFER_ARGS;
}
static errval_t debug_dequeue(struct devq* q, regionid_t* rid, genoffset_t* offset,
genoffset_t* length, genoffset_t* valid_data,
genoffset_t* valid_length, uint64_t* flags)
{
errval_t err;
struct debug_q* que = (struct debug_q*) q;
assert(que->q->f.deq != NULL);
err = que->q->f.deq(que->q, rid, offset, length, valid_data,
valid_length, flags);
if (err_is_fail(err)) {
return err;
}
DEBUG("dequeued offset=%lu \n", *offset);
struct memory_list* region = NULL;
err = find_region(que, &region, *rid);
if (err_is_fail(err)){
// region ids are checked bythe devq library, if we do not find
// the region id when dequeueing here we do not have a consistant
// view of two endpoints
//
// Add region
if (que->regions == NULL) {
printf("Adding region frirst %lu len \n", *offset + *length);
que->regions = slab_alloc(&que->alloc_list);
assert(que->regions != NULL);
que->regions->rid = *rid;
que->regions->not_consistent = true;
// region is at least offset + length
que->regions->length = *offset + *length;
que->regions->next = NULL;
// add the whole regions as a buffer
que->regions->buffers = slab_alloc(&que->alloc);
assert(que->regions->buffers != NULL);
memset(que->regions->buffers, 0, sizeof(que->regions->buffers));
que->regions->buffers->offset = 0;
que->regions->buffers->length = *offset + *length;
que->regions->buffers->next = NULL;
return SYS_ERR_OK;
}
struct memory_list* ele = que->regions;
while (ele->next != NULL) {
ele = ele->next;
}
printf("Adding region second %lu len \n", *offset + *length);
// add the reigon
ele->next = slab_alloc(&que->alloc_list);
assert(ele->next != NULL);
memset(que->regions->buffers, 0, sizeof(ele->next));
ele = ele->next;
ele->rid = *rid;
ele->next = NULL;
ele->not_consistent = true;
ele->length = *offset + *length;
// add the whole regions as a buffer
ele->buffers = slab_alloc(&que->alloc);
assert(ele->buffers != NULL);
memset(ele->buffers, 0, sizeof(ele->buffers));
ele->buffers->offset = 0;
ele->buffers->length = *offset + *length;
ele->buffers->next = NULL;
return SYS_ERR_OK;
}
if (region->not_consistent) {
if ((*offset + *length) > region->length) {
region->length = *offset + *length;
}
}
//check_consistency(region);
// find the buffer
struct memory_ele* buffer = region->buffers;
if (buffer == NULL) {
region->buffers = slab_alloc(&que->alloc);
assert(region->buffers != NULL);
region->buffers->offset = *offset;
region->buffers->length = *length;
region->buffers->next = NULL;
region->buffers->prev = NULL;
return SYS_ERR_OK;
}
if (buffer->next == NULL) {
if (!buffer_in_bounds(*offset, *length, buffer->offset,
buffer->length)) {
insert_merge_buffer(que, region, buffer, *offset, *length);
return SYS_ERR_OK;
} else {
return DEVQ_ERR_BUFFER_NOT_IN_USE;
}
}
while (buffer->next != NULL) {
if (*offset >= buffer->offset) {
buffer = buffer->next;
} else {
if (!buffer_in_bounds(*offset, *length, buffer->offset,
buffer->length)) {
insert_merge_buffer(que, region, buffer, *offset, *length);
return SYS_ERR_OK;
} else {
return DEVQ_ERR_BUFFER_NOT_IN_USE;
}
}
}
// insert after the last buffer
if (!buffer_in_bounds(*offset, *length, buffer->offset,
buffer->length)) {
insert_merge_buffer(que, region, buffer, *offset, *length);
return SYS_ERR_OK;
}
return DEVQ_ERR_BUFFER_NOT_IN_USE;
}
static errval_t debug_destroy(struct devq* devq)
{
// TODO cleanup
return SYS_ERR_OK;
}
/**
* Public functions
*
*/
errval_t debug_create(struct debug_q** q, struct devq* other_q)
{
errval_t err;
struct debug_q* que;
que = calloc(1, sizeof(struct debug_q));
assert(que);
slab_init(&que->alloc, sizeof(struct memory_ele),
slab_default_refill);
slab_init(&que->alloc_list, sizeof(struct memory_list),
slab_default_refill);
que->q = other_q;
err = devq_init(&que->my_q, false);
if (err_is_fail(err)) {
return err;
}
que->my_q.f.reg = debug_register;
que->my_q.f.dereg = debug_deregister;
que->my_q.f.ctrl = debug_control;
que->my_q.f.notify = debug_notify;
que->my_q.f.enq = debug_enqueue;
que->my_q.f.deq = debug_dequeue;
que->my_q.f.destroy = debug_destroy;
*q = que;
return SYS_ERR_OK;
}
errval_t debug_dump_region(struct debug_q* que, regionid_t rid)
{
errval_t err;
// find region
struct memory_list* region = NULL;
err = find_region(que, &region, rid);
if (err_is_fail(err)){
return err;
}
dump_list(region);
return SYS_ERR_OK;
}
void debug_dump_history(struct debug_q* q)
{
#ifdef DQ_ENABLE_HIST
dump_history(q);
#endif
}
errval_t debug_add_region(struct debug_q* q, struct capref cap,
regionid_t rid)
{
return devq_add_region((struct devq*) q, cap, rid);
}
errval_t debug_remove_region(struct debug_q* q, regionid_t rid)
{
return devq_remove_region((struct devq*) q, rid);
}