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