forked from espressif/arduino-esp32
initial import
This commit is contained in:
committed by
Ivan Grokhotkov
parent
668acc2c08
commit
5f3a205955
789
tools/sdk/include/esp32/xtensa/xmp-library.h
Executable file
789
tools/sdk/include/esp32/xtensa/xmp-library.h
Executable file
@ -0,0 +1,789 @@
|
||||
/* Customer ID=11656; Build=0x5f626; Copyright (c) 2008-2009 by Tensilica Inc. ALL RIGHTS RESERVED.
|
||||
These coded instructions, statements, and computer programs are the
|
||||
copyrighted works and confidential proprietary information of Tensilica Inc.
|
||||
They may not be modified, copied, reproduced, distributed, or disclosed to
|
||||
third parties in any manner, medium, or form, in whole or in part, without
|
||||
the prior written consent of Tensilica Inc. */
|
||||
|
||||
#ifndef _XMP_LIBRARY_H
|
||||
#define _XMP_LIBRARY_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <xtensa/config/core-isa.h>
|
||||
#include <xtensa/config/core.h>
|
||||
#include <xtensa/tie/xt_core.h>
|
||||
#if XCHAL_HAVE_RELEASE_SYNC
|
||||
#include <xtensa/tie/xt_sync.h>
|
||||
#endif
|
||||
#if XCHAL_HAVE_EXTERN_REGS
|
||||
#include <xtensa/xtensa-xer.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "xtensa/system/mpsystem.h"
|
||||
|
||||
/*
|
||||
W A R N I N G:
|
||||
|
||||
xmp library clients should treat all data structures in this file
|
||||
as opaque. They are only public to enable users to declare them
|
||||
statically.
|
||||
*/
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
When using XMP on cache-incoherent systems, these macros are helpful
|
||||
to ensure that you are not reading stale data, and to ensure that
|
||||
the data you write makes it all the way back to main memory.
|
||||
*/
|
||||
|
||||
#if !XCHAL_DCACHE_IS_COHERENT
|
||||
#define XMP_WRITE_BACK_ELEMENT(x) xthal_dcache_region_writeback((void *)x, sizeof(*x))
|
||||
#define XMP_INVALIDATE_ELEMENT(x) xthal_dcache_region_invalidate((void *)x, sizeof(*x))
|
||||
#define XMP_WRITE_BACK_INVALIDATE_ELEMENT(x) xthal_dcache_region_writeback_inv((void *)x, sizeof(*x))
|
||||
#define XMP_WRITE_BACK_ARRAY(x) xthal_dcache_region_writeback((void *)x, sizeof(x))
|
||||
#define XMP_INVALIDATE_ARRAY(x) xthal_dcache_region_invalidate((void *)x, sizeof(x))
|
||||
#define XMP_WRITE_BACK_INVALIDATE_ARRAY(x) xthal_dcache_region_writeback_inv((void *)x, sizeof(x))
|
||||
#define XMP_WRITE_BACK_ARRAY_ELEMENTS(x, num_elements) xthal_dcache_region_writeback((void *)x, sizeof(*x) * num_elements)
|
||||
#define XMP_INVALIDATE_ARRAY_ELEMENTS(x, num_elements) xthal_dcache_region_invalidate((void *)x, sizeof(*x) * num_elements)
|
||||
#define XMP_WRITE_BACK_INVALIDATE_ARRAY_ELEMENTS(x, num_elements) xthal_dcache_region_writeback_inv((void *)x, sizeof(*x) * num_elements)
|
||||
#else
|
||||
#define XMP_WRITE_BACK_ELEMENT(x)
|
||||
#define XMP_INVALIDATE_ELEMENT(x)
|
||||
#define XMP_WRITE_BACK_INVALIDATE_ELEMENT(x)
|
||||
#define XMP_WRITE_BACK_ARRAY(x)
|
||||
#define XMP_INVALIDATE_ARRAY(x)
|
||||
#define XMP_WRITE_BACK_INVALIDATE_ARRAY(x)
|
||||
#define XMP_WRITE_BACK_ARRAY_ELEMENTS(x, num_elements)
|
||||
#define XMP_INVALIDATE_ARRAY_ELEMENTS(x, num_elements)
|
||||
#define XMP_WRITE_BACK_INVALIDATE_ARRAY_ELEMENTS(x, num_elements)
|
||||
#endif
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
Initialization, error codes, constants and house-keeping
|
||||
|
||||
Every core should call xmp_init with the number of cores in the
|
||||
system.
|
||||
|
||||
xmp_init should be called before you use any global synchronization
|
||||
primitive or shared data.
|
||||
|
||||
Further, before you use a dynamically allocated synchronization
|
||||
primitives, you need to both initialize it by calling the
|
||||
xmp_*_init function, and you need to have called xmp_init, which
|
||||
sets up interrupt handlers and interrupt routing.
|
||||
|
||||
The second parameter sets the interprocessor interrupt
|
||||
routing. Passing zero instructs the library to use the default
|
||||
routing, which will be suitable for most users.
|
||||
|
||||
*/
|
||||
|
||||
extern void xmp_init (int num_cores, unsigned int interrupt_routing);
|
||||
|
||||
|
||||
/* If you want finer-grained control than that provided by xmp_init,
|
||||
you can the functions below individually--however, this is more
|
||||
inconvenient and requires greater understanding of the library's
|
||||
internals. Don't use them directly unless you have a good reason.
|
||||
*/
|
||||
|
||||
extern void xmp_unpack_shared (void);
|
||||
extern void xmp_route_interrupts (unsigned int routing);
|
||||
|
||||
#if XCHAL_HAVE_MP_INTERRUPTS
|
||||
extern void xmp_enable_ipi_interrupts (void);
|
||||
|
||||
/* Turn off certain things enabled by xmp_init */
|
||||
extern void xmp_disable_ipi_interrupts (void);
|
||||
#endif
|
||||
|
||||
extern void xmp_end (void);
|
||||
|
||||
/* Only valid after xmp_init. */
|
||||
extern int xmp_num_cores (void);
|
||||
|
||||
/* How many cycles should a core wait before rechecking a
|
||||
synchronization variable? Higher values will reduce memory
|
||||
transactions, but will also result in higher latency in returning
|
||||
from synchronization.
|
||||
*/
|
||||
extern void xmp_spin_wait_set_cycles (unsigned int limit);
|
||||
|
||||
/* If you would prefer to provide your own spin wait function,
|
||||
to go to sleep, etc. Declare a function of this type, then call
|
||||
this function. */
|
||||
typedef void (*xmp_spin_wait_function_t)(void);
|
||||
extern void xmp_spin_wait_set_function (xmp_spin_wait_function_t func);
|
||||
extern void xmp_spin(void);
|
||||
|
||||
#define XMP_NO_OWNER 0x07
|
||||
#define XMP_MUTEX_DESTROYED 0xFE
|
||||
#define XMP_ERROR_FATAL 0xFD
|
||||
|
||||
#define XMP_MAX_CORES 0x4
|
||||
|
||||
|
||||
static inline unsigned int xmp_prid (void)
|
||||
{
|
||||
#if XCHAL_HAVE_PRID
|
||||
return XT_RSR_PRID() & 0xFF;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
Tracing
|
||||
|
||||
A core must set a trace_file if it wants any synchronization
|
||||
tracing to occur. Sharing file descriptors among cores is very
|
||||
messy, so don't do it. This, unfortunately, means that two cores
|
||||
contending for a mutex are not able to trace to the same file.
|
||||
|
||||
Any object (except the atomic integer) can have tracing off or on.
|
||||
*/
|
||||
|
||||
extern void xmp_set_trace_file (FILE * file);
|
||||
extern void xmp_trace (const char * fmt, ...);
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
Memory Allocation Functions.
|
||||
|
||||
These do what you would expect, only from shared memory instead of
|
||||
private memory.
|
||||
*/
|
||||
|
||||
#if XCHAL_DCACHE_IS_COHERENT
|
||||
extern void * xmp_malloc (size_t size);
|
||||
extern void * xmp_calloc (size_t nmemb, size_t size);
|
||||
extern void xmp_free (void * ptr);
|
||||
#endif
|
||||
extern void * xmp_sbrk(int size);
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
xmp_atomic_int_t
|
||||
|
||||
The most basic synchronization primitive in the xmp library.
|
||||
Atomic ints are sharable among processors, and even interrupt
|
||||
levels on the same processor. However, their semantics are fairly
|
||||
rudimentary. All other primitives are based on these, therefore,
|
||||
changing this implementation affects all other primitives.
|
||||
|
||||
*/
|
||||
|
||||
typedef unsigned int xmp_atomic_int_t;
|
||||
|
||||
static inline xmp_atomic_int_t
|
||||
xmp_coherent_l32ai(xmp_atomic_int_t * address)
|
||||
{
|
||||
XMP_INVALIDATE_ELEMENT (address);
|
||||
return XT_L32AI(address, 0);
|
||||
}
|
||||
|
||||
static inline void
|
||||
xmp_coherent_s32ri(xmp_atomic_int_t value, xmp_atomic_int_t * address)
|
||||
{
|
||||
XT_S32RI (value, address, 0);
|
||||
XMP_WRITE_BACK_ELEMENT (address);
|
||||
}
|
||||
|
||||
#define XMP_ATOMIC_INT_INITIALIZER(value) (value)
|
||||
|
||||
/* xmp_atomic_int_init - Initialize an int prior to use
|
||||
|
||||
Nonsynchronizing, Nonblocking
|
||||
|
||||
Usage:
|
||||
value - initial value
|
||||
integer - points to an uninitialized integer
|
||||
|
||||
On exit:
|
||||
initialized to given value
|
||||
|
||||
Errors: none
|
||||
*/
|
||||
|
||||
static inline void
|
||||
xmp_atomic_int_init (xmp_atomic_int_t * integer, int value)
|
||||
{
|
||||
xmp_coherent_s32ri (value, integer);
|
||||
}
|
||||
|
||||
|
||||
/* xmp_atomic_int_value - Read the value
|
||||
|
||||
Nonsynchronizing, Nonblocking
|
||||
|
||||
Usage:
|
||||
integer - points to an int
|
||||
|
||||
Returns:
|
||||
the value
|
||||
*/
|
||||
|
||||
static inline int
|
||||
xmp_atomic_int_value (xmp_atomic_int_t * integer)
|
||||
{
|
||||
return xmp_coherent_l32ai (integer);
|
||||
}
|
||||
|
||||
|
||||
/* xmp_atomic_int_conditional_increment - Conditionally increment integer
|
||||
|
||||
Synchronizing, nonblocking
|
||||
|
||||
Usage:
|
||||
integer - points to an initialized integer
|
||||
amount - how much to increment
|
||||
prev - believed value of the integer
|
||||
eg: prev = xmp_atomic_int_value (integer);
|
||||
success = xmp_atomic_int_increment (integer, 1, prev);
|
||||
|
||||
Returns: current value of integer - user should check if it matches
|
||||
the previous value of the integer. If it does, then the update
|
||||
was successful.
|
||||
|
||||
*/
|
||||
|
||||
#define USE_ASSEMBLY_IMPLEMENTATION 0
|
||||
|
||||
static inline int
|
||||
xmp_atomic_int_conditional_increment (xmp_atomic_int_t * integer, int amount, int prev)
|
||||
{
|
||||
int val;
|
||||
int saved;
|
||||
|
||||
#if USE_ASSEMBLY_IMPLEMENTATION
|
||||
/* %0 = prev
|
||||
%1 = saved
|
||||
%2 = atomic integer pointer
|
||||
%3 = amount
|
||||
*/
|
||||
|
||||
asm volatile ("wsr.scompare1 %0\n"
|
||||
"mov %1, %0\n"
|
||||
"add %0, %0, %3\n"
|
||||
"s32c1i %0, %2, 0\n"
|
||||
: "+&a" (prev), "+&a"(saved) : "a" (integer), "a" (amount));
|
||||
|
||||
return prev;
|
||||
|
||||
#else
|
||||
|
||||
XT_WSR_SCOMPARE1 (prev);
|
||||
val = prev + amount;
|
||||
saved = val;
|
||||
XT_S32C1I (val, integer, 0);
|
||||
|
||||
return val;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* xmp_atomic_int_increment - Increment integer
|
||||
|
||||
Synchronizing, blocking
|
||||
|
||||
Usage:
|
||||
integer - points to an initialized integer
|
||||
amount - how much to increment
|
||||
|
||||
Returns: new value of integer
|
||||
|
||||
*/
|
||||
|
||||
static inline int
|
||||
xmp_atomic_int_increment (xmp_atomic_int_t * integer, int amount)
|
||||
{
|
||||
int val;
|
||||
int saved;
|
||||
#if USE_ASSEMBLY_IMPLEMENTATION
|
||||
/* %0 = val
|
||||
%1 = saved
|
||||
%2 = atomic integer pointer
|
||||
%3 = amount
|
||||
*/
|
||||
|
||||
asm volatile ("l32ai %0, %2, 0\n"
|
||||
"1:\n"
|
||||
"wsr.scompare1 %0\n"
|
||||
"mov %1, %0\n"
|
||||
"add %0, %0, %3\n"
|
||||
"s32c1i %0, %2, 0\n"
|
||||
"bne %0, %1, 1b\n"
|
||||
: "+&a" (val), "+&a"(saved) : "a" (integer), "a" (amount));
|
||||
#else
|
||||
/* Accurately naming "val" is tricky. Sometimes it will be what we
|
||||
want to be the new value, but sometimes it contains the value
|
||||
that is currently at the location. */
|
||||
|
||||
/* Load location's current value */
|
||||
val = xmp_coherent_l32ai (integer);
|
||||
|
||||
do {
|
||||
XT_WSR_SCOMPARE1 (val);
|
||||
saved = val;
|
||||
/* Change it to what we would like to store there--"new_val" */
|
||||
val = val + amount;
|
||||
/* Possibly store new_val, but reload location's current value no
|
||||
matter what. */
|
||||
XT_S32C1I (val, integer, 0);
|
||||
if (val != saved)
|
||||
xmp_spin();
|
||||
} while (val != saved);
|
||||
|
||||
#endif
|
||||
return val + amount;
|
||||
}
|
||||
|
||||
|
||||
/* xmp_atomic_int_conditional_set - Set the value of an atomic integer
|
||||
|
||||
Synchronizing, nonblocking
|
||||
|
||||
Usage:
|
||||
integer - points to an initialized integer
|
||||
from - believed value of the integer
|
||||
eg: prev = xmp_atomic_int_value (integer);
|
||||
success = xmp_atomic_int_conditional_set (integer, 1, prev);
|
||||
to - new value
|
||||
|
||||
Returns: current value of integer - user should check if it matches
|
||||
the previous value of the integer. If it does, then the update
|
||||
was successful.
|
||||
|
||||
*/
|
||||
|
||||
static inline int
|
||||
xmp_atomic_int_conditional_set (xmp_atomic_int_t * integer, int from, int to)
|
||||
{
|
||||
int val;
|
||||
|
||||
/* Don't even try to update if the integer's value isn't what we
|
||||
think it should be. This prevents acquiring this cache-line for
|
||||
writing and therefore prevents bus transactions when various
|
||||
cores contend. */
|
||||
val = xmp_coherent_l32ai(integer);
|
||||
if (val == from) {
|
||||
XT_WSR_SCOMPARE1 (from);
|
||||
val = to;
|
||||
/* Possibly store to, but reload location's current value no
|
||||
matter what. */
|
||||
XT_S32C1I (val, integer, 0);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
/* Macros to implement trivial spin locks. These are very primitive, but
|
||||
can be useful when you don't need the higher-overhead synchronization.
|
||||
|
||||
To use an xmp_atomic_int_t as a trivial spin lock, you should
|
||||
initialize it to zero first.
|
||||
*/
|
||||
|
||||
#define XMP_SIMPLE_SPINLOCK_ACQUIRE(atomic_int_ptr) \
|
||||
{ while (xmp_atomic_int_conditional_set (atomic_int_ptr, 0, xmp_prid() + 1) != 0) \
|
||||
xmp_spin(); }
|
||||
#define XMP_SIMPLE_SPINLOCK_RELEASE(atomic_int_ptr) \
|
||||
{ while (xmp_atomic_int_conditional_set (atomic_int_ptr, xmp_prid() + 1, 0) != xmp_prid() + 1) \
|
||||
xmp_spin(); }
|
||||
|
||||
#define XMP_SIMPLE_SPINLOCK_OWNER(atomic_int_ptr) (xmp_atomic_int_value(atomic_int_ptr) - 1)
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
xmp_mutex_t - An even higher-level data structure to enforce
|
||||
mutual exclusion between cores. A core which waits on a mutex might
|
||||
sleep with a waiti and be interrupted by an interrupt.
|
||||
|
||||
Mutexes can be normal or recursive. For a normal mutex, a core
|
||||
attempting to acquire a mutex it already holds will result in
|
||||
deadlock. For a recursive mutex, a core will succeed in acquiring a
|
||||
mutex it already holds, and must release it as many times as it
|
||||
acquired it.
|
||||
|
||||
Mutexes are not sharable between interrupt levels--because
|
||||
ownership is tracked by core, not thread.
|
||||
|
||||
Like all xmp data structures, an object of type xmp_mutex_t
|
||||
should be treated by the programmer as opaque. They are only
|
||||
public in this header file to allow them to be declared statically.
|
||||
|
||||
For configurations with 16-byte cache lines, this has the most
|
||||
frequently used and changed data in the first line.
|
||||
|
||||
*/
|
||||
|
||||
#if XCHAL_DCACHE_IS_COHERENT
|
||||
typedef struct xmp_mutex_t {
|
||||
xmp_atomic_int_t qlock;
|
||||
unsigned int qhead;
|
||||
unsigned int qtail;
|
||||
unsigned char queue[XMP_MAX_CORES];
|
||||
unsigned short held;
|
||||
|
||||
unsigned char owner;
|
||||
unsigned char recursive : 1;
|
||||
unsigned char trace : 1;
|
||||
unsigned char system : 1;
|
||||
unsigned char unused : 5;
|
||||
const char * name;
|
||||
} xmp_mutex_t __attribute__ ((aligned (XMP_MAX_DCACHE_LINESIZE)));
|
||||
|
||||
|
||||
#define XMP_MUTEX_INITIALIZER(name) \
|
||||
{ 0, 0, -1, {XMP_NO_OWNER, XMP_NO_OWNER, XMP_NO_OWNER, XMP_NO_OWNER}, \
|
||||
0, XMP_NO_OWNER, XMP_MUTEX_FLAG_NORMAL, 0, 0, 0, name }
|
||||
|
||||
#define XMP_RECURSIVE_MUTEX_INITIALIZER(name) \
|
||||
{ 0, 0, -1, {XMP_NO_OWNER, XMP_NO_OWNER, XMP_NO_OWNER, XMP_NO_OWNER}, \
|
||||
0, XMP_NO_OWNER, XMP_MUTEX_FLAG_RECURSIVE, 0, 0, 0, name }
|
||||
|
||||
#define XMP_MUTEX_FLAG_NORMAL 0
|
||||
#define XMP_MUTEX_FLAG_RECURSIVE 1
|
||||
|
||||
#define XMP_MUTEX_ACQUIRE_FAILED -1
|
||||
#define XMP_MUTEX_ERROR_DESTROY_OWNED -2
|
||||
#define XMP_MUTEX_ERROR_NOT_OWNED -3
|
||||
#define XMP_MUTEX_ERROR_ALREADY_OWNED -4
|
||||
|
||||
/*
|
||||
xmp_mutex_init
|
||||
|
||||
Nonsynchronizing
|
||||
Nonblocking
|
||||
|
||||
Usage:
|
||||
mutex - points to an uninitialized mutex
|
||||
name - name if you want one, NULL if not.
|
||||
recursive - use recursive semantices
|
||||
|
||||
Returns
|
||||
zero on success (always succeeds)
|
||||
|
||||
*/
|
||||
|
||||
extern int xmp_mutex_init (xmp_mutex_t * mutex,
|
||||
const char * name,
|
||||
unsigned int recursive);
|
||||
|
||||
/*
|
||||
int xmp_mutex_destroy (xmp_mutex_t * mutex);
|
||||
|
||||
Synchronizing - will fail if mutex is held by anyone -- including
|
||||
current processor
|
||||
Nonblocking
|
||||
|
||||
Usage:
|
||||
mutex - points to a mutex
|
||||
|
||||
Returns
|
||||
zero on success
|
||||
non-zero if mutex is held
|
||||
*/
|
||||
|
||||
extern int xmp_mutex_destroy (xmp_mutex_t * mutex);
|
||||
|
||||
|
||||
/*
|
||||
xmp_mutex_lock -- Synchronizing
|
||||
xmp_mutex_trylock
|
||||
|
||||
Usage:
|
||||
mutex - points to a mutex
|
||||
|
||||
Returns
|
||||
zero on success
|
||||
*/
|
||||
|
||||
extern int xmp_mutex_lock (xmp_mutex_t * mutex);
|
||||
extern int xmp_mutex_trylock (xmp_mutex_t * mutex);
|
||||
|
||||
|
||||
/*
|
||||
xmp_mutex_unlock
|
||||
|
||||
Synchronizing
|
||||
Nonblocking
|
||||
|
||||
Usage:
|
||||
mutex - points to a mutex
|
||||
|
||||
Returns
|
||||
zero on success - mutex is released
|
||||
non-zero on failure - mutex is owned by another core
|
||||
- prid of processor that does own it
|
||||
note that by the time this function
|
||||
returns, the owner of the core may
|
||||
have changed.
|
||||
*/
|
||||
|
||||
extern int xmp_mutex_unlock (xmp_mutex_t * mutex);
|
||||
|
||||
|
||||
/*
|
||||
xmp_mutex_name
|
||||
|
||||
Nonsynchronizing
|
||||
Nonblocking
|
||||
|
||||
Usage:
|
||||
mutex - points to a mutex
|
||||
|
||||
Returns the name of the given mutex, which may be NULL.
|
||||
|
||||
*/
|
||||
|
||||
const char * xmp_mutex_name (const xmp_mutex_t * mutex);
|
||||
|
||||
|
||||
/*
|
||||
xmp_mutex_trace_on
|
||||
xmp_mutex_trace_off
|
||||
|
||||
Nonsynchronizing
|
||||
Nonblocking
|
||||
|
||||
Turn off and on tracing for the mutex.
|
||||
|
||||
These functions are only present in the debug version of the library.
|
||||
*/
|
||||
|
||||
extern void xmp_mutex_trace_on (xmp_mutex_t * mutex);
|
||||
extern void xmp_mutex_trace_off (xmp_mutex_t * mutex);
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
xmp_condition_t
|
||||
|
||||
Condition Variables following Mesa semantics.
|
||||
|
||||
Condition variables are not sharable among interrupt levels.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
typedef struct xmp_condition_t {
|
||||
unsigned int qhead;
|
||||
unsigned int qtail;
|
||||
unsigned char queue[XMP_MAX_CORES];
|
||||
unsigned int waiting[XMP_MAX_CORES];
|
||||
|
||||
unsigned char trace : 1;
|
||||
unsigned char unused : 7;
|
||||
const char * name;
|
||||
} xmp_condition_t __attribute__ ((aligned (XMP_MAX_DCACHE_LINESIZE)));
|
||||
|
||||
|
||||
#define XMP_CONDITION_INITIALIZER(name) \
|
||||
{ 0, -1, {XMP_NO_OWNER, XMP_NO_OWNER, XMP_NO_OWNER, XMP_NO_OWNER}, \
|
||||
{0, 0, 0, 0}, 0, 0, name}
|
||||
|
||||
|
||||
/* xmp_condition_init - Initialize a condition variable
|
||||
|
||||
Nonsynchronizing, Nonblocking
|
||||
|
||||
Usage:
|
||||
condition - pointer to an xmp_condition_t
|
||||
|
||||
On exit:
|
||||
condition initialized
|
||||
|
||||
Errors: none
|
||||
*/
|
||||
|
||||
extern int xmp_condition_init (xmp_condition_t * condition,
|
||||
const char * name);
|
||||
extern int xmp_condition_destroy (xmp_condition_t * condition);
|
||||
|
||||
|
||||
/* xmp_condition_wait - Wait for a condition variable
|
||||
|
||||
Synchronizing, blocking
|
||||
|
||||
Usage:
|
||||
condition - pointer to an xmp_condition_t
|
||||
mutex - pointer to an xmp_mutex_t already acquired by the calling
|
||||
process
|
||||
|
||||
Errors: if the mutex isn't held by this core
|
||||
*/
|
||||
|
||||
extern int xmp_condition_wait (xmp_condition_t * condition,
|
||||
xmp_mutex_t * mutex);
|
||||
|
||||
/* xmp_condition_signal
|
||||
|
||||
- Signal the first (if any) core waiting on a condition variable
|
||||
|
||||
You must hold the mutex you passed to xmp_condition_wait before
|
||||
calling this function.
|
||||
|
||||
Synchronizing, nonblocking
|
||||
|
||||
Usage:
|
||||
condition - pointer to an xmp_condition_t
|
||||
|
||||
Errors: none
|
||||
*/
|
||||
|
||||
extern int xmp_condition_signal (xmp_condition_t * condition);
|
||||
|
||||
|
||||
/* xmp_condition_broadcast
|
||||
|
||||
- Signal all cores waiting on a condition variable
|
||||
|
||||
Synchronizing, nonblocking
|
||||
|
||||
You must hold the mutex you passed to xmp_condition_wait before
|
||||
calling this function.
|
||||
|
||||
Usage:
|
||||
condition - pointer to an xmp_condition_t
|
||||
|
||||
Errors: none
|
||||
*/
|
||||
|
||||
extern int xmp_condition_broadcast (xmp_condition_t * condition);
|
||||
|
||||
|
||||
static inline const char * xmp_condition_name (const xmp_condition_t * condition)
|
||||
{
|
||||
return condition->name;
|
||||
}
|
||||
|
||||
/*
|
||||
xmp_condition_trace_on
|
||||
xmp_condition_trace_off
|
||||
|
||||
Nonsynchronizing
|
||||
Nonblocking
|
||||
|
||||
Turn off and on statistics and tracing for the condition. For
|
||||
tracing you must also set a trace file for the core.
|
||||
|
||||
These functions are only present in the debug-version of the library.
|
||||
*/
|
||||
|
||||
extern void xmp_condition_trace_on (xmp_condition_t * condition);
|
||||
extern void xmp_condition_trace_off (xmp_condition_t * condition);
|
||||
|
||||
#endif /* XCHAL_DCACHE_IS_COHERENT */
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
xmp_barrier_t
|
||||
|
||||
Classic barriers that stop any core from continuing until a
|
||||
specified number of cores reach that point. Once the barrier allows
|
||||
cores through, the barrier is reset and will stop cores from
|
||||
progressing again.
|
||||
|
||||
Barriers are not sharable among interrupt levels.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
typedef struct xmp_barrier_t
|
||||
{
|
||||
xmp_atomic_int_t count;
|
||||
xmp_atomic_int_t state;
|
||||
xmp_atomic_int_t sleeping;
|
||||
unsigned short num_cores;
|
||||
unsigned short trace : 1;
|
||||
unsigned short system : 1;
|
||||
const char * name;
|
||||
} xmp_barrier_t __attribute__ ((aligned (XMP_MAX_DCACHE_LINESIZE)));
|
||||
|
||||
#define XMP_BARRIER_INITIALIZER(number, name) \
|
||||
{ 0, 0, 0, number, 0, 0, name }
|
||||
|
||||
|
||||
/* xmp_barrier_init - Initialize a barrier
|
||||
|
||||
Nonsynchronizing, Nonblocking
|
||||
|
||||
Usage:
|
||||
barrier - pointer to an xmp_barrier_t
|
||||
num_cores - number of cores needed to arrive at the
|
||||
barrier before any are allowed through
|
||||
On exit:
|
||||
barrier initialized
|
||||
|
||||
Always returns zero.
|
||||
|
||||
Errors: none
|
||||
*/
|
||||
|
||||
extern int xmp_barrier_init (xmp_barrier_t * barrier, int num_cores,
|
||||
const char * name);
|
||||
|
||||
|
||||
/* xmp_barrier_wait - Wait on a barrier
|
||||
|
||||
Nonsynchronizing, Nonblocking
|
||||
|
||||
Usage:
|
||||
barrier - pointer to an xmp_barrier_t
|
||||
On exit:
|
||||
Enough cores (as determined at the barrier's initialization)
|
||||
have reached the barrier.
|
||||
|
||||
Errors: none
|
||||
*/
|
||||
|
||||
extern int xmp_barrier_wait (xmp_barrier_t * barrier);
|
||||
|
||||
|
||||
static inline const char * xmp_barrier_name (const xmp_barrier_t * barrier)
|
||||
{
|
||||
return barrier->name;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
xmp_barrier_trace_on
|
||||
xmp_barrier_trace_off
|
||||
|
||||
Nonsynchronizing
|
||||
Nonblocking
|
||||
|
||||
Turn on and off tracing for the barrier. For
|
||||
tracing you must also set a trace file for the core.
|
||||
|
||||
These functions are only present in the debug-version of the library.
|
||||
*/
|
||||
|
||||
extern void xmp_barrier_trace_on (xmp_barrier_t * barrier);
|
||||
extern void xmp_barrier_trace_off (xmp_barrier_t * barrier);
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
Portions of the library that are internal, but belong here for
|
||||
convenience.
|
||||
*/
|
||||
|
||||
extern xmp_atomic_int_t _ResetSync;
|
||||
|
||||
static inline void
|
||||
xmp_initial_sync (int num_cores)
|
||||
{
|
||||
xmp_atomic_int_increment (&_ResetSync, 1);
|
||||
while (xmp_coherent_l32ai (&_ResetSync) != num_cores)
|
||||
xmp_spin ();
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _XMP_LIBRARY_H */
|
Reference in New Issue
Block a user