/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Most ideas and some code are copied from the linux' kernels * include/linux/skbuff.h */ #ifndef __TOOLS_FRAME_H #define __TOOLS_FRAME_H #include "SDL.h" #include "list.h" /** * struct frame_queue - sk_buff_head like frame queue * * @list: pointer to head and tail * @lock: mutex lock for serialize access * @len: exact number of queued frames */ struct frame_queue { struct list_head list; SDL_mutex *lock; size_t len; }; /** * struct frame - frame data structure (like sk_buff) * * @list: storage for double-linked &struct frame_queue list * @dev: pointer to private device/driver structure * @timestamp: space for the current timestamp * @cb: private driver data * @dcb: more reserved space for low-level / backend driver * @queue: selected frame queue / priority * @ref: reference counter * @alloced: maximum available space * @total_len: currently consumed and reserved memory * @len: current frame length * @head: points to the buffer head * @data: current frame data pointer * @tail: frame data tail pointer * @payload: frame data storage container */ struct frame { struct list_head list; void *dev; unsigned long timestamp; uint8_t cb[64]; union { struct list_head list; uint8_t raw_data[32]; } dcb; unsigned int queue; unsigned int ref; unsigned int alloced; unsigned int total_len; unsigned int len; uint8_t *head; uint8_t *data; uint8_t *tail; /* payload must be the last entry */ uint8_t payload[0]; }; /** * frame_put - append more data to &struct frame * * Allocate @size bytes from &struct frame tail and * returns a pointer to the requested location. * * @frame: frame to alter * @size: extra size */ static inline void *frame_put(struct frame *frame, unsigned int size) { void *tmp; BUG_ON(frame->total_len + size > frame->alloced); frame->len += size; frame->total_len += size; tmp = (void *) frame->tail; frame->tail += size; BUG_ON(frame->tail > (frame->payload + frame->alloced)); return tmp; } /** * frame_push - allocate head * * returns a pointer to a newly allocate area at &struct frame head. * * @frame: frame to modify * @size: requested extra size */ static inline void *frame_push(struct frame *frame, unsigned int size) { frame->len += size; frame->data -= size; BUG_ON(frame->data < frame->payload); return frame->data; } /** * frame_get - reference frame buffer * * grab a reference from the frame buffer, in order to * prevent it from being freed prematurely by a different user. * * @frame: frame pointer */ static inline struct frame *frame_get(struct frame *frame) { frame->ref++; return frame; } /** * frame_pull - remove space from &struct frame head * * Does the opposite of frame_push() and removes freed-up * space at the frames's head. * * @frame: pointer to frame structure * @size: bytes to remove from head */ static inline void *frame_pull(struct frame *frame, unsigned int size) { BUG_ON(frame->len < size); frame->len -= size; frame->total_len -= size; frame->data += size; return frame->data; } /** * frame_reserve - reserve frame headroom * * Reserve a certain amount of space to allow headroom manipulations * in the future. * * @frame: frame to adjust * @size: bytes to reserve */ static inline void frame_reserve(struct frame *frame, unsigned int size) { BUG_ON(frame->total_len + size > frame->alloced); BUG_ON(frame->len != 0); frame->total_len += size; frame->data += size; frame->tail += size; } /** * frame_trim - set frame length * * cut the frame to @size length. * * @frame: frame to be trimmed * @size: new length */ static inline void frame_trim(struct frame *frame, unsigned int size) { BUG_ON(size > frame->total_len); frame->len = size; frame->total_len = size; frame->data = frame->head; frame->tail = frame->head + size; } /** * frame_alloc - alloc and initialize new frame * * returns a newly created &struct frame object. * * @size: maximum frame size of the new frame */ static inline struct frame *frame_alloc(unsigned int size) { struct frame *tmp; tmp = malloc(size + sizeof(*tmp)); if (tmp != NULL) { memset(tmp, 0, sizeof(*tmp)); init_list_head(&tmp->list); init_list_head(&tmp->dcb.list); tmp->len = 0; tmp->total_len = 0; tmp->alloced = size; tmp->head = tmp->payload; tmp->data = tmp->payload; tmp->tail = tmp->payload; tmp->ref = 1; } return tmp; } /** * frame_free - unref and free frame * * Unreference frame and free it up, if all users are gone. * * @frame: frame to be freed */ static inline void frame_free(struct frame *frame) { if (!--frame->ref) free(frame); } /** * FRAME_WALK - MACRO walker * * Walks over all queued elements in &struct frame_queue * * NOTE: This function is vulnerable in concurrent access * scenarios without proper locking. * * @pos: current position inside the queue * @head: &struct frame_queue head */ #define FRAME_WALK(pos, head) \ list_for_each_entry((pos), &(head)->list, list) static inline void __frame_queue_init(struct frame_queue *queue) { queue->len = 0; init_list_head(&queue->list); } /** * frame_queue_init - initialize frame_queue * * Initialize the given &struct frame_queue object. * * @queue: frame_queue to be initialized */ static inline void frame_queue_init(struct frame_queue *queue) { queue->lock = SDL_CreateMutex(); __frame_queue_init(queue); } /** * frame_queue_len - returns number of queue elements * * @queue: frame_queue object */ static inline unsigned int frame_queue_len(struct frame_queue *queue) { return queue->len; } /** * frame_queue_empty - returns %TRUE whenever queue is empty * * @queue: frame_queue object */ static inline bool frame_queue_empty(struct frame_queue *queue) { return list_empty(&queue->list); } static inline void __frame_queue_head(struct frame_queue *queue, struct frame *frame) { list_add_head(&frame->list, &queue->list); queue->len++; } /** * frame_queue_head - queue a frame at the queues head * @queue: queue to use */ static inline void frame_queue_head(struct frame_queue *queue, struct frame *frame) { BUG_ON((SDL_mutexP(queue->lock) != 0)); __frame_queue_head(queue, frame); SDL_mutexV(queue->lock); } static inline void __frame_queue_tail(struct frame_queue *queue, struct frame *frame) { list_add_tail(&frame->list, &queue->list); queue->len++; } /** * frame_queue_head - queue a frame at the queues tail * @queue: queue to use */ static inline void frame_queue_tail(struct frame_queue *queue, struct frame *frame) { BUG_ON((SDL_mutexP(queue->lock) != 0)); __frame_queue_tail(queue, frame); SDL_mutexV(queue->lock); } static inline void __frame_unlink(struct frame_queue *queue, struct frame *frame) { list_del(&frame->list); queue->len--; } /** * frame_queue_unlink - remove a frame from the queue * @queue: queue to use * @frame: frame to remove */ static inline void frame_unlink(struct frame_queue *queue, struct frame *frame) { BUG_ON((SDL_mutexP(queue->lock) != 0)); __frame_unlink(queue, frame); SDL_mutexV(queue->lock); } static inline struct frame *__frame_dequeue(struct frame_queue *queue) { struct frame *tmp = NULL; if (!frame_queue_empty(queue)) { tmp = list_entry(queue->list.next, struct frame, list); __frame_unlink(queue, tmp); } return tmp; } /** * frame_dequeue - remove frame from the head of the queue * * @queue: queue to dequeue from */ static inline struct frame *frame_dequeue(struct frame_queue *queue) { struct frame *tmp; BUG_ON((SDL_mutexP(queue->lock) != 0)); tmp = __frame_dequeue(queue); SDL_mutexV(queue->lock); return tmp; } static inline void __frame_queue_purge(struct frame_queue *queue) { while (list_empty(&queue->list) == false) frame_free(__frame_dequeue(queue)); } /** * frame_queue_purge - frees all queued &struct frame objects * * @queue: queue to be freed */ static inline void frame_queue_purge(struct frame_queue *queue) { BUG_ON((SDL_mutexP(queue->lock) != 0)); __frame_queue_purge(queue); SDL_mutexV(queue->lock); } /** * frame_queue_kill - destroys frame_queue object * * Destroy object and frees up all remaining elements * * @queue: frame_queue victim */ static inline void frame_queue_kill(struct frame_queue *queue) { SDL_DestroyMutex(queue->lock); __frame_queue_purge(queue); } #endif /* __TOOLS_FRAME_H */