From 3ed571f9d933e5c5dadef650c07e20e8aad06213 Mon Sep 17 00:00:00 2001 From: IPMbox Team Date: Fri, 3 Feb 2012 14:32:28 +0100 Subject: cesar, cleopatre, common: new ipmbox design, closes #848 --- cesar/bufmgr/Module | 4 + cesar/bufmgr/bufmgr.h | 96 ++++++++++ cesar/bufmgr/inc/context.h | 69 ++++++++ cesar/bufmgr/inc/trace.h | 56 ++++++ cesar/bufmgr/src/bufmgr.c | 180 +++++++++++++++++++ cesar/bufmgr/src/trace.c | 42 +++++ cesar/bufmgr/stub/Module | 1 + cesar/bufmgr/stub/src/bufmgr.c | 76 ++++++++ cesar/bufmgr/test/utest/Config | 1 + cesar/bufmgr/test/utest/Makefile | 11 ++ cesar/bufmgr/test/utest/inc/scenario_defs.h | 84 +++++++++ cesar/bufmgr/test/utest/inc/test_bufmgr.h | 20 +++ cesar/bufmgr/test/utest/src/bufmgr.c | 260 ++++++++++++++++++++++++++++ cesar/bufmgr/test/utest/src/ipmbox.c | 48 +++++ cesar/bufmgr/test/utest/src/scenario_defs.c | 90 ++++++++++ 15 files changed, 1038 insertions(+) create mode 100644 cesar/bufmgr/Module create mode 100644 cesar/bufmgr/bufmgr.h create mode 100644 cesar/bufmgr/inc/context.h create mode 100644 cesar/bufmgr/inc/trace.h create mode 100644 cesar/bufmgr/src/bufmgr.c create mode 100644 cesar/bufmgr/src/trace.c create mode 100644 cesar/bufmgr/stub/Module create mode 100644 cesar/bufmgr/stub/src/bufmgr.c create mode 100644 cesar/bufmgr/test/utest/Config create mode 100644 cesar/bufmgr/test/utest/Makefile create mode 100644 cesar/bufmgr/test/utest/inc/scenario_defs.h create mode 100644 cesar/bufmgr/test/utest/inc/test_bufmgr.h create mode 100644 cesar/bufmgr/test/utest/src/bufmgr.c create mode 100644 cesar/bufmgr/test/utest/src/ipmbox.c create mode 100644 cesar/bufmgr/test/utest/src/scenario_defs.c (limited to 'cesar/bufmgr') diff --git a/cesar/bufmgr/Module b/cesar/bufmgr/Module new file mode 100644 index 0000000000..7054f922ce --- /dev/null +++ b/cesar/bufmgr/Module @@ -0,0 +1,4 @@ +SOURCES := bufmgr.c +ifeq ($(CONFIG_TRACE),y) +SOURCES += trace.c +endif diff --git a/cesar/bufmgr/bufmgr.h b/cesar/bufmgr/bufmgr.h new file mode 100644 index 0000000000..b4cf912fd0 --- /dev/null +++ b/cesar/bufmgr/bufmgr.h @@ -0,0 +1,96 @@ +#ifndef bufmgr_bufmgr_h +#define bufmgr_bufmgr_h + +/* Cesar project {{{ + * + * Copyright (C) 2012 Spidcom + * + * <<>> + * + * }}} */ +/** + * \file bufmgr/bufmgr.h + * \brief Public interfaces for buffer manager. + * \ingroup bufmgr + * + * The buffer manager is responsible for passing empty buffers coming from + * Linux to other cesar components and returning used buffers from those + * components to Linux. + * + * Buffer manager is responsible for informing clients after a try get that + * new buffers are available. For that, clients must register. + */ +#include "hal/ipmbox/ipmbox.h" + +/* Forward declaration. */ +typedef struct bufmgr_t bufmgr_t; + +/** + * Callback prototype. + * \param user_data the user_data to give with the callback + */ +typedef void (*bufmgr_callback_t) (void *user_data); + +BEGIN_DECLS + +/** + * Get a buffer from the buffer manager. + * \param ctx module context + * \return a buffer, NULL if none available + */ +u8 * +bufmgr_get (bufmgr_t *ctx); + +/** + * Get a buffer from the buffer manager and wait it for a certain delay or + * until it gets it. + * \param ctx module context + * \param delay_ms delay of wait in ms, 0 if client wants to wait forever + * \return a buffer, NULL if no buffer available and the delay expired + */ +u8 * +bufmgr_get_wait (bufmgr_t *ctx, uint delay_rtc); + +/** + * Give back a buffer. + * \param ctx module context + * \param buffer buffer to return + */ +void +bufmgr_give_back (bufmgr_t *ctx, u8 *buffer); + +/** + * Give the buffer to buffer manager to keep it. + * \param ctx module context + * \param buffer buffer to return + */ +void +bufmgr_keep_buffer (bufmgr_t *ctx, u8 *buffer); + +/** + * Register a client to the buffer manager. + * \param ctx module context + * \param cb the callback to call + * \param user_data the user data to provide + */ +void +bufmgr_client_register (bufmgr_t *ctx, bufmgr_callback_t cb, void *user_data); + +/** + * Initialise the module. + * \param ipmbox the ipmbox context + * \return buffer manager context + */ +bufmgr_t * +bufmgr_init (ipmbox_t *ipmbox); + +/** + * Uninitialise the module. + * \param ctx module context + */ +void +bufmgr_uninit (bufmgr_t *ctx); + +END_DECLS + +#endif /* bufmgr_bufmgr_h */ diff --git a/cesar/bufmgr/inc/context.h b/cesar/bufmgr/inc/context.h new file mode 100644 index 0000000000..1f2d59e75c --- /dev/null +++ b/cesar/bufmgr/inc/context.h @@ -0,0 +1,69 @@ +#ifndef bufmgr_inc_context_h +#define bufmgr_inc_context_h + +/* Cesar project {{{ + * + * Copyright (C) 2012 Spidcom + * + * <<>> + * + * }}} */ +/** + * \file bufmgr/inc/context.h + * \brief Buffer manager context structure definition. + * \ingroup bufmgr + */ +#include "common/ipmbox/protocol.h" +#include "hal/ipmbox/ipmbox.h" +#include "hal/arch/sem.h" + +#include "bufmgr/inc/trace.h" + +/* Size of the local buffer list. */ +#define BUFMGR_BUFFER_LIST_SIZE \ + (IPMBOX_PROTOCOL_QUEUE_SIZE_A2L_EMPTY_BUF / 2) + +/* Number of required local buffers in local list. + * The list is bigger to store empty buffers received from the PLC to the CP. + * Those buffers are empty buffers given by linux and must be kept in the + * buffer manager. */ +#define BUFMGR_BUFFER_LIST_NB (BUFMGR_BUFFER_LIST_SIZE / 2) + +/* Number of buffer reserved for blocking clients. */ +#define BUFMGR_RESERVED_BUFFER_NB 4 + +/* Number of registered clients. */ +#define BUFMGR_CLIENT_NB 5 + +/* Client callback. */ +struct bufmgr_client_t +{ + /** Callback. */ + bufmgr_callback_t cb; + /** User data. */ + void *user_data; +}; +typedef struct bufmgr_client_t bufmgr_client_t; + +/* Context structure. */ +struct bufmgr_t +{ + /* IPMbox context. */ + ipmbox_t *ipmbox; + /** Table of client callback. */ + bufmgr_client_t client[BUFMGR_CLIENT_NB]; + /** Number of clients registered. */ + uint client_nb; + /** List of buffers. */ + u32 buffers [BUFMGR_BUFFER_LIST_SIZE]; + /** Number of available buffers. */ + uint buffers_nb; + /** Semaphore for reserved buffers. */ + hal_arch_sem_t sem; +#if CONFIG_TRACE + /** Buffer Manager Trace */ + trace_buffer_t trace; +#endif +}; + +#endif /*bufmgr_inc_context_h*/ diff --git a/cesar/bufmgr/inc/trace.h b/cesar/bufmgr/inc/trace.h new file mode 100644 index 0000000000..bb9600eb92 --- /dev/null +++ b/cesar/bufmgr/inc/trace.h @@ -0,0 +1,56 @@ +#ifndef bufmgr_inc_trace_h +#define bufmgr_inc_trace_h +/* Cesar project {{{ + * + * Copyright (C) 2012 Spidcom + * + * <<>> + * + * }}} */ +/** + * \file cesar/bufmgr/inc/trace.h + * \brief Buffer manager traces. + * \ingroup bufmgr + */ + +#include "lib/trace.h" + +/** Shortcut for tracing inside buffer manager . */ +#define BUFMGR_TRACE(id, args...) \ + TRACE_FAST_SHORT (BUFMGR_TRACE_, &ctx->trace, id, ## args) + +#if CONFIG_TRACE + +enum +{ + BUFMGR_TRACE_BUFFER_GET, + BUFMGR_TRACE_BUFFER_GET_WAIT, + BUFMGR_TRACE_BUFFER_GIVE_BACK, + BUFMGR_TRACE_BUFFER_NEW, + BUFMGR_TRACE_BUFFER_KEEP, +}; + +/** + * Initialize the trace system + * \param ctx the bufmgr context. + */ +void +bufmgr_trace_init (bufmgr_t *ctx); + +/** + * Uninitialise the trace system + * \param ctx the bufmgr context + */ +void +bufmgr_trace_uninit (bufmgr_t *ctx); + +END_DECLS + +#else /* !CONFIG_TRACE */ + +#define bufmgr_trace_init(ctx) ((void) 0) +#define bufmgr_trace_uninit(ctx) ((void) 0) + +#endif /* !CONFIG_TRACE */ + +#endif /* bufmgr_inc_trace_h */ diff --git a/cesar/bufmgr/src/bufmgr.c b/cesar/bufmgr/src/bufmgr.c new file mode 100644 index 0000000000..73ff9d8e7b --- /dev/null +++ b/cesar/bufmgr/src/bufmgr.c @@ -0,0 +1,180 @@ +/* Cesar project {{{ + * + * Copyright (C) 2012 Spidcom + * + * <<>> + * + * }}} */ +/** + * \file bufmgr/src/bufmgr.c + * \brief Buffer Manager + * \ingroup bufmgr + */ +#include "common/std.h" + +#include "common/ipmbox/msg.h" + +#include "hal/ipmbox/ipmbox.h" + +#include "bufmgr/bufmgr.h" +#include "bufmgr/inc/context.h" +#include "bufmgr/inc/trace.h" + +static bufmgr_t bufmgr_global; + +/** + * Fill buffer cache table. + * \param ctx module context + * + * Must be called DSR locked. + */ +PRIVATE inline void +bufmgr_fill_cache (bufmgr_t *ctx) +{ + /* This is OK as DSR is locked. */ + uint reserved_buf_nb = hal_arch_sem_peek (&ctx->sem); + uint missing_reserved_buffers = BUFMGR_RESERVED_BUFFER_NB + - reserved_buf_nb; + if (ctx->buffers_nb < BUFMGR_BUFFER_LIST_NB) + { + uint nb_got = ipmbox_empty_buf_get ( + ctx->ipmbox, &ctx->buffers[ctx->buffers_nb], + BUFMGR_BUFFER_LIST_NB - ctx->buffers_nb); + ctx->buffers_nb += nb_got; + } + /* Try to convert cached buffers into reserved buffers. */ + missing_reserved_buffers = + MIN (missing_reserved_buffers, ctx->buffers_nb - reserved_buf_nb); + for ( ; missing_reserved_buffers; missing_reserved_buffers--) + hal_arch_sem_post (&ctx->sem); +} + +u8 * +bufmgr_get (bufmgr_t *ctx) +{ + dbg_claim (ctx); + u8 *buffer = NULL; + arch_dsr_lock (); + if (ctx->buffers_nb <= BUFMGR_RESERVED_BUFFER_NB) + bufmgr_fill_cache (ctx); + /* Give a buffer is possible. */ + if (ctx->buffers_nb > BUFMGR_RESERVED_BUFFER_NB) + { + buffer = (u8 *) ctx->buffers[ctx->buffers_nb - 1]; + ctx->buffers_nb--; + } + BUFMGR_TRACE (BUFFER_GET, buffer); + arch_dsr_unlock (); + return buffer; +} + +static inline u8 * +bufmgr_reserved_get (bufmgr_t *ctx) +{ + u8 *buffer = NULL; + arch_dsr_lock (); + buffer = (u8 *) ctx->buffers[ctx->buffers_nb - 1]; + ctx->buffers_nb--; + arch_dsr_unlock (); + return buffer; +} + +u8 * +bufmgr_get_wait (bufmgr_t *ctx, uint delay_rtc) +{ + u8 *buffer = NULL; + do + { + buffer = bufmgr_get (ctx); + if (buffer) + break; + if (delay_rtc) + { + if (hal_arch_sem_timed_wait (&ctx->sem, delay_rtc)) + buffer = bufmgr_reserved_get (ctx); + break; + } + else + { + hal_arch_sem_wait (&ctx->sem); + buffer = bufmgr_reserved_get (ctx); + } + } while (!buffer); + BUFMGR_TRACE (BUFFER_GET_WAIT, buffer, delay_rtc); + return buffer; +} + +void +bufmgr_give_back (bufmgr_t *ctx, u8 *buffer) +{ + dbg_claim (ctx); + dbg_claim (buffer); + BUFMGR_TRACE (BUFFER_GIVE_BACK, buffer); + ipmbox_msg_empty_buf_t msg = { .buffer_addr = (u32) buffer }; + ipmbox_tx_empty_buf (ctx->ipmbox, (u32 *) &msg, + IPMBOX_MSG_EMPTY_BUF_WORDS); +} + +void +bufmgr_keep_buffer (bufmgr_t *ctx, u8 *buffer) +{ + dbg_claim (ctx); + dbg_claim (buffer); + arch_dsr_lock (); + BUFMGR_TRACE (BUFFER_KEEP, buffer); + dbg_assert (ctx->buffers_nb < BUFMGR_BUFFER_LIST_SIZE); + ctx->buffers[ctx->buffers_nb] = (u32) buffer; + ctx->buffers_nb++; + if (hal_arch_sem_peek (&ctx->sem) < BUFMGR_RESERVED_BUFFER_NB) + hal_arch_sem_post (&ctx->sem); + arch_dsr_unlock (); +} + +/** + * Call each client that has asked to be recalled on a lack of buffers. + * \param ctx module context + */ +static void +bufmgr_handle_new_buf (bufmgr_t *ctx) +{ + uint i; + bufmgr_fill_cache (ctx); + /* Call each registered client's callback. */ + for (i = 0; i < ctx->client_nb; i++) + ctx->client[i].cb (ctx->client[i].user_data); + BUFMGR_TRACE (BUFFER_NEW); +} + +void +bufmgr_client_register (bufmgr_t *ctx, bufmgr_callback_t cb, void *user_data) +{ + dbg_assert (ctx); + dbg_assert (cb); + dbg_assert (ctx->client_nb < BUFMGR_CLIENT_NB); + ctx->client[ctx->client_nb].cb = cb; + ctx->client[ctx->client_nb].user_data = user_data; + ctx->client_nb++; +} + +bufmgr_t * +bufmgr_init (ipmbox_t *ipmbox) +{ + bufmgr_t *ctx = &bufmgr_global; + ctx->ipmbox = ipmbox; + ctx->client_nb = 0; + ctx->buffers_nb = 0; + hal_arch_sem_init (&ctx->sem, 0); + /* Register a callback for empty_buf IT. */ + ipmbox_register_empty_buf_cb (ipmbox, ctx, + (ipmbox_empty_buf_cb_t) bufmgr_handle_new_buf); + bufmgr_trace_init (ctx); + return ctx; +} + +void +bufmgr_uninit (bufmgr_t *ctx) +{ + dbg_assert (ctx); + ctx->client_nb = 0; + ctx->buffers_nb = 0; +} diff --git a/cesar/bufmgr/src/trace.c b/cesar/bufmgr/src/trace.c new file mode 100644 index 0000000000..54b3f549ad --- /dev/null +++ b/cesar/bufmgr/src/trace.c @@ -0,0 +1,42 @@ +/* Cesar project {{{ + * + * Copyright (C) 2012 Spidcom + * + * <<>> + * + * }}} */ +/** + * \file bufmgr/src/trace.c + * \brief Buffer manager traces. + * \ingroup bufmgr + */ +#include "common/std.h" +#include "bufmgr/bufmgr.h" +#include "bufmgr/inc/trace.h" +#include "bufmgr/inc/context.h" + +void +bufmgr_trace_init (bufmgr_t *ctx) +{ + static trace_namespace_t namespace; + static const trace_event_id_t event_ids[] = + { + TRACE_EVENT (BUFMGR_TRACE_BUFFER_GET, "Buffer get %x"), + TRACE_EVENT (BUFMGR_TRACE_BUFFER_GET_WAIT, + "Buffer get wait %x delay_rtc %d"), + TRACE_EVENT (BUFMGR_TRACE_BUFFER_GIVE_BACK, + "Buffer give back %x"), + TRACE_EVENT (BUFMGR_TRACE_BUFFER_NEW, "new buffers"), + TRACE_EVENT (BUFMGR_TRACE_BUFFER_KEEP, "Buffer keep %x"), + }; + dbg_assert (ctx); + trace_namespace_init (&namespace, event_ids, COUNT (event_ids)); + trace_buffer_add (&ctx->trace, "bufmgr", 8, 4, true, &namespace); +} + +void +bufmgr_trace_uninit (bufmgr_t *ctx) +{ + dbg_assert (ctx); + trace_buffer_remove (&ctx->trace); +} diff --git a/cesar/bufmgr/stub/Module b/cesar/bufmgr/stub/Module new file mode 100644 index 0000000000..d4846f1daf --- /dev/null +++ b/cesar/bufmgr/stub/Module @@ -0,0 +1 @@ +SOURCES := bufmgr.c \ No newline at end of file diff --git a/cesar/bufmgr/stub/src/bufmgr.c b/cesar/bufmgr/stub/src/bufmgr.c new file mode 100644 index 0000000000..fd61d8725d --- /dev/null +++ b/cesar/bufmgr/stub/src/bufmgr.c @@ -0,0 +1,76 @@ +/* Cesar project {{{ + * + * Copyright (C) 2012 Spidcom + * + * <<>> + * + * }}} */ +/** + * \file bufmgr/stub/src/bufmgr.c + * \brief Buffer Manager stub functions + * \ingroup bufmgr_stub + */ +#include "common/std.h" + +#include "bufmgr/bufmgr.h" + +u8* +bufmgr_get (bufmgr_t *ctx) __attribute__((weak)); + +u8* +bufmgr_get (bufmgr_t *ctx) +{ + return NULL; +} + +u8* +bufmgr_get_wait (bufmgr_t *ctx, uint delay_rtc) __attribute__((weak)); + +u8* +bufmgr_get_wait (bufmgr_t *ctx, uint delay_rtc) +{ + return NULL; +} + +void +bufmgr_give_back (bufmgr_t *ctx, u8 *buffer) __attribute__((weak)); + +void +bufmgr_give_back (bufmgr_t *ctx, u8 *buffer) +{ +} + +void +bufmgr_client_register (bufmgr_t *ctx, bufmgr_callback_t cb, + void *user_data) __attribute__((weak)); + +void +bufmgr_client_register (bufmgr_t *ctx, bufmgr_callback_t cb, + void *user_data) +{ +} + +bufmgr_t* +bufmgr_init (ipmbox_t *ipmbox) __attribute__((weak)); + +bufmgr_t* +bufmgr_init (ipmbox_t *ipmbox) +{ + return NULL; +} + +void +bufmgr_uninit (bufmgr_t *ctx) __attribute__((weak)); + +void +bufmgr_uninit (bufmgr_t *ctx) +{ +} + +void +bufmgr_keep_buffer (bufmgr_t *ctx, u8 *buffer) __attribute__((weak)); + +void +bufmgr_keep_buffer (bufmgr_t *ctx, u8 *buffer) +{ +} diff --git a/cesar/bufmgr/test/utest/Config b/cesar/bufmgr/test/utest/Config new file mode 100644 index 0000000000..dbdade324f --- /dev/null +++ b/cesar/bufmgr/test/utest/Config @@ -0,0 +1 @@ +CONFIG_DEBUG_FATAL_CATCH=y diff --git a/cesar/bufmgr/test/utest/Makefile b/cesar/bufmgr/test/utest/Makefile new file mode 100644 index 0000000000..e3ece7526e --- /dev/null +++ b/cesar/bufmgr/test/utest/Makefile @@ -0,0 +1,11 @@ +BASE = ../../.. + +INCLUDES = bufmgr bufmgr/test/utest + +DEFS=-DNO_PRIVATE + +HOST_PROGRAMS = test_bufmgr +test_bufmgr_SOURCES = bufmgr.c ipmbox.c scenario_defs.c +test_bufmgr_MODULES = lib lib/scenario bufmgr + +include $(BASE)/common/make/top.mk diff --git a/cesar/bufmgr/test/utest/inc/scenario_defs.h b/cesar/bufmgr/test/utest/inc/scenario_defs.h new file mode 100644 index 0000000000..eb80cd6984 --- /dev/null +++ b/cesar/bufmgr/test/utest/inc/scenario_defs.h @@ -0,0 +1,84 @@ +#ifndef inc_scenario_defs_h +#define inc_scenario_defs_h +/* Cesar project {{{ + * + * Copyright (C) 2012 Spidcom + * + * <<>> + * + * }}} */ +/** + * \file inc/scenario_defs.h + * \brief Scenario entries definition. + * \ingroup test + */ +#include "bufmgr/bufmgr.h" + +/* Scenario globals. */ +#define SCENARIO_DEFS_GLOBALS \ + bufmgr_t *bufmgr; + +/* Scenario actions. */ +#define SCENARIO_DEFS_ACTIONS \ + bufmgr_fill_cache, \ + bufmgr_get, \ + bufmgr_get_wait, \ + bufmgr_give_back, \ + bufmgr_keep_buffer + +typedef struct +{ + uint ipmbox_buf_available; +} scenario_action_bufmgr_fill_cache_t; + +void +scenario_action_bufmgr_fill_cache_cb (scenario_globals_t *globals, + scenario_params_t *params); + +typedef struct +{ + u8 *buf_expected; +} scenario_action_bufmgr_get_t; + +void +scenario_action_bufmgr_get_cb (scenario_globals_t *globals, + scenario_params_t *params); + +typedef scenario_action_bufmgr_get_t scenario_action_bufmgr_get_wait_t; + +void +scenario_action_bufmgr_get_wait_cb (scenario_globals_t *globals, + scenario_params_t *params); + +typedef struct +{ + u8 *buffer; +} scenario_action_bufmgr_keep_buffer_t; + +void +scenario_action_bufmgr_keep_buffer_cb(scenario_globals_t *globals, + scenario_params_t *params); + +typedef scenario_empty_t scenario_action_bufmgr_give_back_t; + +void +scenario_action_bufmgr_give_back_cb (scenario_globals_t *globals, + scenario_params_t *params); + +/* Scenario events. */ +#define SCENARIO_DEFS_EVENTS \ + ipmbox_empty_buf_get, \ + ipmbox_tx_empty_buf + +typedef struct +{ + uint nb_req; + uint nb_return; +} scenario_event_ipmbox_empty_buf_get_t; + +typedef struct +{ + uint length; +} scenario_event_ipmbox_tx_empty_buf_t; + +#endif /* inc_scenario_defs_h */ diff --git a/cesar/bufmgr/test/utest/inc/test_bufmgr.h b/cesar/bufmgr/test/utest/inc/test_bufmgr.h new file mode 100644 index 0000000000..50a16da254 --- /dev/null +++ b/cesar/bufmgr/test/utest/inc/test_bufmgr.h @@ -0,0 +1,20 @@ +#ifndef inc_test_bufmgr_h +#define inc_test_bufmgr_h + +/* Cesar project {{{ + * + * Copyright (C) 2012 Spidcom + * + * <<>> + * + * }}} */ +/** + * \file inc/test_bufmgr.h + * \brief Buffer manager unitary test private data + * \ingroup test + */ + +/* Define a fake buffer address for tests. */ +#define BUFMGR_TEST_FAKE_BUFFER_ADDRESS 0x42 + +#endif /* inc_test_bufmgr_h */ diff --git a/cesar/bufmgr/test/utest/src/bufmgr.c b/cesar/bufmgr/test/utest/src/bufmgr.c new file mode 100644 index 0000000000..3274fa0ebe --- /dev/null +++ b/cesar/bufmgr/test/utest/src/bufmgr.c @@ -0,0 +1,260 @@ +/* Cesar project {{{ + * + * Copyright (C) 2012 Spidcom + * + * <<>> + * + * }}} */ +/** + * \file bufmgr/test/utest/src/bufmgr.c + * \brief Buffer Manager unitary test + * \ingroup bufmgr_test + */ +#include "common/std.h" + +#include "lib/test.h" +#include "lib/scenario/scenario.h" +#include "lib/blk.h" +#include "lib/rnd.h" + +#include "bufmgr/bufmgr.h" +#include "bufmgr/inc/context.h" + +#include "inc/test_bufmgr.h" + +void +bufmgr_fill_cache_test_case (test_t t) +{ + test_case_begin (t, "Fill cache buffer"); + test_begin (t, "all cases.") + { + bufmgr_t *bufmgr = bufmgr_init (NULL); + uint i, j; + scenario_globals_t globals = { + .bufmgr = bufmgr + }; + for (i = 0; i < BUFMGR_BUFFER_LIST_SIZE; i++) + { + for (j = 0; j < BUFMGR_BUFFER_LIST_SIZE; j++) + { + + bufmgr->sem = MIN (i, (uint) BUFMGR_RESERVED_BUFFER_NB); + bufmgr->buffers_nb = i; + scenario_entry_t entries[] = { + SCENARIO_ACTION (bufmgr_fill_cache, + .ipmbox_buf_available = j), + SCENARIO_EVENT_COND (i < BUFMGR_BUFFER_LIST_NB, + ipmbox_empty_buf_get, + .nb_req = BUFMGR_BUFFER_LIST_NB - i, + .nb_return = + MIN (BUFMGR_BUFFER_LIST_NB - i, j)), + SCENARIO_END + }; + scenario_run (t, entries, &globals); + } + } + bufmgr_uninit (bufmgr); + } + test_end; +} + +void +bufmgr_get_test_case (test_t t) +{ + test_case_begin (t, "Get buffer"); + test_begin (t, "all cases.") + { + bufmgr_t *bufmgr = bufmgr_init (NULL); + scenario_globals_t globals = { + .bufmgr = bufmgr + }; + bufmgr->sem = bufmgr->buffers_nb = 0; + scenario_entry_t entries[] = { + /* No buffers. */ + SCENARIO_ACTION (bufmgr_get, + .buf_expected = NULL), + SCENARIO_EVENT (ipmbox_empty_buf_get, + .nb_req = BUFMGR_BUFFER_LIST_NB, + .nb_return = 0), + /* Get only buffers for reserved list. */ + SCENARIO_ACTION (bufmgr_get, + .buf_expected = NULL), + SCENARIO_EVENT (ipmbox_empty_buf_get, + .nb_req = BUFMGR_BUFFER_LIST_NB, + .nb_return = BUFMGR_RESERVED_BUFFER_NB), + /* Get a buffer. */ + SCENARIO_ACTION (bufmgr_get, + .buf_expected = (u8*) BUFMGR_TEST_FAKE_BUFFER_ADDRESS), + SCENARIO_EVENT (ipmbox_empty_buf_get, + .nb_req = BUFMGR_BUFFER_LIST_NB + - BUFMGR_RESERVED_BUFFER_NB, + .nb_return = 1), + /* Only reserved buffers available. */ + SCENARIO_ACTION (bufmgr_get, + .buf_expected = NULL), + SCENARIO_EVENT (ipmbox_empty_buf_get, + .nb_req = BUFMGR_BUFFER_LIST_NB + - BUFMGR_RESERVED_BUFFER_NB, + .nb_return = 0), + SCENARIO_END + }; + scenario_run (t, entries, &globals); + bufmgr_uninit (bufmgr); + } + test_end; +} + +void +bufmgr_get_wait_test_case (test_t t) +{ + test_case_begin (t, "Wait to get buffer"); + test_begin (t, "all cases.") + { + bufmgr_t *bufmgr = bufmgr_init (NULL); + scenario_globals_t globals = { + .bufmgr = bufmgr + }; + bufmgr->sem = bufmgr->buffers_nb = 0; + scenario_entry_t entries[] = { + /* No buffers. */ + SCENARIO_ACTION (bufmgr_get_wait, + .buf_expected = NULL), + SCENARIO_EVENT (ipmbox_empty_buf_get, + .nb_req = BUFMGR_BUFFER_LIST_NB, + .nb_return = 0), + /* Get a buffer from reserved list. */ + SCENARIO_ACTION (bufmgr_get_wait, + .buf_expected = + (u8*) BUFMGR_TEST_FAKE_BUFFER_ADDRESS), + SCENARIO_EVENT (ipmbox_empty_buf_get, + .nb_req = BUFMGR_BUFFER_LIST_NB, + .nb_return = BUFMGR_RESERVED_BUFFER_NB), + /* Get a buffer from cached list. */ + SCENARIO_ACTION (bufmgr_get_wait, + .buf_expected = (u8*) BUFMGR_TEST_FAKE_BUFFER_ADDRESS), + SCENARIO_EVENT (ipmbox_empty_buf_get, + .nb_req = BUFMGR_BUFFER_LIST_NB + - BUFMGR_RESERVED_BUFFER_NB + 1, + .nb_return = 2), + SCENARIO_END + }; + scenario_run (t, entries, &globals); + test_fail_unless (bufmgr->sem == BUFMGR_RESERVED_BUFFER_NB - 1); + bufmgr_uninit (bufmgr); + } + test_end; +} + +void +bufmgr_give_back_test_case (test_t t) +{ + test_case_begin (t, "Give back an empty buffer"); + bufmgr_t *bufmgr; + /* Context init. */ + bufmgr = bufmgr_init (NULL); + test_begin (t, "Nominal") + { + scenario_entry_t entries[] = { + SCENARIO_ACTION (bufmgr_give_back), + SCENARIO_EVENT (ipmbox_tx_empty_buf, .length = 1), + SCENARIO_END + }; + scenario_globals_t globals = { + .bufmgr = bufmgr + }; + scenario_run (t, entries, &globals); + } test_end; + test_begin (t, "Keep buffer, to not give back to linux") + { + bufmgr->buffers_nb = BUFMGR_BUFFER_LIST_NB; + scenario_entry_t entries[] = { + SCENARIO_ACTION (bufmgr_keep_buffer, + .buffer = (u8*) BUFMGR_TEST_FAKE_BUFFER_ADDRESS), + SCENARIO_END + }; + scenario_globals_t globals = { + .bufmgr = bufmgr + }; + scenario_run (t, entries, &globals); + test_fail_unless (bufmgr->buffers_nb == BUFMGR_BUFFER_LIST_NB + 1); + /* Get a buffer. */ + scenario_entry_t entries_get_buffer[] = { + SCENARIO_ACTION (bufmgr_get_wait, + .buf_expected = + (u8*) BUFMGR_TEST_FAKE_BUFFER_ADDRESS), + SCENARIO_END + }; + scenario_run (t, entries_get_buffer, &globals); + test_fail_unless (bufmgr->buffers_nb == BUFMGR_BUFFER_LIST_NB); + } test_end; + bufmgr_uninit (bufmgr); +} + +void +bufmgr_callback_test_case (test_t t) +{ + test_case_begin (t, "Register callbacks"); + test_begin (t, "Register callback.") + { + lib_rnd_t rand; + lib_rnd_init (&rand, 0x12afe); + bufmgr_client_t client[BUFMGR_CLIENT_NB]; + bufmgr_t *bufmgr; + bufmgr = bufmgr_init (NULL); + test_fail_unless (!bufmgr->client_nb); + uint i; + for (i = 0; i < BUFMGR_CLIENT_NB; i++) + { + client[i].cb = INVALID_PTR + i; + client[i].user_data = INVALID_PTR + i + 1; + bufmgr_client_register (bufmgr, client[i].cb, + client[i].user_data); + } + /* Add a new one... */ + dbg_fatal_try_begin + { + bufmgr_client_register (bufmgr, (void*)0x42, (void*)0x43); + test_fail_unless (false); + } + dbg_fatal_try_catch (const char *fatal_message) + { + test_verbose_print (fatal_message); + test_fail_unless (true); + } + dbg_fatal_try_end; + /* Check values. */ + for (i = 0; i < BUFMGR_CLIENT_NB; i++) + { + test_fail_unless (bufmgr->client[i].cb == client[i].cb); + test_fail_unless (bufmgr->client[i].user_data == + client[i].user_data); + } + bufmgr_uninit (bufmgr); + } test_end; +} + +void +bufmger_test_suite (test_t t) +{ + test_suite_begin (t, "buffer manager"); + bufmgr_fill_cache_test_case (t); + bufmgr_get_test_case (t); + bufmgr_get_wait_test_case (t); + bufmgr_give_back_test_case (t); + bufmgr_callback_test_case (t); + test_case_begin (t, "memory"); + test_begin (t, "memory") + { + test_fail_unless (blk_check_memory ()); + } test_end; +} + +int +main (int argc, char **argv) +{ + test_t t; + test_init (t, argc, argv); + bufmger_test_suite (t); + test_result (t); + return test_nb_failed (t) == 0 ? 0 : 1; +} diff --git a/cesar/bufmgr/test/utest/src/ipmbox.c b/cesar/bufmgr/test/utest/src/ipmbox.c new file mode 100644 index 0000000000..bae1c46f2c --- /dev/null +++ b/cesar/bufmgr/test/utest/src/ipmbox.c @@ -0,0 +1,48 @@ +/* Cesar project {{{ + * + * Copyright (C) 2012 Spidcom + * + * <<>> + * + * }}} */ +/** + * \file bufmgr/test/utest/src/ipmbox.c + * \brief Override IPMbox functions. + * \ingroup bufmgr_test + */ +#include "common/std.h" + +#include "lib/test.h" +#include "lib/scenario/scenario.h" + +#include "hal/ipmbox/ipmbox.h" + +#include "inc/test_bufmgr.h" + +uint +ipmbox_empty_buf_get (ipmbox_t *ctx, u32 *msg_buf, uint nb) +{ + scenario_event (ipmbox_empty_buf_get, params); + test_fail_unless (nb == params->nb_req); + if (params->nb_return) + { + *msg_buf = (u32) BUFMGR_TEST_FAKE_BUFFER_ADDRESS; + } + else + *msg_buf = (u32) NULL; + return params->nb_return; +} + +void +ipmbox_tx_empty_buf (ipmbox_t *ctx, u32 *first_msg, uint length) +{ + scenario_event (ipmbox_tx_empty_buf, params); + test_fail_unless (*first_msg == BUFMGR_TEST_FAKE_BUFFER_ADDRESS); + test_fail_unless (length == params->length); +} + +void +ipmbox_register_empty_buf_cb (ipmbox_t *ctx, void *user_data, + ipmbox_empty_buf_cb_t empty_buf_cb) +{ +} diff --git a/cesar/bufmgr/test/utest/src/scenario_defs.c b/cesar/bufmgr/test/utest/src/scenario_defs.c new file mode 100644 index 0000000000..c2b0cad991 --- /dev/null +++ b/cesar/bufmgr/test/utest/src/scenario_defs.c @@ -0,0 +1,90 @@ +/* Cesar project {{{ + * + * Copyright (C) 2012 Spidcom + * + * <<>> + * + * }}} */ +/** + * \file src/scenario_defs.c + * \brief Scenario actions. + * \ingroup test + */ +#include "common/std.h" + +#include "lib/test.h" +#include "lib/scenario/scenario.h" + +#include "bufmgr/bufmgr.h" +#include "bufmgr/inc/context.h" + +#include "inc/test_bufmgr.h" + +void +bufmgr_fill_cache (bufmgr_t *ctx); + +void +scenario_action_bufmgr_fill_cache_cb (scenario_globals_t *globals, + scenario_params_t *params) +{ + test_within (scenario.t); + bufmgr_t *ctx = globals->bufmgr; + scenario_action_bufmgr_fill_cache_t *p = + ¶ms->action_bufmgr_fill_cache; + uint buffers_init_nb = ctx->buffers_nb; + uint reserved_buf_init_nb = ctx->sem; + uint ipmbox_buf_available = p->ipmbox_buf_available; + uint reserved_buf_added = + MIN (BUFMGR_RESERVED_BUFFER_NB - reserved_buf_init_nb, + ipmbox_buf_available); + uint buffers_end_nb = buffers_init_nb; + if (buffers_init_nb < BUFMGR_BUFFER_LIST_NB) + { + buffers_end_nb += + MIN ((uint) BUFMGR_BUFFER_LIST_NB - buffers_init_nb, + ipmbox_buf_available); + } + bufmgr_fill_cache (ctx); + test_fail_unless (ctx->sem == reserved_buf_init_nb + reserved_buf_added); + test_fail_unless (ctx->buffers_nb == buffers_end_nb); +} + +void +scenario_action_bufmgr_get_cb (scenario_globals_t *globals, + scenario_params_t *params) +{ + test_within (scenario.t); + bufmgr_t *ctx = globals->bufmgr; + scenario_action_bufmgr_get_t *p = ¶ms->action_bufmgr_get; + u8 *buf = bufmgr_get (ctx); + test_fail_unless (buf == p->buf_expected); +} + +void +scenario_action_bufmgr_get_wait_cb (scenario_globals_t *globals, + scenario_params_t *params) +{ + test_within (scenario.t); + bufmgr_t *ctx = globals->bufmgr; + scenario_action_bufmgr_get_wait_t *p = ¶ms->action_bufmgr_get_wait; + u8 *buf = bufmgr_get_wait (ctx, 10); + test_fail_unless (buf == p->buf_expected); +} + +void +scenario_action_bufmgr_keep_buffer_cb (scenario_globals_t *globals, + scenario_params_t *params) +{ + bufmgr_t *ctx = globals->bufmgr; + scenario_action_bufmgr_keep_buffer_t *p = + ¶ms->action_bufmgr_keep_buffer; + bufmgr_keep_buffer (ctx, p->buffer); +} + +void +scenario_action_bufmgr_give_back_cb (scenario_globals_t *globals, + scenario_params_t *params) +{ + bufmgr_t *ctx = globals->bufmgr; + bufmgr_give_back (ctx, (u8 *) BUFMGR_TEST_FAKE_BUFFER_ADDRESS); +} -- cgit v1.2.3