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