Three-in-one commit:
[blender-staging.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 "MEM_guardedalloc.h"
35
36 #include "BLI_blenlib.h"
37 #include "BLI_threads.h"
38
39 #include "SDL_thread.h"
40
41 /* ********** basic thread control API ************ 
42
43 Many thread cases have an X amount of jobs, and only an Y amount of
44 threads are useful (typically amount of cpus)
45
46 This code can be used to start a maximum amount of 'thread slots', which
47 then can be filled in a loop with an idle timer. 
48
49 A sample loop can look like this (pseudo c);
50
51         ListBase lb;
52         int maxthreads= 2;
53         int cont= 1;
54
55         BLI_init_threads(&lb, do_something_func, maxthreads);
56
57         while(cont) {
58                 if(BLI_available_threads(&lb) && !(escape loop event)) {
59                         // get new job (data pointer)
60                         // tag job 'processed 
61                         BLI_insert_thread(&lb, job);
62                 }
63                 else PIL_sleep_ms(50);
64                 
65                 // find if a job is ready, this the do_something_func() should write in job somewhere
66                 cont= 0;
67                 for(go over all jobs)
68                         if(job is ready) {
69                                 if(job was not removed) {
70                                         BLI_remove_thread(&lb, job);
71                                 }
72                         }
73                         else cont= 1;
74                 }
75                 // conditions to exit loop 
76                 if(if escape loop event) {
77                         if(BLI_available_threadslots(&lb)==maxthreads)
78                                 break;
79                 }
80         }
81
82         BLI_end_threads(&lb);
83
84  ************************************************ */
85
86 /* just a max for security reasons */
87 #define RE_MAX_THREAD   8
88
89 typedef struct ThreadSlot {
90         struct ThreadSlot *next, *prev;
91         int (*do_thread)(void *);
92         void *callerdata;
93         SDL_Thread *sdlthread;
94         int avail;
95 } ThreadSlot;
96
97 static ThreadSlot threadslots[RE_MAX_THREAD];
98
99 void BLI_init_threads(ListBase *threadbase, int (*do_thread)(void *), int tot)
100 {
101         int a;
102         
103         if(threadbase==NULL)
104                 return;
105         threadbase->first= threadbase->last= NULL;
106         
107         if(tot>RE_MAX_THREAD) tot= RE_MAX_THREAD;
108         else if(tot<1) tot= 1;
109         
110         for(a=0; a<tot; a++) {
111                 ThreadSlot *tslot= MEM_callocN(sizeof(ThreadSlot), "threadslot");
112                 BLI_addtail(threadbase, tslot);
113                 tslot->do_thread= do_thread;
114         }
115 }
116
117 /* amount of available threads */
118 int BLI_available_threads(ListBase *threadbase)
119 {
120         ThreadSlot *tslot;
121         int counter=0;
122         
123         for(tslot= threadbase->first; tslot; tslot= tslot->next) {
124                 if(tslot->sdlthread==NULL)
125                         counter++;
126         }
127         return counter;
128 }
129
130 /* returns thread number, for sample patterns or threadsafe tables */
131 int BLI_available_thread_index(ListBase *threadbase)
132 {
133         ThreadSlot *tslot;
134         int counter=0;
135         
136         for(tslot= threadbase->first; tslot; tslot= tslot->next, counter++) {
137                 if(tslot->sdlthread==NULL)
138                         return counter;
139         }
140         return 0;
141 }
142
143
144 void BLI_insert_thread(ListBase *threadbase, void *callerdata)
145 {
146         ThreadSlot *tslot;
147         
148         for(tslot= threadbase->first; tslot; tslot= tslot->next) {
149                 if(tslot->sdlthread==NULL) {
150                         tslot->callerdata= callerdata;
151                         tslot->sdlthread= SDL_CreateThread(tslot->do_thread, tslot->callerdata);
152                         return;
153                 }
154         }
155         printf("ERROR: could not insert thread slot\n");
156 }
157
158 void BLI_remove_thread(ListBase *threadbase, void *callerdata)
159 {
160         ThreadSlot *tslot;
161         
162         for(tslot= threadbase->first; tslot; tslot= tslot->next) {
163                 if(tslot->callerdata==callerdata) {
164                         tslot->callerdata= NULL;
165                         SDL_WaitThread(tslot->sdlthread, NULL);
166                         tslot->sdlthread= NULL;
167                 }
168         }
169 }
170
171 void BLI_end_threads(ListBase *threadbase)
172 {
173         ThreadSlot *tslot;
174         
175         for(tslot= threadbase->first; tslot; tslot= tslot->next) {
176                 if(tslot->sdlthread) {
177                         SDL_WaitThread(tslot->sdlthread, NULL);
178                 }
179         }
180         BLI_freelistN(threadbase);
181 }
182
183 /* eof */