Use xrange() rather than range() for loop iterations.
[blender.git] / source / blender / blenlib / intern / threads.c
1 /**
2  *
3  * $Id$
4  *
5  * ***** BEGIN GPL LICENSE BLOCK *****
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version. 
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software Foundation,
19  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20  *
21  * The Original Code is Copyright (C) 2006 Blender Foundation
22  * All rights reserved.
23  *
24  * The Original Code is: all of this file.
25  *
26  * Contributor(s): none yet.
27  *
28  * ***** END GPL LICENSE BLOCK *****
29  */
30
31 #include <math.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <pthread.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "BLI_blenlib.h"
39 #include "BLI_threads.h"
40
41 /* for checking system threads - BLI_system_thread_count */
42 #ifdef WIN32
43 #include "Windows.h"
44 #elif defined(__APPLE__)
45 #include <sys/types.h>
46 #include <sys/sysctl.h>
47 #else
48 #include <unistd.h> 
49 #endif
50
51 /* ********** basic thread control API ************ 
52
53 Many thread cases have an X amount of jobs, and only an Y amount of
54 threads are useful (typically amount of cpus)
55
56 This code can be used to start a maximum amount of 'thread slots', which
57 then can be filled in a loop with an idle timer. 
58
59 A sample loop can look like this (pseudo c);
60
61         ListBase lb;
62         int maxthreads= 2;
63         int cont= 1;
64
65         BLI_init_threads(&lb, do_something_func, maxthreads);
66
67         while(cont) {
68                 if(BLI_available_threads(&lb) && !(escape loop event)) {
69                         // get new job (data pointer)
70                         // tag job 'processed 
71                         BLI_insert_thread(&lb, job);
72                 }
73                 else PIL_sleep_ms(50);
74                 
75                 // find if a job is ready, this the do_something_func() should write in job somewhere
76                 cont= 0;
77                 for(go over all jobs)
78                         if(job is ready) {
79                                 if(job was not removed) {
80                                         BLI_remove_thread(&lb, job);
81                                 }
82                         }
83                         else cont= 1;
84                 }
85                 // conditions to exit loop 
86                 if(if escape loop event) {
87                         if(BLI_available_threadslots(&lb)==maxthreads)
88                                 break;
89                 }
90         }
91
92         BLI_end_threads(&lb);
93
94  ************************************************ */
95 static pthread_mutex_t _malloc_lock = PTHREAD_MUTEX_INITIALIZER;
96 static pthread_mutex_t _image_lock = PTHREAD_MUTEX_INITIALIZER;
97 static pthread_mutex_t _custom1_lock = PTHREAD_MUTEX_INITIALIZER;
98 static int thread_levels= 0;    /* threads can be invoked inside threads */
99
100 /* just a max for security reasons */
101 #define RE_MAX_THREAD   8
102
103 typedef struct ThreadSlot {
104         struct ThreadSlot *next, *prev;
105         void *(*do_thread)(void *);
106         void *callerdata;
107         pthread_t pthread;
108         int avail;
109 } ThreadSlot;
110
111 static void BLI_lock_malloc_thread(void)
112 {
113         pthread_mutex_lock(&_malloc_lock);
114 }
115
116 static void BLI_unlock_malloc_thread(void)
117 {
118         pthread_mutex_unlock(&_malloc_lock);
119 }
120
121 /* tot = 0 only initializes malloc mutex in a safe way (see sequence.c)
122    problem otherwise: scene render will kill of the mutex!
123 */
124
125 void BLI_init_threads(ListBase *threadbase, void *(*do_thread)(void *), int tot)
126 {
127         int a;
128         
129         if(threadbase != NULL && tot > 0) {
130                 threadbase->first= threadbase->last= NULL;
131         
132                 if(tot>RE_MAX_THREAD) tot= RE_MAX_THREAD;
133                 else if(tot<1) tot= 1;
134         
135                 for(a=0; a<tot; a++) {
136                         ThreadSlot *tslot= MEM_callocN(sizeof(ThreadSlot), "threadslot");
137                         BLI_addtail(threadbase, tslot);
138                         tslot->do_thread= do_thread;
139                         tslot->avail= 1;
140                 }
141         }
142
143         MEM_set_lock_callback(BLI_lock_malloc_thread, BLI_unlock_malloc_thread);
144         thread_levels++;
145 }
146
147 /* amount of available threads */
148 int BLI_available_threads(ListBase *threadbase)
149 {
150         ThreadSlot *tslot;
151         int counter=0;
152         
153         for(tslot= threadbase->first; tslot; tslot= tslot->next) {
154                 if(tslot->avail)
155                         counter++;
156         }
157         return counter;
158 }
159
160 /* returns thread number, for sample patterns or threadsafe tables */
161 int BLI_available_thread_index(ListBase *threadbase)
162 {
163         ThreadSlot *tslot;
164         int counter=0;
165         
166         for(tslot= threadbase->first; tslot; tslot= tslot->next, counter++) {
167                 if(tslot->avail)
168                         return counter;
169         }
170         return 0;
171 }
172
173
174 void BLI_insert_thread(ListBase *threadbase, void *callerdata)
175 {
176         ThreadSlot *tslot;
177         
178         for(tslot= threadbase->first; tslot; tslot= tslot->next) {
179                 if(tslot->avail) {
180                         tslot->avail= 0;
181                         tslot->callerdata= callerdata;
182                         pthread_create(&tslot->pthread, NULL, tslot->do_thread, tslot->callerdata);
183                         return;
184                 }
185         }
186         printf("ERROR: could not insert thread slot\n");
187 }
188
189 void BLI_remove_thread(ListBase *threadbase, void *callerdata)
190 {
191         ThreadSlot *tslot;
192         
193         for(tslot= threadbase->first; tslot; tslot= tslot->next) {
194                 if(tslot->callerdata==callerdata) {
195                         tslot->callerdata= NULL;
196                         pthread_join(tslot->pthread, NULL);
197                         tslot->avail= 1;
198                 }
199         }
200 }
201
202 void BLI_end_threads(ListBase *threadbase)
203 {
204         ThreadSlot *tslot;
205         
206         if (threadbase) {
207                 for(tslot= threadbase->first; tslot; tslot= tslot->next) {
208                         if(tslot->avail==0) {
209                                 pthread_join(tslot->pthread, NULL);
210                         }
211                 }
212                 BLI_freelistN(threadbase);
213         }
214         
215         thread_levels--;
216         if(thread_levels==0)
217                 MEM_set_lock_callback(NULL, NULL);
218 }
219
220 void BLI_lock_thread(int type)
221 {
222         if (type==LOCK_IMAGE)
223                 pthread_mutex_lock(&_image_lock);
224         else if (type==LOCK_CUSTOM1)
225                 pthread_mutex_lock(&_custom1_lock);
226 }
227
228 void BLI_unlock_thread(int type)
229 {
230         if (type==LOCK_IMAGE)
231                 pthread_mutex_unlock(&_image_lock);
232         else if(type==LOCK_CUSTOM1)
233                 pthread_mutex_unlock(&_custom1_lock);
234 }
235
236 /* how many threads are native on this system? */
237 int BLI_system_thread_count( void )
238 {
239         int t;
240 #ifdef WIN32
241         SYSTEM_INFO info;
242         GetSystemInfo(&info);
243         t = (int) info.dwNumberOfProcessors;
244 #else 
245 #       ifdef __APPLE__
246         int mib[2];
247         size_t len;
248         
249         mib[0] = CTL_HW;
250         mib[1] = HW_NCPU;
251         len = sizeof(t);
252         sysctl(mib, 2, &t, &len, NULL, 0);
253 #       elif defined(__sgi)
254         t = sysconf(_SC_NPROC_ONLN);
255 #       else
256         t = (int)sysconf(_SC_NPROCESSORS_ONLN);
257 #       endif
258 #endif
259         
260         if (t>RE_MAX_THREAD)
261                 return RE_MAX_THREAD;
262         if (t<1)
263                 return 1;
264         
265         return t;
266 }
267
268 /* eof */