c049ab85546838fd77322fa0fafc597742b4cf96
[blender.git] / source / blender / blenlib / intern / threads.c
1 /*
2  *
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2006 Blender Foundation
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 /** \file blender/blenlib/intern/threads.c
31  *  \ingroup bli
32  */
33
34
35 #include <errno.h>
36 #include <string.h>
37
38 #include "MEM_guardedalloc.h"
39
40
41 #include "BLI_blenlib.h"
42 #include "BLI_gsqueue.h"
43 #include "BLI_threads.h"
44
45 #include "PIL_time.h"
46
47 /* for checking system threads - BLI_system_thread_count */
48 #ifdef WIN32
49 #include "windows.h"
50 #include <sys/timeb.h>
51 #elif defined(__APPLE__)
52 #include <sys/types.h>
53 #include <sys/sysctl.h>
54 #else
55 #include <unistd.h> 
56 #include <sys/time.h>
57 #endif
58
59 #if defined(__APPLE__) && (PARALLEL == 1) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 2)
60 /* ************** libgomp (Apple gcc 4.2.1) TLS bug workaround *************** */
61 extern pthread_key_t gomp_tls_key;
62 static void *thread_tls_data;
63 #endif
64
65 /* ********** basic thread control API ************ 
66
67 Many thread cases have an X amount of jobs, and only an Y amount of
68 threads are useful (typically amount of cpus)
69
70 This code can be used to start a maximum amount of 'thread slots', which
71 then can be filled in a loop with an idle timer. 
72
73 A sample loop can look like this (pseudo c);
74
75         ListBase lb;
76         int maxthreads= 2;
77         int cont= 1;
78
79         BLI_init_threads(&lb, do_something_func, maxthreads);
80
81         while(cont) {
82                 if(BLI_available_threads(&lb) && !(escape loop event)) {
83                         // get new job (data pointer)
84                         // tag job 'processed 
85                         BLI_insert_thread(&lb, job);
86                 }
87                 else PIL_sleep_ms(50);
88                 
89                 // find if a job is ready, this the do_something_func() should write in job somewhere
90                 cont= 0;
91                 for(go over all jobs)
92                         if(job is ready) {
93                                 if(job was not removed) {
94                                         BLI_remove_thread(&lb, job);
95                                 }
96                         }
97                         else cont= 1;
98                 }
99                 // conditions to exit loop 
100                 if(if escape loop event) {
101                         if(BLI_available_threadslots(&lb)==maxthreads)
102                                 break;
103                 }
104         }
105
106         BLI_end_threads(&lb);
107
108  ************************************************ */
109 static pthread_mutex_t _malloc_lock = PTHREAD_MUTEX_INITIALIZER;
110 static pthread_mutex_t _image_lock = PTHREAD_MUTEX_INITIALIZER;
111 static pthread_mutex_t _preview_lock = PTHREAD_MUTEX_INITIALIZER;
112 static pthread_mutex_t _viewer_lock = PTHREAD_MUTEX_INITIALIZER;
113 static pthread_mutex_t _custom1_lock = PTHREAD_MUTEX_INITIALIZER;
114 static pthread_mutex_t _rcache_lock = PTHREAD_MUTEX_INITIALIZER;
115 static pthread_mutex_t _opengl_lock = PTHREAD_MUTEX_INITIALIZER;
116 static pthread_t mainid;
117 static int thread_levels= 0;    /* threads can be invoked inside threads */
118
119 /* just a max for security reasons */
120 #define RE_MAX_THREAD BLENDER_MAX_THREADS
121
122 typedef struct ThreadSlot {
123         struct ThreadSlot *next, *prev;
124         void *(*do_thread)(void *);
125         void *callerdata;
126         pthread_t pthread;
127         int avail;
128 } ThreadSlot;
129
130 static void BLI_lock_malloc_thread(void)
131 {
132         pthread_mutex_lock(&_malloc_lock);
133 }
134
135 static void BLI_unlock_malloc_thread(void)
136 {
137         pthread_mutex_unlock(&_malloc_lock);
138 }
139
140 void BLI_threadapi_init(void)
141 {
142         mainid = pthread_self();
143 }
144
145 /* tot = 0 only initializes malloc mutex in a safe way (see sequence.c)
146    problem otherwise: scene render will kill of the mutex!
147 */
148
149 void BLI_init_threads(ListBase *threadbase, void *(*do_thread)(void *), int tot)
150 {
151         int a;
152
153         if(threadbase != NULL && tot > 0) {
154                 threadbase->first= threadbase->last= NULL;
155         
156                 if(tot>RE_MAX_THREAD) tot= RE_MAX_THREAD;
157                 else if(tot<1) tot= 1;
158         
159                 for(a=0; a<tot; a++) {
160                         ThreadSlot *tslot= MEM_callocN(sizeof(ThreadSlot), "threadslot");
161                         BLI_addtail(threadbase, tslot);
162                         tslot->do_thread= do_thread;
163                         tslot->avail= 1;
164                 }
165         }
166         
167         if(thread_levels == 0) {
168                 MEM_set_lock_callback(BLI_lock_malloc_thread, BLI_unlock_malloc_thread);
169
170 #if defined(__APPLE__) && (PARALLEL == 1) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 2)
171                 /* workaround for Apple gcc 4.2.1 omp vs background thread bug,
172                    we copy gomp thread local storage pointer to setting it again
173                    inside the thread that we start */
174                 thread_tls_data = pthread_getspecific(gomp_tls_key);
175 #endif
176         }
177
178         thread_levels++;
179 }
180
181 /* amount of available threads */
182 int BLI_available_threads(ListBase *threadbase)
183 {
184         ThreadSlot *tslot;
185         int counter=0;
186         
187         for(tslot= threadbase->first; tslot; tslot= tslot->next) {
188                 if(tslot->avail)
189                         counter++;
190         }
191         return counter;
192 }
193
194 /* returns thread number, for sample patterns or threadsafe tables */
195 int BLI_available_thread_index(ListBase *threadbase)
196 {
197         ThreadSlot *tslot;
198         int counter=0;
199         
200         for(tslot= threadbase->first; tslot; tslot= tslot->next, counter++) {
201                 if(tslot->avail)
202                         return counter;
203         }
204         return 0;
205 }
206
207 static void *tslot_thread_start(void *tslot_p)
208 {
209         ThreadSlot *tslot= (ThreadSlot*)tslot_p;
210
211 #if defined(__APPLE__) && (PARALLEL == 1) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 2)
212         /* workaround for Apple gcc 4.2.1 omp vs background thread bug,
213            set gomp thread local storage pointer which was copied beforehand */
214         pthread_setspecific (gomp_tls_key, thread_tls_data);
215 #endif
216
217         return tslot->do_thread(tslot->callerdata);
218 }
219
220 int BLI_thread_is_main(void)
221 {
222         return pthread_equal(pthread_self(), mainid);
223 }
224
225 void BLI_insert_thread(ListBase *threadbase, void *callerdata)
226 {
227         ThreadSlot *tslot;
228         
229         for(tslot= threadbase->first; tslot; tslot= tslot->next) {
230                 if(tslot->avail) {
231                         tslot->avail= 0;
232                         tslot->callerdata= callerdata;
233                         pthread_create(&tslot->pthread, NULL, tslot_thread_start, tslot);
234                         return;
235                 }
236         }
237         printf("ERROR: could not insert thread slot\n");
238 }
239
240 void BLI_remove_thread(ListBase *threadbase, void *callerdata)
241 {
242         ThreadSlot *tslot;
243         
244         for(tslot= threadbase->first; tslot; tslot= tslot->next) {
245                 if(tslot->callerdata==callerdata) {
246                         pthread_join(tslot->pthread, NULL);
247                         tslot->callerdata= NULL;
248                         tslot->avail= 1;
249                 }
250         }
251 }
252
253 void BLI_remove_thread_index(ListBase *threadbase, int index)
254 {
255         ThreadSlot *tslot;
256         int counter=0;
257         
258         for(tslot = threadbase->first; tslot; tslot = tslot->next, counter++) {
259                 if (counter == index && tslot->avail == 0) {
260                         pthread_join(tslot->pthread, NULL);
261                         tslot->callerdata = NULL;
262                         tslot->avail = 1;
263                         break;
264                 }
265         }
266 }
267
268 void BLI_remove_threads(ListBase *threadbase)
269 {
270         ThreadSlot *tslot;
271         
272         for(tslot = threadbase->first; tslot; tslot = tslot->next) {
273                 if (tslot->avail == 0) {
274                         pthread_join(tslot->pthread, NULL);
275                         tslot->callerdata = NULL;
276                         tslot->avail = 1;
277                 }
278         }
279 }
280
281 void BLI_end_threads(ListBase *threadbase)
282 {
283         ThreadSlot *tslot;
284         
285         /* only needed if there's actually some stuff to end
286          * this way we don't end up decrementing thread_levels on an empty threadbase 
287          * */
288         if (threadbase && threadbase->first != NULL) {
289                 for(tslot= threadbase->first; tslot; tslot= tslot->next) {
290                         if(tslot->avail==0) {
291                                 pthread_join(tslot->pthread, NULL);
292                         }
293                 }
294                 BLI_freelistN(threadbase);
295         }
296
297         thread_levels--;
298         if(thread_levels==0)
299                 MEM_set_lock_callback(NULL, NULL);
300 }
301
302 /* System Information */
303
304 /* how many threads are native on this system? */
305 int BLI_system_thread_count( void )
306 {
307         int t;
308 #ifdef WIN32
309         SYSTEM_INFO info;
310         GetSystemInfo(&info);
311         t = (int) info.dwNumberOfProcessors;
312 #else 
313 #       ifdef __APPLE__
314         int mib[2];
315         size_t len;
316         
317         mib[0] = CTL_HW;
318         mib[1] = HW_NCPU;
319         len = sizeof(t);
320         sysctl(mib, 2, &t, &len, NULL, 0);
321 #       else
322         t = (int)sysconf(_SC_NPROCESSORS_ONLN);
323 #       endif
324 #endif
325         
326         if (t>RE_MAX_THREAD)
327                 return RE_MAX_THREAD;
328         if (t<1)
329                 return 1;
330         
331         return t;
332 }
333
334 /* Global Mutex Locks */
335
336 void BLI_lock_thread(int type)
337 {
338         if (type==LOCK_IMAGE)
339                 pthread_mutex_lock(&_image_lock);
340         else if (type==LOCK_PREVIEW)
341                 pthread_mutex_lock(&_preview_lock);
342         else if (type==LOCK_VIEWER)
343                 pthread_mutex_lock(&_viewer_lock);
344         else if (type==LOCK_CUSTOM1)
345                 pthread_mutex_lock(&_custom1_lock);
346         else if (type==LOCK_RCACHE)
347                 pthread_mutex_lock(&_rcache_lock);
348         else if (type==LOCK_OPENGL)
349                 pthread_mutex_lock(&_opengl_lock);
350 }
351
352 void BLI_unlock_thread(int type)
353 {
354         if (type==LOCK_IMAGE)
355                 pthread_mutex_unlock(&_image_lock);
356         else if (type==LOCK_PREVIEW)
357                 pthread_mutex_unlock(&_preview_lock);
358         else if (type==LOCK_VIEWER)
359                 pthread_mutex_unlock(&_viewer_lock);
360         else if(type==LOCK_CUSTOM1)
361                 pthread_mutex_unlock(&_custom1_lock);
362         else if(type==LOCK_RCACHE)
363                 pthread_mutex_unlock(&_rcache_lock);
364         else if(type==LOCK_OPENGL)
365                 pthread_mutex_unlock(&_opengl_lock);
366 }
367
368 /* Mutex Locks */
369
370 void BLI_mutex_init(ThreadMutex *mutex)
371 {
372         pthread_mutex_init(mutex, NULL);
373 }
374
375 void BLI_mutex_lock(ThreadMutex *mutex)
376 {
377         pthread_mutex_lock(mutex);
378 }
379
380 void BLI_mutex_unlock(ThreadMutex *mutex)
381 {
382         pthread_mutex_unlock(mutex);
383 }
384
385 void BLI_mutex_end(ThreadMutex *mutex)
386 {
387         pthread_mutex_destroy(mutex);
388 }
389
390 /* Read/Write Mutex Lock */
391
392 void BLI_rw_mutex_init(ThreadRWMutex *mutex)
393 {
394         pthread_rwlock_init(mutex, NULL);
395 }
396
397 void BLI_rw_mutex_lock(ThreadRWMutex *mutex, int mode)
398 {
399         if(mode == THREAD_LOCK_READ)
400                 pthread_rwlock_rdlock(mutex);
401         else
402                 pthread_rwlock_wrlock(mutex);
403 }
404
405 void BLI_rw_mutex_unlock(ThreadRWMutex *mutex)
406 {
407         pthread_rwlock_unlock(mutex);
408 }
409
410 void BLI_rw_mutex_end(ThreadRWMutex *mutex)
411 {
412         pthread_rwlock_destroy(mutex);
413 }
414
415 /* ************************************************ */
416
417 typedef struct ThreadedWorker {
418         ListBase threadbase;
419         void *(*work_fnct)(void *);
420         char     busy[RE_MAX_THREAD];
421         int              total;
422         int              sleep_time;
423 } ThreadedWorker;
424
425 typedef struct WorkParam {
426         ThreadedWorker *worker;
427         void *param;
428         int       index;
429 } WorkParam;
430
431 static void *exec_work_fnct(void *v_param)
432 {
433         WorkParam *p = (WorkParam*)v_param;
434         void *value;
435         
436         value = p->worker->work_fnct(p->param);
437         
438         p->worker->busy[p->index] = 0;
439         MEM_freeN(p);
440         
441         return value;
442 }
443
444 ThreadedWorker *BLI_create_worker(void *(*do_thread)(void *), int tot, int sleep_time)
445 {
446         ThreadedWorker *worker;
447         
448         (void)sleep_time; /* unused */
449         
450         worker = MEM_callocN(sizeof(ThreadedWorker), "threadedworker");
451         
452         if (tot > RE_MAX_THREAD)
453         {
454                 tot = RE_MAX_THREAD;
455         }
456         else if (tot < 1)
457         {
458                 tot= 1;
459         }
460         
461         worker->total = tot;
462         worker->work_fnct = do_thread;
463         
464         BLI_init_threads(&worker->threadbase, exec_work_fnct, tot);
465         
466         return worker;
467 }
468
469 void BLI_end_worker(ThreadedWorker *worker)
470 {
471         BLI_remove_threads(&worker->threadbase);
472 }
473
474 void BLI_destroy_worker(ThreadedWorker *worker)
475 {
476         BLI_end_worker(worker);
477         BLI_freelistN(&worker->threadbase);
478         MEM_freeN(worker);
479 }
480
481 void BLI_insert_work(ThreadedWorker *worker, void *param)
482 {
483         WorkParam *p = MEM_callocN(sizeof(WorkParam), "workparam");
484         int index;
485         
486         if (BLI_available_threads(&worker->threadbase) == 0)
487         {
488                 index = worker->total;
489                 while(index == worker->total)
490                 {
491                         PIL_sleep_ms(worker->sleep_time);
492                         
493                         for (index = 0; index < worker->total; index++)
494                         {
495                                 if (worker->busy[index] == 0)
496                                 {
497                                         BLI_remove_thread_index(&worker->threadbase, index);
498                                         break;
499                                 }
500                         }
501                 }
502         }
503         else
504         {
505                 index = BLI_available_thread_index(&worker->threadbase);
506         }
507         
508         worker->busy[index] = 1;
509         
510         p->param = param;
511         p->index = index;
512         p->worker = worker;
513         
514         BLI_insert_thread(&worker->threadbase, p);
515 }
516
517 /* ************************************************ */
518
519 struct ThreadQueue {
520         GSQueue *queue;
521         pthread_mutex_t mutex;
522         pthread_cond_t cond;
523         int nowait;
524 };
525
526 ThreadQueue *BLI_thread_queue_init(void)
527 {
528         ThreadQueue *queue;
529
530         queue= MEM_callocN(sizeof(ThreadQueue), "ThreadQueue");
531         queue->queue= BLI_gsqueue_new(sizeof(void*));
532
533         pthread_mutex_init(&queue->mutex, NULL);
534         pthread_cond_init(&queue->cond, NULL);
535
536         return queue;
537 }
538
539 void BLI_thread_queue_free(ThreadQueue *queue)
540 {
541         pthread_cond_destroy(&queue->cond);
542         pthread_mutex_destroy(&queue->mutex);
543
544         BLI_gsqueue_free(queue->queue);
545
546         MEM_freeN(queue);
547 }
548
549 void BLI_thread_queue_push(ThreadQueue *queue, void *work)
550 {
551         pthread_mutex_lock(&queue->mutex);
552
553         BLI_gsqueue_push(queue->queue, &work);
554
555         /* signal threads waiting to pop */
556         pthread_cond_signal(&queue->cond);
557         pthread_mutex_unlock(&queue->mutex);
558 }
559
560 void *BLI_thread_queue_pop(ThreadQueue *queue)
561 {
562         void *work= NULL;
563
564         /* wait until there is work */
565         pthread_mutex_lock(&queue->mutex);
566         while(BLI_gsqueue_is_empty(queue->queue) && !queue->nowait)
567                 pthread_cond_wait(&queue->cond, &queue->mutex);
568
569         /* if we have something, pop it */
570         if(!BLI_gsqueue_is_empty(queue->queue))
571                 BLI_gsqueue_pop(queue->queue, &work);
572
573         pthread_mutex_unlock(&queue->mutex);
574
575         return work;
576 }
577
578 static void wait_timeout(struct timespec *timeout, int ms)
579 {
580         ldiv_t div_result;
581         long sec, usec, x;
582
583 #ifdef WIN32
584         {
585                 struct _timeb now;
586                 _ftime(&now);
587                 sec = now.time;
588                 usec = now.millitm*1000; /* microsecond precision would be better */
589         }
590 #else
591         {
592                 struct timeval now;
593                 gettimeofday(&now, NULL);
594                 sec = now.tv_sec;
595                 usec = now.tv_usec;
596         }
597 #endif
598
599         /* add current time + millisecond offset */
600         div_result = ldiv(ms, 1000);
601         timeout->tv_sec = sec + div_result.quot;
602
603         x = usec + (div_result.rem*1000);
604
605         if (x >= 1000000) {
606                 timeout->tv_sec++;
607                 x -= 1000000;
608         }
609
610         timeout->tv_nsec = x*1000;
611 }
612
613 void *BLI_thread_queue_pop_timeout(ThreadQueue *queue, int ms)
614 {
615         double t;
616         void *work= NULL;
617         struct timespec timeout;
618
619         t= PIL_check_seconds_timer();
620         wait_timeout(&timeout, ms);
621
622         /* wait until there is work */
623         pthread_mutex_lock(&queue->mutex);
624         while(BLI_gsqueue_is_empty(queue->queue) && !queue->nowait) {
625                 if(pthread_cond_timedwait(&queue->cond, &queue->mutex, &timeout) == ETIMEDOUT)
626                         break;
627                 else if(PIL_check_seconds_timer() - t >= ms*0.001)
628                         break;
629         }
630
631         /* if we have something, pop it */
632         if(!BLI_gsqueue_is_empty(queue->queue))
633                 BLI_gsqueue_pop(queue->queue, &work);
634
635         pthread_mutex_unlock(&queue->mutex);
636
637         return work;
638 }
639
640 int BLI_thread_queue_size(ThreadQueue *queue)
641 {
642         int size;
643
644         pthread_mutex_lock(&queue->mutex);
645         size= BLI_gsqueue_size(queue->queue);
646         pthread_mutex_unlock(&queue->mutex);
647
648         return size;
649 }
650
651 void BLI_thread_queue_nowait(ThreadQueue *queue)
652 {
653         pthread_mutex_lock(&queue->mutex);
654
655         queue->nowait= 1;
656
657         /* signal threads waiting to pop */
658         pthread_cond_signal(&queue->cond);
659         pthread_mutex_unlock(&queue->mutex);
660 }
661