blob: 4f8b07a6aea71e4493e3a52373fc4d0267660a47 [file] [log] [blame]
/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#if !defined(_FIFO_H_)
#define _FIFO_H_
#include <unistd.h>
#include "pthread.h"
#include "stdmacro.h"
#include "linkerset.h"
/* fifo_entry_t: FIFO entry handler information
*
* This type is the primary data which is placed into a FIFO.
*
* inv: fe_handler != NULL
* fe_handler is a function which is called to 'handle' the FIFO element.
*
* inv: fe_name != NULL
* fe_name is a string which identifies the fifo_entry_t.
* The names need not be unique; uniqueness is guaranteed by the
* fact that each 'fifo_entry_t' has a unique address.
*/
typedef struct fifo_entry_t {
void (*fe_handler)(void *);
const char *fe_name;
} fifo_entry_t;
/* fifo_node_t: A node which is stored in the fifo.
*
* inv: fn_prev != NULL
* inv: fn_next != NULL
* inv: fn_entry != NULL
* inv: fn_data is not managed by the FIFO system.
* It is the responsibility of the code which added the element
* to the FIFO, or the handler described by 'fn_entry' to manage
* any resources associated with 'fn_data'.
*/
typedef struct fifo_node_t fifo_node_t;
struct fifo_node_t {
fifo_node_t *fn_prev;
fifo_node_t *fn_next;
const fifo_entry_t *fn_entry;
void *fn_data;
};
/* fifo_t: generic FIFO descriptor.
*
* A FIFO is implemented using a mutex and an doubly linked list with
* a dummy head node. The mutex is used to ensure that the data
* structure is not corrupted via simultaneous access.
*
* Create: fifo_create()
* Destroy: fifo_destroy()
*
* inv: fifo_head != NULL
* inv: fifo empty -> fifo_head->fn_next == fifo_head
* inv: fifo empty -> fifo_head->fn_next == fifo->fn_prev
*/
typedef struct fifo_t {
fifo_node_t *fifo_head;
pthread_mutex_t fifo_mutex;
} fifo_t;
/* FIFO_ENTRY_NAME(<fifo name>)
*
* Creates an identifier based on the name of the FIFO. This name is
* used to create a unique 'FIFO entry type', and this unique type is
* used to ensure that different FIFO implementations cannot have
* incorrect elements inserted into them.
*/
#define FIFO_ENTRY_NAME(_type) \
XCONCAT(fifo_entry_, _type)
/* FIFO_ENTRY_TYPE(<fifo name>): Create a typename for a FIFO */
#define FIFO_ENTRY_TYPE(_type) \
XCONCAT(FIFO_ENTRY_NAME(_type), _t)
/* FIFO_DECLARE(<fifo name>): Declare types & variables for a FIFO.
*
* This macro creates a unique type and external function reference
* for a FIFO named '<fifo name>'.
*
* See FIFO_DEFINE.
*/
#define FIFO_DECLARE(_name) \
typedef struct FIFO_ENTRY_TYPE(_name) { \
fifo_entry_t entry; \
} FIFO_ENTRY_TYPE(_name); \
extern fifo_t *_name; \
extern unsigned XCONCAT(fifo_add_item_, _name)(fifo_t *fifo, \
const FIFO_ENTRY_TYPE(_name) *entry, \
void *data)
/* FIFO_ADD_ITEM: Add an item to the named FIFO.
*
* _name : The name of the fifo. See FIFO_DEFINE, FIFO_DECLARE
* _entry: The name of the FIFO entry handler. See FIFO_ENTRY.
* _data : The data which is passed as an argument to '_entry'.
*/
#define FIFO_ADD_ITEM(_name, _entry, _data) \
XCONCAT(fifo_add_item_, _name)(_name, \
__FIFO_DESCRIPTOR_ADDRESS(_name, \
_entry), \
_data)
/* FIFO_DEFINE(<fifo name>): Define types & variables for a FIFO.
*
* See FIFO_DECLARE.
*/
#define FIFO_DEFINE(_name) \
LINKERSET_DECLARE(XCONCAT(fifo_entry_, _name)); \
fifo_t *_name; \
unsigned XCONCAT(fifo_add_item_, _name)(fifo_t *fifo, \
const FIFO_ENTRY_TYPE(_name) *entry, \
void *data) \
{ \
return __fifo_add_item(fifo, &entry->entry, data); \
}
/* __FIFO_DESCRIPTOR_ID: Creates the name of the internal FIFO descriptor.
*
* Internal use only.
*
* _fifo: The name of the FIFO. See FIFO_DECLARE().
* _id : The name of the FIFO entry. See FIFO_ENTRY().
*/
#define __FIFO_DESCRIPTOR_ID(_fifo, _id) \
XCONCAT(__fifo_descriptor_, XCONCAT(_fifo, XCONCAT(_, _id)))
/* __FIFO_DESCRIPTOR_ADDRESS: Obtains address of the descrbied FIFO
* descriptor.
*
* Internal use only.
*
* _fifo: The name of the FIFO. See FIFO_DECLARE().
* _id : The name of the FIFO entry. See FIFO_ENTRY().
*/
#define __FIFO_DESCRIPTOR_ADDRESS(_fifo, _id) \
&__FIFO_DESCRIPTOR_ID(_fifo, _id)
/* __FIFO_ENTRY_FUNCTION: Creates function name for FIFO entry handler.
*
* Internal use only.
*/
#define __FIFO_ENTRY_FUNCTION(_fifo, _id) \
XCONCAT(fifo_handler_, XCONCAT(_fifo, XCONCAT(_, _id)))
/* FIFO_ENTRY: Describes a handler for a FIFO entry.
*
* _name : String literal name which describes the handler.
* _fifo : The name of the fifo. See FIFO_DECLARE().
* _id : The name of the handler.
* This must be a valid C identifier, and it is used
* to create a function name for the FIFO element
* handler code.
* _handler: Code used to handle the FIFO element.
*/
#define FIFO_ENTRY(_name, _fifo, _id, _handler) \
static void __FIFO_ENTRY_FUNCTION(_fifo, _id)(void *data) \
{ \
_handler; \
} \
static const FIFO_ENTRY_TYPE(_fifo) \
__FIFO_DESCRIPTOR_ID(_fifo, _id) = { \
.entry = { \
.fe_name = _name, \
.fe_handler = __FIFO_ENTRY_FUNCTION(_fifo, _id), \
}, \
}; \
LINKERSET_ADD_ITEM(FIFO_ENTRY_NAME(_fifo), \
__FIFO_DESCRIPTOR_ID(_fifo, _id))
/* FIFO_EVENT_ITERATE: Iterate over all FIFO elements
*
* _fifo: The name of the FIFO. See FIFO_DECLARE().
* _var : Locally created variable name. Use in '_code'.
* _code: Code to be executed for each FIFO element type.
*/
#define FIFO_ELEMENT_ITERATE(_fifo, _var, _code) \
LINKERSET_ITERATE(FIFO_ENTRY_NAME(_fifo), _var, _code);
/* __fifo_add_item: Add an item to the end of the work fifo.
* INTERNAL USE ONLY.
*
* result == 1 -> Successfully added.
* result == 0 -> Entry not added.
*
* result == 1 -> 'data' is managed (i.e., free()) by 'handler'.
* result == 0 -> 'data' is managed (i.e., free()) by the caller
* of this function.
*/
unsigned __fifo_add_item(fifo_t *fifo,
const fifo_entry_t *handler,
void *data);
/* fifo_monitor_work: Function which monitors the fifo, and
* dispatches to the handler for each element.
*
* thread_name: The name of the thread running this function.
* fifo : The FIFO to be monitored.
* sleep_usec : Time to wait between checking if FIFO is not empty.
*/
void fifo_monitor_work(const char *thread_name,
fifo_t *fifo,
useconds_t sleep_usec);
fifo_t *fifo_create(void);
void fifo_destroy(fifo_t *fifo);
#endif