Änderungen Gruppe 30_10_2022 V2

This commit is contained in:
2022-10-30 20:01:47 +01:00
parent 269f807b31
commit 2517e52e59
239 changed files with 54983 additions and 9 deletions
@@ -0,0 +1,21 @@
set (HEADERS
vcos_common.h
vcos_generic_blockpool.h
vcos_generic_event_flags.h
vcos_generic_named_sem.h
vcos_generic_quickslow_mutex.h
vcos_generic_reentrant_mtx.h
vcos_generic_tls.h
vcos_joinable_thread_from_plain.h
vcos_latch_from_sem.h
vcos_mem_from_malloc.h
vcos_mutexes_are_reentrant.h
vcos_thread_reaper.h
)
foreach (header ${HEADERS})
configure_file ("${header}" "${VCOS_HEADERS_BUILD_DIR}/generic/${header}" COPYONLY)
endforeach ()
install (FILES ${HEADERS} DESTINATION include/interface/vcos/generic)
@@ -0,0 +1,85 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "interface/vcos/vcos.h"
#ifdef __VIDEOCORE__
#include "host_support/include/vc_debug_sym.h"
#include "vcfw/vclib/vclib.h"
#endif
#include <stdlib.h>
int vcos_verify_bkpts = 0;
#ifdef __VIDEOCORE__
VC_DEBUG_VAR(vcos_verify_bkpts);
#endif
int vcos_verify_bkpts_enabled(void)
{
return vcos_verify_bkpts;
}
int vcos_verify_bkpts_enable(int enable)
{
int old = vcos_verify_bkpts;
vcos_verify_bkpts = enable;
return old;
}
/**
* Call the fatal error handler.
*/
void vcos_abort(void)
{
VCOS_ALERT("vcos_abort: Halting");
#ifdef __VIDEOCORE__
_bkpt();
#endif
#if defined(VCOS_HAVE_BACKTRACE) && !defined(NDEBUG)
vcos_backtrace_self();
#endif
#ifdef __VIDEOCORE__
/* Flush the cache to help with postmortem RAM-dump debugging */
vclib_cache_flush();
#endif
#ifdef PLATFORM_RASPBERRYPI
extern void pattern(int);
while(1)
pattern(8);
#endif
/* Insert chosen fatal error handler here */
#if defined __VIDEOCORE__ && !defined(NDEBUG)
while(1); /* allow us to attach a debugger after the fact and see where we came from. */
#else
abort(); /* on vc this ends up in _exit_halt which doesn't give us any stack backtrace */
#endif
}
@@ -0,0 +1,722 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*****************************************************************************
*
* This file provides a generic command line interface which allows
* vcos internals to be manipulated and/or displayed.
*
*****************************************************************************/
/* ---- Include Files ---------------------------------------------------- */
#include "interface/vcos/vcos.h"
#ifdef HAVE_VCOS_VERSION
#include "interface/vcos/vcos_build_info.h"
#endif
#ifdef _VIDEOCORE
#include "vcfw/logging/logging.h"
#endif
/* ---- Public Variables ------------------------------------------------- */
/* ---- Private Constants and Types -------------------------------------- */
#define VCOS_LOG_CATEGORY (&vcos_cmd_log_category)
VCOS_LOG_CAT_T vcos_cmd_log_category;
/* ---- Private Variables ------------------------------------------------ */
static struct VCOS_CMD_GLOBALS_T
{
VCOS_MUTEX_T lock;
VCOS_ONCE_T initialized;
unsigned num_cmd_entries;
unsigned num_cmd_alloc;
VCOS_CMD_T *cmd_entry;
VCOS_LOG_CAT_T *log_category;
} cmd_globals;
#ifdef HAVE_VCOS_VERSION
/* Keep the static strings in the image from being dropped by
* the linker.
*/
extern const char *vcos_get_build_strings(unsigned id);
const char *(*vcos_keep_static_strings)(unsigned);
#endif
/* ---- Private Function Prototypes -------------------------------------- */
static VCOS_STATUS_T help_cmd( VCOS_CMD_PARAM_T *param );
/* ---- Functions ------------------------------------------------------- */
/*****************************************************************************
*
* Walks through the commands looking for a particular command
*
*****************************************************************************/
static VCOS_CMD_T *find_cmd( VCOS_CMD_T *cmd_entry, const char *name )
{
VCOS_CMD_T *scan_entry = cmd_entry;
while ( scan_entry->name != NULL )
{
if ( vcos_strcmp( scan_entry->name, name ) == 0 )
{
return scan_entry;
}
scan_entry++;
}
return NULL;
}
/*****************************************************************************
*
* Saves away
* each line individually.
*
*****************************************************************************/
void vcos_cmd_always_log_output( VCOS_LOG_CAT_T *log_category )
{
cmd_globals.log_category = log_category;
}
/*****************************************************************************
*
* Walks through a buffer containing newline separated lines, and logs
* each line individually.
*
*****************************************************************************/
static void cmd_log_results( VCOS_CMD_PARAM_T *param )
{
char *start;
char *end;
start = end = param->result_buf;
while ( *start != '\0' )
{
while (( *end != '\0' ) && ( *end != '\n' ))
end++;
if ( *end == '\n' )
{
*end++ = '\0';
}
if ( cmd_globals.log_category != NULL )
{
if ( vcos_is_log_enabled( cmd_globals.log_category, VCOS_LOG_INFO ))
{
vcos_log_impl( cmd_globals.log_category, VCOS_LOG_INFO, "%s", start );
}
}
else
{
vcos_log_info( "%s", start );
}
start = end;
}
/* Since we logged the buffer, reset the pointer back to the beginning. */
param->result_ptr = param->result_buf;
param->result_buf[0] = '\0';
}
/*****************************************************************************
*
* Since we may have limited output space, we create a generic routine
* which tries to use the result space, but will switch over to using
* logging if the output is too large.
*
*****************************************************************************/
void vcos_cmd_vprintf( VCOS_CMD_PARAM_T *param, const char *fmt, va_list args )
{
int bytes_written;
int bytes_remaining;
bytes_remaining = (int)(param->result_size - ( param->result_ptr - param->result_buf ));
bytes_written = vcos_vsnprintf( param->result_ptr, bytes_remaining, fmt, args );
if ( cmd_globals.log_category != NULL )
{
/* We're going to log each line as we encounter it. If the buffer
* doesn't end in a newline, then we'll wait for one first.
*/
if ( (( bytes_written + 1 ) >= bytes_remaining )
|| ( param->result_ptr[ bytes_written - 1 ] == '\n' ))
{
cmd_log_results( param );
}
else
{
param->result_ptr += bytes_written;
}
}
else
{
if (( bytes_written + 1 ) >= bytes_remaining )
{
/* Output doesn't fit - switch over to logging */
param->use_log = 1;
*param->result_ptr = '\0'; /* Zap the partial line that didn't fit above. */
cmd_log_results( param ); /* resets result_ptr */
bytes_written = vcos_vsnprintf( param->result_ptr, bytes_remaining, fmt, args );
}
param->result_ptr += bytes_written;
}
}
/*****************************************************************************
*
* Prints the output.
*
*****************************************************************************/
void vcos_cmd_printf( VCOS_CMD_PARAM_T *param, const char *fmt, ... )
{
va_list args;
va_start( args, fmt );
vcos_cmd_vprintf( param, fmt, args );
va_end( args );
}
/*****************************************************************************
*
* Prints the arguments which were on the command line prior to ours.
*
*****************************************************************************/
static void print_argument_prefix( VCOS_CMD_PARAM_T *param )
{
int arg_idx;
for ( arg_idx = 0; &param->argv_orig[arg_idx] != param->argv; arg_idx++ )
{
vcos_cmd_printf( param, "%s ", param->argv_orig[arg_idx] );
}
}
/*****************************************************************************
*
* Prints an error message, prefixed by the command chain required to get
* to where we're at.
*
*****************************************************************************/
void vcos_cmd_error( VCOS_CMD_PARAM_T *param, const char *fmt, ... )
{
va_list args;
print_argument_prefix( param );
va_start( args, fmt );
vcos_cmd_vprintf( param, fmt, args );
va_end( args );
vcos_cmd_printf( param, "\n" );
}
/****************************************************************************
*
* usage - prints command usage for an array of commands.
*
***************************************************************************/
static void usage( VCOS_CMD_PARAM_T *param, VCOS_CMD_T *cmd_entry )
{
int cmd_idx;
int nameWidth = 0;
int argsWidth = 0;
VCOS_CMD_T *scan_entry;
vcos_cmd_printf( param, "Usage: " );
print_argument_prefix( param );
vcos_cmd_printf( param, "command [args ...]\n" );
vcos_cmd_printf( param, "\n" );
vcos_cmd_printf( param, "Where command is one of the following:\n" );
for ( cmd_idx = 0; cmd_entry[cmd_idx].name != NULL; cmd_idx++ )
{
int aw;
int nw;
scan_entry = &cmd_entry[cmd_idx];
nw = vcos_strlen( scan_entry->name );
aw = vcos_strlen( scan_entry->args );
if ( nw > nameWidth )
{
nameWidth = nw;
}
if ( aw > argsWidth )
{
argsWidth = aw;
}
}
for ( cmd_idx = 0; cmd_entry[cmd_idx].name != NULL; cmd_idx++ )
{
scan_entry = &cmd_entry[cmd_idx];
vcos_cmd_printf( param, " %-*s %-*s - %s\n",
nameWidth, scan_entry->name,
argsWidth, scan_entry->args,
scan_entry->descr );
}
}
/****************************************************************************
*
* Prints the usage for the current command.
*
***************************************************************************/
void vcos_cmd_usage( VCOS_CMD_PARAM_T *param )
{
VCOS_CMD_T *cmd_entry;
cmd_entry = param->cmd_entry;
if ( cmd_entry->sub_cmd_entry != NULL )
{
/* This command is command with sub-commands */
usage( param, param->cmd_entry->sub_cmd_entry );
}
else
{
vcos_cmd_printf( param, "Usage: " );
print_argument_prefix( param );
vcos_cmd_printf( param, "%s %s - %s\n",
param->argv[0],
param->cmd_entry->args,
param->cmd_entry->descr );
}
}
/*****************************************************************************
*
* Command to print out the help
*
* This help command is only called from the main menu.
*
*****************************************************************************/
static VCOS_STATUS_T help_cmd( VCOS_CMD_PARAM_T *param )
{
VCOS_CMD_T *found_entry;
#if 0
{
int arg_idx;
vcos_log_trace( "%s: argc = %d", __func__, param->argc );
for ( arg_idx = 0; arg_idx < param->argc; arg_idx++ )
{
vcos_log_trace( "%s: argv[%d] = '%s'", __func__, arg_idx, param->argv[arg_idx] );
}
}
#endif
/* If there is an argument after the word help, then we want to print
* help for that command.
*/
if ( param->argc == 1 )
{
if ( param->cmd_parent_entry == cmd_globals.cmd_entry )
{
/* Bare help - print the command usage for the root */
usage( param, cmd_globals.cmd_entry );
return VCOS_SUCCESS;
}
/* For all other cases help requires an argument */
vcos_cmd_error( param, "%s requires an argument", param->argv[0] );
return VCOS_EINVAL;
}
/* We were given an argument. */
if (( found_entry = find_cmd( param->cmd_parent_entry, param->argv[1] )) != NULL )
{
/* Make it look like the command that was specified is the one that's
* currently running
*/
param->cmd_entry = found_entry;
param->argv[0] = param->argv[1];
param->argv++;
param->argc--;
vcos_cmd_usage( param );
return VCOS_SUCCESS;
}
vcos_cmd_error( param, "- unrecognized command: '%s'", param->argv[1] );
return VCOS_ENOENT;
}
/*****************************************************************************
*
* Command to print out the version/build information.
*
*****************************************************************************/
#ifdef HAVE_VCOS_VERSION
static VCOS_STATUS_T version_cmd( VCOS_CMD_PARAM_T *param )
{
static const char* copyright = "Copyright (c) 2011 Broadcom";
vcos_cmd_printf( param, "%s %s\n%s\nversion %s\nhost %s",
vcos_get_build_date(),
vcos_get_build_time(),
copyright,
vcos_get_build_version(),
vcos_get_build_hostname() );
return VCOS_SUCCESS;
}
#endif
/*****************************************************************************
*
* Internal commands
*
*****************************************************************************/
static VCOS_CMD_T cmd_help = { "help", "[command]", help_cmd, NULL, "Prints command help information" };
#ifdef HAVE_VCOS_VERSION
static VCOS_CMD_T cmd_version = { "version", "", version_cmd, NULL, "Prints build/version information" };
#endif
/*****************************************************************************
*
* Walks the command table and executes the commands
*
*****************************************************************************/
static VCOS_STATUS_T execute_cmd( VCOS_CMD_PARAM_T *param, VCOS_CMD_T *cmd_entry )
{
const char *cmdStr;
VCOS_CMD_T *found_entry;
#if 0
{
int arg_idx;
vcos_cmd_printf( param, "%s: argc = %d", __func__, param->argc );
for ( arg_idx = 0; arg_idx < param->argc; arg_idx++ )
{
vcos_cmd_printf( param, " argv[%d] = '%s'", arg_idx, param->argv[arg_idx] );
}
vcos_cmd_printf( param, "\n" );
}
#endif
if ( param->argc <= 1 )
{
/* No command specified */
vcos_cmd_error( param, "%s - no command specified", param->argv[0] );
return VCOS_EINVAL;
}
/* argv[0] is the command/program that caused us to get invoked, so we strip
* it off.
*/
param->argc--;
param->argv++;
param->cmd_parent_entry = cmd_entry;
/* Not the help command, scan for the command and execute it. */
cmdStr = param->argv[0];
if (( found_entry = find_cmd( cmd_entry, cmdStr )) != NULL )
{
if ( found_entry->sub_cmd_entry != NULL )
{
return execute_cmd( param, found_entry->sub_cmd_entry );
}
param->cmd_entry = found_entry;
return found_entry->cmd_fn( param );
}
/* Unrecognized command - check to see if it was the help command */
if ( vcos_strcmp( cmdStr, cmd_help.name ) == 0 )
{
return help_cmd( param );
}
vcos_cmd_error( param, "- unrecognized command: '%s'", cmdStr );
return VCOS_ENOENT;
}
/*****************************************************************************
*
* Initializes the command line parser.
*
*****************************************************************************/
static void vcos_cmd_init( void )
{
vcos_mutex_create( &cmd_globals.lock, "vcos_cmd" );
cmd_globals.num_cmd_entries = 0;
cmd_globals.num_cmd_alloc = 0;
cmd_globals.cmd_entry = NULL;
#ifdef HAVE_VCOS_VERSION
vcos_keep_static_strings = vcos_get_build_strings;
#endif
}
/*****************************************************************************
*
* Shuts down the command line parser.
*
*****************************************************************************/
void vcos_cmd_shutdown( void )
{
vcos_mutex_delete( &cmd_globals.lock );
vcos_free( cmd_globals.cmd_entry );
cmd_globals.cmd_entry = NULL;
}
/*****************************************************************************
*
* Command line processor.
*
*****************************************************************************/
VCOS_STATUS_T vcos_cmd_execute( int argc, char **argv, size_t result_size, char *result_buf )
{
VCOS_STATUS_T rc = VCOS_EINVAL;
VCOS_CMD_PARAM_T param;
vcos_once( &cmd_globals.initialized, vcos_cmd_init );
param.argc = argc;
param.argv = param.argv_orig = argv;
param.use_log = 0;
param.result_size = result_size;
param.result_ptr = result_buf;
param.result_buf = result_buf;
result_buf[0] = '\0';
vcos_mutex_lock( &cmd_globals.lock );
rc = execute_cmd( &param, cmd_globals.cmd_entry );
if ( param.use_log )
{
cmd_log_results( &param );
vcos_snprintf( result_buf, result_size, "results logged" );
}
else
if ( cmd_globals.log_category != NULL )
{
if ( result_buf[0] != '\0' )
{
/* There is a partial line still buffered. */
vcos_cmd_printf( &param, "\n" );
}
}
vcos_mutex_unlock( &cmd_globals.lock );
return rc;
}
/*****************************************************************************
*
* Registers a command entry with the command line processor
*
*****************************************************************************/
VCOS_STATUS_T vcos_cmd_register( VCOS_CMD_T *cmd_entry )
{
VCOS_STATUS_T rc;
VCOS_UNSIGNED new_num_cmd_alloc;
VCOS_CMD_T *new_cmd_entry;
VCOS_CMD_T *old_cmd_entry;
VCOS_CMD_T *scan_entry;
vcos_once( &cmd_globals.initialized, vcos_cmd_init );
vcos_assert( cmd_entry != NULL );
vcos_assert( cmd_entry->name != NULL );
vcos_log_trace( "%s: cmd '%s'", __FUNCTION__, cmd_entry->name );
vcos_assert( cmd_entry->args != NULL );
vcos_assert(( cmd_entry->cmd_fn != NULL ) || ( cmd_entry->sub_cmd_entry != NULL ));
vcos_assert( cmd_entry->descr != NULL );
/* We expect vcos_cmd_init to be called before vcos_logging_init, so we
* need to defer registering our logging category until someplace
* like right here.
*/
if ( vcos_cmd_log_category.name == NULL )
{
/*
* If you're using the command interface, you pretty much always want
* log messages from this file to show up. So we change the default
* from ERROR to be the more reasonable INFO level.
*/
vcos_log_set_level(&vcos_cmd_log_category, VCOS_LOG_INFO);
vcos_log_register("vcos_cmd", &vcos_cmd_log_category);
/* We register a help command so that it shows up in the usage. */
vcos_cmd_register( &cmd_help );
#ifdef HAVE_VCOS_VERSION
vcos_cmd_register( &cmd_version );
#endif
}
vcos_mutex_lock( &cmd_globals.lock );
if ( cmd_globals.num_cmd_entries >= cmd_globals.num_cmd_alloc )
{
if ( cmd_globals.num_cmd_alloc == 0 )
{
/* We haven't allocated a table yet */
}
/* The number 8 is rather arbitrary. */
new_num_cmd_alloc = cmd_globals.num_cmd_alloc + 8;
/* The + 1 is to ensure that we always have a NULL entry at the end. */
new_cmd_entry = (VCOS_CMD_T *)vcos_calloc( new_num_cmd_alloc + 1, sizeof( *cmd_entry ), "vcos_cmd_entries" );
if ( new_cmd_entry == NULL )
{
rc = VCOS_ENOMEM;
goto out;
}
memcpy( new_cmd_entry, cmd_globals.cmd_entry, cmd_globals.num_cmd_entries * sizeof( *cmd_entry ));
cmd_globals.num_cmd_alloc = new_num_cmd_alloc;
old_cmd_entry = cmd_globals.cmd_entry;
cmd_globals.cmd_entry = new_cmd_entry;
vcos_free( old_cmd_entry );
}
if ( cmd_globals.num_cmd_entries == 0 )
{
/* This is the first command being registered */
cmd_globals.cmd_entry[0] = *cmd_entry;
}
else
{
/* Keep the list in alphabetical order. We start at the end and work backwards
* shuffling entries up one until we find an insertion point.
*/
for ( scan_entry = &cmd_globals.cmd_entry[cmd_globals.num_cmd_entries - 1];
scan_entry >= cmd_globals.cmd_entry; scan_entry-- )
{
if ( vcos_strcmp( cmd_entry->name, scan_entry->name ) > 0 )
{
/* We found an insertion point. */
break;
}
scan_entry[1] = scan_entry[0];
}
scan_entry[1] = *cmd_entry;
}
cmd_globals.num_cmd_entries++;
rc = VCOS_SUCCESS;
out:
vcos_mutex_unlock( &cmd_globals.lock );
return rc;
}
/*****************************************************************************
*
* Registers multiple commands.
*
*****************************************************************************/
VCOS_STATUS_T vcos_cmd_register_multiple( VCOS_CMD_T *cmd_entry )
{
VCOS_STATUS_T status;
while ( cmd_entry->name != NULL )
{
if (( status = vcos_cmd_register( cmd_entry )) != VCOS_SUCCESS )
{
return status;
}
cmd_entry++;
}
return VCOS_SUCCESS;
}
@@ -0,0 +1,96 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*=============================================================================
VideoCore OS Abstraction Layer - common postamble code
=============================================================================*/
/** \file
*
* Postamble code included by the platform-specific header files
*/
#define VCOS_THREAD_PRI_DEFAULT VCOS_THREAD_PRI_NORMAL
#if !defined(VCOS_THREAD_PRI_INCREASE)
#error Which way to thread priorities go?
#endif
#if VCOS_THREAD_PRI_INCREASE < 0
/* smaller numbers are higher priority */
#define VCOS_THREAD_PRI_LESS(x) ((x)<VCOS_THREAD_PRI_MAX?(x)+1:VCOS_THREAD_PRI_MAX)
#define VCOS_THREAD_PRI_MORE(x) ((x)>VCOS_THREAD_PRI_MIN?(x)-1:VCOS_THREAD_PRI_MIN)
#else
/* bigger numbers are lower priority */
#define VCOS_THREAD_PRI_MORE(x) ((x)<VCOS_THREAD_PRI_MAX?(x)+1:VCOS_THREAD_PRI_MAX)
#define VCOS_THREAD_PRI_LESS(x) ((x)>VCOS_THREAD_PRI_MIN?(x)-1:VCOS_THREAD_PRI_MIN)
#endif
/* Convenience for Brits: */
#define VCOS_APPLICATION_INITIALISE VCOS_APPLICATION_INITIALIZE
/*
* Check for constant definitions
*/
#ifndef VCOS_TICKS_PER_SECOND
#error VCOS_TICKS_PER_SECOND not defined
#endif
#if !defined(VCOS_THREAD_PRI_MIN) || !defined(VCOS_THREAD_PRI_MAX)
#error Priority range not defined
#endif
#if !defined(VCOS_THREAD_PRI_HIGHEST) || !defined(VCOS_THREAD_PRI_LOWEST) || !defined(VCOS_THREAD_PRI_NORMAL)
#error Priority ordering not defined
#endif
#if !defined(VCOS_CAN_SET_STACK_ADDR)
#error Can stack addresses be set on this platform? Please set this macro to either 0 or 1.
#endif
#if (_VCOS_AFFINITY_CPU0|_VCOS_AFFINITY_CPU1) & (~_VCOS_AFFINITY_MASK)
#error _VCOS_AFFINITY_CPUxxx values are not consistent with _VCOS_AFFINITY_MASK
#endif
/** Append to the end of a singly-linked queue, O(1). Works with
* any structure where list has members 'head' and 'tail' and
* item has a 'next' pointer.
*/
#define VCOS_QUEUE_APPEND_TAIL(list, item) {\
(item)->next = NULL;\
if (!(list)->head) {\
(list)->head = (list)->tail = (item); \
} else {\
(list)->tail->next = (item); \
(list)->tail = (item); \
} \
}
#ifndef VCOS_HAVE_TIMER
VCOSPRE_ void VCOSPOST_ vcos_timer_init(void);
#endif
@@ -0,0 +1,36 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
The symbol vcos_deprecated_code may be defined at most once, by the inclusion of "vcos_deprecated.h" in vcos_init.c.
Any other inclusions of this header will cause the linker to warn about multiple definitions of vcos_deprecated_code, for example:
[ldvc] (Warning) "vcos_deprecated_code" is multiply defined in libs/vcos_threadx/vcos_init.c.o and libs/xxxxx/xxxxx.c.o
If you see a build message like this then the configuration you are building is using deprecated code.
Contact the person named in the accompanying comment for advice - do not remove the inclusion.
*/
int vcos_deprecated_code;
@@ -0,0 +1,568 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define VCOS_LOG_CATEGORY (&vcos_blockpool_log)
#include <stddef.h>
#include <string.h>
#include "interface/vcos/vcos.h"
#include "interface/vcos/generic/vcos_generic_blockpool.h"
#define VCOS_BLOCKPOOL_FOURCC(a,b,c,d) ((a) | (b << 8) | (c << 16) | (d << 24))
#define VCOS_BLOCKPOOL_MAGIC VCOS_BLOCKPOOL_FOURCC('v', 'b', 'p', 'l')
#define VCOS_BLOCKPOOL_SUBPOOL_MAGIC VCOS_BLOCKPOOL_FOURCC('v', 's', 'p', 'l')
#define VCOS_BLOCKPOOL_SUBPOOL_FLAG_NONE (0)
#define VCOS_BLOCKPOOL_SUBPOOL_FLAG_OWNS_MEM (1 << 0)
#define VCOS_BLOCKPOOL_SUBPOOL_FLAG_EXTENSION (1 << 1)
/* Uncomment to enable really verbose debug messages */
/* #define VCOS_BLOCKPOOL_DEBUGGING */
/* Whether to overwrite freed blocks with 0xBD */
#ifdef VCOS_BLOCKPOOL_DEBUGGING
#define VCOS_BLOCKPOOL_OVERWRITE_ON_FREE 1
#define VCOS_BLOCKPOOL_DEBUG_MEMSET_MAX_SIZE (UINT32_MAX)
#else
#define VCOS_BLOCKPOOL_OVERWRITE_ON_FREE 0
#define VCOS_BLOCKPOOL_DEBUG_MEMSET_MAX_SIZE (2 * 1024 * 1024)
#endif
#ifdef VCOS_BLOCKPOOL_DEBUGGING
#define VCOS_BLOCKPOOL_ASSERT vcos_demand
#define VCOS_BLOCKPOOL_TRACE_LEVEL VCOS_LOG_TRACE
#define VCOS_BLOCKPOOL_DEBUG_LOG(s, ...) vcos_log_trace("%s: " s, VCOS_FUNCTION, __VA_ARGS__)
#undef VCOS_BLOCKPOOL_OVERWRITE_ON_FREE
#define VCOS_BLOCKPOOL_OVERWRITE_ON_FREE 1
#else
#define VCOS_BLOCKPOOL_ASSERT vcos_demand
#define VCOS_BLOCKPOOL_TRACE_LEVEL VCOS_LOG_ERROR
#define VCOS_BLOCKPOOL_DEBUG_LOG(s, ...)
#endif
#define ASSERT_POOL(p) \
VCOS_BLOCKPOOL_ASSERT((p) && (p)->magic == VCOS_BLOCKPOOL_MAGIC);
#define ASSERT_SUBPOOL(p) \
VCOS_BLOCKPOOL_ASSERT((p) && (p)->magic == VCOS_BLOCKPOOL_SUBPOOL_MAGIC && \
p->start >= p->mem);
#if defined(VCOS_LOGGING_ENABLED)
static VCOS_LOG_CAT_T vcos_blockpool_log =
VCOS_LOG_INIT("vcos_blockpool", VCOS_BLOCKPOOL_TRACE_LEVEL);
#endif
static void vcos_generic_blockpool_subpool_init(
VCOS_BLOCKPOOL_T *pool, VCOS_BLOCKPOOL_SUBPOOL_T *subpool,
void *mem, size_t pool_size, VCOS_UNSIGNED num_blocks, int align,
uint32_t flags)
{
VCOS_BLOCKPOOL_HEADER_T *block;
VCOS_BLOCKPOOL_HEADER_T *end;
vcos_unused(flags);
vcos_log_trace(
"%s: pool %p subpool %p mem %p pool_size %d " \
"num_blocks %d align %d flags %x",
VCOS_FUNCTION,
pool, subpool, mem, (uint32_t) pool_size,
num_blocks, align, flags);
subpool->magic = VCOS_BLOCKPOOL_SUBPOOL_MAGIC;
subpool->mem = mem;
/* The block data pointers must be aligned according to align and the
* block header pre-preceeds the first block data.
* For large alignments there may be wasted space between subpool->mem
* and the first block header.
*/
subpool->start = (char *) subpool->mem + sizeof(VCOS_BLOCKPOOL_HEADER_T);
subpool->start = (void*)
VCOS_BLOCKPOOL_ROUND_UP((unsigned long) subpool->start, align);
subpool->start = (char *) subpool->start - sizeof(VCOS_BLOCKPOOL_HEADER_T);
vcos_assert(subpool->start >= subpool->mem);
vcos_log_trace("%s: mem %p subpool->start %p" \
" pool->block_size %d pool->block_data_size %d",
VCOS_FUNCTION, mem, subpool->start,
(int) pool->block_size, (int) pool->block_data_size);
subpool->num_blocks = num_blocks;
subpool->available_blocks = num_blocks;
subpool->free_list = NULL;
subpool->owner = pool;
/* Initialise to a predictable bit pattern unless the pool is so big
* that the delay would be noticable. */
if (pool_size < VCOS_BLOCKPOOL_DEBUG_MEMSET_MAX_SIZE)
memset(subpool->mem, 0xBC, pool_size); /* For debugging */
block = (VCOS_BLOCKPOOL_HEADER_T*) subpool->start;
end = (VCOS_BLOCKPOOL_HEADER_T*)
((char *) subpool->start + (pool->block_size * num_blocks));
subpool->end = end;
/* Initialise the free list for this subpool */
while (block < end)
{
block->owner.next = subpool->free_list;
subpool->free_list = block;
block = (VCOS_BLOCKPOOL_HEADER_T*)((char*) block + pool->block_size);
}
}
VCOS_STATUS_T vcos_generic_blockpool_init(VCOS_BLOCKPOOL_T *pool,
VCOS_UNSIGNED num_blocks, VCOS_UNSIGNED block_size,
void *start, VCOS_UNSIGNED pool_size, VCOS_UNSIGNED align,
VCOS_UNSIGNED flags, const char *name)
{
VCOS_STATUS_T status = VCOS_SUCCESS;
vcos_unused(name);
vcos_unused(flags);
vcos_log_trace(
"%s: pool %p num_blocks %d block_size %d start %p pool_size %d name %p",
VCOS_FUNCTION, pool, num_blocks, block_size, start, pool_size, name);
vcos_demand(pool);
vcos_demand(start);
vcos_assert((block_size > 0));
vcos_assert(num_blocks > 0);
if (! align)
align = VCOS_BLOCKPOOL_ALIGN_DEFAULT;
if (align & 0x3)
{
vcos_log_error("%s: invalid alignment %d", VCOS_FUNCTION, align);
return VCOS_EINVAL;
}
if (VCOS_BLOCKPOOL_SIZE(num_blocks, block_size, align) > pool_size)
{
vcos_log_error("%s: Pool is too small" \
" num_blocks %d block_size %d align %d"
" pool_size %d required size %d", VCOS_FUNCTION,
num_blocks, block_size, align,
pool_size, (int) VCOS_BLOCKPOOL_SIZE(num_blocks, block_size, align));
return VCOS_ENOMEM;
}
status = vcos_mutex_create(&pool->mutex, "vcos blockpool mutex");
if (status != VCOS_SUCCESS)
return status;
pool->block_data_size = block_size;
/* TODO - create flag that if set forces the header to be in its own cache
* line */
pool->block_size = VCOS_BLOCKPOOL_ROUND_UP(pool->block_data_size +
(align >= 4096 ? 32 : 0) +
sizeof(VCOS_BLOCKPOOL_HEADER_T), align);
pool->magic = VCOS_BLOCKPOOL_MAGIC;
pool->num_subpools = 1;
pool->num_extension_blocks = 0;
pool->align = align;
memset(pool->subpools, 0, sizeof(pool->subpools));
vcos_generic_blockpool_subpool_init(pool, &pool->subpools[0], start,
pool_size, num_blocks, align, VCOS_BLOCKPOOL_SUBPOOL_FLAG_NONE);
return status;
}
VCOS_STATUS_T vcos_generic_blockpool_create_on_heap(VCOS_BLOCKPOOL_T *pool,
VCOS_UNSIGNED num_blocks, VCOS_UNSIGNED block_size, VCOS_UNSIGNED align,
VCOS_UNSIGNED flags, const char *name)
{
VCOS_STATUS_T status = VCOS_SUCCESS;
size_t size = VCOS_BLOCKPOOL_SIZE(num_blocks, block_size, align);
void* mem = vcos_malloc(size, name);
vcos_log_trace("%s: num_blocks %d block_size %d name %s",
VCOS_FUNCTION, num_blocks, block_size, name);
if (! mem)
return VCOS_ENOMEM;
status = vcos_generic_blockpool_init(pool, num_blocks,
block_size, mem, size, align, flags, name);
if (status != VCOS_SUCCESS)
goto fail;
pool->subpools[0].flags |= VCOS_BLOCKPOOL_SUBPOOL_FLAG_OWNS_MEM;
return status;
fail:
free(mem);
return status;
}
VCOS_STATUS_T vcos_generic_blockpool_extend(VCOS_BLOCKPOOL_T *pool,
VCOS_UNSIGNED num_extensions, VCOS_UNSIGNED num_blocks)
{
VCOS_UNSIGNED i;
ASSERT_POOL(pool);
vcos_log_trace("%s: pool %p num_extensions %d num_blocks %d",
VCOS_FUNCTION, pool, num_extensions, num_blocks);
/* Extend may only be called once */
if (pool->num_subpools > 1)
return VCOS_EACCESS;
if (num_extensions < 1 ||
num_extensions > VCOS_BLOCKPOOL_MAX_SUBPOOLS - 1)
return VCOS_EINVAL;
if (num_blocks < 1)
return VCOS_EINVAL;
pool->num_subpools += num_extensions;
pool->num_extension_blocks = num_blocks;
/* Mark these subpools as valid but unallocated */
for (i = 1; i < pool->num_subpools; ++i)
{
pool->subpools[i].magic = VCOS_BLOCKPOOL_SUBPOOL_MAGIC;
pool->subpools[i].start = NULL;
pool->subpools[i].mem = NULL;
}
return VCOS_SUCCESS;
}
void *vcos_generic_blockpool_alloc(VCOS_BLOCKPOOL_T *pool)
{
VCOS_UNSIGNED i;
void* ret = NULL;
VCOS_BLOCKPOOL_SUBPOOL_T *subpool = NULL;
ASSERT_POOL(pool);
vcos_mutex_lock(&pool->mutex);
/* Starting with the main pool try and find a free block */
for (i = 0; i < pool->num_subpools; ++i)
{
if (pool->subpools[i].start && pool->subpools[i].available_blocks > 0)
{
subpool = &pool->subpools[i];
break; /* Found a subpool with free blocks */
}
}
if (! subpool)
{
/* All current subpools are full, try to allocate a new one */
for (i = 1; i < pool->num_subpools; ++i)
{
if (! pool->subpools[i].start)
{
VCOS_BLOCKPOOL_SUBPOOL_T *s = &pool->subpools[i];
size_t size = VCOS_BLOCKPOOL_SIZE(pool->num_extension_blocks,
pool->block_data_size, pool->align);
void *mem = vcos_malloc(size, pool->name);
if (mem)
{
vcos_log_trace("%s: Allocated subpool %d", VCOS_FUNCTION, i);
vcos_generic_blockpool_subpool_init(pool, s, mem, size,
pool->num_extension_blocks,
pool->align,
VCOS_BLOCKPOOL_SUBPOOL_FLAG_OWNS_MEM |
VCOS_BLOCKPOOL_SUBPOOL_FLAG_EXTENSION);
subpool = s;
break; /* Created a subpool */
}
else
{
vcos_log_warn("%s: Failed to allocate subpool", VCOS_FUNCTION);
}
}
}
}
if (subpool)
{
/* Remove from free list */
VCOS_BLOCKPOOL_HEADER_T* nb = subpool->free_list;
vcos_assert(subpool->free_list);
subpool->free_list = nb->owner.next;
/* Owner is pool so free can be called without passing pool
* as a parameter */
nb->owner.subpool = subpool;
ret = nb + 1; /* Return pointer to block data */
--(subpool->available_blocks);
}
vcos_mutex_unlock(&pool->mutex);
VCOS_BLOCKPOOL_DEBUG_LOG("pool %p subpool %p ret %p", pool, subpool, ret);
if (ret)
{
vcos_assert(ret > subpool->start);
vcos_assert(ret < subpool->end);
}
return ret;
}
void *vcos_generic_blockpool_calloc(VCOS_BLOCKPOOL_T *pool)
{
void* ret = vcos_generic_blockpool_alloc(pool);
if (ret)
memset(ret, 0, pool->block_data_size);
return ret;
}
void vcos_generic_blockpool_free(void *block)
{
VCOS_BLOCKPOOL_DEBUG_LOG("block %p", block);
if (block)
{
VCOS_BLOCKPOOL_HEADER_T* hdr = (VCOS_BLOCKPOOL_HEADER_T*) block - 1;
VCOS_BLOCKPOOL_SUBPOOL_T *subpool = hdr->owner.subpool;
VCOS_BLOCKPOOL_T *pool = NULL;
ASSERT_SUBPOOL(subpool);
pool = subpool->owner;
ASSERT_POOL(pool);
vcos_mutex_lock(&pool->mutex);
vcos_assert((unsigned) subpool->available_blocks < subpool->num_blocks);
/* Change ownership of block to be the free list */
hdr->owner.next = subpool->free_list;
subpool->free_list = hdr;
++(subpool->available_blocks);
if (VCOS_BLOCKPOOL_OVERWRITE_ON_FREE)
memset(block, 0xBD, pool->block_data_size); /* For debugging */
if ( (subpool->flags & VCOS_BLOCKPOOL_SUBPOOL_FLAG_EXTENSION) &&
subpool->available_blocks == subpool->num_blocks)
{
VCOS_BLOCKPOOL_DEBUG_LOG("%s: freeing subpool %p mem %p", VCOS_FUNCTION,
subpool, subpool->mem);
/* Free the sub-pool if it was dynamically allocated */
vcos_free(subpool->mem);
subpool->mem = NULL;
subpool->start = NULL;
}
vcos_mutex_unlock(&pool->mutex);
}
}
VCOS_UNSIGNED vcos_generic_blockpool_available_count(VCOS_BLOCKPOOL_T *pool)
{
VCOS_UNSIGNED ret = 0;
VCOS_UNSIGNED i;
ASSERT_POOL(pool);
vcos_mutex_lock(&pool->mutex);
for (i = 0; i < pool->num_subpools; ++i)
{
VCOS_BLOCKPOOL_SUBPOOL_T *subpool = &pool->subpools[i];
ASSERT_SUBPOOL(subpool);
/* Assume the malloc of sub pool would succeed */
if (subpool->start)
ret += subpool->available_blocks;
else
ret += pool->num_extension_blocks;
}
vcos_mutex_unlock(&pool->mutex);
return ret;
}
VCOS_UNSIGNED vcos_generic_blockpool_used_count(VCOS_BLOCKPOOL_T *pool)
{
VCOS_UNSIGNED ret = 0;
VCOS_UNSIGNED i;
ASSERT_POOL(pool);
vcos_mutex_lock(&pool->mutex);
for (i = 0; i < pool->num_subpools; ++i)
{
VCOS_BLOCKPOOL_SUBPOOL_T *subpool = &pool->subpools[i];
ASSERT_SUBPOOL(subpool);
if (subpool->start)
ret += (subpool->num_blocks - subpool->available_blocks);
}
vcos_mutex_unlock(&pool->mutex);
return ret;
}
void vcos_generic_blockpool_delete(VCOS_BLOCKPOOL_T *pool)
{
vcos_log_trace("%s: pool %p", VCOS_FUNCTION, pool);
if (pool)
{
VCOS_UNSIGNED i;
ASSERT_POOL(pool);
for (i = 0; i < pool->num_subpools; ++i)
{
VCOS_BLOCKPOOL_SUBPOOL_T *subpool = &pool->subpools[i];
ASSERT_SUBPOOL(subpool);
if (subpool->mem)
{
/* For debugging */
memset(subpool->mem,
0xBE,
VCOS_BLOCKPOOL_SIZE(subpool->num_blocks,
pool->block_data_size, pool->align));
if (subpool->flags & VCOS_BLOCKPOOL_SUBPOOL_FLAG_OWNS_MEM)
vcos_free(subpool->mem);
subpool->mem = NULL;
subpool->start = NULL;
}
}
vcos_mutex_delete(&pool->mutex);
memset(pool, 0xBE, sizeof(VCOS_BLOCKPOOL_T)); /* For debugging */
}
}
uint32_t vcos_generic_blockpool_elem_to_handle(void *block)
{
uint32_t ret = -1;
uint32_t index = -1;
VCOS_BLOCKPOOL_HEADER_T *hdr = NULL;
VCOS_BLOCKPOOL_T *pool = NULL;
VCOS_BLOCKPOOL_SUBPOOL_T *subpool = NULL;
uint32_t subpool_id;
vcos_assert(block);
hdr = (VCOS_BLOCKPOOL_HEADER_T*) block - 1;
subpool = hdr->owner.subpool;
ASSERT_SUBPOOL(subpool);
pool = subpool->owner;
ASSERT_POOL(pool);
vcos_mutex_lock(&pool->mutex);
/* The handle is the index into the array of blocks combined
* with the subpool id.
*/
index = ((size_t) hdr - (size_t) subpool->start) / pool->block_size;
vcos_assert(index < subpool->num_blocks);
subpool_id = ((char*) subpool - (char*) &pool->subpools[0]) /
sizeof(VCOS_BLOCKPOOL_SUBPOOL_T);
vcos_assert(subpool_id < VCOS_BLOCKPOOL_MAX_SUBPOOLS);
vcos_assert(subpool_id < pool->num_subpools);
ret = VCOS_BLOCKPOOL_HANDLE_CREATE(index, subpool_id);
vcos_log_trace("%s: index %d subpool_id %d handle 0x%08x",
VCOS_FUNCTION, index, subpool_id, ret);
vcos_mutex_unlock(&pool->mutex);
return ret;
}
void *vcos_generic_blockpool_elem_from_handle(
VCOS_BLOCKPOOL_T *pool, uint32_t handle)
{
VCOS_BLOCKPOOL_SUBPOOL_T *subpool;
uint32_t subpool_id;
uint32_t index;
void *ret = NULL;
ASSERT_POOL(pool);
vcos_mutex_lock(&pool->mutex);
subpool_id = VCOS_BLOCKPOOL_HANDLE_GET_SUBPOOL(handle);
if (subpool_id < pool->num_subpools)
{
index = VCOS_BLOCKPOOL_HANDLE_GET_INDEX(handle);
subpool = &pool->subpools[subpool_id];
if (pool->subpools[subpool_id].magic == VCOS_BLOCKPOOL_SUBPOOL_MAGIC &&
pool->subpools[subpool_id].mem && index < subpool->num_blocks)
{
VCOS_BLOCKPOOL_HEADER_T *hdr = (VCOS_BLOCKPOOL_HEADER_T*)
((size_t) subpool->start + (index * pool->block_size));
if (hdr->owner.subpool == subpool) /* Check block is allocated */
ret = hdr + 1;
}
}
vcos_mutex_unlock(&pool->mutex);
vcos_log_trace("%s: pool %p handle 0x%08x elem %p", VCOS_FUNCTION, pool,
handle, ret);
return ret;
}
uint32_t vcos_generic_blockpool_is_valid_elem(
VCOS_BLOCKPOOL_T *pool, const void *block)
{
uint32_t ret = 0;
const char *pool_end;
VCOS_UNSIGNED i = 0;
ASSERT_POOL(pool);
if (((size_t) block) & 0x3)
return 0;
vcos_mutex_lock(&pool->mutex);
for (i = 0; i < pool->num_subpools; ++i)
{
VCOS_BLOCKPOOL_SUBPOOL_T *subpool = &pool->subpools[i];
ASSERT_SUBPOOL(subpool);
if (subpool->mem && subpool->start)
{
pool_end = (const char*)subpool->start +
(subpool->num_blocks * pool->block_size);
if ((const char*)block > (const char*)subpool->start &&
(const char*)block < pool_end)
{
const VCOS_BLOCKPOOL_HEADER_T *hdr = (
const VCOS_BLOCKPOOL_HEADER_T*) block - 1;
/* If the block has a header where the owner points to the pool then
* it's a valid block. */
ret = (hdr->owner.subpool == subpool && subpool->owner == pool);
break;
}
}
}
vcos_mutex_unlock(&pool->mutex);
return ret;
}
@@ -0,0 +1,294 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*=============================================================================
VideoCore OS Abstraction Layer - event flags implemented via a semaphore
=============================================================================*/
#ifndef VCOS_GENERIC_BLOCKPOOL_H
#define VCOS_GENERIC_BLOCKPOOL_H
/**
* \file
*
* This provides a generic, thread safe implementation of a VCOS block pool
* fixed size memory allocator.
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "vcos_types.h"
/** Bits 0 to (VCOS_BLOCKPOOL_SUBPOOL_BITS - 1) are used to store the
* subpool id. */
#define VCOS_BLOCKPOOL_SUBPOOL_BITS 3
#define VCOS_BLOCKPOOL_MAX_SUBPOOLS (1 << VCOS_BLOCKPOOL_SUBPOOL_BITS)
/* Make zero an invalid handle at the cost of decreasing the maximum
* number of blocks (2^28) by 1. Alternatively, a spare bit could be
* used to indicated valid blocks but there are likely to be better
* uses for spare bits. e.g. allowing more subpools
*/
#define INDEX_OFFSET 1
#define VCOS_BLOCKPOOL_HANDLE_GET_INDEX(h) \
(((h) >> VCOS_BLOCKPOOL_SUBPOOL_BITS) - INDEX_OFFSET)
#define VCOS_BLOCKPOOL_HANDLE_GET_SUBPOOL(h) \
((h) & ((1 << VCOS_BLOCKPOOL_SUBPOOL_BITS) - 1))
#define VCOS_BLOCKPOOL_HANDLE_CREATE(i,s) \
((((i) + INDEX_OFFSET) << VCOS_BLOCKPOOL_SUBPOOL_BITS) | (s))
#define VCOS_BLOCKPOOL_INVALID_HANDLE 0
#define VCOS_BLOCKPOOL_ALIGN_DEFAULT sizeof(unsigned long)
#define VCOS_BLOCKPOOL_FLAG_NONE 0
typedef struct VCOS_BLOCKPOOL_HEADER_TAG
{
/* Blocks either refer to to the pool if they are allocated
* or the free list if they are available.
*/
union {
struct VCOS_BLOCKPOOL_HEADER_TAG *next;
struct VCOS_BLOCKPOOL_SUBPOOL_TAG* subpool;
} owner;
} VCOS_BLOCKPOOL_HEADER_T;
typedef struct VCOS_BLOCKPOOL_SUBPOOL_TAG
{
/** VCOS_BLOCKPOOL_SUBPOOL_MAGIC */
uint32_t magic;
VCOS_BLOCKPOOL_HEADER_T* free_list;
/* The start of the pool memory */
void *mem;
/* Address of the first block header */
void *start;
/* The end of the subpool */
void *end;
/** The number of blocks in this sub-pool */
VCOS_UNSIGNED num_blocks;
/** Current number of available blocks in this sub-pool */
VCOS_UNSIGNED available_blocks;
/** Pointers to the pool that owns this sub-pool */
struct VCOS_BLOCKPOOL_TAG* owner;
/** Define properties such as memory ownership */
uint32_t flags;
} VCOS_BLOCKPOOL_SUBPOOL_T;
typedef struct VCOS_BLOCKPOOL_TAG
{
/** VCOS_BLOCKPOOL_MAGIC */
uint32_t magic;
/** Thread safety for Alloc, Free, Delete, Stats */
VCOS_MUTEX_T mutex;
/** Alignment of block data pointers */
VCOS_UNSIGNED align;
/** Flags for future use e.g. cache options */
VCOS_UNSIGNED flags;
/** The size of the block data */
size_t block_data_size;
/** Block size inc overheads */
size_t block_size;
/** Name for debugging */
const char *name;
/* The number of subpools that may be used */
VCOS_UNSIGNED num_subpools;
/** Number of blocks in each dynamically allocated subpool */
VCOS_UNSIGNED num_extension_blocks;
/** Array of subpools. Subpool zero is is not deleted until the pool is
* destroed. If the index of the pool is < num_subpools and
* subpool[index.mem] is null then the subpool entry is valid but
* "not currently allocated" */
VCOS_BLOCKPOOL_SUBPOOL_T subpools[VCOS_BLOCKPOOL_MAX_SUBPOOLS];
} VCOS_BLOCKPOOL_T;
#define VCOS_BLOCKPOOL_ROUND_UP(x,s) (((x) + ((s) - 1)) & ~((s) - 1))
/**
* Calculates the size in bytes required for a block pool containing
* num_blocks of size block_size plus any overheads.
*
* The block pool header (VCOS_BLOCKPOOL_T) is allocated separately
*
* Overheads:
* block_size + header must be rounded up to meet the required alignment
* The start of the first block may need to be up to align bytes
* into the given buffer because statically allocated buffers within structures
* are not guaranteed to be aligned as required.
*/
#define VCOS_BLOCKPOOL_SIZE(num_blocks, block_size, align) \
((VCOS_BLOCKPOOL_ROUND_UP((block_size) + (align >= 4096 ? 32 : 0) + sizeof(VCOS_BLOCKPOOL_HEADER_T), \
(align)) * (num_blocks)) + (align))
/**
* Sanity check to verify whether a handle is potentially a blockpool handle
* when the pool pointer is not available.
*
* If the pool pointer is availabe use vcos_blockpool_elem_to_handle instead.
*
* @param handle the handle to verify
* @param max_blocks the expected maximum number of block in the pool
* that the handle belongs to.
*/
#define VCOS_BLOCKPOOL_IS_VALID_HANDLE_FORMAT(handle, max_blocks) \
((handle) != VCOS_BLOCKPOOL_INVALID_HANDLE \
&& VCOS_BLOCKPOOL_HANDLE_GET_INDEX((handle)) < (max_blocks))
VCOSPRE_
VCOS_STATUS_T VCOSPOST_ vcos_generic_blockpool_init(VCOS_BLOCKPOOL_T *pool,
VCOS_UNSIGNED num_blocks, VCOS_UNSIGNED block_size,
void *start, VCOS_UNSIGNED pool_size,
VCOS_UNSIGNED align, VCOS_UNSIGNED flags,
const char *name);
VCOSPRE_
VCOS_STATUS_T VCOSPOST_ vcos_generic_blockpool_create_on_heap(
VCOS_BLOCKPOOL_T *pool, VCOS_UNSIGNED num_blocks,
VCOS_UNSIGNED block_size,
VCOS_UNSIGNED align, VCOS_UNSIGNED flags,
const char *name);
VCOSPRE_
VCOS_STATUS_T VCOSPOST_ vcos_generic_blockpool_extend(VCOS_BLOCKPOOL_T *pool,
VCOS_UNSIGNED num_extensions, VCOS_UNSIGNED num_blocks);
VCOSPRE_ void VCOSPOST_ *vcos_generic_blockpool_alloc(VCOS_BLOCKPOOL_T *pool);
VCOSPRE_ void VCOSPOST_ *vcos_generic_blockpool_calloc(VCOS_BLOCKPOOL_T *pool);
VCOSPRE_ void VCOSPOST_ vcos_generic_blockpool_free(void *block);
VCOSPRE_
VCOS_UNSIGNED VCOSPOST_ vcos_generic_blockpool_available_count(
VCOS_BLOCKPOOL_T *pool);
VCOSPRE_
VCOS_UNSIGNED VCOSPOST_ vcos_generic_blockpool_used_count(
VCOS_BLOCKPOOL_T *pool);
VCOSPRE_ void VCOSPOST_ vcos_generic_blockpool_delete(VCOS_BLOCKPOOL_T *pool);
VCOSPRE_ uint32_t VCOSPOST_ vcos_generic_blockpool_elem_to_handle(void *block);
VCOSPRE_ void VCOSPOST_
*vcos_generic_blockpool_elem_from_handle(
VCOS_BLOCKPOOL_T *pool, uint32_t handle);
VCOSPRE_ uint32_t VCOSPOST_
vcos_generic_blockpool_is_valid_elem(
VCOS_BLOCKPOOL_T *pool, const void *block);
#if defined(VCOS_INLINE_BODIES)
VCOS_INLINE_IMPL
VCOS_STATUS_T vcos_blockpool_init(VCOS_BLOCKPOOL_T *pool,
VCOS_UNSIGNED num_blocks, VCOS_UNSIGNED block_size,
void *start, VCOS_UNSIGNED pool_size,
VCOS_UNSIGNED align, VCOS_UNSIGNED flags, const char *name)
{
return vcos_generic_blockpool_init(pool, num_blocks, block_size,
start, pool_size, align, flags, name);
}
VCOS_INLINE_IMPL
VCOS_STATUS_T vcos_blockpool_create_on_heap(VCOS_BLOCKPOOL_T *pool,
VCOS_UNSIGNED num_blocks, VCOS_UNSIGNED block_size,
VCOS_UNSIGNED align, VCOS_UNSIGNED flags, const char *name)
{
return vcos_generic_blockpool_create_on_heap(
pool, num_blocks, block_size, align, flags, name);
}
VCOS_INLINE_IMPL
VCOS_STATUS_T VCOSPOST_ vcos_blockpool_extend(VCOS_BLOCKPOOL_T *pool,
VCOS_UNSIGNED num_extensions, VCOS_UNSIGNED num_blocks)
{
return vcos_generic_blockpool_extend(pool, num_extensions, num_blocks);
}
VCOS_INLINE_IMPL
void *vcos_blockpool_alloc(VCOS_BLOCKPOOL_T *pool)
{
return vcos_generic_blockpool_alloc(pool);
}
VCOS_INLINE_IMPL
void *vcos_blockpool_calloc(VCOS_BLOCKPOOL_T *pool)
{
return vcos_generic_blockpool_calloc(pool);
}
VCOS_INLINE_IMPL
void vcos_blockpool_free(void *block)
{
vcos_generic_blockpool_free(block);
}
VCOS_INLINE_IMPL
VCOS_UNSIGNED vcos_blockpool_available_count(VCOS_BLOCKPOOL_T *pool)
{
return vcos_generic_blockpool_available_count(pool);
}
VCOS_INLINE_IMPL
VCOS_UNSIGNED vcos_blockpool_used_count(VCOS_BLOCKPOOL_T *pool)
{
return vcos_generic_blockpool_used_count(pool);
}
VCOS_INLINE_IMPL
void vcos_blockpool_delete(VCOS_BLOCKPOOL_T *pool)
{
vcos_generic_blockpool_delete(pool);
}
VCOS_INLINE_IMPL
uint32_t vcos_blockpool_elem_to_handle(void *block)
{
return vcos_generic_blockpool_elem_to_handle(block);
}
VCOS_INLINE_IMPL
void *vcos_blockpool_elem_from_handle(VCOS_BLOCKPOOL_T *pool, uint32_t handle)
{
return vcos_generic_blockpool_elem_from_handle(pool, handle);
}
VCOS_INLINE_IMPL
uint32_t vcos_blockpool_is_valid_elem(VCOS_BLOCKPOOL_T *pool, const void *block)
{
return vcos_generic_blockpool_is_valid_elem(pool, block);
}
#endif /* VCOS_INLINE_BODIES */
#ifdef __cplusplus
}
#endif
#endif /* VCOS_GENERIC_BLOCKPOOL_H */
@@ -0,0 +1,320 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*=============================================================================
VideoCore OS Abstraction Layer - event flags implemented via mutexes
=============================================================================*/
#include "interface/vcos/vcos.h"
#include "interface/vcos/generic/vcos_generic_event_flags.h"
#include <stddef.h>
/** A structure created by a thread that waits on the event flags
* for a particular combination of flags to arrive.
*/
typedef struct VCOS_EVENT_WAITER_T
{
VCOS_UNSIGNED requested_events; /**< The events wanted */
VCOS_UNSIGNED actual_events; /**< Actual events found */
VCOS_UNSIGNED op; /**< The event operation to be used */
VCOS_STATUS_T return_status; /**< The return status the waiter should pass back */
VCOS_EVENT_FLAGS_T *flags; /**< Pointer to the original 'flags' structure */
VCOS_THREAD_T *thread; /**< Thread waiting */
struct VCOS_EVENT_WAITER_T *next;
} VCOS_EVENT_WAITER_T;
#ifndef NDEBUG
static int waiter_list_valid(VCOS_EVENT_FLAGS_T *flags);
#endif
static void event_flags_timer_expired(void *cxt);
VCOS_STATUS_T vcos_generic_event_flags_create(VCOS_EVENT_FLAGS_T *flags, const char *name)
{
VCOS_STATUS_T rc;
if ((rc=vcos_mutex_create(&flags->lock, name)) != VCOS_SUCCESS)
{
return rc;
}
flags->events = 0;
flags->waiters.head = flags->waiters.tail = 0;
return rc;
}
void vcos_generic_event_flags_set(VCOS_EVENT_FLAGS_T *flags,
VCOS_UNSIGNED bitmask,
VCOS_OPTION op)
{
vcos_assert(flags);
vcos_mutex_lock(&flags->lock);
if (op == VCOS_OR)
{
flags->events |= bitmask;
}
else if (op == VCOS_AND)
{
flags->events &= bitmask;
}
else
{
vcos_assert(0);
}
/* Now wake up any threads that have now become signalled. */
if (flags->waiters.head != NULL)
{
VCOS_UNSIGNED consumed_events = 0;
VCOS_EVENT_WAITER_T **pcurrent_waiter = &flags->waiters.head;
VCOS_EVENT_WAITER_T *prev_waiter = NULL;
/* Walk the chain of tasks suspend on this event flag group to determine
* if any of their requests can be satisfied.
*/
while ((*pcurrent_waiter) != NULL)
{
VCOS_EVENT_WAITER_T *curr_waiter = *pcurrent_waiter;
/* Determine if this request has been satisfied */
/* First, find the event flags in common. */
VCOS_UNSIGNED waiter_satisfied = flags->events & curr_waiter->requested_events;
/* Second, determine if all the event flags must match */
if (curr_waiter->op & VCOS_AND)
{
/* All requested events must be present */
waiter_satisfied = (waiter_satisfied == curr_waiter->requested_events);
}
/* Wake this one up? */
if (waiter_satisfied)
{
if (curr_waiter->op & VCOS_CONSUME)
{
consumed_events |= curr_waiter->requested_events;
}
/* remove this block from the list, taking care at the end */
*pcurrent_waiter = curr_waiter->next;
if (curr_waiter->next == NULL)
flags->waiters.tail = prev_waiter;
vcos_assert(waiter_list_valid(flags));
curr_waiter->return_status = VCOS_SUCCESS;
curr_waiter->actual_events = flags->events;
_vcos_thread_sem_post(curr_waiter->thread);
}
else
{
/* move to next element in the list */
prev_waiter = *pcurrent_waiter;
pcurrent_waiter = &(curr_waiter->next);
}
}
flags->events &= ~consumed_events;
}
vcos_mutex_unlock(&flags->lock);
}
void vcos_generic_event_flags_delete(VCOS_EVENT_FLAGS_T *flags)
{
vcos_mutex_delete(&flags->lock);
}
extern VCOS_STATUS_T vcos_generic_event_flags_get(VCOS_EVENT_FLAGS_T *flags,
VCOS_UNSIGNED bitmask,
VCOS_OPTION op,
VCOS_UNSIGNED suspend,
VCOS_UNSIGNED *retrieved_bits)
{
VCOS_EVENT_WAITER_T waitreq;
VCOS_STATUS_T rc = VCOS_EAGAIN;
int satisfied = 0;
vcos_assert(flags);
/* default retrieved bits to 0 */
*retrieved_bits = 0;
vcos_mutex_lock(&flags->lock);
switch (op & VCOS_EVENT_FLAG_OP_MASK)
{
case VCOS_AND:
if ((flags->events & bitmask) == bitmask)
{
*retrieved_bits = flags->events;
rc = VCOS_SUCCESS;
satisfied = 1;
if (op & VCOS_CONSUME)
flags->events &= ~bitmask;
}
break;
case VCOS_OR:
if (flags->events & bitmask)
{
*retrieved_bits = flags->events;
rc = VCOS_SUCCESS;
satisfied = 1;
if (op & VCOS_CONSUME)
flags->events &= ~bitmask;
}
break;
default:
vcos_assert(0);
rc = VCOS_EINVAL;
break;
}
if (!satisfied && suspend)
{
/* Have to go to sleep.
*
* Append to tail so we get FIFO ordering.
*/
waitreq.requested_events = bitmask;
waitreq.op = op;
waitreq.return_status = VCOS_EAGAIN;
waitreq.flags = flags;
waitreq.actual_events = 0;
waitreq.thread = vcos_thread_current();
waitreq.next = 0;
vcos_assert(waitreq.thread != (VCOS_THREAD_T*)-1);
VCOS_QUEUE_APPEND_TAIL(&flags->waiters, &waitreq);
if (suspend != (VCOS_UNSIGNED)-1)
_vcos_task_timer_set(event_flags_timer_expired, &waitreq, suspend);
vcos_mutex_unlock(&flags->lock);
/* go to sleep and wait to be signalled or timeout */
_vcos_thread_sem_wait();
*retrieved_bits = waitreq.actual_events;
rc = waitreq.return_status;
/* cancel the timer - do not do this while holding the mutex as it
* might be waiting for the timeout function to complete, which will
* try to take the mutex.
*/
if (suspend != (VCOS_UNSIGNED)-1)
_vcos_task_timer_cancel();
}
else
{
vcos_mutex_unlock(&flags->lock);
}
return rc;
}
/** Called when a get call times out. Remove this thread's
* entry from the waiting queue, then resume the thread.
*/
static void event_flags_timer_expired(void *cxt)
{
VCOS_EVENT_WAITER_T *waitreq = (VCOS_EVENT_WAITER_T *)cxt;
VCOS_EVENT_FLAGS_T *flags = waitreq->flags;
VCOS_EVENT_WAITER_T **plist;
VCOS_EVENT_WAITER_T *prev = NULL;
VCOS_THREAD_T *thread = 0;
vcos_assert(flags);
vcos_mutex_lock(&flags->lock);
/* walk the list of waiting threads on this event group, and remove
* the one that has expired.
*
* FIXME: could use doubly-linked list if lots of threads are found
* to be waiting on a single event flag instance.
*/
plist = &flags->waiters.head;
while (*plist != NULL)
{
if (*plist == waitreq)
{
int at_end;
/* found it */
thread = (*plist)->thread;
at_end = ((*plist)->next == NULL);
/* link past */
*plist = (*plist)->next;
if (at_end)
flags->waiters.tail = prev;
break;
}
prev = *plist;
plist = &(*plist)->next;
}
vcos_assert(waiter_list_valid(flags));
vcos_mutex_unlock(&flags->lock);
if (thread)
{
_vcos_thread_sem_post(thread);
}
}
#ifndef NDEBUG
static int waiter_list_valid(VCOS_EVENT_FLAGS_T *flags)
{
int valid;
/* Either both head and tail are NULL, or neither are NULL */
if (flags->waiters.head == NULL)
{
valid = (flags->waiters.tail == NULL);
}
else
{
valid = (flags->waiters.tail != NULL);
}
/* If head and tail point at the same non-NULL element, then there
* is only one element in the list.
*/
if (flags->waiters.head && (flags->waiters.head == flags->waiters.tail))
{
valid = (flags->waiters.head->next == NULL);
}
return valid;
}
#endif
@@ -0,0 +1,127 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*=============================================================================
VideoCore OS Abstraction Layer - event flags implemented via a semaphore
=============================================================================*/
#ifndef VCOS_GENERIC_EVENT_FLAGS_H
#define VCOS_GENERIC_EVENT_FLAGS_H
#ifdef __cplusplus
extern "C" {
#endif
#include "vcos_types.h"
/**
* \file
*
* This provides event flags (as per Nucleus Event Groups) based on a
* mutex, a semaphore (per waiting thread) and a timer (per waiting
* thread).
*
* The data structure is a 32 bit unsigned int (the current set of
* flags) and a linked list of clients waiting to be 'satisfied'.
*
* The mutex merely locks access to the data structure. If a client
* calls vcos_event_flags_get() and the requested bits are not already
* present, it then sleeps on its per-thread semaphore after adding
* this semaphore to the queue waiting. It also sets up a timer.
*
* The per-thread semaphore and timer are actually stored in the
* thread context (joinable thread). In future it may become necessary
* to support non-VCOS threads by using thread local storage to
* create these objects and associate them with the thread.
*/
struct VCOS_EVENT_WAITER_T;
typedef struct VCOS_EVENT_FLAGS_T
{
VCOS_UNSIGNED events; /**< Events currently set */
VCOS_MUTEX_T lock; /**< Serialize access */
struct
{
struct VCOS_EVENT_WAITER_T *head; /**< List of threads waiting */
struct VCOS_EVENT_WAITER_T *tail; /**< List of threads waiting */
} waiters;
} VCOS_EVENT_FLAGS_T;
#define VCOS_OR 1
#define VCOS_AND 2
#define VCOS_CONSUME 4
#define VCOS_OR_CONSUME (VCOS_OR | VCOS_CONSUME)
#define VCOS_AND_CONSUME (VCOS_AND | VCOS_CONSUME)
#define VCOS_EVENT_FLAG_OP_MASK (VCOS_OR|VCOS_AND)
VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_generic_event_flags_create(VCOS_EVENT_FLAGS_T *flags, const char *name);
VCOSPRE_ void VCOSPOST_ vcos_generic_event_flags_set(VCOS_EVENT_FLAGS_T *flags,
VCOS_UNSIGNED events,
VCOS_OPTION op);
VCOSPRE_ void VCOSPOST_ vcos_generic_event_flags_delete(VCOS_EVENT_FLAGS_T *);
VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_generic_event_flags_get(VCOS_EVENT_FLAGS_T *flags,
VCOS_UNSIGNED requested_events,
VCOS_OPTION op,
VCOS_UNSIGNED suspend,
VCOS_UNSIGNED *retrieved_events);
#ifdef VCOS_INLINE_BODIES
VCOS_INLINE_IMPL
VCOS_STATUS_T vcos_event_flags_create(VCOS_EVENT_FLAGS_T *flags, const char *name) {
return vcos_generic_event_flags_create(flags, name);
}
VCOS_INLINE_IMPL
void vcos_event_flags_set(VCOS_EVENT_FLAGS_T *flags,
VCOS_UNSIGNED events,
VCOS_OPTION op) {
vcos_generic_event_flags_set(flags, events, op);
}
VCOS_INLINE_IMPL
void vcos_event_flags_delete(VCOS_EVENT_FLAGS_T *f) {
vcos_generic_event_flags_delete(f);
}
VCOS_INLINE_IMPL
VCOS_STATUS_T vcos_event_flags_get(VCOS_EVENT_FLAGS_T *flags,
VCOS_UNSIGNED requested_events,
VCOS_OPTION op,
VCOS_UNSIGNED suspend,
VCOS_UNSIGNED *retrieved_events) {
return vcos_generic_event_flags_get(flags, requested_events, op, suspend, retrieved_events);
}
#endif /* VCOS_INLINE_BODIES */
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,268 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define VCOS_LOG_CATEGORY (&vcos_named_sem_log_cat)
#include "interface/vcos/vcos.h"
#include "interface/vcos/generic/vcos_generic_named_sem.h"
#include "interface/vcos/vcos_blockpool.h"
#if defined(VCOS_LOGGING_ENABLED)
static VCOS_LOG_CAT_T vcos_named_sem_log_cat =
VCOS_LOG_INIT("vcos_named_sem", VCOS_LOG_ERROR);
#endif
/**
* \file
*
* Named semaphores, primarily for VCFW.
*
* Does not actually work across processes; merely emulate the API.
*
* The client initialises a VCOS_NAMED_SEMAPHORE_T, but this merely
* points at the real underlying VCOS_NAMED_SEMAPHORE_IMPL_T.
*
* semaphore_t ---\
* ----- semaphore_impl_t
* semaphore_t ---/
* /
* semaphore_t -/
*
*/
/* Maintain a block pool of semaphore implementations */
#define NUM_SEMS 16
/* Allow the pool to expand to MAX_SEMS in size */
#define MAX_SEMS 512
/** Each actual real semaphore is stored in one of these. Clients just
* get a structure with a pointer to this in it.
*
* It also contains a doubly linked list tracking the semaphores in-use.
*/
typedef struct VCOS_NAMED_SEMAPHORE_IMPL_T
{
VCOS_SEMAPHORE_T sem; /**< Actual underlying semaphore */
char name[VCOS_NAMED_SEMAPHORE_NAMELEN]; /**< Name of semaphore, copied */
unsigned refs; /**< Reference count */
struct VCOS_NAMED_SEMAPHORE_IMPL_T *next; /**< Next in the in-use list */
struct VCOS_NAMED_SEMAPHORE_IMPL_T *prev; /**< Previous in the in-use list */
} VCOS_NAMED_SEMAPHORE_IMPL_T;
static VCOS_MUTEX_T lock;
static VCOS_NAMED_SEMAPHORE_IMPL_T* sems_in_use = NULL;
static int sems_in_use_count = 0;
static int sems_total_ref_count = 0;
static VCOS_BLOCKPOOL_T sems_pool;
static char pool_mem[VCOS_BLOCKPOOL_SIZE(
NUM_SEMS, sizeof(VCOS_NAMED_SEMAPHORE_IMPL_T), VCOS_BLOCKPOOL_ALIGN_DEFAULT)];
VCOS_STATUS_T _vcos_named_semaphore_init()
{
VCOS_STATUS_T status;
status = vcos_blockpool_init(&sems_pool,
NUM_SEMS, sizeof(VCOS_NAMED_SEMAPHORE_IMPL_T),
pool_mem, sizeof(pool_mem),
VCOS_BLOCKPOOL_ALIGN_DEFAULT, 0, "vcos named semaphores");
if (status != VCOS_SUCCESS)
goto fail_blockpool;
status = vcos_blockpool_extend(&sems_pool, VCOS_BLOCKPOOL_MAX_SUBPOOLS - 1,
(MAX_SEMS - NUM_SEMS) / (VCOS_BLOCKPOOL_MAX_SUBPOOLS - 1));
if (status != VCOS_SUCCESS)
goto fail_extend;
status = vcos_mutex_create(&lock, "vcosnmsem");
if (status != VCOS_SUCCESS)
goto fail_mutex;
return status;
fail_mutex:
fail_extend:
vcos_blockpool_delete(&sems_pool);
fail_blockpool:
return status;
}
void _vcos_named_semaphore_deinit(void)
{
vcos_blockpool_delete(&sems_pool);
vcos_mutex_delete(&lock);
sems_in_use = NULL;
}
VCOS_STATUS_T
vcos_generic_named_semaphore_create(VCOS_NAMED_SEMAPHORE_T *sem,
const char *name, VCOS_UNSIGNED count)
{
VCOS_STATUS_T status = VCOS_ENOSPC;
int name_len, cmp = -1;
VCOS_NAMED_SEMAPHORE_IMPL_T *impl;
VCOS_NAMED_SEMAPHORE_IMPL_T *new_impl;
vcos_log_trace("%s: sem %p name %s count %d", __FUNCTION__,
sem, (name ? name : "null"), count);
vcos_assert(name);
vcos_mutex_lock(&lock);
name_len = vcos_strlen(name);
if (name_len >= VCOS_NAMED_SEMAPHORE_NAMELEN)
{
vcos_assert(0);
status = VCOS_EINVAL;
goto end;
}
/* do we already have this semaphore? */
impl = sems_in_use;
while (impl && (cmp = vcos_strcmp(name, impl->name)) < 0)
impl = impl->next;
if (impl && cmp == 0)
{
/* Semaphore is already in use so just increase the ref count */
impl->refs++;
sems_total_ref_count++;
sem->actual = impl;
sem->sem = &impl->sem;
status = VCOS_SUCCESS;
vcos_log_trace(
"%s: ref count %d name %s total refs %d num sems %d",
__FUNCTION__, impl->refs, impl->name,
sems_total_ref_count, sems_in_use_count);
goto end;
}
/* search for unused semaphore */
new_impl = vcos_blockpool_calloc(&sems_pool);
if (new_impl)
{
status = vcos_semaphore_create(&new_impl->sem, name, count);
if (status == VCOS_SUCCESS)
{
new_impl->refs = 1;
sems_total_ref_count++;
sems_in_use_count++;
memcpy(new_impl->name, name, name_len + 1); /* already checked length! */
sem->actual = new_impl;
sem->sem = &new_impl->sem;
/* Insert into the sorted list
* impl is either NULL or the first element where
* name > impl->name.
*/
if (impl)
{
new_impl->prev = impl->prev;
impl->prev = new_impl;
new_impl->next = impl;
if (new_impl->prev)
new_impl->prev->next = new_impl;
}
else
{
/* Appending to the tail of the list / empty list */
VCOS_NAMED_SEMAPHORE_IMPL_T *tail = sems_in_use;
while(tail && tail->next)
tail = tail->next;
if (tail)
{
tail->next = new_impl;
new_impl->prev = tail;
}
}
if (sems_in_use == impl)
{
/* Inserted at head or list was empty */
sems_in_use = new_impl;
}
vcos_log_trace(
"%s: new ref actual %p prev %p next %p count %d name %s " \
"total refs %d num sems %d",
__FUNCTION__,
new_impl, new_impl->prev, new_impl->next,
new_impl->refs, new_impl->name,
sems_total_ref_count, sems_in_use_count);
}
}
end:
vcos_mutex_unlock(&lock);
if (status != VCOS_SUCCESS)
{
vcos_log_error("%s: failed to create named semaphore name %s status %d " \
"total refs %d num sems %d",
__FUNCTION__, (name ? name : "NULL"), status,
sems_total_ref_count, sems_in_use_count);
}
return status;
}
void vcos_named_semaphore_delete(VCOS_NAMED_SEMAPHORE_T *sem)
{
VCOS_NAMED_SEMAPHORE_IMPL_T *actual = sem->actual;
vcos_mutex_lock(&lock);
/* if this fires, the semaphore has already been deleted */
vcos_assert(actual->refs);
vcos_log_trace(
"%s: actual %p ref count %d name %s prev %p next %p total refs %d num sems %d",
__FUNCTION__, actual, actual->refs, actual->name,
actual->prev, actual->next,
sems_total_ref_count, sems_in_use_count);
sems_total_ref_count--;
if (--actual->refs == 0)
{
sems_in_use_count--;
if (actual->prev)
actual->prev->next = actual->next;
if (actual->next)
actual->next->prev = actual->prev;
if (sems_in_use == actual)
sems_in_use = actual->next;
vcos_semaphore_delete(&actual->sem);
sem->actual = NULL;
sem->sem = NULL;
vcos_blockpool_free(actual);
}
vcos_mutex_unlock(&lock);
}
@@ -0,0 +1,101 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*=============================================================================
VideoCore OS Abstraction Layer - named semaphores
=============================================================================*/
#ifndef VCOS_GENERIC_NAMED_SEM_H
#define VCOS_GENERIC_NAMED_SEM_H
#ifdef __cplusplus
extern "C" {
#endif
#include "vcos_types.h"
/**
* \file
*
* Generic support for named semaphores, using regular ones. This is only
* suitable for emulating them on an embedded MMUless system, since there is
* no support for opening semaphores across process boundaries.
*
*/
#define VCOS_NAMED_SEMAPHORE_NAMELEN 64
/* In theory we could use the name facility provided within Nucleus. However, this
* is hard to do as semaphores are constantly being created and destroyed; we
* would need to stop everything while allocating the memory for the semaphore
* list and then walking it. So keep our own list.
*/
typedef struct VCOS_NAMED_SEMAPHORE_T
{
struct VCOS_NAMED_SEMAPHORE_IMPL_T *actual; /**< There are 'n' named semaphores per 1 actual semaphore */
VCOS_SEMAPHORE_T *sem; /**< Pointer to actual underlying semaphore */
} VCOS_NAMED_SEMAPHORE_T;
VCOSPRE_ VCOS_STATUS_T VCOSPOST_
vcos_generic_named_semaphore_create(VCOS_NAMED_SEMAPHORE_T *sem, const char *name, VCOS_UNSIGNED count);
VCOSPRE_ void VCOSPOST_ vcos_named_semaphore_delete(VCOS_NAMED_SEMAPHORE_T *sem);
VCOSPRE_ VCOS_STATUS_T VCOSPOST_ _vcos_named_semaphore_init(void);
VCOSPRE_ void VCOSPOST_ _vcos_named_semaphore_deinit(void);
#if defined(VCOS_INLINE_BODIES)
VCOS_INLINE_IMPL
VCOS_STATUS_T vcos_named_semaphore_create(VCOS_NAMED_SEMAPHORE_T *sem, const char *name, VCOS_UNSIGNED count) {
return vcos_generic_named_semaphore_create(sem, name, count);
}
VCOS_INLINE_IMPL
void vcos_named_semaphore_wait(VCOS_NAMED_SEMAPHORE_T *sem) {
vcos_semaphore_wait(sem->sem);
}
VCOS_INLINE_IMPL
VCOS_STATUS_T vcos_named_semaphore_trywait(VCOS_NAMED_SEMAPHORE_T *sem) {
return vcos_semaphore_trywait(sem->sem);
}
VCOS_INLINE_IMPL
void vcos_named_semaphore_post(VCOS_NAMED_SEMAPHORE_T *sem) {
vcos_semaphore_post(sem->sem);
}
#endif
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,95 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*=============================================================================
VideoCore OS Abstraction Layer - reentrant mutexes created from regular ones.
=============================================================================*/
#ifndef VCOS_GENERIC_QUICKSLOW_MUTEX_H
#define VCOS_GENERIC_QUICKSLOW_MUTEX_H
#ifdef __cplusplus
extern "C" {
#endif
#include "vcos_types.h"
/**
* \file
*
* Quickslow Mutexes implemented as regular ones (i.e. quick and slow modes are the same).
*
*/
typedef VCOS_MUTEX_T VCOS_QUICKSLOW_MUTEX_T;
#if defined(VCOS_INLINE_BODIES)
VCOS_INLINE_IMPL
VCOS_STATUS_T vcos_quickslow_mutex_create(VCOS_QUICKSLOW_MUTEX_T *m, const char *name)
{
return vcos_mutex_create(m, name);
}
VCOS_INLINE_IMPL
void vcos_quickslow_mutex_delete(VCOS_QUICKSLOW_MUTEX_T *m)
{
vcos_mutex_delete(m);
}
VCOS_INLINE_IMPL
void vcos_quickslow_mutex_lock(VCOS_QUICKSLOW_MUTEX_T *m)
{
while (vcos_mutex_lock(m) == VCOS_EAGAIN);
}
VCOS_INLINE_IMPL
void vcos_quickslow_mutex_unlock(VCOS_QUICKSLOW_MUTEX_T *m)
{
vcos_mutex_unlock(m);
}
VCOS_INLINE_IMPL
void vcos_quickslow_mutex_lock_quick(VCOS_QUICKSLOW_MUTEX_T *m)
{
while (vcos_mutex_lock(m) == VCOS_EAGAIN);
}
VCOS_INLINE_IMPL
void vcos_quickslow_mutex_unlock_quick(VCOS_QUICKSLOW_MUTEX_T *m)
{
vcos_mutex_unlock(m);
}
#endif
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,76 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "interface/vcos/vcos.h"
#include "interface/vcos/vcos_reentrant_mutex.h"
VCOS_STATUS_T vcos_generic_reentrant_mutex_create(VCOS_REENTRANT_MUTEX_T *m, const char *name)
{
m->count = 0;
m->owner = 0;
return vcos_mutex_create(&m->mutex, name);
}
void vcos_generic_reentrant_mutex_delete(VCOS_REENTRANT_MUTEX_T *m)
{
vcos_assert(m->count == 0);
vcos_mutex_delete(&m->mutex);
}
void vcos_generic_reentrant_mutex_lock(VCOS_REENTRANT_MUTEX_T *m)
{
VCOS_THREAD_T *thread = vcos_thread_current();
vcos_assert(m);
vcos_assert(thread != 0);
if (m->owner != thread)
{
vcos_mutex_lock(&m->mutex);
m->owner = thread;
vcos_assert(m->count == 0);
}
m->count++;
}
void vcos_generic_reentrant_mutex_unlock(VCOS_REENTRANT_MUTEX_T *m)
{
vcos_assert(m->count != 0);
vcos_assert(m->owner == vcos_thread_current());
m->count--;
if (m->count == 0)
{
m->owner = 0;
vcos_mutex_unlock(&m->mutex);
}
}
@@ -0,0 +1,95 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*=============================================================================
VideoCore OS Abstraction Layer - reentrant mutexes created from regular ones.
=============================================================================*/
#ifndef VCOS_GENERIC_REENTRANT_MUTEX_H
#define VCOS_GENERIC_REENTRANT_MUTEX_H
#ifdef __cplusplus
extern "C" {
#endif
#include "vcos_types.h"
/**
* \file
*
* Reentrant Mutexes from regular ones.
*
*/
typedef struct VCOS_REENTRANT_MUTEX_T
{
VCOS_MUTEX_T mutex;
VCOS_THREAD_T *owner;
unsigned count;
} VCOS_REENTRANT_MUTEX_T;
/* Extern definitions of functions that do the actual work */
VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_generic_reentrant_mutex_create(VCOS_REENTRANT_MUTEX_T *m, const char *name);
VCOSPRE_ void VCOSPOST_ vcos_generic_reentrant_mutex_delete(VCOS_REENTRANT_MUTEX_T *m);
VCOSPRE_ void VCOSPOST_ vcos_generic_reentrant_mutex_lock(VCOS_REENTRANT_MUTEX_T *m);
VCOSPRE_ void VCOSPOST_ vcos_generic_reentrant_mutex_unlock(VCOS_REENTRANT_MUTEX_T *m);
/* Inline forwarding functions */
#if defined(VCOS_INLINE_BODIES)
VCOS_INLINE_IMPL
VCOS_STATUS_T vcos_reentrant_mutex_create(VCOS_REENTRANT_MUTEX_T *m, const char *name) {
return vcos_generic_reentrant_mutex_create(m,name);
}
VCOS_INLINE_IMPL
void vcos_reentrant_mutex_delete(VCOS_REENTRANT_MUTEX_T *m) {
vcos_generic_reentrant_mutex_delete(m);
}
VCOS_INLINE_IMPL
void vcos_reentrant_mutex_lock(VCOS_REENTRANT_MUTEX_T *m) {
vcos_generic_reentrant_mutex_lock(m);
}
VCOS_INLINE_IMPL
void vcos_reentrant_mutex_unlock(VCOS_REENTRANT_MUTEX_T *m) {
vcos_generic_reentrant_mutex_unlock(m);
}
#endif
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,130 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*****************************************************************************
* Copyright 2012 Broadcom Corporation. All rights reserved.
*
* This program is the proprietary software of Broadcom Corporation and/or
* its licensors, and may only be used, duplicated, modified or distributed
* pursuant to the terms and conditions of a separate, written license
* agreement executed between you and Broadcom (an "Authorized License").
* Except as set forth in an Authorized License, Broadcom grants no license
* (express or implied), right to use, or waiver of any kind with respect to
* the Software, and Broadcom expressly reserves all rights in and to the
* Software and all intellectual property rights therein. IF YOU HAVE NO
* AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS SOFTWARE IN ANY
* WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE ALL USE OF
* THE SOFTWARE.
*
* Except as expressly set forth in the Authorized License,
* 1. This program, including its structure, sequence and organization,
* constitutes the valuable trade secrets of Broadcom, and you shall use
* all reasonable efforts to protect the confidentiality thereof, and to
* use this information only in connection with your use of Broadcom
* integrated circuit products.
* 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
* AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES, REPRESENTATIONS OR
* WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH
* RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY DISCLAIMS ANY AND ALL
* IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS
* FOR A PARTICULAR PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS,
* QUIET ENJOYMENT, QUIET POSSESSION OR CORRESPONDENCE TO DESCRIPTION. YOU
* ASSUME THE ENTIRE RISK ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE.
* 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR ITS
* LICENSORS BE LIABLE FOR (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT,
* OR EXEMPLARY DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
* YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR (ii) ANY AMOUNT IN EXCESS
* OF THE AMOUNT ACTUALLY PAID FOR THE SOFTWARE ITSELF OR U.S. $1, WHICHEVER
* IS GREATER. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
* ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
*****************************************************************************/
#include "interface/vcos/vcos.h"
#if defined( __KERNEL__ )
#include <linux/string.h>
#include <linux/module.h>
#else
#include <string.h>
#endif
#include <stdarg.h>
/** Like vsnprintf, except it places the output at the specified offset.
* Output is truncated to fit in buflen bytes, and is guaranteed to be NUL-terminated.
* Returns the string length before/without truncation.
*/
size_t vcos_safe_vsprintf(char *buf, size_t buflen, size_t offset, const char *fmt, va_list ap)
{
size_t space = (offset < buflen) ? (buflen - offset) : 0;
offset += vcos_vsnprintf(buf ? (buf + offset) : NULL, space, fmt, ap);
return offset;
}
/** Like snprintf, except it places the output at the specified offset.
* Output is truncated to fit in buflen bytes, and is guaranteed to be NUL-terminated.
* Returns the string length before/without truncation.
*/
size_t vcos_safe_sprintf(char *buf, size_t buflen, size_t offset, const char *fmt, ...)
{
size_t space = (offset < buflen) ? (buflen - offset) : 0;
va_list ap;
va_start(ap, fmt);
offset += vcos_vsnprintf(buf ? (buf + offset) : NULL, space, fmt, ap);
va_end(ap);
return offset;
}
/** Copies string src to dst at the specified offset.
* Output is truncated to fit in dstlen bytes, i.e. the string is at most
* (buflen - 1) characters long. Unlike strncpy, exactly one NUL is written
* to dst, which is always NUL-terminated.
* Returns the string length before/without truncation.
*/
size_t vcos_safe_strcpy(char *dst, const char *src, size_t dstlen, size_t offset)
{
if (offset < dstlen)
{
const char *p = src;
char *endp = dst + dstlen -1;
dst += offset;
for (; *p!='\0' && dst != endp; dst++, p++)
*dst = *p;
*dst = '\0';
}
offset += strlen(src);
return offset;
}
@@ -0,0 +1,164 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*=============================================================================
VideoCore OS Abstraction Layer - generic thread local storage
=============================================================================*/
#ifndef VCOS_GENERIC_TLS_H
#define VCOS_GENERIC_TLS_H
#ifdef __cplusplus
extern "C" {
#endif
#include "interface/vcos/vcos_types.h"
/**
* \file
*
* Do an emulation of Thread Local Storage. The platform needs to
* provide a way to set and get a per-thread pointer which is
* where the TLS data itself is stored.
*
*
* Each thread that wants to join in this scheme needs to call
* vcos_tls_thread_register().
*
* The platform needs to support the macros/functions
* _vcos_tls_thread_ptr_set() and _vcos_tls_thread_ptr_get().
*/
#ifndef VCOS_WANT_TLS_EMULATION
#error Should not be included unless TLS emulation is defined
#endif
/** Number of slots to reserve per thread. This results in an overhead
* of this many words per thread.
*/
#define VCOS_TLS_MAX_SLOTS 4
/** TLS key. Allocating one of these reserves the client one of the
* available slots.
*/
typedef VCOS_UNSIGNED VCOS_TLS_KEY_T;
/** TLS per-thread structure. Each thread gets one of these
* if TLS emulation (rather than native TLS support) is
* being used.
*/
typedef struct VCOS_TLS_THREAD_T
{
void *slots[VCOS_TLS_MAX_SLOTS];
} VCOS_TLS_THREAD_T;
/*
* Internal APIs
*/
/** Register this thread's TLS storage area. */
VCOSPRE_ void VCOSPOST_ vcos_tls_thread_register(VCOS_TLS_THREAD_T *);
/** Create a new TLS key */
VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_generic_tls_create(VCOS_TLS_KEY_T *key);
/** Delete a TLS key */
VCOSPRE_ void VCOSPOST_ vcos_generic_tls_delete(VCOS_TLS_KEY_T tls);
/** Initialise the TLS library */
VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_tls_init(void);
/** Deinitialise the TLS library */
VCOSPRE_ void VCOSPOST_ vcos_tls_deinit(void);
#if defined(VCOS_INLINE_BODIES)
#undef VCOS_ASSERT_LOGGING_DISABLE
#define VCOS_ASSERT_LOGGING_DISABLE 1
/*
* Implementations of public API functions
*/
/** Set the given value. Since everything is per-thread, there is no need
* for any locking.
*/
VCOS_INLINE_IMPL
VCOS_STATUS_T vcos_tls_set(VCOS_TLS_KEY_T tls, void *v) {
VCOS_TLS_THREAD_T *tlsdata = _vcos_tls_thread_ptr_get();
vcos_assert(tlsdata); /* Fires if this thread has not been registered */
if (tls<VCOS_TLS_MAX_SLOTS)
{
tlsdata->slots[tls] = v;
return VCOS_SUCCESS;
}
else
{
vcos_assert(0);
return VCOS_EINVAL;
}
}
/** Get the given value. No locking required.
*/
VCOS_INLINE_IMPL
void *vcos_tls_get(VCOS_TLS_KEY_T tls) {
VCOS_TLS_THREAD_T *tlsdata = _vcos_tls_thread_ptr_get();
vcos_assert(tlsdata); /* Fires if this thread has not been registered */
if (tls<VCOS_TLS_MAX_SLOTS)
{
return tlsdata->slots[tls];
}
else
{
vcos_assert(0);
return NULL;
}
}
VCOS_INLINE_IMPL
VCOS_STATUS_T vcos_tls_create(VCOS_TLS_KEY_T *key) {
return vcos_generic_tls_create(key);
}
VCOS_INLINE_IMPL
void vcos_tls_delete(VCOS_TLS_KEY_T tls) {
vcos_generic_tls_delete(tls);
}
#undef VCOS_ASSERT_LOGGING_DISABLE
#define VCOS_ASSERT_LOGGING_DISABLE 0
#endif /* VCOS_INLINE_BODIES */
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,84 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
The following header is included in order to provide one instance of the symbol vcos_deprecated_code.
Any other inclusions of this header (or "vcos_deprecated_code.inc" for assembly language) will cause the linker to warn
about multiple definitions of vcos_deprecated_code.
The idea is to include this header file for the source files which are deprecated.
Therefore the above warnning in a build indicates that the build is using deprecated code!
Contact the person named in the accompanying comment for advice - do not remove the inclusion.
*/
#include "vcos_deprecated.h"
#include "interface/vcos/vcos.h"
static int init_refcount;
VCOS_STATUS_T vcos_init(void)
{
VCOS_STATUS_T st = VCOS_SUCCESS;
vcos_global_lock();
if (init_refcount++ == 0)
st = vcos_platform_init();
vcos_global_unlock();
return st;
}
void vcos_deinit(void)
{
vcos_global_lock();
vcos_assert(init_refcount > 0);
if (init_refcount > 0 && --init_refcount == 0)
vcos_platform_deinit();
vcos_global_unlock();
}
#if defined(__GNUC__) && (__GNUC__ > 2)
void vcos_ctor(void) __attribute__((constructor, used));
void vcos_ctor(void)
{
vcos_init();
}
void vcos_dtor(void) __attribute__((destructor, used));
void vcos_dtor(void)
{
vcos_deinit();
}
#endif
@@ -0,0 +1,229 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*=============================================================================
VideoCore OS Abstraction Layer - implementation: joinable thread from plain
=============================================================================*/
/** \file
*
* Header file for platforms creating the joinable thread from a lowlevel
* thread.
*
* In addition to the actual thread, the following are also created:
*
* - a semaphore to wait on when joining the thread
* - a semaphore to support counted suspend/resume (used by event group)
* - a per-thread timer (used by event group, but could be removed)
*/
#ifndef VCOS_JOINABLE_THREAD_FROM_PLAIN_H
#define VCOS_JOINABLE_THREAD_FROM_PLAIN_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef VCOS_SEMAPHORE_H
#include "interface/vcos/vcos_semaphore.h"
#endif
#ifndef VCOS_LOWLEVEL_THREAD_H
#include "interface/vcos/vcos_lowlevel_thread.h"
#endif
#ifndef VCOS_TIMER_H
#include "interface/vcos/vcos_timer.h"
#endif
#ifdef VCOS_WANT_TLS_EMULATION
#include "interface/vcos/generic/vcos_generic_tls.h"
#endif
#define VCOS_THREAD_MAGIC 0x56436a74
#define VCOS_THREAD_VALID(t) (t->magic == VCOS_THREAD_MAGIC)
#define VCOS_HAVE_THREAD_AT_EXIT 1
/** Thread attribute structure. Clients should not manipulate this directly, but
* should instead use the provided functions.
*/
typedef struct VCOS_THREAD_ATTR_T
{
void *ta_stackaddr;
VCOS_UNSIGNED ta_stacksz;
VCOS_UNSIGNED ta_priority;
VCOS_UNSIGNED ta_affinity;
VCOS_UNSIGNED ta_timeslice;
VCOS_UNSIGNED legacy;
VCOS_UNSIGNED ta_autostart;
} VCOS_THREAD_ATTR_T;
/** Each thread gets a timer, which is for internal VCOS use.
*/
typedef struct _VCOS_THREAD_TIMER_T
{
VCOS_TIMER_T timer;
void (*pfn)(void *);
void *cxt;
} _VCOS_THREAD_TIMER_T;
typedef void (*VCOS_THREAD_EXIT_HANDLER_T)(void *);
/** Called at thread exit.
*/
typedef struct VCOS_THREAD_EXIT_T
{
VCOS_THREAD_EXIT_HANDLER_T pfn;
void *cxt;
} VCOS_THREAD_EXIT_T;
#define VCOS_MAX_EXIT_HANDLERS 8
/* The name field isn't used for anything, so we can just copy the
* the pointer. Nucleus makes its own copy.
*/
typedef const char * VCOS_LLTHREAD_T_NAME;
#define _VCOS_LLTHREAD_NAME(dst,src) (dst)=(src)
/*
* Simulated TLS support
*/
/** Thread structure.
*
* \warning Do not access the members of this structure directly!
*/
typedef struct VCOS_THREAD_T
{
VCOS_LLTHREAD_T thread; /**< The underlying thread */
char name[16]; /**< The name */
unsigned int magic; /**< For debug */
void *exit_data; /**< Exit data passed out in vcos_joinable_thread_exit() */
void *stack; /**< Stack, if not supplied by caller */
VCOS_SEMAPHORE_T wait; /**< Semaphore to wait on at join */
VCOS_SEMAPHORE_T suspend; /**< Semaphore to wait on for counted suspend */
int16_t joined; /**< Joined yet? For debug. */
VCOS_UNSIGNED legacy; /**< Use (argc,argv) for entry point arguments */
void *(*entry)(void*); /**< Entry point */
void *arg; /**< Argument passed to entry point */
void *(*term)(void*); /**< Termination function, used by reaper */
void *term_arg; /**< Argument passed to termination function */
_VCOS_THREAD_TIMER_T _timer; /**< Internal timer, mainly for event groups */
#ifdef VCOS_WANT_TLS_EMULATION
VCOS_TLS_THREAD_T _tls; /**< TLS data when native TLS not available, or NULL */
#endif
/** Array of functions to call at thread exit */
VCOS_THREAD_EXIT_T at_exit[VCOS_MAX_EXIT_HANDLERS];
struct VCOS_THREAD_T *next; /**< For linked lists of threads */
} VCOS_THREAD_T;
#if defined(VCOS_INLINE_BODIES)
VCOS_INLINE_IMPL
void vcos_thread_attr_setstack(VCOS_THREAD_ATTR_T *attrs, void *addr, VCOS_UNSIGNED stacksz) {
attrs->ta_stackaddr = addr;
attrs->ta_stacksz = stacksz;
}
VCOS_INLINE_IMPL
void vcos_thread_attr_setstacksize(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED stacksz) {
attrs->ta_stacksz = stacksz;
}
VCOS_INLINE_IMPL
void vcos_thread_attr_setpriority(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED pri) {
attrs->ta_priority = pri;
}
VCOS_INLINE_IMPL
void vcos_thread_attr_setaffinity(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED affinity) {
attrs->ta_affinity = affinity;
}
VCOS_INLINE_IMPL
void vcos_thread_attr_settimeslice(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED ts) {
attrs->ta_timeslice = ts;
}
VCOS_INLINE_IMPL
void _vcos_thread_attr_setlegacyapi(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED legacy) {
attrs->legacy = legacy;
}
VCOS_INLINE_IMPL
void vcos_thread_attr_setautostart(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED autostart) {
attrs->ta_autostart = autostart;
}
VCOS_INLINE_IMPL
VCOS_THREAD_T *vcos_thread_current(void) {
VCOS_THREAD_T *ret = (VCOS_THREAD_T*)vcos_llthread_current();
/*If we're called from a non-vcos thread, this assert will fail.
*XXX FIXME why is this commented out?
*vcos_assert(ret->magic == VCOS_THREAD_MAGIC);
*/
return ret;
}
VCOS_INLINE_IMPL
int vcos_thread_running(VCOS_THREAD_T *thread) {
return vcos_llthread_running(&thread->thread);
}
VCOS_INLINE_IMPL
void vcos_thread_resume(VCOS_THREAD_T *thread) {
vcos_llthread_resume(&thread->thread);
}
#endif /* VCOS_INLINE_BODIES */
/**
* \brief Create a VCOS_THREAD_T for the current thread. This is so we can have
* VCOS_THREAD_Ts even for threads not originally created by VCOS (eg the
* thread that calls vcos_init)
*/
extern VCOS_STATUS_T _vcos_thread_create_attach(VCOS_THREAD_T *thread,
const char *name);
/**
* \brief Deletes the VCOS_THREAD_T, but does not wait for the underlying
* thread to exit. This will cleanup everything created by
* _vcos_thread_create_attach
*/
extern void _vcos_thread_delete(VCOS_THREAD_T *thread);
/** Register a function to be called when the current thread exits.
*/
extern VCOS_STATUS_T vcos_thread_at_exit(void (*pfn)(void*), void *cxt);
/** Deregister a previously registered at-exit function.
*/
extern void vcos_thread_deregister_at_exit(void (*pfn)(void*), void *cxt);
#ifdef __cplusplus
}
#endif
#endif /* VCOS_JOINABLE_THREAD_FROM_PLAIN_H */
@@ -0,0 +1,68 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*=============================================================================
VideoCore OS Abstraction Layer - Construct a latch from a semaphore
=============================================================================*/
/** FIXME: rename to vcos_mutex_from_sem.c
*/
typedef struct VCOS_MUTEX_T {
VCOS_SEMAPHORE_T sem;
struct VCOS_THREAD_T *owner;
} VCOS_MUTEX_T;
extern VCOS_STATUS_T vcos_generic_mutex_create(VCOS_MUTEX_T *latch, const char *name);
extern void vcos_generic_mutex_delete(VCOS_MUTEX_T *latch);
extern VCOS_STATUS_T vcos_generic_mutex_lock(VCOS_MUTEX_T *latch);
extern void vcos_generic_mutex_unlock(VCOS_MUTEX_T *latch);
#if defined(VCOS_INLINE_BODIES)
VCOS_INLINE_IMPL
VCOS_STATUS_T vcos_mutex_create(VCOS_MUTEX_T *latch, const char *name) {
return vcos_generic_mutex_create(latch,name);
}
VCOS_INLINE_IMPL
void vcos_mutex_delete(VCOS_MUTEX_T *latch) {
vcos_generic_mutex_delete(latch);
}
VCOS_INLINE_IMPL
VCOS_STATUS_T vcos_mutex_lock(VCOS_MUTEX_T *latch) {
return vcos_generic_mutex_lock(latch);
}
VCOS_INLINE_IMPL
void vcos_mutex_unlock(VCOS_MUTEX_T *latch) {
vcos_generic_mutex_unlock(latch);
}
#endif /* VCOS_INLINE_BODIES */
@@ -0,0 +1,587 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*=============================================================================
Categorized logging for VCOS - a generic implementation.
=============================================================================*/
#include "interface/vcos/vcos.h"
#include "interface/vcos/vcos_ctype.h"
#include "interface/vcos/vcos_string.h"
#include "interface/vcos/vcos_inttypes.h"
static VCOS_MUTEX_T lock;
static int warned_loglevel; /* only warn about invalid log level once */
static VCOS_VLOG_IMPL_FUNC_T vcos_vlog_impl_func = vcos_vlog_default_impl;
#define VCOS_LOG_CATEGORY (&dflt_log_category)
static VCOS_LOG_CAT_T dflt_log_category;
VCOS_LOG_CAT_T *vcos_logging_categories = NULL;
static int inited;
#if VCOS_HAVE_CMD
/*
* For kernel or videocore purposes, we generally want the log command. For
* user-space apps, they might want to provide their own log command, so we
* don't include the built in on.
*
* So pthreads/vcos_platform.h defines VCOS_WANT_LOG_CMD to be 0. It is
* undefined elsewhere.
*/
# if !defined( VCOS_WANT_LOG_CMD )
# define VCOS_WANT_LOG_CMD 1
# endif
#else
# define VCOS_WANT_LOG_CMD 0
#endif
/* For now, do not link logging categories into linked lists
* as it breaks when people unload shared libraries without
* getting the counts right.
*/
#ifdef __VIDEOCORE__
#define REGISTER_CATEGORIES 1
#else
#define REGISTER_CATEGORIES 0
#endif
#if VCOS_WANT_LOG_CMD
/*****************************************************************************
*
* Does a vcos_assert(0), which is useful to test logging.
*
*****************************************************************************/
VCOS_STATUS_T vcos_log_assert_cmd( VCOS_CMD_PARAM_T *param )
{
(void)param;
#if defined( NDEBUG ) && !defined( VCOS_RELEASE_ASSERTS )
vcos_log_error( "vcos_asserts have been compiled out" );
vcos_cmd_printf( param, "vcos_asserts have been compiled out - did a vcos_log_error instead\n" );
#else
vcos_assert(0);
vcos_cmd_printf( param, "Executed vcos_assert(0)\n" );
#endif
return VCOS_SUCCESS;
}
/*****************************************************************************
*
* Sets a vcos logging level
*
*****************************************************************************/
VCOS_STATUS_T vcos_log_set_cmd( VCOS_CMD_PARAM_T *param )
{
VCOS_LOG_CAT_T *cat;
char *name;
char *levelStr;
VCOS_LOG_LEVEL_T level;
VCOS_STATUS_T status;
if ( param->argc != 3 )
{
vcos_cmd_usage( param );
return VCOS_EINVAL;
}
name = param->argv[1];
levelStr = param->argv[2];
if ( vcos_string_to_log_level( levelStr, &level ) != VCOS_SUCCESS )
{
vcos_cmd_printf( param, "Unrecognized logging level: '%s'\n", levelStr );
return VCOS_EINVAL;
}
vcos_mutex_lock(&lock);
status = VCOS_SUCCESS;
for ( cat = vcos_logging_categories; cat != NULL; cat = cat->next )
{
if ( vcos_strcmp( name, cat->name ) == 0 )
{
cat->level = level;
vcos_cmd_printf( param, "Category %s level set to %s\n", name, levelStr );
break;
}
}
if ( cat == NULL )
{
vcos_cmd_printf( param, "Unrecognized category: '%s'\n", name );
status = VCOS_ENOENT;
}
vcos_mutex_unlock(&lock);
return status;
}
/*****************************************************************************
*
* Prints out the current settings for a given category (or all cvategories)
*
*****************************************************************************/
VCOS_STATUS_T vcos_log_status_cmd( VCOS_CMD_PARAM_T *param )
{
VCOS_LOG_CAT_T *cat;
VCOS_STATUS_T status;
vcos_mutex_lock(&lock);
if ( param->argc == 1)
{
int nw;
int nameWidth = 0;
/* Print information about all of the categories. */
for ( cat = vcos_logging_categories; cat != NULL; cat = cat->next )
{
nw = (int)strlen( cat->name );
if ( nw > nameWidth )
{
nameWidth = nw;
}
}
for ( cat = vcos_logging_categories; cat != NULL; cat = cat->next )
{
vcos_cmd_printf( param, "%-*s - %s\n", nameWidth, cat->name, vcos_log_level_to_string( cat->level ));
}
}
else
{
/* Print information about a particular category */
for ( cat = vcos_logging_categories; cat != NULL; cat = cat->next )
{
if ( vcos_strcmp( cat->name, param->argv[1] ) == 0 )
{
vcos_cmd_printf( param, "%s - %s\n", cat->name, vcos_log_level_to_string( cat->level ));
break;
}
}
if ( cat == NULL )
{
vcos_cmd_printf( param, "Unrecognized logging category: '%s'\n", param->argv[1] );
status = VCOS_ENOENT;
goto out;
}
}
status = VCOS_SUCCESS;
out:
vcos_mutex_unlock(&lock);
return status;
}
/*****************************************************************************
*
* Prints out the current settings for a given category (or all cvategories)
*
*****************************************************************************/
VCOS_STATUS_T vcos_log_test_cmd( VCOS_CMD_PARAM_T *param )
{
if ( param->argc == 1 )
{
static int seq_num = 100;
/* No additional arguments - generate a message with an incrementing number */
vcos_log_error( "Test message %d", seq_num );
seq_num++;
vcos_cmd_printf( param, "Logged 'Test message %d'\n", seq_num );
}
else
{
int arg_idx;
/* Arguments supplied - log these */
for ( arg_idx = 0; arg_idx < param->argc; arg_idx++ )
{
vcos_log_error( "argv[%d] = '%s'", arg_idx, param->argv[arg_idx] );
}
vcos_cmd_printf( param, "Logged %d line(s) of test data\n", param->argc );
}
return VCOS_SUCCESS;
}
/*****************************************************************************
*
* Internal commands
*
*****************************************************************************/
static VCOS_CMD_T log_cmd_entry[] =
{
{ "assert", "", vcos_log_assert_cmd, NULL, "Does a vcos_assert(0) to test logging" },
{ "set", "category level", vcos_log_set_cmd, NULL, "Sets the vcos logging level for a category" },
{ "status", "[category]", vcos_log_status_cmd, NULL, "Prints the vcos log status for a (or all) categories" },
{ "test", "[arbitrary text]", vcos_log_test_cmd, NULL, "Does a vcos_log to test logging" },
{ NULL, NULL, NULL, NULL, NULL }
};
static VCOS_CMD_T cmd_log =
{ "log", "command [args]", NULL, log_cmd_entry, "Commands related to vcos logging" };
#endif
void vcos_logging_init(void)
{
if (inited)
{
/* FIXME: should print a warning or something here */
return;
}
vcos_mutex_create(&lock, "vcos_log");
vcos_log_platform_init();
vcos_log_register("default", &dflt_log_category);
#if VCOS_WANT_LOG_CMD
vcos_cmd_register( &cmd_log );
#endif
vcos_assert(!inited);
inited = 1;
}
/** Read an alphanumeric token, returning True if we succeeded.
*/
static int read_tok(char *tok, size_t toklen, const char **pstr, char sep)
{
const char *str = *pstr;
size_t n = 0;
char ch;
/* skip past any whitespace */
while (str[0] && isspace((int)(str[0])))
str++;
while ((ch = *str) != '\0' &&
ch != sep &&
(isalnum((int)ch) || (ch == '_')) &&
n != toklen-1)
{
tok[n++] = ch;
str++;
}
/* did it work out? */
if (ch == '\0' || ch == sep)
{
if (ch) str++; /* move to next token if not at end */
/* yes */
tok[n] = '\0';
*pstr = str;
return 1;
}
else
{
/* no */
return 0;
}
}
const char *vcos_log_level_to_string( VCOS_LOG_LEVEL_T level )
{
switch (level)
{
case VCOS_LOG_UNINITIALIZED: return "uninit";
case VCOS_LOG_NEVER: return "never";
case VCOS_LOG_ERROR: return "error";
case VCOS_LOG_WARN: return "warn";
case VCOS_LOG_INFO: return "info";
case VCOS_LOG_TRACE: return "trace";
}
return "???";
}
VCOS_STATUS_T vcos_string_to_log_level( const char *str, VCOS_LOG_LEVEL_T *level )
{
if (strcmp(str,"error") == 0)
*level = VCOS_LOG_ERROR;
else if (strcmp(str,"never") == 0)
*level = VCOS_LOG_NEVER;
else if (strcmp(str,"warn") == 0)
*level = VCOS_LOG_WARN;
else if (strcmp(str,"warning") == 0)
*level = VCOS_LOG_WARN;
else if (strcmp(str,"info") == 0)
*level = VCOS_LOG_INFO;
else if (strcmp(str,"trace") == 0)
*level = VCOS_LOG_TRACE;
else
return VCOS_EINVAL;
return VCOS_SUCCESS;
}
static int read_level(VCOS_LOG_LEVEL_T *level, const char **pstr, char sep)
{
char buf[16];
int ret = 1;
if (read_tok(buf,sizeof(buf),pstr,sep))
{
if (vcos_string_to_log_level(buf,level) != VCOS_SUCCESS)
{
vcos_log("Invalid trace level '%s'\n", buf);
ret = 0;
}
}
else
{
ret = 0;
}
return ret;
}
void vcos_log_register(const char *name, VCOS_LOG_CAT_T *category)
{
const char *env;
VCOS_LOG_CAT_T *i;
category->name = name;
if ( category->level == VCOS_LOG_UNINITIALIZED )
{
category->level = VCOS_LOG_ERROR;
}
category->flags.want_prefix = (category != &dflt_log_category );
if (!REGISTER_CATEGORIES)
return;
vcos_mutex_lock(&lock);
/* is it already registered? */
for (i = vcos_logging_categories; i ; i = i->next )
{
if (i == category)
{
i->refcount++;
break;
}
}
if (!i)
{
/* not yet registered */
category->next = vcos_logging_categories;
vcos_logging_categories = category;
category->refcount++;
vcos_log_platform_register(category);
}
vcos_mutex_unlock(&lock);
/* Check to see if this log level has been enabled. Look for
* (<category:level>,)*
*
* VC_LOGLEVEL=ilcs:info,vchiq:warn
*/
env = _VCOS_LOG_LEVEL();
if (env)
{
do
{
char env_name[64];
VCOS_LOG_LEVEL_T level;
if (read_tok(env_name, sizeof(env_name), &env, ':') &&
read_level(&level, &env, ','))
{
if (strcmp(env_name, name) == 0)
{
category->level = level;
break;
}
}
else
{
if (!warned_loglevel)
{
vcos_log("VC_LOGLEVEL format invalid at %s\n", env);
warned_loglevel = 1;
}
return;
}
} while (env[0] != '\0');
}
vcos_log_info( "Registered log category '%s' with level %s",
category->name,
vcos_log_level_to_string( category->level ));
}
void vcos_log_unregister(VCOS_LOG_CAT_T *category)
{
VCOS_LOG_CAT_T **pcat;
if (!REGISTER_CATEGORIES)
return;
vcos_mutex_lock(&lock);
category->refcount--;
if (category->refcount == 0)
{
pcat = &vcos_logging_categories;
while (*pcat != category)
{
if (!*pcat)
break; /* possibly deregistered twice? */
if ((*pcat)->next == NULL)
{
vcos_assert(0); /* already removed! */
vcos_mutex_unlock(&lock);
return;
}
pcat = &(*pcat)->next;
}
if (*pcat)
*pcat = category->next;
vcos_log_platform_unregister(category);
}
vcos_mutex_unlock(&lock);
}
VCOSPRE_ const VCOS_LOG_CAT_T * VCOSPOST_ vcos_log_get_default_category(void)
{
return &dflt_log_category;
}
void vcos_set_log_options(const char *opt)
{
(void)opt;
}
void vcos_log_dump_mem_impl( const VCOS_LOG_CAT_T *cat,
const char *label,
uint32_t addr,
const void *voidMem,
size_t numBytes )
{
const uint8_t *mem = (const uint8_t *)voidMem;
size_t offset;
char lineBuf[ 100 ];
char *s;
while ( numBytes > 0 )
{
s = lineBuf;
for ( offset = 0; offset < 16; offset++ )
{
if ( offset < numBytes )
{
s += vcos_snprintf( s, 4, "%02x ", mem[ offset ]);
}
else
{
s += vcos_snprintf( s, 4, " " );
}
}
for ( offset = 0; offset < 16; offset++ )
{
if ( offset < numBytes )
{
uint8_t ch = mem[ offset ];
if (( ch < ' ' ) || ( ch > '~' ))
{
ch = '.';
}
*s++ = (char)ch;
}
}
*s++ = '\0';
if (( label != NULL ) && ( *label != '\0' ))
{
vcos_log_impl( cat, VCOS_LOG_INFO, "%s: %08" PRIx32 ": %s", label, addr, lineBuf );
}
else
{
vcos_log_impl( cat, VCOS_LOG_INFO, "%08" PRIx32 ": %s", addr, lineBuf );
}
addr += 16;
mem += 16;
if ( numBytes > 16 )
{
numBytes -= 16;
}
else
{
numBytes = 0;
}
}
}
void vcos_log_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, ...)
{
va_list ap;
va_start(ap,fmt);
vcos_vlog_impl( cat, _level, fmt, ap );
va_end(ap);
}
void vcos_vlog_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, va_list args)
{
vcos_vlog_impl_func( cat, _level, fmt, args );
}
void vcos_set_vlog_impl( VCOS_VLOG_IMPL_FUNC_T vlog_impl_func )
{
if ( vlog_impl_func == NULL )
{
vcos_vlog_impl_func = vcos_vlog_default_impl;
}
else
{
vcos_vlog_impl_func = vlog_impl_func;
}
}
@@ -0,0 +1,98 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*=============================================================================
VideoCore OS Abstraction Layer - memory alloc implementation
=============================================================================*/
#include "interface/vcos/vcos.h"
#ifndef _vcos_platform_malloc
#include <stdlib.h>
#define _vcos_platform_malloc malloc
#define _vcos_platform_free free
#endif
typedef struct malloc_header_s {
uint32_t guardword;
uint32_t size;
const char *description;
void *ptr;
} MALLOC_HEADER_T;
#define MIN_ALIGN sizeof(MALLOC_HEADER_T)
#define GUARDWORDHEAP 0xa55a5aa5
void *vcos_generic_mem_alloc_aligned(VCOS_UNSIGNED size, VCOS_UNSIGNED align, const char *desc)
{
int local_align = align == 0 ? 1 : align;
int required_size = size + local_align + sizeof(MALLOC_HEADER_T);
void *ptr = _vcos_platform_malloc(required_size);
void *ret = NULL;
MALLOC_HEADER_T *h;
if (ptr)
{
ret = (void *)VCOS_ALIGN_UP(((char *)ptr)+sizeof(MALLOC_HEADER_T), local_align);
h = ((MALLOC_HEADER_T *)ret)-1;
h->size = size;
h->description = desc;
h->guardword = GUARDWORDHEAP;
h->ptr = ptr;
}
return ret;
}
void *vcos_generic_mem_alloc(VCOS_UNSIGNED size, const char *desc)
{
return vcos_generic_mem_alloc_aligned(size,MIN_ALIGN,desc);
}
void *vcos_generic_mem_calloc(VCOS_UNSIGNED count, VCOS_UNSIGNED sz, const char *desc)
{
uint32_t size = count*sz;
void *ptr = vcos_generic_mem_alloc_aligned(size,MIN_ALIGN,desc);
if (ptr)
{
memset(ptr, 0, size);
}
return ptr;
}
void vcos_generic_mem_free(void *ptr)
{
MALLOC_HEADER_T *h;
if (! ptr) return;
h = ((MALLOC_HEADER_T *)ptr)-1;
vcos_assert(h->guardword == GUARDWORDHEAP);
_vcos_platform_free(h->ptr);
}
@@ -0,0 +1,74 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*=============================================================================
Create the vcos_malloc API from the regular system malloc/free
=============================================================================*/
/**
* \file
*
* Create the vcos malloc API from a regular system malloc/free library.
*
* The API lets callers specify an alignment.
*
* Under VideoCore this is not needed, as we can simply use the rtos_malloc routines.
* But on host platforms that won't be the case.
*
*/
VCOSPRE_ void * VCOSPOST_ vcos_generic_mem_alloc(VCOS_UNSIGNED sz, const char *desc);
VCOSPRE_ void * VCOSPOST_ vcos_generic_mem_calloc(VCOS_UNSIGNED count, VCOS_UNSIGNED sz, const char *descr);
VCOSPRE_ void VCOSPOST_ vcos_generic_mem_free(void *ptr);
VCOSPRE_ void * VCOSPOST_ vcos_generic_mem_alloc_aligned(VCOS_UNSIGNED sz, VCOS_UNSIGNED align, const char *desc);
#ifdef VCOS_INLINE_BODIES
VCOS_INLINE_IMPL
void *vcos_malloc(VCOS_UNSIGNED size, const char *description) {
return vcos_generic_mem_alloc(size, description);
}
VCOS_INLINE_IMPL
void *vcos_calloc(VCOS_UNSIGNED num, VCOS_UNSIGNED size, const char *description) {
return vcos_generic_mem_calloc(num, size, description);
}
VCOS_INLINE_IMPL
void vcos_free(void *ptr) {
vcos_generic_mem_free(ptr);
}
VCOS_INLINE_IMPL
void * vcos_malloc_aligned(VCOS_UNSIGNED size, VCOS_UNSIGNED align, const char *description) {
return vcos_generic_mem_alloc_aligned(size, align, description);
}
#endif /* VCOS_INLINE_BODIES */
@@ -0,0 +1,389 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "vcos.h"
#include "vcos_msgqueue.h"
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#define MAGIC VCOS_MSGQ_MAGIC
/* Probably a good idea for MSG_T to be multiple of 8 so that doubles
* are naturally aligned without problem.
*/
vcos_static_assert((sizeof(VCOS_MSG_T) & 7) == 0);
static void vcos_msgq_pool_on_reply(VCOS_MSG_WAITER_T *waiter,
VCOS_MSG_T *msg);
static void vcos_msgq_queue_waiter_on_reply(VCOS_MSG_WAITER_T *waiter,
VCOS_MSG_T *msg);
/** Simple reply protocol. The client creates a semaphore and waits
* for it. No queuing of multiple replies is possible but nothing needs
* to be setup in advance. Because creating semaphores is very fast on
* VideoCore there's no need to do anything elaborate to optimize create
* time - this might need revisiting on other platforms.
*/
typedef struct
{
VCOS_MSG_WAITER_T waiter;
VCOS_SEMAPHORE_T waitsem;
} VCOS_MSG_SIMPLE_WAITER_T;
static void vcos_msgq_simple_waiter_on_reply(VCOS_MSG_WAITER_T *waiter,
VCOS_MSG_T *msg)
{
VCOS_MSG_SIMPLE_WAITER_T *self;
(void)msg;
self = (VCOS_MSG_SIMPLE_WAITER_T*)waiter;
vcos_semaphore_post(&self->waitsem);
}
static VCOS_STATUS_T vcos_msgq_simple_waiter_init(VCOS_MSG_SIMPLE_WAITER_T *waiter)
{
VCOS_STATUS_T status;
status = vcos_semaphore_create(&waiter->waitsem, "waiter", 0);
waiter->waiter.on_reply = vcos_msgq_simple_waiter_on_reply;
return status;
}
static void vcos_msgq_simple_waiter_deinit(VCOS_MSG_SIMPLE_WAITER_T *waiter)
{
vcos_semaphore_delete(&waiter->waitsem);
}
/*
* Message queues
*/
static VCOS_STATUS_T vcos_msgq_create_internal(VCOS_MSGQUEUE_T *q, const char *name)
{
VCOS_STATUS_T st;
memset(q, 0, sizeof(*q));
q->waiter.on_reply = vcos_msgq_queue_waiter_on_reply;
st = vcos_semaphore_create(&q->sem, name, 0);
if (st != VCOS_SUCCESS)
goto fail_sem;
st = vcos_mutex_create(&q->lock, name);
if (st != VCOS_SUCCESS)
goto fail_mtx;
return st;
fail_mtx:
vcos_semaphore_delete(&q->sem);
fail_sem:
return st;
}
static void vcos_msgq_delete_internal(VCOS_MSGQUEUE_T *q)
{
vcos_semaphore_delete(&q->sem);
vcos_mutex_delete(&q->lock);
}
VCOS_STATUS_T vcos_msgq_create(VCOS_MSGQUEUE_T *q, const char *name)
{
VCOS_STATUS_T st;
st = vcos_msgq_create_internal(q, name);
return st;
}
void vcos_msgq_delete(VCOS_MSGQUEUE_T *q)
{
vcos_msgq_delete_internal(q);
}
/* append a message to a message queue */
static _VCOS_INLINE void msgq_append(VCOS_MSGQUEUE_T *q, VCOS_MSG_T *msg)
{
vcos_mutex_lock(&q->lock);
if (q->head == NULL)
{
q->head = q->tail = msg;
}
else
{
q->tail->next = msg;
q->tail = msg;
}
vcos_mutex_unlock(&q->lock);
}
/*
* A waiter for a message queue. Just appends the message to the
* queue, waking up the waiting thread.
*/
static void vcos_msgq_queue_waiter_on_reply(VCOS_MSG_WAITER_T *waiter,
VCOS_MSG_T *msg)
{
VCOS_MSGQUEUE_T *queue = (VCOS_MSGQUEUE_T*)waiter;
msgq_append(queue, msg);
vcos_semaphore_post(&queue->sem);
}
/* initialise this library */
VCOS_STATUS_T vcos_msgq_init(void)
{
return VCOS_SUCCESS;
}
void vcos_msgq_deinit(void)
{
}
static _VCOS_INLINE
void vcos_msg_send_helper(VCOS_MSG_WAITER_T *waiter,
VCOS_MSGQUEUE_T *dest,
uint32_t code,
VCOS_MSG_T *msg)
{
vcos_assert(msg);
vcos_assert(dest);
msg->code = code;
if (waiter)
msg->waiter = waiter;
msg->next = NULL;
msg->src_thread = vcos_thread_current();
msgq_append(dest, msg);
vcos_semaphore_post(&dest->sem);
}
/* wait on a queue for a message */
VCOS_MSG_T *vcos_msg_wait(VCOS_MSGQUEUE_T *queue)
{
VCOS_MSG_T *msg;
vcos_semaphore_wait(&queue->sem);
vcos_mutex_lock(&queue->lock);
msg = queue->head;
vcos_assert(msg); /* should always be a message here! */
queue->head = msg->next;
if (queue->head == NULL)
queue->tail = NULL;
vcos_mutex_unlock(&queue->lock);
return msg;
}
/* peek on a queue for a message */
VCOS_MSG_T *vcos_msg_peek(VCOS_MSGQUEUE_T *queue)
{
VCOS_MSG_T *msg;
vcos_mutex_lock(&queue->lock);
msg = queue->head;
/* if there's a message, remove it from the queue */
if (msg)
{
queue->head = msg->next;
if (queue->head == NULL)
queue->tail = NULL;
/* keep the semaphore count consistent */
/* coverity[lock_order]
* the semaphore must have a non-zero count so cannot block here.
*/
vcos_semaphore_wait(&queue->sem);
}
vcos_mutex_unlock(&queue->lock);
return msg;
}
void vcos_msg_send(VCOS_MSGQUEUE_T *dest, uint32_t code, VCOS_MSG_T *msg)
{
vcos_assert(msg->magic == MAGIC);
vcos_msg_send_helper(NULL, dest, code, msg);
}
/** Send on to the target queue, then wait on a simple waiter for the reply
*/
VCOS_STATUS_T vcos_msg_sendwait(VCOS_MSGQUEUE_T *dest, uint32_t code, VCOS_MSG_T *msg)
{
VCOS_STATUS_T st;
VCOS_MSG_SIMPLE_WAITER_T waiter;
vcos_assert(msg->magic == MAGIC);
/* if this fires, you've set a waiter up but are now about to obliterate it
* with the 'wait for a reply' waiter.
*/
vcos_assert(msg->waiter == NULL);
if ((st=vcos_msgq_simple_waiter_init(&waiter)) != VCOS_SUCCESS)
return st;
vcos_msg_send_helper(&waiter.waiter, dest, code, msg);
vcos_semaphore_wait(&waiter.waitsem);
vcos_msgq_simple_waiter_deinit(&waiter);
return VCOS_SUCCESS;
}
/** Send a reply to a message
*/
void vcos_msg_reply(VCOS_MSG_T *msg)
{
vcos_assert(msg->magic == MAGIC);
msg->code |= MSG_REPLY_BIT;
if (msg->waiter)
{
msg->waiter->on_reply(msg->waiter, msg);
}
else
{
VCOS_ALERT("%s: reply to non-reply message id %d",
VCOS_FUNCTION,
msg->code);
vcos_assert(0);
}
}
void vcos_msg_set_source(VCOS_MSG_T *msg, VCOS_MSGQUEUE_T *queue)
{
vcos_assert(msg);
vcos_assert(msg->magic == MAGIC);
vcos_assert(queue);
msg->waiter = &queue->waiter;
}
/*
* Message pools
*/
VCOS_STATUS_T vcos_msgq_pool_create(VCOS_MSGQ_POOL_T *pool,
size_t count,
size_t payload_size,
const char *name)
{
VCOS_STATUS_T status;
int bp_size = payload_size + sizeof(VCOS_MSG_T);
status = vcos_blockpool_create_on_heap(&pool->blockpool,
count, bp_size,
VCOS_BLOCKPOOL_ALIGN_DEFAULT,
0,
name);
if (status != VCOS_SUCCESS)
goto fail_pool;
status = vcos_semaphore_create(&pool->sem, name, count);
if (status != VCOS_SUCCESS)
goto fail_sem;
pool->waiter.on_reply = vcos_msgq_pool_on_reply;
pool->magic = MAGIC;
return status;
fail_sem:
vcos_blockpool_delete(&pool->blockpool);
fail_pool:
return status;
}
void vcos_msgq_pool_delete(VCOS_MSGQ_POOL_T *pool)
{
vcos_blockpool_delete(&pool->blockpool);
vcos_semaphore_delete(&pool->sem);
}
/** Called when a message from a pool is replied-to. Just returns
* the message back to the blockpool.
*/
static void vcos_msgq_pool_on_reply(VCOS_MSG_WAITER_T *waiter,
VCOS_MSG_T *msg)
{
vcos_unused(waiter);
vcos_assert(msg->magic == MAGIC);
vcos_msgq_pool_free(msg);
}
VCOS_MSG_T *vcos_msgq_pool_alloc(VCOS_MSGQ_POOL_T *pool)
{
VCOS_MSG_T *msg;
if (vcos_semaphore_trywait(&pool->sem) == VCOS_SUCCESS)
{
msg = vcos_blockpool_calloc(&pool->blockpool);
vcos_assert(msg);
msg->magic = MAGIC;
msg->waiter = &pool->waiter;
msg->pool = pool;
}
else
{
msg = NULL;
}
return msg;
}
void vcos_msgq_pool_free(VCOS_MSG_T *msg)
{
if (msg)
{
VCOS_MSGQ_POOL_T *pool;
vcos_assert(msg->pool);
pool = msg->pool;
vcos_assert(msg->pool->magic == MAGIC);
vcos_blockpool_free(msg);
vcos_semaphore_post(&pool->sem);
}
}
VCOS_MSG_T *vcos_msgq_pool_wait(VCOS_MSGQ_POOL_T *pool)
{
VCOS_MSG_T *msg;
vcos_semaphore_wait(&pool->sem);
msg = vcos_blockpool_calloc(&pool->blockpool);
vcos_assert(msg);
msg->magic = MAGIC;
msg->waiter = &pool->waiter;
msg->pool = pool;
return msg;
}
void vcos_msg_init(VCOS_MSG_T *msg)
{
msg->magic = MAGIC;
msg->next = NULL;
msg->waiter = NULL;
msg->pool = NULL;
}
@@ -0,0 +1,88 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*=============================================================================
VideoCore OS Abstraction Layer - reentrant mutexes mapped directly to regular ones
=============================================================================*/
#ifndef VCOS_GENERIC_REENTRANT_MUTEX_H
#define VCOS_GENERIC_REENTRANT_MUTEX_H
#ifdef __cplusplus
extern "C" {
#endif
#include "interface/vcos/vcos_types.h"
#include "interface/vcos/vcos_mutex.h"
/**
* \file
*
* Reentrant Mutexes directly using the native re-entrant mutex.
*
*/
typedef VCOS_MUTEX_T VCOS_REENTRANT_MUTEX_T;
/* Inline forwarding functions */
#if defined(VCOS_INLINE_BODIES)
VCOS_INLINE_IMPL
VCOS_STATUS_T vcos_reentrant_mutex_create(VCOS_REENTRANT_MUTEX_T *m, const char *name) {
return vcos_mutex_create(m,name);
}
VCOS_INLINE_IMPL
void vcos_reentrant_mutex_delete(VCOS_REENTRANT_MUTEX_T *m) {
vcos_mutex_delete(m);
}
VCOS_INLINE_IMPL
void vcos_reentrant_mutex_lock(VCOS_REENTRANT_MUTEX_T *m) {
vcos_mutex_lock(m);
}
VCOS_INLINE_IMPL
void vcos_reentrant_mutex_unlock(VCOS_REENTRANT_MUTEX_T *m) {
vcos_mutex_unlock(m);
}
VCOS_INLINE_IMPL
int vcos_reentrant_mutex_is_locked(VCOS_REENTRANT_MUTEX_T *m) {
return vcos_mutex_is_locked(m);
}
#endif
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,55 @@
/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*=============================================================================
VideoCore OS Abstraction Layer - thread reaping
=============================================================================*/
#ifndef VCOS_THREAD_REAPER_H
#define VCOS_THREAD_REAPER_H
#define VCOS_HAVE_THREAD_REAPER
/** Initialise the thread reaper.
*/
VCOS_STATUS_T vcos_thread_reaper_init(void);
/** Reap a thread. Arranges for the thread to be automatically
* joined.
*
* @sa vcos_thread_join().
*
* @param thread the thread to terminate
* @param on_terminated called after the thread has exited
* @param cxt pass back to the callback
*
*/
void vcos_thread_reap(VCOS_THREAD_T *thread, void (*on_terminated)(void*), void *cxt);
#endif