queue implement reminder.
#ifndef __FF_QUEUE_TEMPLATE__
#define __FF_QUEUE_TEMPLATE__
#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include <SDL/SDL.h>
#include <SDL/SDL_mutex.h>
#include <SDL/SDL_thread.h>
#if 0
#define LOCK_TRACE(tag) av_log(NULL, AV_LOG_DEBUG, "[%s-%d]%s.\n", __func__, __LINE__, tag)
#else
#define LOCK_TRACE(arg...) ((void)0)
#endif
#ifdef __NOTE__ //note only
#define _queue_peek_readable
#define _queue_init
#define _queue_flush
#define _queue_abort
#define _queue_destory
#define _queue_nb_remaining
#define _queue_push
#define _queue_pop
#define _queue_peek_writable
#endif
#define QUEUE_TEMPLATE(TYPE) \
typedef struct TYPE ## _QUEUE { \
TYPE **frame; \
int rindex; \
int windex; \
int size; \
int max_size; \
int abort_request; \
SDL_mutex *mutex; \
SDL_cond *cond; \
TYPE *(*alloc_func)(void); \
void (*free_func)(void* unit); \
}TYPE ## _QUEUE; \
\
static inline int TYPE ##_queue_init(TYPE ## _QUEUE *q, int max_size, TYPE *(*alloc_func)(), void (*free_func)(void* unit)) \
{ \
int i; \
memset(q, 0, sizeof(TYPE ## _QUEUE)); \
if (!(q->mutex = SDL_CreateMutex())) \
return -ENOMEM; \
if (!(q->cond = SDL_CreateCond())) \
return -ENOMEM; \
q->max_size = max_size; \
q->alloc_func = alloc_func; \
q->free_func = free_func; \
q->frame = (TYPE**)malloc(sizeof(TYPE*)*max_size); \
if (!q->frame) \
return -ENOMEM; \
for (i=0; i<max_size; i++){ \
q->frame[i] = alloc_func ? (alloc_func()) : (TYPE*)malloc(sizeof(TYPE));\
if (!q->frame[i]) \
return -ENOMEM; \
} \
return 0; \
} \
\
\
static inline void TYPE ##_queue_flush(TYPE ## _QUEUE *q) \
{ \
SDL_LockMutex(q->mutex); \
LOCK_TRACE("Lock"); \
q->size = 0; \
q->rindex = 0; \
q->windex = 0; \
SDL_UnlockMutex(q->mutex); \
LOCK_TRACE("UNLock"); \
} \
\
static inline void TYPE ##_queue_abort(TYPE ## _QUEUE *q) \
{ \
LOCK_TRACE("Lock"); \
SDL_LockMutex(q->mutex); \
q->abort_request = 1; \
SDL_CondSignal(q->cond); \
SDL_UnlockMutex(q->mutex); \
LOCK_TRACE("UNLock"); \
} \
\
static inline void TYPE ##_queue_destory(TYPE ## _QUEUE *q) \
{ \
int i; \
LOCK_TRACE("Lock"); \
SDL_LockMutex(q->mutex); \
for (i = 0; i < q->max_size; i++) { \
if (q->free_func) \
q->free_func(q->frame[i]); \
else \
free(q->frame[i]); \
} \
free(q->frame); \
SDL_UnlockMutex(q->mutex); \
LOCK_TRACE("UNLock"); \
SDL_DestroyMutex(q->mutex); \
SDL_DestroyCond(q->cond); \
} \
\
static inline int TYPE ##_queue_nb_remaining(TYPE ## _QUEUE *q) \
{return q->size;} \
\
static inline void TYPE ##_queue_signal(TYPE ## _QUEUE *q) \
{ \
SDL_LockMutex(q->mutex); \
LOCK_TRACE("Lock"); \
SDL_CondSignal(q->cond); \
SDL_UnlockMutex(q->mutex); \
LOCK_TRACE("UNLock"); \
} \
\
static inline void TYPE ##_queue_push(TYPE ## _QUEUE *q) \
{ \
if (++q->windex == q->max_size) \
q->windex = 0; \
LOCK_TRACE("Lock"); \
SDL_LockMutex(q->mutex); \
q->size++; \
SDL_CondSignal(q->cond); \
SDL_UnlockMutex(q->mutex); \
LOCK_TRACE("UNLock"); \
} \
\
static inline void *TYPE ##_queue_peek_writable(TYPE ## _QUEUE *q, int block) \
{ \
LOCK_TRACE("Lock"); \
SDL_LockMutex(q->mutex); \
while (q->size >= q->max_size && !q->abort_request) \
{ \
if (block){ \
LOCK_TRACE("Wait"); \
SDL_CondWait(q->cond, q->mutex); \
} \
else{ \
SDL_UnlockMutex(q->mutex); \
LOCK_TRACE("UNLock"); \
return NULL; \
} \
} \
SDL_UnlockMutex(q->mutex); \
LOCK_TRACE("UNLock"); \
return (q->abort_request) ? NULL : q->frame[q->windex]; \
} \
\
static inline void TYPE ##_queue_pop(TYPE ## _QUEUE *q) \
{ \
if (++q->rindex == q->max_size) \
q->rindex = 0; \
LOCK_TRACE("Lock"); \
SDL_LockMutex(q->mutex); \
q->size--; \
LOCK_TRACE("Signal"); \
SDL_CondSignal(q->cond); \
SDL_UnlockMutex(q->mutex); \
LOCK_TRACE("UNLock"); \
} \
\
static inline void *TYPE ##_queue_peek_readable(TYPE ## _QUEUE *q, int block) \
{ \
LOCK_TRACE("Lock"); \
SDL_LockMutex(q->mutex); \
while (q->size <= 0 && !q->abort_request) \
{ \
if (block){ \
LOCK_TRACE("Wait"); \
SDL_CondWait(q->cond, q->mutex); \
} \
else{ \
SDL_UnlockMutex(q->mutex); \
LOCK_TRACE("UNLock"); \
return NULL; \
} \
} \
SDL_UnlockMutex(q->mutex); \
LOCK_TRACE("UNLock"); \
return (q->abort_request) ? NULL : q->frame[q->rindex]; \
}
#ifdef __TEST__QUEUE__
typedef int MINT;
MINT *alloc_mint()
{
MINT *ptr = (MINT*)malloc(sizeof(MINT));
memset(ptr, 0, sizeof(MINT));
return ptr;
}
void free_mint(void *mint)
{
free((int *)mint);
}
QUEUE_TEMPLATE(MINT);
MINT_QUEUE myqueue;
#define MAX_QUEUE_SIZE 32
int main(int argc, char *argv[])
{
int i=0;
int size = 0;
MINT *unit;
//MINT_queue_init(&myqueue, 8, NULL, NULL);
MINT_queue_init(&myqueue, MAX_QUEUE_SIZE, alloc_mint, free_mint);
assert(MINT_queue_nb_remaining(&myqueue) == 0);
for (i=0;i<MAX_QUEUE_SIZE/2;i++)
{
if ((unit = MINT_queue_peek_writable(&myqueue, 0)) != NULL)
{
*unit = i;
MINT_queue_push(&myqueue);
assert((MINT_queue_nb_remaining(&myqueue) == (i+1)) ||
(printf("nb[%d]=%d.\n", MINT_queue_nb_remaining(&myqueue), i+1), 0));
}
}
assert(MINT_queue_nb_remaining(&myqueue) == MAX_QUEUE_SIZE/2);
size = MINT_queue_nb_remaining(&myqueue);
for (i=0;i<MAX_QUEUE_SIZE/2;i++)
{
if ((unit = MINT_queue_peek_readable(&myqueue, 0)) != NULL)
{
assert((*unit == i) ||
(printf("unit[%d]=%d.\n", *unit, i), 0));
MINT_queue_pop(&myqueue);
assert(MINT_queue_nb_remaining(&myqueue) == size-1-i);
}
}
assert(MINT_queue_nb_remaining(&myqueue) == 0);
MINT_queue_flush(&myqueue);
assert(MINT_queue_nb_remaining(&myqueue) == 0);
printf("nb after flush: %d.\n", MINT_queue_nb_remaining(&myqueue));
MINT_queue_destory(&myqueue);
return 0;
}
#endif
#endif