Replace ASMALIGN() with .p2align
[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 #include <pthread.h>
25
26 #include "avcodec.h"
27
28 typedef int (action_func)(AVCodecContext *c, void *arg);
29 typedef int (action_func2)(AVCodecContext *c, void *arg, int jobnr, int threadnr);
30
31 typedef struct ThreadContext {
32     pthread_t *workers;
33     action_func *func;
34     action_func2 *func2;
35     void *args;
36     int *rets;
37     int rets_count;
38     int job_count;
39     int job_size;
40
41     pthread_cond_t last_job_cond;
42     pthread_cond_t current_job_cond;
43     pthread_mutex_t current_job_lock;
44     int current_job;
45     int done;
46 } ThreadContext;
47
48 static void* attribute_align_arg worker(void *v)
49 {
50     AVCodecContext *avctx = v;
51     ThreadContext *c = avctx->thread_opaque;
52     int our_job = c->job_count;
53     int thread_count = avctx->thread_count;
54     int self_id;
55
56     pthread_mutex_lock(&c->current_job_lock);
57     self_id = c->current_job++;
58     for (;;){
59         while (our_job >= c->job_count) {
60             if (c->current_job == thread_count + c->job_count)
61                 pthread_cond_signal(&c->last_job_cond);
62
63             pthread_cond_wait(&c->current_job_cond, &c->current_job_lock);
64             our_job = self_id;
65
66             if (c->done) {
67                 pthread_mutex_unlock(&c->current_job_lock);
68                 return NULL;
69             }
70         }
71         pthread_mutex_unlock(&c->current_job_lock);
72
73         c->rets[our_job%c->rets_count] = c->func ? c->func(avctx, (char*)c->args + our_job*c->job_size):
74                                                    c->func2(avctx, c->args, our_job, self_id);
75
76         pthread_mutex_lock(&c->current_job_lock);
77         our_job = c->current_job++;
78     }
79 }
80
81 static av_always_inline void avcodec_thread_park_workers(ThreadContext *c, int thread_count)
82 {
83     pthread_cond_wait(&c->last_job_cond, &c->current_job_lock);
84     pthread_mutex_unlock(&c->current_job_lock);
85 }
86
87 void avcodec_thread_free(AVCodecContext *avctx)
88 {
89     ThreadContext *c = avctx->thread_opaque;
90     int i;
91
92     pthread_mutex_lock(&c->current_job_lock);
93     c->done = 1;
94     pthread_cond_broadcast(&c->current_job_cond);
95     pthread_mutex_unlock(&c->current_job_lock);
96
97     for (i=0; i<avctx->thread_count; i++)
98          pthread_join(c->workers[i], NULL);
99
100     pthread_mutex_destroy(&c->current_job_lock);
101     pthread_cond_destroy(&c->current_job_cond);
102     pthread_cond_destroy(&c->last_job_cond);
103     av_free(c->workers);
104     av_freep(&avctx->thread_opaque);
105 }
106
107 static int avcodec_thread_execute(AVCodecContext *avctx, action_func* func, void *arg, int *ret, int job_count, int job_size)
108 {
109     ThreadContext *c= avctx->thread_opaque;
110     int dummy_ret;
111
112     if (job_count <= 0)
113         return 0;
114
115     pthread_mutex_lock(&c->current_job_lock);
116
117     c->current_job = avctx->thread_count;
118     c->job_count = job_count;
119     c->job_size = job_size;
120     c->args = arg;
121     c->func = func;
122     if (ret) {
123         c->rets = ret;
124         c->rets_count = job_count;
125     } else {
126         c->rets = &dummy_ret;
127         c->rets_count = 1;
128     }
129     pthread_cond_broadcast(&c->current_job_cond);
130
131     avcodec_thread_park_workers(c, avctx->thread_count);
132
133     return 0;
134 }
135
136 static int avcodec_thread_execute2(AVCodecContext *avctx, action_func2* func2, void *arg, int *ret, int job_count)
137 {
138     ThreadContext *c= avctx->thread_opaque;
139     c->func2 = func2;
140     return avcodec_thread_execute(avctx, NULL, arg, ret, job_count, 0);
141 }
142
143 int avcodec_thread_init(AVCodecContext *avctx, int thread_count)
144 {
145     int i;
146     ThreadContext *c;
147
148     avctx->thread_count = thread_count;
149
150     if (thread_count <= 1)
151         return 0;
152
153     c = av_mallocz(sizeof(ThreadContext));
154     if (!c)
155         return -1;
156
157     c->workers = av_mallocz(sizeof(pthread_t)*thread_count);
158     if (!c->workers) {
159         av_free(c);
160         return -1;
161     }
162
163     avctx->thread_opaque = c;
164     c->current_job = 0;
165     c->job_count = 0;
166     c->job_size = 0;
167     c->done = 0;
168     pthread_cond_init(&c->current_job_cond, NULL);
169     pthread_cond_init(&c->last_job_cond, NULL);
170     pthread_mutex_init(&c->current_job_lock, NULL);
171     pthread_mutex_lock(&c->current_job_lock);
172     for (i=0; i<thread_count; i++) {
173         if(pthread_create(&c->workers[i], NULL, worker, avctx)) {
174            avctx->thread_count = i;
175            pthread_mutex_unlock(&c->current_job_lock);
176            avcodec_thread_free(avctx);
177            return -1;
178         }
179     }
180
181     avcodec_thread_park_workers(c, thread_count);
182
183     avctx->execute = avcodec_thread_execute;
184     avctx->execute2 = avcodec_thread_execute2;
185     return 0;
186 }