2004-08-13 03:31:15 +04:00
|
|
|
/*
|
2005-11-05 22:57:48 +03:00
|
|
|
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
|
|
|
|
* University Research and Technology
|
|
|
|
* Corporation. All rights reserved.
|
2006-08-24 20:38:08 +04:00
|
|
|
* Copyright (c) 2004-2006 The University of Tennessee and The University
|
2005-11-05 22:57:48 +03:00
|
|
|
* of Tennessee Research Foundation. All rights
|
|
|
|
* reserved.
|
2004-11-28 23:09:25 +03:00
|
|
|
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
|
|
|
* University of Stuttgart. All rights reserved.
|
2005-03-24 15:43:37 +03:00
|
|
|
* Copyright (c) 2004-2005 The Regents of the University of California.
|
|
|
|
* All rights reserved.
|
2004-11-22 04:38:40 +03:00
|
|
|
* $COPYRIGHT$
|
|
|
|
*
|
|
|
|
* Additional copyrights may follow
|
|
|
|
*
|
2004-08-13 03:31:15 +04:00
|
|
|
* $HEADER$
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _OMPI_CIRCULAR_BUFFER_FIFO
|
|
|
|
#define _OMPI_CIRCULAR_BUFFER_FIFO
|
|
|
|
|
2006-02-12 04:33:29 +03:00
|
|
|
#include "ompi/constants.h"
|
|
|
|
#include "opal/sys/cache.h"
|
|
|
|
#include "opal/sys/atomic.h"
|
2005-09-19 20:28:25 +04:00
|
|
|
#include "ompi/mca/mpool/mpool.h"
|
2005-07-04 05:59:52 +04:00
|
|
|
#include "opal/util/pow2.h"
|
2004-08-13 03:31:15 +04:00
|
|
|
|
|
|
|
|
|
|
|
/** @file
|
|
|
|
*
|
|
|
|
* This defines a set of functions to create, and manipulate a FIFO
|
|
|
|
* set up in a circular buffer. FIFO elements are assumed to be
|
|
|
|
* pointers. Pointers are written to the head, and read from the
|
2004-08-18 01:49:01 +04:00
|
|
|
* tail. For thread safety, a spin lock is provided in the
|
|
|
|
* ompi_cb_fifo_ctl_t structure, but it's use must be managed by
|
|
|
|
* the calling routines - this is not by these set of routines.
|
2004-08-30 05:25:34 +04:00
|
|
|
* Queues are addressed relative to an offset from the base of
|
|
|
|
* a memory pool, in this way, different processes with different
|
|
|
|
* base addresses can access these queue at the same time.
|
2004-08-13 03:31:15 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* error code */
|
|
|
|
#define OMPI_CB_ERROR -1
|
2004-08-25 02:25:59 +04:00
|
|
|
#define OMPI_CB_FREE (void *)-2
|
|
|
|
#define OMPI_CB_RESERVED (void *)-3
|
2004-08-30 05:25:34 +04:00
|
|
|
#define OMPI_CB_NULL (void *)-4
|
2004-08-13 03:31:15 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Structure used to keep track of the fifo status
|
|
|
|
*/
|
|
|
|
struct ompi_cb_fifo_ctl_t {
|
|
|
|
/* spin-lock for access control */
|
2005-07-04 01:38:51 +04:00
|
|
|
opal_atomic_lock_t lock;
|
2004-08-13 03:31:15 +04:00
|
|
|
|
|
|
|
/* current queue index */
|
2004-10-19 03:24:53 +04:00
|
|
|
volatile int fifo_index;
|
2004-08-13 03:31:15 +04:00
|
|
|
|
|
|
|
/* number of entries that have been used, but not invalidated. used
|
|
|
|
* for lazy resource reclamation */
|
2007-03-05 17:27:26 +03:00
|
|
|
int num_to_clear;
|
2004-08-13 03:31:15 +04:00
|
|
|
};
|
|
|
|
typedef struct ompi_cb_fifo_ctl_t ompi_cb_fifo_ctl_t;
|
|
|
|
|
|
|
|
/* data structure used to describe the fifo */
|
|
|
|
struct ompi_cb_fifo_t {
|
2007-03-05 17:27:26 +03:00
|
|
|
/* head of queue - where next entry will be written (sender address)*/
|
|
|
|
ompi_cb_fifo_ctl_t *head;
|
2004-08-13 03:31:15 +04:00
|
|
|
|
2007-03-05 17:27:26 +03:00
|
|
|
/* tail of queue - next element to read (receiver address) */
|
|
|
|
ompi_cb_fifo_ctl_t *tail;
|
2004-08-25 00:17:44 +04:00
|
|
|
|
2007-03-05 17:27:26 +03:00
|
|
|
/* head of queue - where next entry will be written (receiver address) */
|
|
|
|
ompi_cb_fifo_ctl_t *recv_head;
|
2004-08-25 00:17:44 +04:00
|
|
|
|
2007-03-05 17:27:26 +03:00
|
|
|
/* circular buffer array (sender address) */
|
|
|
|
volatile void **queue;
|
2004-08-25 00:17:44 +04:00
|
|
|
|
2007-03-05 17:27:26 +03:00
|
|
|
/* circular buffer array (receiver address) */
|
|
|
|
volatile void **recv_queue;
|
2004-08-13 03:31:15 +04:00
|
|
|
|
2007-03-05 17:27:26 +03:00
|
|
|
/* frequency of lazy free */
|
|
|
|
int lazy_free_frequency;
|
2004-08-13 03:31:15 +04:00
|
|
|
|
|
|
|
/* mask - to handle wrap around */
|
|
|
|
unsigned int mask;
|
2004-08-13 23:49:13 +04:00
|
|
|
};
|
|
|
|
typedef struct ompi_cb_fifo_t ompi_cb_fifo_t;
|
2004-08-13 03:31:15 +04:00
|
|
|
|
2004-08-17 03:37:07 +04:00
|
|
|
/**
|
|
|
|
* Return the fifo size
|
|
|
|
*
|
|
|
|
* @param fifo Pointer to data structure defining this fifo (IN)
|
|
|
|
*
|
|
|
|
* @returncode fifo size
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static inline int ompi_cb_fifo_size(ompi_cb_fifo_t *fifo) {
|
|
|
|
|
2007-03-05 17:27:26 +03:00
|
|
|
return fifo->mask + 1;
|
2004-08-17 03:37:07 +04:00
|
|
|
}
|
|
|
|
|
2004-11-07 01:00:24 +03:00
|
|
|
/**
|
|
|
|
* Initialize a fifo
|
|
|
|
*
|
|
|
|
* @param size_of_fifo Length of fifo array (IN)
|
|
|
|
*
|
|
|
|
* @param fifo_memory_locality_index Locality index to apply to
|
|
|
|
* the fifo array. Not currently
|
|
|
|
* in use (IN)
|
|
|
|
*
|
|
|
|
* @param tail_memory_locality_index Locality index to apply to the
|
|
|
|
* head control structure. Not
|
|
|
|
* currently in use (IN)
|
|
|
|
*
|
|
|
|
* @param tail_memory_locality_index Locality index to apply to the
|
|
|
|
* tail control structure. Not
|
|
|
|
* currently in use (IN)
|
|
|
|
*
|
|
|
|
* @param fifo Pointer to data structure defining this fifo (IN)
|
|
|
|
*
|
|
|
|
* @param memory_allocator Pointer to the memory allocator to use
|
|
|
|
* to allocate memory for this fifo. (IN)
|
|
|
|
*
|
|
|
|
* @returncode Error code
|
|
|
|
*
|
|
|
|
*/
|
2007-03-05 17:27:26 +03:00
|
|
|
static inline int ompi_cb_fifo_init(int size_of_fifo,
|
2004-11-07 01:00:24 +03:00
|
|
|
int lazy_free_freq, int fifo_memory_locality_index,
|
|
|
|
int head_memory_locality_index, int tail_memory_locality_index,
|
2007-03-05 17:27:26 +03:00
|
|
|
ompi_cb_fifo_t *fifo, ptrdiff_t offset,
|
|
|
|
mca_mpool_base_module_t *memory_allocator)
|
2004-11-07 01:00:24 +03:00
|
|
|
{
|
2007-03-05 17:27:26 +03:00
|
|
|
int i, size;
|
|
|
|
char *buf;
|
2004-11-07 01:00:24 +03:00
|
|
|
|
2007-03-05 17:27:26 +03:00
|
|
|
/* verify that size is power of 2, and greater that 0 - if not,
|
2004-11-07 01:00:24 +03:00
|
|
|
* round up */
|
2007-03-05 17:27:26 +03:00
|
|
|
if(size_of_fifo <= 0) {
|
2004-11-07 01:00:24 +03:00
|
|
|
return OMPI_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set fifo size */
|
2007-03-05 17:27:26 +03:00
|
|
|
size = opal_round_up_to_nearest_pow2(size_of_fifo);
|
2004-11-07 01:00:24 +03:00
|
|
|
|
|
|
|
/* set lazy free frequence */
|
2007-03-05 17:27:26 +03:00
|
|
|
if((lazy_free_freq <= 0) || (lazy_free_freq > size)) {
|
2004-11-07 01:00:24 +03:00
|
|
|
return OMPI_ERROR;
|
|
|
|
}
|
2007-03-05 17:27:26 +03:00
|
|
|
|
|
|
|
fifo->lazy_free_frequency = lazy_free_freq;
|
2004-11-07 01:00:24 +03:00
|
|
|
|
|
|
|
/* this will be used to mask off the higher order bits,
|
|
|
|
* and use the & operator for the wrap-around */
|
2007-03-05 17:27:26 +03:00
|
|
|
fifo->mask = (size - 1);
|
2004-11-07 01:00:24 +03:00
|
|
|
|
|
|
|
/* allocate fifo array */
|
2007-03-05 17:27:26 +03:00
|
|
|
buf = memory_allocator->mpool_alloc(memory_allocator,
|
|
|
|
sizeof(void *) * size + 2*CACHE_LINE_SIZE, CACHE_LINE_SIZE, 0,
|
|
|
|
NULL);
|
|
|
|
if (NULL == buf) {
|
2004-11-07 01:00:24 +03:00
|
|
|
return OMPI_ERR_OUT_OF_RESOURCE;
|
|
|
|
}
|
2007-03-05 17:27:26 +03:00
|
|
|
fifo->queue = (volatile void**)(buf + 2*CACHE_LINE_SIZE);
|
|
|
|
/* buffer address in a receiver address space */
|
|
|
|
fifo->recv_queue = (volatile void**)((char*)fifo->queue - offset);
|
2004-11-07 01:00:24 +03:00
|
|
|
/* initialize the queue entries */
|
2007-03-05 17:27:26 +03:00
|
|
|
for (i = 0; i < size; i++) {
|
2004-11-07 01:00:24 +03:00
|
|
|
fifo->queue[i] = OMPI_CB_FREE;
|
|
|
|
}
|
|
|
|
|
2007-03-05 17:27:26 +03:00
|
|
|
fifo->head = (ompi_cb_fifo_ctl_t*)buf;
|
|
|
|
/* head address in a receiver address space */
|
|
|
|
fifo->recv_head = (ompi_cb_fifo_ctl_t*)((char*)fifo->head - offset);
|
|
|
|
fifo->tail = (ompi_cb_fifo_ctl_t*)(buf + CACHE_LINE_SIZE);
|
2004-11-07 01:00:24 +03:00
|
|
|
|
|
|
|
/* initialize the head structure */
|
2005-07-04 01:38:51 +04:00
|
|
|
opal_atomic_unlock(&(fifo->head->lock));
|
2004-11-07 01:00:24 +03:00
|
|
|
fifo->head->fifo_index=0;
|
|
|
|
fifo->head->num_to_clear=0;
|
|
|
|
|
|
|
|
/* initialize the head structure */
|
2005-07-04 01:38:51 +04:00
|
|
|
opal_atomic_unlock(&(fifo->tail->lock));
|
2004-11-07 01:00:24 +03:00
|
|
|
fifo->tail->fifo_index=0;
|
|
|
|
fifo->tail->num_to_clear=0;
|
|
|
|
|
2007-03-05 17:27:26 +03:00
|
|
|
/* recalculate tail address in a receiver address space */
|
|
|
|
fifo->tail = (ompi_cb_fifo_ctl_t*)((char*)fifo->tail - offset);
|
2004-11-07 01:00:24 +03:00
|
|
|
|
|
|
|
/* return */
|
2007-01-20 02:28:04 +03:00
|
|
|
return OMPI_SUCCESS;
|
2004-11-07 01:00:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* function to cleanup the fifo
|
|
|
|
*
|
|
|
|
* @param fifo Pointer to data structure defining this fifo (IN)
|
|
|
|
*
|
|
|
|
* @param memory_allocator Pointer to the memory allocator to use
|
|
|
|
* to allocate memory for this fifo. (IN)
|
|
|
|
*
|
|
|
|
*/
|
2007-03-05 17:27:26 +03:00
|
|
|
static inline int ompi_cb_fifo_free(ompi_cb_fifo_t *fifo,
|
|
|
|
mca_mpool_base_module_t *memory_allocator)
|
2004-11-07 01:00:24 +03:00
|
|
|
{
|
|
|
|
char *ptr;
|
|
|
|
|
|
|
|
/* make sure null fifo is not passed in */
|
2007-03-05 17:27:26 +03:00
|
|
|
if(NULL == fifo) {
|
2004-11-07 01:00:24 +03:00
|
|
|
return OMPI_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* free fifo array */
|
2007-03-05 17:27:26 +03:00
|
|
|
if(OMPI_CB_NULL != fifo->head){
|
2004-11-07 01:00:24 +03:00
|
|
|
ptr=(char *)(fifo->head);
|
2005-06-22 01:20:23 +04:00
|
|
|
memory_allocator->mpool_free(memory_allocator, ptr, NULL);
|
2007-03-05 17:27:26 +03:00
|
|
|
fifo->queue = (volatile void**)OMPI_CB_NULL;
|
2004-11-07 01:00:24 +03:00
|
|
|
}
|
|
|
|
|
2007-01-20 02:28:04 +03:00
|
|
|
return OMPI_SUCCESS;
|
2004-11-07 01:00:24 +03:00
|
|
|
}
|
2007-03-05 17:27:26 +03:00
|
|
|
|
2004-11-07 01:00:24 +03:00
|
|
|
/**
|
|
|
|
* Write pointer to the specified slot
|
|
|
|
*
|
|
|
|
* @param slot Slot index (IN)
|
|
|
|
*
|
|
|
|
* @param data Pointer value to write in specified slot (IN)
|
|
|
|
*
|
|
|
|
* @param fifo Pointer to data structure defining this fifo (IN)
|
|
|
|
*
|
|
|
|
* @returncode Slot index to which data is written
|
|
|
|
*
|
|
|
|
*/
|
2007-03-05 17:27:26 +03:00
|
|
|
static inline int ompi_cb_fifo_write_to_slot(int slot, void* data,
|
2004-11-07 01:00:24 +03:00
|
|
|
ompi_cb_fifo_t *fifo)
|
|
|
|
{
|
|
|
|
volatile void **ptr;
|
|
|
|
/* make sure that this slot is already reserved */
|
|
|
|
ptr=fifo->queue;
|
|
|
|
if (ptr[slot] == OMPI_CB_RESERVED ) {
|
2007-03-05 17:27:26 +03:00
|
|
|
opal_atomic_rmb();
|
2004-11-07 01:00:24 +03:00
|
|
|
ptr[slot] = data;
|
2007-03-05 17:27:26 +03:00
|
|
|
opal_atomic_wmb();
|
2004-11-07 01:00:24 +03:00
|
|
|
return slot;
|
|
|
|
}
|
2007-01-20 02:28:04 +03:00
|
|
|
|
|
|
|
return OMPI_CB_ERROR;
|
2004-11-07 01:00:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Try to write pointer to the head of the queue
|
|
|
|
*
|
|
|
|
* @param data Pointer value to write in specified slot (IN)
|
|
|
|
*
|
|
|
|
* @param fifo Pointer to data structure defining this fifo (IN)
|
|
|
|
*
|
|
|
|
* @returncode Slot index to which data is written
|
|
|
|
*
|
|
|
|
*/
|
2007-03-05 17:27:26 +03:00
|
|
|
static inline int ompi_cb_fifo_write_to_head(void *data, ompi_cb_fifo_t *fifo)
|
2004-11-07 01:00:24 +03:00
|
|
|
{
|
|
|
|
volatile void **ptr;
|
|
|
|
ompi_cb_fifo_ctl_t *h_ptr;
|
2007-03-05 17:27:26 +03:00
|
|
|
int index;
|
2004-11-07 01:00:24 +03:00
|
|
|
|
|
|
|
h_ptr=fifo->head;
|
|
|
|
ptr=fifo->queue;
|
2007-03-05 17:27:26 +03:00
|
|
|
index = h_ptr->fifo_index;
|
2007-01-19 22:48:06 +03:00
|
|
|
|
|
|
|
/* make sure the head is pointing at a free element */
|
2007-03-05 17:27:26 +03:00
|
|
|
if (ptr[index] == OMPI_CB_FREE) {
|
|
|
|
opal_atomic_rmb();
|
|
|
|
ptr[index] = data;
|
2006-02-16 23:14:33 +03:00
|
|
|
opal_atomic_wmb();
|
2007-03-05 17:27:26 +03:00
|
|
|
h_ptr->fifo_index = (index + 1) & fifo->mask;
|
|
|
|
return index;
|
2004-11-07 01:00:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* return */
|
2007-03-05 17:27:26 +03:00
|
|
|
return OMPI_CB_ERROR;
|
2004-11-07 01:00:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reserve slot in the fifo array
|
|
|
|
*
|
|
|
|
* @param fifo Pointer to data structure defining this fifo (IN)
|
|
|
|
*
|
|
|
|
* @returncode Slot index to which data is written
|
|
|
|
*
|
|
|
|
* @returncode OMPI_CB_ERROR failed to allocate index
|
|
|
|
*
|
|
|
|
*/
|
2007-03-05 17:27:26 +03:00
|
|
|
static inline int ompi_cb_fifo_get_slot(ompi_cb_fifo_t *fifo)
|
2004-11-07 01:00:24 +03:00
|
|
|
{
|
2007-03-05 17:27:26 +03:00
|
|
|
return ompi_cb_fifo_write_to_head(OMPI_CB_RESERVED, fifo);
|
2004-11-07 01:00:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Try to read pointer from the tail of the queue
|
|
|
|
*
|
|
|
|
* @param data Pointer to where data was be written (OUT)
|
|
|
|
*
|
|
|
|
* @param fifo Pointer to data structure defining this fifo (IN)
|
|
|
|
*
|
|
|
|
* @param flush_entries_read force the lazy free to happen (IN)
|
|
|
|
*
|
|
|
|
* @param queue_empty checks to see if the fifo is empty, but only if
|
|
|
|
* flush_entries_read is set (OUT)
|
|
|
|
*
|
|
|
|
* @returncode Slot index to which data is written
|
|
|
|
*
|
|
|
|
*/
|
2007-03-05 17:27:26 +03:00
|
|
|
static inline void *ompi_cb_fifo_read_from_tail(
|
2004-11-07 01:00:24 +03:00
|
|
|
ompi_cb_fifo_t *fifo,
|
|
|
|
bool flush_entries_read, bool *queue_empty)
|
2005-01-18 00:26:17 +03:00
|
|
|
{
|
2007-03-05 17:27:26 +03:00
|
|
|
int index, i;
|
2005-01-18 00:26:17 +03:00
|
|
|
volatile void **q_ptr;
|
2007-03-05 17:27:26 +03:00
|
|
|
ompi_cb_fifo_ctl_t *t_ptr;
|
|
|
|
void *read_from_tail;
|
2005-01-18 00:26:17 +03:00
|
|
|
|
|
|
|
*queue_empty=false;
|
|
|
|
|
|
|
|
t_ptr=fifo->tail;
|
2007-03-05 17:27:26 +03:00
|
|
|
q_ptr=fifo->recv_queue;
|
|
|
|
index = t_ptr->fifo_index;
|
|
|
|
read_from_tail = (void *)q_ptr[index];
|
|
|
|
opal_atomic_rmb();
|
2005-01-18 00:26:17 +03:00
|
|
|
|
|
|
|
/* check to see that the data is valid */
|
2007-03-05 17:27:26 +03:00
|
|
|
if ((read_from_tail == OMPI_CB_FREE) ||
|
|
|
|
(read_from_tail == OMPI_CB_RESERVED)) {
|
|
|
|
return (void*)OMPI_CB_FREE;
|
2005-01-18 00:26:17 +03:00
|
|
|
}
|
|
|
|
|
2007-03-05 17:27:26 +03:00
|
|
|
/* increment counter for later lazy free */
|
2005-01-18 00:26:17 +03:00
|
|
|
t_ptr->num_to_clear++;
|
|
|
|
|
2007-03-05 17:27:26 +03:00
|
|
|
t_ptr->fifo_index = (index + 1) & fifo->mask;
|
2005-01-18 00:26:17 +03:00
|
|
|
|
|
|
|
/* check to see if time to do a lazy free of queue slots */
|
|
|
|
if ( (t_ptr->num_to_clear == fifo->lazy_free_frequency) ||
|
|
|
|
flush_entries_read ) {
|
2007-03-05 17:27:26 +03:00
|
|
|
ompi_cb_fifo_ctl_t *h_ptr = fifo->recv_head;
|
|
|
|
index = (index - t_ptr->num_to_clear + 1) & fifo->mask;
|
2005-01-18 00:26:17 +03:00
|
|
|
|
|
|
|
for (i = 0; i < t_ptr->num_to_clear; i++) {
|
2007-03-05 17:27:26 +03:00
|
|
|
q_ptr[index] = OMPI_CB_FREE;
|
|
|
|
index = (index + 1) & fifo->mask;
|
2005-01-18 00:26:17 +03:00
|
|
|
}
|
2007-03-05 17:27:26 +03:00
|
|
|
opal_atomic_wmb();
|
2005-01-18 00:26:17 +03:00
|
|
|
t_ptr->num_to_clear = 0;
|
|
|
|
|
|
|
|
/* check to see if queue is empty */
|
|
|
|
if( flush_entries_read &&
|
|
|
|
(t_ptr->fifo_index == h_ptr->fifo_index) ) {
|
|
|
|
*queue_empty=true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return read_from_tail;
|
|
|
|
}
|
2004-11-07 01:00:24 +03:00
|
|
|
|
2004-08-13 03:31:15 +04:00
|
|
|
#endif /* !_OMPI_CIRCULAR_BUFFER_FIFO */
|