parent
6e52fc3832
commit
4114651e59
@ -0,0 +1,70 @@ |
|||||||
|
//
|
||||||
|
// Created by frank on 2021/08/08.
|
||||||
|
//
|
||||||
|
#include "block_queue.h" |
||||||
|
#include <stdlib.h> |
||||||
|
#include <libavcodec/avcodec.h> |
||||||
|
|
||||||
|
|
||||||
|
vlc_queue_t *vlc_queue_init(int size) { |
||||||
|
vlc_queue_t *queue = (vlc_queue_t *)(malloc(sizeof(vlc_queue_t))); |
||||||
|
queue->size = size; |
||||||
|
queue->next_to_read = 0; |
||||||
|
queue->next_to_write = 0; |
||||||
|
int i; |
||||||
|
queue->packets = (void **)(malloc(sizeof(*queue->packets) * size)); |
||||||
|
for (i = 0; i < size; i++) { |
||||||
|
queue->packets[i] = malloc(sizeof(AVPacket)); |
||||||
|
} |
||||||
|
pthread_mutex_init(&queue->mutex, NULL); |
||||||
|
pthread_cond_init(&queue->cond, NULL); |
||||||
|
return queue; |
||||||
|
} |
||||||
|
|
||||||
|
void vlc_queue_free(vlc_queue_t *queue) { |
||||||
|
int i; |
||||||
|
for (i = 0; i < queue->size; i++) { |
||||||
|
free(queue->packets[i]); |
||||||
|
} |
||||||
|
free(queue->packets); |
||||||
|
free(queue); |
||||||
|
pthread_cond_destroy(&queue->cond); |
||||||
|
pthread_mutex_destroy(&queue->mutex); |
||||||
|
} |
||||||
|
|
||||||
|
int vlc_queue_next(vlc_queue_t *queue, int current) { |
||||||
|
return (current + 1) % queue->size; |
||||||
|
} |
||||||
|
|
||||||
|
void *vlc_queue_push(vlc_queue_t *queue, void *data) { |
||||||
|
pthread_mutex_lock(&queue->mutex);//lock
|
||||||
|
int current = queue->next_to_write; |
||||||
|
int next_to_write; |
||||||
|
for (;;) { |
||||||
|
next_to_write = vlc_queue_next(queue, current); |
||||||
|
if (next_to_write != queue->next_to_read) { |
||||||
|
break; |
||||||
|
} |
||||||
|
pthread_cond_wait(&queue->cond, &queue->mutex); |
||||||
|
} |
||||||
|
queue->next_to_write = next_to_write; |
||||||
|
queue->packets[current] = data;//TODO
|
||||||
|
pthread_cond_broadcast(&queue->cond); |
||||||
|
pthread_mutex_unlock(&queue->mutex);//unlock
|
||||||
|
return queue->packets[current]; |
||||||
|
} |
||||||
|
|
||||||
|
void *vlc_queue_pop(vlc_queue_t *queue) { |
||||||
|
pthread_mutex_lock(&queue->mutex); |
||||||
|
int current = queue->next_to_read; |
||||||
|
for (;;) { |
||||||
|
if (queue->next_to_write != queue->next_to_read) { |
||||||
|
break; |
||||||
|
} |
||||||
|
pthread_cond_wait(&queue->cond, &queue->mutex); |
||||||
|
} |
||||||
|
queue->next_to_read = vlc_queue_next(queue, current); |
||||||
|
pthread_cond_broadcast(&queue->cond); |
||||||
|
pthread_mutex_unlock(&queue->mutex); |
||||||
|
return queue->packets[current]; |
||||||
|
} |
@ -0,0 +1,40 @@ |
|||||||
|
//
|
||||||
|
// Created by frank on 2021/08/08.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef BLOCK_QUEUE_H |
||||||
|
#define BLOCK_QUEUE_H |
||||||
|
|
||||||
|
#include <pthread.h> |
||||||
|
|
||||||
|
#ifdef __cplusplus |
||||||
|
extern "C" { |
||||||
|
#endif |
||||||
|
|
||||||
|
typedef struct vlc_queue { |
||||||
|
//the size of queue
|
||||||
|
int size; |
||||||
|
//packet array
|
||||||
|
void **packets; |
||||||
|
//the packet next to write
|
||||||
|
int next_to_write; |
||||||
|
//the packet next to read
|
||||||
|
int next_to_read; |
||||||
|
|
||||||
|
pthread_mutex_t mutex; |
||||||
|
pthread_cond_t cond; |
||||||
|
} vlc_queue_t; |
||||||
|
|
||||||
|
vlc_queue_t *vlc_queue_init(int size); |
||||||
|
|
||||||
|
void vlc_queue_free(vlc_queue_t *queue); |
||||||
|
|
||||||
|
void *vlc_queue_push(vlc_queue_t *queue, void *data); |
||||||
|
|
||||||
|
void *vlc_queue_pop(vlc_queue_t *queue); |
||||||
|
|
||||||
|
#endif //BLOCK_QUEUE_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus |
||||||
|
} |
||||||
|
#endif |
@ -1,154 +0,0 @@ |
|||||||
/*****************************************************************************
|
|
||||||
* queue.c: generic queue (FIFO) |
|
||||||
***************************************************************************** |
|
||||||
* Copyright (C) 2020 Rémi Denis-Courmont |
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or modify it |
|
||||||
* under the terms of the GNU Lesser General Public License as published by |
|
||||||
* the Free Software Foundation; either version 2.1 of the License, or |
|
||||||
* (at your option) any later version. |
|
||||||
* |
|
||||||
* 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 Lesser General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU Lesser 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. |
|
||||||
*****************************************************************************/ |
|
||||||
|
|
||||||
#include <assert.h> |
|
||||||
#include <stdint.h> |
|
||||||
#include <stdlib.h> |
|
||||||
|
|
||||||
#include "vlc_queue.h" |
|
||||||
|
|
||||||
/* Opaque struct type.
|
|
||||||
* |
|
||||||
* ISO C uses the same representation for all pointer-to-struct types. |
|
||||||
* Still different pointer types are not compatible, i.e. cannot alias. |
|
||||||
* So use memcpy() to read/write pointer values. |
|
||||||
*/ |
|
||||||
struct vlc_queue_entry; |
|
||||||
|
|
||||||
static void entry_set(struct vlc_queue_entry **pp, struct vlc_queue_entry *e) |
|
||||||
{ |
|
||||||
memcpy(pp, &e, sizeof (e)); |
|
||||||
} |
|
||||||
|
|
||||||
static struct vlc_queue_entry *entry_get(struct vlc_queue_entry *const *pp) |
|
||||||
{ |
|
||||||
struct vlc_queue_entry *e; |
|
||||||
|
|
||||||
memcpy(&e, pp, sizeof (e)); |
|
||||||
return e; |
|
||||||
} |
|
||||||
|
|
||||||
static struct vlc_queue_entry **next_p(const struct vlc_queue_entry *e, |
|
||||||
ptrdiff_t offset) |
|
||||||
{ |
|
||||||
return (struct vlc_queue_entry **)(((unsigned char *)e) + offset); |
|
||||||
} |
|
||||||
|
|
||||||
static void next_set(struct vlc_queue_entry *e, struct vlc_queue_entry *next, |
|
||||||
ptrdiff_t offset) |
|
||||||
{ |
|
||||||
entry_set(next_p(e, offset), next); |
|
||||||
} |
|
||||||
|
|
||||||
static struct vlc_queue_entry *next_get(const struct vlc_queue_entry *e, |
|
||||||
ptrdiff_t offset) |
|
||||||
{ |
|
||||||
return entry_get(next_p(e, offset)); |
|
||||||
} |
|
||||||
|
|
||||||
void vlc_queue_Init(vlc_queue_t *q, ptrdiff_t next_offset) |
|
||||||
{ |
|
||||||
q->first = NULL; |
|
||||||
q->lastp = &q->first; |
|
||||||
q->next_offset = next_offset; |
|
||||||
pthread_mutex_init(&q->lock, NULL); |
|
||||||
pthread_cond_init(&q->wait, NULL); |
|
||||||
} |
|
||||||
|
|
||||||
void vlc_queue_EnqueueUnlocked(vlc_queue_t *q, void *entry) |
|
||||||
{ |
|
||||||
struct vlc_queue_entry **lastp; |
|
||||||
const ptrdiff_t offset = q->next_offset; |
|
||||||
|
|
||||||
// vlc_mutex_assert(&q->lock);
|
|
||||||
assert(entry_get(q->lastp) == NULL); |
|
||||||
entry_set(q->lastp, entry); |
|
||||||
|
|
||||||
for (lastp = q->lastp; entry != NULL; entry = next_get(entry, offset)) |
|
||||||
lastp = next_p(entry, offset); |
|
||||||
|
|
||||||
q->lastp = lastp; |
|
||||||
vlc_queue_Signal(q); |
|
||||||
} |
|
||||||
|
|
||||||
void *vlc_queue_DequeueUnlocked(vlc_queue_t *q) |
|
||||||
{ |
|
||||||
// vlc_mutex_assert(&q->lock);
|
|
||||||
|
|
||||||
void *entry = q->first; |
|
||||||
const ptrdiff_t offset = q->next_offset; |
|
||||||
|
|
||||||
if (entry != NULL) { |
|
||||||
struct vlc_queue_entry *next = next_get(entry, offset); |
|
||||||
|
|
||||||
next_set(entry, NULL, offset); |
|
||||||
q->first = next; |
|
||||||
|
|
||||||
if (next == NULL) |
|
||||||
q->lastp = &q->first; |
|
||||||
} |
|
||||||
|
|
||||||
return entry; |
|
||||||
} |
|
||||||
|
|
||||||
void *vlc_queue_DequeueAllUnlocked(vlc_queue_t *q) |
|
||||||
{ |
|
||||||
// vlc_mutex_assert(&q->lock);
|
|
||||||
|
|
||||||
void *entry = q->first; |
|
||||||
|
|
||||||
q->first = NULL; |
|
||||||
q->lastp = &q->first; |
|
||||||
|
|
||||||
return entry; |
|
||||||
} |
|
||||||
|
|
||||||
void vlc_queue_Enqueue(vlc_queue_t *q, void *entry) |
|
||||||
{ |
|
||||||
vlc_queue_Lock(q); |
|
||||||
vlc_queue_EnqueueUnlocked(q, entry); |
|
||||||
vlc_queue_Unlock(q); |
|
||||||
} |
|
||||||
|
|
||||||
void *vlc_queue_Dequeue(vlc_queue_t *q) |
|
||||||
{ |
|
||||||
void *entry; |
|
||||||
|
|
||||||
vlc_queue_Lock(q); |
|
||||||
|
|
||||||
while (vlc_queue_IsEmpty(q)) |
|
||||||
vlc_queue_Wait(q); |
|
||||||
|
|
||||||
entry = vlc_queue_DequeueUnlocked(q); |
|
||||||
vlc_queue_Unlock(q); |
|
||||||
|
|
||||||
return entry; |
|
||||||
} |
|
||||||
|
|
||||||
void *vlc_queue_DequeueAll(vlc_queue_t *q) |
|
||||||
{ |
|
||||||
void *entry; |
|
||||||
|
|
||||||
vlc_queue_Lock(q); |
|
||||||
entry = vlc_queue_DequeueAllUnlocked(q); |
|
||||||
vlc_queue_Unlock(q); |
|
||||||
|
|
||||||
return entry; |
|
||||||
} |
|
@ -1,258 +0,0 @@ |
|||||||
/*****************************************************************************
|
|
||||||
* vlc_queue.h: generic queue functions |
|
||||||
***************************************************************************** |
|
||||||
* Copyright (C) 2020 Rémi Denis-Courmont |
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or modify it |
|
||||||
* under the terms of the GNU Lesser General Public License as published by |
|
||||||
* the Free Software Foundation; either version 2.1 of the License, or |
|
||||||
* (at your option) any later version. |
|
||||||
* |
|
||||||
* 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 Lesser General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU Lesser 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. |
|
||||||
*****************************************************************************/ |
|
||||||
|
|
||||||
#ifndef VLC_QUEUE_H |
|
||||||
#define VLC_QUEUE_H |
|
||||||
|
|
||||||
/**
|
|
||||||
* @defgroup queue Thread-safe queues (FIFO) |
|
||||||
* @ingroup cext |
|
||||||
* @{ |
|
||||||
* @file vlc_queue.h |
|
||||||
*/ |
|
||||||
|
|
||||||
#include <stdbool.h> |
|
||||||
#include <stdint.h> |
|
||||||
#include <string.h> |
|
||||||
#include <pthread.h> |
|
||||||
|
|
||||||
/**
|
|
||||||
* Opaque type for queue entry. |
|
||||||
*/ |
|
||||||
struct vlc_queue_entry; |
|
||||||
|
|
||||||
/**
|
|
||||||
* Thread-safe queue (a.k.a. FIFO). |
|
||||||
*/ |
|
||||||
typedef struct vlc_queue |
|
||||||
{ |
|
||||||
struct vlc_queue_entry *first; |
|
||||||
struct vlc_queue_entry **lastp; |
|
||||||
ptrdiff_t next_offset; |
|
||||||
pthread_mutex_t lock; |
|
||||||
pthread_cond_t wait; |
|
||||||
} vlc_queue_t; |
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes a queue. |
|
||||||
* |
|
||||||
* @param queue storage space for the queue |
|
||||||
* @param next_offset offset of the pointer to the next element |
|
||||||
* within a queue entry (as per @c offsetof()) |
|
||||||
*/ |
|
||||||
void vlc_queue_Init(vlc_queue_t *queue, ptrdiff_t next_offset); |
|
||||||
|
|
||||||
/**
|
|
||||||
* @defgroup queue_ll Queue internals |
|
||||||
* |
|
||||||
* Low-level queue functions. |
|
||||||
* |
|
||||||
* In some cases, the high-level queue functions do not exactly fit the |
|
||||||
* use case requirements, and it is necessary to access the queue internals. |
|
||||||
* This typically occurs when threads wait for elements to be added to the |
|
||||||
* queue at the same time as some other type of events. |
|
||||||
* @{ |
|
||||||
*/ |
|
||||||
/**
|
|
||||||
* Locks a queue. |
|
||||||
* |
|
||||||
* No more than one thread can lock a queue at any given time, and no other |
|
||||||
* thread can modify the queue while it is locked. |
|
||||||
* Accordingly, if the queue is already locked by another thread, this function |
|
||||||
* waits. |
|
||||||
* |
|
||||||
* Use vlc_queue_Unlock() to release the lock. |
|
||||||
* |
|
||||||
* @warning Recursively locking a single queue is undefined. |
|
||||||
* Also locking more than one queue at a time may lead to lock inversion: |
|
||||||
* mind the locking order! |
|
||||||
*/ |
|
||||||
static inline void vlc_queue_Lock(vlc_queue_t *q) |
|
||||||
{ |
|
||||||
pthread_mutex_lock(&q->lock); |
|
||||||
} |
|
||||||
|
|
||||||
/**
|
|
||||||
* Unlocks a queue. |
|
||||||
* |
|
||||||
* This releases the lock on a queue, allowing other threads to manipulate the |
|
||||||
* queue. The behaviour is undefined if the calling thread is not holding the |
|
||||||
* queue lock. |
|
||||||
*/ |
|
||||||
static inline void vlc_queue_Unlock(vlc_queue_t *q) |
|
||||||
{ |
|
||||||
pthread_mutex_unlock(&q->lock); |
|
||||||
} |
|
||||||
|
|
||||||
/**
|
|
||||||
* Wakes one thread waiting for a queue entry up. |
|
||||||
*/ |
|
||||||
static inline void vlc_queue_Signal(vlc_queue_t *q) |
|
||||||
{ |
|
||||||
pthread_cond_signal(&q->wait); |
|
||||||
} |
|
||||||
|
|
||||||
/**
|
|
||||||
* Waits for a queue entry. |
|
||||||
* |
|
||||||
* @note This function is a cancellation point. |
|
||||||
* In case of cancellation, the queue will be locked, |
|
||||||
* as is consistent for condition variable semantics. |
|
||||||
* |
|
||||||
* @bug This function should probably not be aware of cancellation. |
|
||||||
*/ |
|
||||||
static inline void vlc_queue_Wait(vlc_queue_t *q) |
|
||||||
{ |
|
||||||
pthread_cond_wait(&q->wait, &q->lock); |
|
||||||
} |
|
||||||
|
|
||||||
/**
|
|
||||||
* Queues an entry (without locking). |
|
||||||
* |
|
||||||
* This function enqueues an entry, or rather a linked-list of entries, in a |
|
||||||
* thread-safe queue, without taking the queue lock. |
|
||||||
* |
|
||||||
* @warning It is assumed that the caller already holds the queue lock; |
|
||||||
* otherwise the behaviour is undefined. |
|
||||||
* |
|
||||||
* @param entry NULL-terminated list of entries to queue |
|
||||||
* (if NULL, this function has no effects) |
|
||||||
*/ |
|
||||||
void vlc_queue_EnqueueUnlocked(vlc_queue_t *, void *entry); |
|
||||||
|
|
||||||
/**
|
|
||||||
* Dequeues the oldest entry (without locking). |
|
||||||
* |
|
||||||
* This function dequeues an entry from a thread-safe queue. It is assumed |
|
||||||
* that the caller already holds the queue lock; otherwise the behaviour is |
|
||||||
* undefined. |
|
||||||
* |
|
||||||
* @warning It is assumed that the caller already holds the queue lock; |
|
||||||
* otherwise the behaviour is undefined. |
|
||||||
* |
|
||||||
* @return the first entry in the queue, or NULL if the queue is empty |
|
||||||
*/ |
|
||||||
void *vlc_queue_DequeueUnlocked(vlc_queue_t *); |
|
||||||
|
|
||||||
/**
|
|
||||||
* Dequeues all entries (without locking). |
|
||||||
* |
|
||||||
* This is equivalent to calling vlc_queue_DequeueUnlocked() repeatedly until |
|
||||||
* the queue is emptied. However this function is much faster than that, as it |
|
||||||
* does not need to update the linked-list pointers. |
|
||||||
* |
|
||||||
* @warning It is assumed that the caller already holds the queue lock; |
|
||||||
* otherwise the behaviour is undefined. |
|
||||||
* |
|
||||||
* @return a linked-list of all entries (possibly NULL if none) |
|
||||||
*/ |
|
||||||
void *vlc_queue_DequeueAllUnlocked(vlc_queue_t *); |
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a queue is empty (without locking). |
|
||||||
* |
|
||||||
* @warning It is assumed that the caller already holds the queue lock; |
|
||||||
* otherwise the behaviour is undefined. |
|
||||||
* |
|
||||||
* @retval false the queue contains one or more entries |
|
||||||
* @retval true the queue is empty |
|
||||||
*/ |
|
||||||
static inline bool vlc_queue_IsEmpty(const vlc_queue_t *q) |
|
||||||
{ |
|
||||||
return q->first == NULL; |
|
||||||
} |
|
||||||
|
|
||||||
/** @} */ |
|
||||||
|
|
||||||
/**
|
|
||||||
* Queues an entry. |
|
||||||
* |
|
||||||
* This function enqueues an entry, or rather a linked-list of entries, in a |
|
||||||
* thread-safe queue. |
|
||||||
* |
|
||||||
* @param entry list of entries (if NULL, this function has no effects) |
|
||||||
*/ |
|
||||||
void vlc_queue_Enqueue(vlc_queue_t *, void *entry); |
|
||||||
|
|
||||||
/**
|
|
||||||
* Dequeues the oldest entry. |
|
||||||
* |
|
||||||
* This function dequeues an entry from a thread-safe queue. If the queue is |
|
||||||
* empty, it will wait until at least one entry is available. |
|
||||||
* |
|
||||||
* @param offset offset of the next pointer within a queue entry |
|
||||||
* |
|
||||||
* @return the first entry in the queue, or NULL if the queue is empty |
|
||||||
*/ |
|
||||||
void *vlc_queue_Dequeue(vlc_queue_t *); |
|
||||||
|
|
||||||
/**
|
|
||||||
* Dequeues all entries. |
|
||||||
* |
|
||||||
* This is equivalent to calling vlc_queue_Dequeue() repeatedly until the queue |
|
||||||
* is emptied. However this function is much faster than that, as it |
|
||||||
* does not need to update the linked-list pointers. |
|
||||||
* |
|
||||||
* @return a linked-list of all entries (possibly NULL if none) |
|
||||||
*/ |
|
||||||
void *vlc_queue_DequeueAll(vlc_queue_t *); |
|
||||||
|
|
||||||
/**
|
|
||||||
* @defgroup queue_killable Killable queues |
|
||||||
* |
|
||||||
* Thread-safe queues with an end flag. |
|
||||||
* |
|
||||||
* @{ |
|
||||||
*/ |
|
||||||
|
|
||||||
/**
|
|
||||||
* Marks a queue ended. |
|
||||||
*/ |
|
||||||
static inline void vlc_queue_Kill(vlc_queue_t *q, |
|
||||||
bool */*restrict*/ tombstone) |
|
||||||
{ |
|
||||||
vlc_queue_Lock(q); |
|
||||||
*tombstone = true; |
|
||||||
vlc_queue_Signal(q); |
|
||||||
vlc_queue_Unlock(q); |
|
||||||
pthread_cond_destroy(&q->wait); |
|
||||||
pthread_mutex_destroy(&q->lock); |
|
||||||
} |
|
||||||
|
|
||||||
/**
|
|
||||||
* Dequeues one entry from a killable queue. |
|
||||||
* |
|
||||||
* @return an entry, or NULL if the queue is empty and has been ended. |
|
||||||
*/ |
|
||||||
static inline void *vlc_queue_DequeueKillable(vlc_queue_t *q, |
|
||||||
bool */*restrict*/ tombstone) |
|
||||||
{ |
|
||||||
void *entry; |
|
||||||
|
|
||||||
vlc_queue_Lock(q); |
|
||||||
while (vlc_queue_IsEmpty(q) && !*tombstone) |
|
||||||
vlc_queue_Wait(q); |
|
||||||
|
|
||||||
entry = vlc_queue_DequeueUnlocked(q); |
|
||||||
vlc_queue_Unlock(q); |
|
||||||
return entry; |
|
||||||
} |
|
||||||
|
|
||||||
#endif |
|
Loading…
Reference in new issue