6048ca8cfc3738b40e7778bdc30c3b8edfdbdc58
[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_mutex_t _nodes_lock = PTHREAD_MUTEX_INITIALIZER;
117 static pthread_mutex_t _movieclip_lock = PTHREAD_MUTEX_INITIALIZER;
118 static pthread_mutex_t _scanfill_lock = PTHREAD_MUTEX_INITIALIZER;
119 static pthread_t mainid;
120 static int thread_levels= 0;    /* threads can be invoked inside threads */
121
122 /* just a max for security reasons */
123 #define RE_MAX_THREAD BLENDER_MAX_THREADS
124
125 typedef struct ThreadSlot {
126         struct ThreadSlot *next, *prev;
127         void *(*do_thread)(void *);
128         void *callerdata;
129         pthread_t pthread;
130         int avail;
131 } ThreadSlot;
132
133 static void BLI_lock_malloc_thread(void)
134 {
135         pthread_mutex_lock(&_malloc_lock);
136 }
137
138 static void BLI_unlock_malloc_thread(void)
139 {
140         pthread_mutex_unlock(&_malloc_lock);
141 }
142
143 void BLI_threadapi_init(void)
144 {
145         mainid = pthread_self();
146 }
147
148 /* tot = 0 only initializes malloc mutex in a safe way (see sequence.c)
149  * problem otherwise: scene render will kill of the mutex!
150  */
151
152 void BLI_init_threads(ListBase *threadbase, void *(*do_thread)(void *), int tot)
153 {
154         int a;
155
156         if(threadbase != NULL && tot > 0) {
157                 threadbase->first= threadbase->last= NULL;
158         
159                 if(tot>RE_MAX_THREAD) tot= RE_MAX_THREAD;
160                 else if(tot<1) tot= 1;
161         
162                 for(a=0; a<tot; a++) {
163                         ThreadSlot *tslot= MEM_callocN(sizeof(ThreadSlot), "threadslot");
164                         BLI_addtail(threadbase, tslot);
165                         tslot->do_thread= do_thread;
166                         tslot->avail= 1;
167                 }
168         }
169         
170         if(thread_levels == 0) {
171                 MEM_set_lock_callback(BLI_lock_malloc_thread, BLI_unlock_malloc_thread);
172
173 #if defined(__APPLE__) && (PARALLEL == 1) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 2)
174                 /* workaround for Apple gcc 4.2.1 omp vs background thread bug,
175                  * we copy gomp thread local storage pointer to setting it again
176                  * inside the thread that we start */
177                 thread_tls_data = pthread_getspecific(gomp_tls_key);
178 #endif
179         }
180
181         thread_levels++;
182 }
183
184 /* amount of available threads */
185 int BLI_available_threads(ListBase *threadbase)
186 {
187         ThreadSlot *tslot;
188         int counter=0;
189         
190         for(tslot= threadbase->first; tslot; tslot= tslot->next) {
191                 if(tslot->avail)
192                         counter++;
193         }
194         return counter;
195 }
196
197 /* returns thread number, for sample patterns or threadsafe tables */
198 int BLI_available_thread_index(ListBase *threadbase)
199 {
200         ThreadSlot *tslot;
201         int counter=0;
202         
203         for(tslot= threadbase->first; tslot; tslot= tslot->next, counter++) {
204                 if(tslot->avail)
205                         return counter;
206         }
207         return 0;
208 }
209
210 static void *tslot_thread_start(void *tslot_p)
211 {
212         ThreadSlot *tslot= (ThreadSlot*)tslot_p;
213
214 #if defined(__APPLE__) && (PARALLEL == 1) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 2)
215         /* workaround for Apple gcc 4.2.1 omp vs background thread bug,
216          * set gomp thread local storage pointer which was copied beforehand */
217         pthread_setspecific (gomp_tls_key, thread_tls_data);
218 #endif
219
220         return tslot->do_thread(tslot->callerdata);
221 }
222
223 int BLI_thread_is_main(void)
224 {
225         return pthread_equal(pthread_self(), mainid);
226 }
227
228 void BLI_insert_thread(ListBase *threadbase, void *callerdata)
229 {
230         ThreadSlot *tslot;
231         
232         for(tslot= threadbase->first; tslot; tslot= tslot->next) {
233                 if(tslot->avail) {
234                         tslot->avail= 0;
235                         tslot->callerdata= callerdata;
236                         pthread_create(&tslot->pthread, NULL, tslot_thread_start, tslot);
237                         return;
238                 }
239         }
240         printf("ERROR: could not insert thread slot\n");
241 }
242
243 void BLI_remove_thread(ListBase *threadbase, void *callerdata)
244 {
245         ThreadSlot *tslot;
246         
247         for(tslot= threadbase->first; tslot; tslot= tslot->next) {
248                 if(tslot->callerdata==callerdata) {
249                         pthread_join(tslot->pthread, NULL);
250                         tslot->callerdata= NULL;
251                         tslot->avail= 1;
252                 }
253         }
254 }
255
256 void BLI_remove_thread_index(ListBase *threadbase, int index)
257 {
258         ThreadSlot *tslot;
259         int counter=0;
260         
261         for(tslot = threadbase->first; tslot; tslot = tslot->next, counter++) {
262                 if (counter == index && tslot->avail == 0) {
263                         pthread_join(tslot->pthread, NULL);
264                         tslot->callerdata = NULL;
265                         tslot->avail = 1;
266                         break;
267                 }
268         }
269 }
270
271 void BLI_remove_threads(ListBase *threadbase)
272 {
273         ThreadSlot *tslot;
274         
275         for(tslot = threadbase->first; tslot; tslot = tslot->next) {
276                 if (tslot->avail == 0) {
277                         pthread_join(tslot->pthread, NULL);
278                         tslot->callerdata = NULL;
279                         tslot->avail = 1;
280                 }
281         }
282 }
283
284 void BLI_end_threads(ListBase *threadbase)
285 {
286         ThreadSlot *tslot;
287         
288         /* only needed if there's actually some stuff to end
289          * this way we don't end up decrementing thread_levels on an empty threadbase 
290          * */
291         if (threadbase && threadbase->first != NULL) {
292                 for(tslot= threadbase->first; tslot; tslot= tslot->next) {
293                         if(tslot->avail==0) {
294                                 pthread_join(tslot->pthread, NULL);
295                         }
296                 }
297                 BLI_freelistN(threadbase);
298         }
299
300         thread_levels--;
301         if(thread_levels==0)
302                 MEM_set_lock_callback(NULL, NULL);
303 }
304
305 /* System Information */
306
307 /* how many threads are native on this system? */
308 int BLI_system_thread_count( void )
309 {
310         int t;
311 #ifdef WIN32
312         SYSTEM_INFO info;
313         GetSystemInfo(&info);
314         t = (int) info.dwNumberOfProcessors;
315 #else 
316 #       ifdef __APPLE__
317         int mib[2];
318         size_t len;
319         
320         mib[0] = CTL_HW;
321         mib[1] = HW_NCPU;
322         len = sizeof(t);
323         sysctl(mib, 2, &t, &len, NULL, 0);
324 #       else
325         t = (int)sysconf(_SC_NPROCESSORS_ONLN);
326 #       endif
327 #endif
328         
329         if (t>RE_MAX_THREAD)
330                 return RE_MAX_THREAD;
331         if (t<1)
332                 return 1;
333         
334         return t;
335 }
336
337 /* Global Mutex Locks */
338
339 void BLI_lock_thread(int type)
340 {
341         if (type==LOCK_IMAGE)
342                 pthread_mutex_lock(&_image_lock);
343         else if (type==LOCK_PREVIEW)
344                 pthread_mutex_lock(&_preview_lock);
345         else if (type==LOCK_VIEWER)
346                 pthread_mutex_lock(&_viewer_lock);
347         else if (type==LOCK_CUSTOM1)
348                 pthread_mutex_lock(&_custom1_lock);
349         else if (type==LOCK_RCACHE)
350                 pthread_mutex_lock(&_rcache_lock);
351         else if (type==LOCK_OPENGL)
352                 pthread_mutex_lock(&_opengl_lock);
353         else if (type==LOCK_NODES)
354                 pthread_mutex_lock(&_nodes_lock);
355         else if (type==LOCK_MOVIECLIP)
356                 pthread_mutex_lock(&_movieclip_lock);
357         else if (type == LOCK_SCANFILL)
358                 pthread_mutex_lock(&_scanfill_lock);
359 }
360
361 void BLI_unlock_thread(int type)
362 {
363         if (type==LOCK_IMAGE)
364                 pthread_mutex_unlock(&_image_lock);
365         else if (type==LOCK_PREVIEW)
366                 pthread_mutex_unlock(&_preview_lock);
367         else if (type==LOCK_VIEWER)
368                 pthread_mutex_unlock(&_viewer_lock);
369         else if(type==LOCK_CUSTOM1)
370                 pthread_mutex_unlock(&_custom1_lock);
371         else if(type==LOCK_RCACHE)
372                 pthread_mutex_unlock(&_rcache_lock);
373         else if(type==LOCK_OPENGL)
374                 pthread_mutex_unlock(&_opengl_lock);
375         else if(type==LOCK_NODES)
376                 pthread_mutex_unlock(&_nodes_lock);
377         else if(type==LOCK_MOVIECLIP)
378                 pthread_mutex_unlock(&_movieclip_lock);
379         else if(type == LOCK_SCANFILL)
380                 pthread_mutex_unlock(&_scanfill_lock);
381 }
382
383 /* Mutex Locks */
384
385 void BLI_mutex_init(ThreadMutex *mutex)
386 {
387         pthread_mutex_init(mutex, NULL);
388 }
389
390 void BLI_mutex_lock(ThreadMutex *mutex)
391 {
392         pthread_mutex_lock(mutex);
393 }
394
395 void BLI_mutex_unlock(ThreadMutex *mutex)
396 {
397         pthread_mutex_unlock(mutex);
398 }
399
400 void BLI_mutex_end(ThreadMutex *mutex)
401 {
402         pthread_mutex_destroy(mutex);
403 }
404
405 /* Read/Write Mutex Lock */
406
407 void BLI_rw_mutex_init(ThreadRWMutex *mutex)
408 {
409         pthread_rwlock_init(mutex, NULL);
410 }
411
412 void BLI_rw_mutex_lock(ThreadRWMutex *mutex, int mode)
413 {
414         if(mode == THREAD_LOCK_READ)
415                 pthread_rwlock_rdlock(mutex);
416         else
417                 pthread_rwlock_wrlock(mutex);
418 }
419
420 void BLI_rw_mutex_unlock(ThreadRWMutex *mutex)
421 {
422         pthread_rwlock_unlock(mutex);
423 }
424
425 void BLI_rw_mutex_end(ThreadRWMutex *mutex)
426 {
427         pthread_rwlock_destroy(mutex);
428 }
429
430 /* ************************************************ */
431
432 typedef struct ThreadedWorker {
433         ListBase threadbase;
434         void *(*work_fnct)(void *);
435         char     busy[RE_MAX_THREAD];
436         int              total;
437         int              sleep_time;
438 } ThreadedWorker;
439
440 typedef struct WorkParam {
441         ThreadedWorker *worker;
442         void *param;
443         int       index;
444 } WorkParam;
445
446 static void *exec_work_fnct(void *v_param)
447 {
448         WorkParam *p = (WorkParam*)v_param;
449         void *value;
450         
451         value = p->worker->work_fnct(p->param);
452         
453         p->worker->busy[p->index] = 0;
454         MEM_freeN(p);
455         
456         return value;
457 }
458
459 ThreadedWorker *BLI_create_worker(void *(*do_thread)(void *), int tot, int sleep_time)
460 {
461         ThreadedWorker *worker;
462         
463         (void)sleep_time; /* unused */
464         
465         worker = MEM_callocN(sizeof(ThreadedWorker), "threadedworker");
466         
467         if (tot > RE_MAX_THREAD)
468         {
469                 tot = RE_MAX_THREAD;
470         }
471         else if (tot < 1)
472         {
473                 tot= 1;
474         }
475         
476         worker->total = tot;
477         worker->work_fnct = do_thread;
478         
479         BLI_init_threads(&worker->threadbase, exec_work_fnct, tot);
480         
481         return worker;
482 }
483
484 void BLI_end_worker(ThreadedWorker *worker)
485 {
486         BLI_remove_threads(&worker->threadbase);
487 }
488
489 void BLI_destroy_worker(ThreadedWorker *worker)
490 {
491         BLI_end_worker(worker);
492         BLI_freelistN(&worker->threadbase);
493         MEM_freeN(worker);
494 }
495
496 void BLI_insert_work(ThreadedWorker *worker, void *param)
497 {
498         WorkParam *p = MEM_callocN(sizeof(WorkParam), "workparam");
499         int index;
500         
501         if (BLI_available_threads(&worker->threadbase) == 0)
502         {
503                 index = worker->total;
504                 while(index == worker->total)
505                 {
506                         PIL_sleep_ms(worker->sleep_time);
507                         
508                         for (index = 0; index < worker->total; index++)
509                         {
510                                 if (worker->busy[index] == 0)
511                                 {
512                                         BLI_remove_thread_index(&worker->threadbase, index);
513                                         break;
514                                 }
515                         }
516                 }
517         }
518         else
519         {
520                 index = BLI_available_thread_index(&worker->threadbase);
521         }
522         
523         worker->busy[index] = 1;
524         
525         p->param = param;
526         p->index = index;
527         p->worker = worker;
528         
529         BLI_insert_thread(&worker->threadbase, p);
530 }
531
532 /* ************************************************ */
533
534 struct ThreadQueue {
535         GSQueue *queue;
536         pthread_mutex_t mutex;
537         pthread_cond_t cond;
538         int nowait;
539 };
540
541 ThreadQueue *BLI_thread_queue_init(void)
542 {
543         ThreadQueue *queue;
544
545         queue= MEM_callocN(sizeof(ThreadQueue), "ThreadQueue");
546         queue->queue= BLI_gsqueue_new(sizeof(void*));
547
548         pthread_mutex_init(&queue->mutex, NULL);
549         pthread_cond_init(&queue->cond, NULL);
550
551         return queue;
552 }
553
554 void BLI_thread_queue_free(ThreadQueue *queue)
555 {
556         pthread_cond_destroy(&queue->cond);
557         pthread_mutex_destroy(&queue->mutex);
558
559         BLI_gsqueue_free(queue->queue);
560
561         MEM_freeN(queue);
562 }
563
564 void BLI_thread_queue_push(ThreadQueue *queue, void *work)
565 {
566         pthread_mutex_lock(&queue->mutex);
567
568         BLI_gsqueue_push(queue->queue, &work);
569
570         /* signal threads waiting to pop */
571         pthread_cond_signal(&queue->cond);
572         pthread_mutex_unlock(&queue->mutex);
573 }
574
575 void *BLI_thread_queue_pop(ThreadQueue *queue)
576 {
577         void *work= NULL;
578
579         /* wait until there is work */
580         pthread_mutex_lock(&queue->mutex);
581         while(BLI_gsqueue_is_empty(queue->queue) && !queue->nowait)
582                 pthread_cond_wait(&queue->cond, &queue->mutex);
583
584         /* if we have something, pop it */
585         if(!BLI_gsqueue_is_empty(queue->queue))
586                 BLI_gsqueue_pop(queue->queue, &work);
587
588         pthread_mutex_unlock(&queue->mutex);
589
590         return work;
591 }
592
593 static void wait_timeout(struct timespec *timeout, int ms)
594 {
595         ldiv_t div_result;
596         long sec, usec, x;
597
598 #ifdef WIN32
599         {
600                 struct _timeb now;
601                 _ftime(&now);
602                 sec = now.time;
603                 usec = now.millitm*1000; /* microsecond precision would be better */
604         }
605 #else
606         {
607                 struct timeval now;
608                 gettimeofday(&now, NULL);
609                 sec = now.tv_sec;
610                 usec = now.tv_usec;
611         }
612 #endif
613
614         /* add current time + millisecond offset */
615         div_result = ldiv(ms, 1000);
616         timeout->tv_sec = sec + div_result.quot;
617
618         x = usec + (div_result.rem*1000);
619
620         if (x >= 1000000) {
621                 timeout->tv_sec++;
622                 x -= 1000000;
623         }
624
625         timeout->tv_nsec = x*1000;
626 }
627
628 void *BLI_thread_queue_pop_timeout(ThreadQueue *queue, int ms)
629 {
630         double t;
631         void *work= NULL;
632         struct timespec timeout;
633
634         t= PIL_check_seconds_timer();
635         wait_timeout(&timeout, ms);
636
637         /* wait until there is work */
638         pthread_mutex_lock(&queue->mutex);
639         while(BLI_gsqueue_is_empty(queue->queue) && !queue->nowait) {
640                 if(pthread_cond_timedwait(&queue->cond, &queue->mutex, &timeout) == ETIMEDOUT)
641                         break;
642                 else if(PIL_check_seconds_timer() - t >= ms*0.001)
643                         break;
644         }
645
646         /* if we have something, pop it */
647         if(!BLI_gsqueue_is_empty(queue->queue))
648                 BLI_gsqueue_pop(queue->queue, &work);
649
650         pthread_mutex_unlock(&queue->mutex);
651
652         return work;
653 }
654
655 int BLI_thread_queue_size(ThreadQueue *queue)
656 {
657         int size;
658
659         pthread_mutex_lock(&queue->mutex);
660         size= BLI_gsqueue_size(queue->queue);
661         pthread_mutex_unlock(&queue->mutex);
662
663         return size;
664 }
665
666 void BLI_thread_queue_nowait(ThreadQueue *queue)
667 {
668         pthread_mutex_lock(&queue->mutex);
669
670         queue->nowait= 1;
671
672         /* signal threads waiting to pop */
673         pthread_cond_signal(&queue->cond);
674         pthread_mutex_unlock(&queue->mutex);
675 }
676
677 void BLI_begin_threaded_malloc(void)
678 {
679         if(thread_levels == 0) {
680                 MEM_set_lock_callback(BLI_lock_malloc_thread, BLI_unlock_malloc_thread);
681         }
682         thread_levels++;
683 }
684
685 void BLI_end_threaded_malloc(void)
686 {
687         thread_levels--;
688         if(thread_levels==0)
689                 MEM_set_lock_callback(NULL, NULL);
690 }