2 * Copyright (c) 2014 Nicolas George
4 * This file is part of FFmpeg.
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "threadmessage.h"
25 struct AVThreadMessageQueue {
29 pthread_cond_t cond_recv;
30 pthread_cond_t cond_send;
34 void (*free_func)(void *msg);
40 int av_thread_message_queue_alloc(AVThreadMessageQueue **mq,
45 AVThreadMessageQueue *rmq;
48 if (nelem > INT_MAX / elsize)
49 return AVERROR(EINVAL);
50 if (!(rmq = av_mallocz(sizeof(*rmq))))
51 return AVERROR(ENOMEM);
52 if ((ret = pthread_mutex_init(&rmq->lock, NULL))) {
56 if ((ret = pthread_cond_init(&rmq->cond_recv, NULL))) {
57 pthread_mutex_destroy(&rmq->lock);
61 if ((ret = pthread_cond_init(&rmq->cond_send, NULL))) {
62 pthread_cond_destroy(&rmq->cond_recv);
63 pthread_mutex_destroy(&rmq->lock);
67 if (!(rmq->fifo = av_fifo_alloc(elsize * nelem))) {
68 pthread_cond_destroy(&rmq->cond_send);
69 pthread_cond_destroy(&rmq->cond_recv);
70 pthread_mutex_destroy(&rmq->lock);
79 return AVERROR(ENOSYS);
80 #endif /* HAVE_THREADS */
83 void av_thread_message_queue_set_free_func(AVThreadMessageQueue *mq,
84 void (*free_func)(void *msg))
87 mq->free_func = free_func;
91 void av_thread_message_queue_free(AVThreadMessageQueue **mq)
95 av_thread_message_flush(*mq);
96 av_fifo_freep(&(*mq)->fifo);
97 pthread_cond_destroy(&(*mq)->cond_send);
98 pthread_cond_destroy(&(*mq)->cond_recv);
99 pthread_mutex_destroy(&(*mq)->lock);
107 static int av_thread_message_queue_send_locked(AVThreadMessageQueue *mq,
111 while (!mq->err_send && av_fifo_space(mq->fifo) < mq->elsize) {
112 if ((flags & AV_THREAD_MESSAGE_NONBLOCK))
113 return AVERROR(EAGAIN);
114 pthread_cond_wait(&mq->cond_send, &mq->lock);
118 av_fifo_generic_write(mq->fifo, msg, mq->elsize, NULL);
119 /* one message is sent, signal one receiver */
120 pthread_cond_signal(&mq->cond_recv);
124 static int av_thread_message_queue_recv_locked(AVThreadMessageQueue *mq,
128 while (!mq->err_recv && av_fifo_size(mq->fifo) < mq->elsize) {
129 if ((flags & AV_THREAD_MESSAGE_NONBLOCK))
130 return AVERROR(EAGAIN);
131 pthread_cond_wait(&mq->cond_recv, &mq->lock);
133 if (av_fifo_size(mq->fifo) < mq->elsize)
135 av_fifo_generic_read(mq->fifo, msg, mq->elsize, NULL);
136 /* one message space appeared, signal one sender */
137 pthread_cond_signal(&mq->cond_send);
141 #endif /* HAVE_THREADS */
143 int av_thread_message_queue_send(AVThreadMessageQueue *mq,
150 pthread_mutex_lock(&mq->lock);
151 ret = av_thread_message_queue_send_locked(mq, msg, flags);
152 pthread_mutex_unlock(&mq->lock);
155 return AVERROR(ENOSYS);
156 #endif /* HAVE_THREADS */
159 int av_thread_message_queue_recv(AVThreadMessageQueue *mq,
166 pthread_mutex_lock(&mq->lock);
167 ret = av_thread_message_queue_recv_locked(mq, msg, flags);
168 pthread_mutex_unlock(&mq->lock);
171 return AVERROR(ENOSYS);
172 #endif /* HAVE_THREADS */
175 void av_thread_message_queue_set_err_send(AVThreadMessageQueue *mq,
179 pthread_mutex_lock(&mq->lock);
181 pthread_cond_broadcast(&mq->cond_send);
182 pthread_mutex_unlock(&mq->lock);
183 #endif /* HAVE_THREADS */
186 void av_thread_message_queue_set_err_recv(AVThreadMessageQueue *mq,
190 pthread_mutex_lock(&mq->lock);
192 pthread_cond_broadcast(&mq->cond_recv);
193 pthread_mutex_unlock(&mq->lock);
194 #endif /* HAVE_THREADS */
198 static void free_func_wrap(void *arg, void *msg, int size)
200 AVThreadMessageQueue *mq = arg;
205 void av_thread_message_flush(AVThreadMessageQueue *mq)
209 void *free_func = mq->free_func;
211 pthread_mutex_lock(&mq->lock);
212 used = av_fifo_size(mq->fifo);
214 for (off = 0; off < used; off += mq->elsize)
215 av_fifo_generic_peek_at(mq->fifo, mq, off, mq->elsize, free_func_wrap);
216 av_fifo_drain(mq->fifo, used);
217 /* only the senders need to be notified since the queue is empty and there
218 * is nothing to read */
219 pthread_cond_broadcast(&mq->cond_send);
220 pthread_mutex_unlock(&mq->lock);
221 #endif /* HAVE_THREADS */