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);
72 return AVERROR(ENOMEM);
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);
105 int av_thread_message_queue_nb_elems(AVThreadMessageQueue *mq)
109 pthread_mutex_lock(&mq->lock);
110 ret = av_fifo_size(mq->fifo);
111 pthread_mutex_unlock(&mq->lock);
112 return ret / mq->elsize;
114 return AVERROR(ENOSYS);
120 static int av_thread_message_queue_send_locked(AVThreadMessageQueue *mq,
124 while (!mq->err_send && av_fifo_space(mq->fifo) < mq->elsize) {
125 if ((flags & AV_THREAD_MESSAGE_NONBLOCK))
126 return AVERROR(EAGAIN);
127 pthread_cond_wait(&mq->cond_send, &mq->lock);
131 av_fifo_generic_write(mq->fifo, msg, mq->elsize, NULL);
132 /* one message is sent, signal one receiver */
133 pthread_cond_signal(&mq->cond_recv);
137 static int av_thread_message_queue_recv_locked(AVThreadMessageQueue *mq,
141 while (!mq->err_recv && av_fifo_size(mq->fifo) < mq->elsize) {
142 if ((flags & AV_THREAD_MESSAGE_NONBLOCK))
143 return AVERROR(EAGAIN);
144 pthread_cond_wait(&mq->cond_recv, &mq->lock);
146 if (av_fifo_size(mq->fifo) < mq->elsize)
148 av_fifo_generic_read(mq->fifo, msg, mq->elsize, NULL);
149 /* one message space appeared, signal one sender */
150 pthread_cond_signal(&mq->cond_send);
154 #endif /* HAVE_THREADS */
156 int av_thread_message_queue_send(AVThreadMessageQueue *mq,
163 pthread_mutex_lock(&mq->lock);
164 ret = av_thread_message_queue_send_locked(mq, msg, flags);
165 pthread_mutex_unlock(&mq->lock);
168 return AVERROR(ENOSYS);
169 #endif /* HAVE_THREADS */
172 int av_thread_message_queue_recv(AVThreadMessageQueue *mq,
179 pthread_mutex_lock(&mq->lock);
180 ret = av_thread_message_queue_recv_locked(mq, msg, flags);
181 pthread_mutex_unlock(&mq->lock);
184 return AVERROR(ENOSYS);
185 #endif /* HAVE_THREADS */
188 void av_thread_message_queue_set_err_send(AVThreadMessageQueue *mq,
192 pthread_mutex_lock(&mq->lock);
194 pthread_cond_broadcast(&mq->cond_send);
195 pthread_mutex_unlock(&mq->lock);
196 #endif /* HAVE_THREADS */
199 void av_thread_message_queue_set_err_recv(AVThreadMessageQueue *mq,
203 pthread_mutex_lock(&mq->lock);
205 pthread_cond_broadcast(&mq->cond_recv);
206 pthread_mutex_unlock(&mq->lock);
207 #endif /* HAVE_THREADS */
211 static void free_func_wrap(void *arg, void *msg, int size)
213 AVThreadMessageQueue *mq = arg;
218 void av_thread_message_flush(AVThreadMessageQueue *mq)
222 void *free_func = mq->free_func;
224 pthread_mutex_lock(&mq->lock);
225 used = av_fifo_size(mq->fifo);
227 for (off = 0; off < used; off += mq->elsize)
228 av_fifo_generic_peek_at(mq->fifo, mq, off, mq->elsize, free_func_wrap);
229 av_fifo_drain(mq->fifo, used);
230 /* only the senders need to be notified since the queue is empty and there
231 * is nothing to read */
232 pthread_cond_broadcast(&mq->cond_send);
233 pthread_mutex_unlock(&mq->lock);
234 #endif /* HAVE_THREADS */