Remove redundant #inclusion of common.h, avcodec.h already #includes it.
[ffmpeg.git] / libavcodec / pthread.c
1 /*
2  * Copyright (c) 2004 Roman Shaposhnik.
3  *
4  * Many thanks to Steven M. Schultz for providing clever ideas and
5  * to Michael Niedermayer <michaelni@gmx.at> for writing initial
6  * implementation.
7  *
8  * This file is part of FFmpeg.
9  *
10  * FFmpeg is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * FFmpeg is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with FFmpeg; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23  *
24  */
25 #include <pthread.h>
26
27 #include "avcodec.h"
28
29 typedef int (action_t)(AVCodecContext *c, void *arg);
30
31 typedef struct ThreadContext {
32     pthread_t *workers;
33     action_t *func;
34     void **args;
35     int *rets;
36     int rets_count;
37     int job_count;
38
39     pthread_cond_t last_job_cond;
40     pthread_cond_t current_job_cond;
41     pthread_mutex_t current_job_lock;
42     int current_job;
43     int done;
44 } ThreadContext;
45
46 static void* worker(void *v)
47 {
48     AVCodecContext *avctx = v;
49     ThreadContext *c = avctx->thread_opaque;
50     int our_job = c->job_count;
51     int thread_count = avctx->thread_count;
52     int self_id;
53
54     pthread_mutex_lock(&c->current_job_lock);
55     self_id = c->current_job++;
56     for (;;){
57         while (our_job >= c->job_count) {
58             if (c->current_job == thread_count + c->job_count)
59                 pthread_cond_signal(&c->last_job_cond);
60
61             pthread_cond_wait(&c->current_job_cond, &c->current_job_lock);
62             our_job = self_id;
63
64             if (c->done) {
65                 pthread_mutex_unlock(&c->current_job_lock);
66                 return NULL;
67             }
68         }
69         pthread_mutex_unlock(&c->current_job_lock);
70
71         c->rets[our_job%c->rets_count] = c->func(avctx, c->args[our_job]);
72
73         pthread_mutex_lock(&c->current_job_lock);
74         our_job = c->current_job++;
75     }
76 }
77
78 static av_always_inline void avcodec_thread_park_workers(ThreadContext *c, int thread_count)
79 {
80     pthread_cond_wait(&c->last_job_cond, &c->current_job_lock);
81     pthread_mutex_unlock(&c->current_job_lock);
82 }
83
84 void avcodec_thread_free(AVCodecContext *avctx)
85 {
86     ThreadContext *c = avctx->thread_opaque;
87     int i;
88
89     pthread_mutex_lock(&c->current_job_lock);
90     c->done = 1;
91     pthread_cond_broadcast(&c->current_job_cond);
92     pthread_mutex_unlock(&c->current_job_lock);
93
94     for (i=0; i<avctx->thread_count; i++)
95          pthread_join(c->workers[i], NULL);
96
97     pthread_mutex_destroy(&c->current_job_lock);
98     pthread_cond_destroy(&c->current_job_cond);
99     pthread_cond_destroy(&c->last_job_cond);
100     av_free(c->workers);
101     av_free(c);
102 }
103
104 int avcodec_thread_execute(AVCodecContext *avctx, action_t* func, void **arg, int *ret, int job_count)
105 {
106     ThreadContext *c= avctx->thread_opaque;
107     int dummy_ret;
108
109     if (job_count <= 0)
110         return 0;
111
112     pthread_mutex_lock(&c->current_job_lock);
113
114     c->current_job = avctx->thread_count;
115     c->job_count = job_count;
116     c->args = arg;
117     c->func = func;
118     if (ret) {
119         c->rets = ret;
120         c->rets_count = job_count;
121     } else {
122         c->rets = &dummy_ret;
123         c->rets_count = 1;
124     }
125     pthread_cond_broadcast(&c->current_job_cond);
126
127     avcodec_thread_park_workers(c, avctx->thread_count);
128
129     return 0;
130 }
131
132 int avcodec_thread_init(AVCodecContext *avctx, int thread_count)
133 {
134     int i;
135     ThreadContext *c;
136
137     c = av_mallocz(sizeof(ThreadContext));
138     if (!c)
139         return -1;
140
141     c->workers = av_mallocz(sizeof(pthread_t)*thread_count);
142     if (!c->workers) {
143         av_free(c);
144         return -1;
145     }
146
147     avctx->thread_opaque = c;
148     avctx->thread_count = thread_count;
149     c->current_job = 0;
150     c->job_count = 0;
151     c->done = 0;
152     pthread_cond_init(&c->current_job_cond, NULL);
153     pthread_cond_init(&c->last_job_cond, NULL);
154     pthread_mutex_init(&c->current_job_lock, NULL);
155     pthread_mutex_lock(&c->current_job_lock);
156     for (i=0; i<thread_count; i++) {
157         if(pthread_create(&c->workers[i], NULL, worker, avctx)) {
158            avctx->thread_count = i;
159            pthread_mutex_unlock(&c->current_job_lock);
160            avcodec_thread_free(avctx);
161            return -1;
162         }
163     }
164
165     avcodec_thread_park_workers(c, thread_count);
166
167     avctx->execute = avcodec_thread_execute;
168     return 0;
169 }