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