7b59a7905aa290da3f185a7165d9aa04f5d32dfb
[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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 /** \file blender/blenlib/intern/threads.c
32  *  \ingroup bli
33  */
34
35
36 #include <errno.h>
37 #include <string.h>
38
39 #include "MEM_guardedalloc.h"
40
41
42 #include "BLI_blenlib.h"
43 #include "BLI_gsqueue.h"
44 #include "BLI_threads.h"
45
46 #include "PIL_time.h"
47
48 /* for checking system threads - BLI_system_thread_count */
49 #ifdef WIN32
50 #include "windows.h"
51 #include <sys/timeb.h>
52 #elif defined(__APPLE__)
53 #include <sys/types.h>
54 #include <sys/sysctl.h>
55 #else
56 #include <unistd.h> 
57 #include <sys/time.h>
58 #endif
59
60 #if defined(__APPLE__) && (PARALLEL == 1) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 2)
61 /* ************** libgomp (Apple gcc 4.2.1) TLS bug workaround *************** */
62 extern pthread_key_t gomp_tls_key;
63 static void *thread_tls_data;
64 #endif
65
66 /* ********** basic thread control API ************ 
67
68 Many thread cases have an X amount of jobs, and only an Y amount of
69 threads are useful (typically amount of cpus)
70
71 This code can be used to start a maximum amount of 'thread slots', which
72 then can be filled in a loop with an idle timer. 
73
74 A sample loop can look like this (pseudo c);
75
76         ListBase lb;
77         int maxthreads= 2;
78         int cont= 1;
79
80         BLI_init_threads(&lb, do_something_func, maxthreads);
81
82         while(cont) {
83                 if(BLI_available_threads(&lb) && !(escape loop event)) {
84                         // get new job (data pointer)
85                         // tag job 'processed 
86                         BLI_insert_thread(&lb, job);
87                 }
88                 else PIL_sleep_ms(50);
89                 
90                 // find if a job is ready, this the do_something_func() should write in job somewhere
91                 cont= 0;
92                 for(go over all jobs)
93                         if(job is ready) {
94                                 if(job was not removed) {
95                                         BLI_remove_thread(&lb, job);
96                                 }
97                         }
98                         else cont= 1;
99                 }
100                 // conditions to exit loop 
101                 if(if escape loop event) {
102                         if(BLI_available_threadslots(&lb)==maxthreads)
103                                 break;
104                 }
105         }
106
107         BLI_end_threads(&lb);
108
109  ************************************************ */
110 static pthread_mutex_t _malloc_lock = PTHREAD_MUTEX_INITIALIZER;
111 static pthread_mutex_t _image_lock = PTHREAD_MUTEX_INITIALIZER;
112 static pthread_mutex_t _preview_lock = PTHREAD_MUTEX_INITIALIZER;
113 static pthread_mutex_t _viewer_lock = PTHREAD_MUTEX_INITIALIZER;
114 static pthread_mutex_t _custom1_lock = PTHREAD_MUTEX_INITIALIZER;
115 static pthread_mutex_t _rcache_lock = PTHREAD_MUTEX_INITIALIZER;
116 static pthread_mutex_t _opengl_lock = PTHREAD_MUTEX_INITIALIZER;
117 static pthread_t mainid;
118 static int thread_levels= 0;    /* threads can be invoked inside threads */
119
120 /* just a max for security reasons */
121 #define RE_MAX_THREAD BLENDER_MAX_THREADS
122
123 typedef struct ThreadSlot {
124         struct ThreadSlot *next, *prev;
125         void *(*do_thread)(void *);
126         void *callerdata;
127         pthread_t pthread;
128         int avail;
129 } ThreadSlot;
130
131 static void BLI_lock_malloc_thread(void)
132 {
133         pthread_mutex_lock(&_malloc_lock);
134 }
135
136 static void BLI_unlock_malloc_thread(void)
137 {
138         pthread_mutex_unlock(&_malloc_lock);
139 }
140
141 void BLI_threadapi_init(void)
142 {
143         mainid = pthread_self();
144 }
145
146 /* tot = 0 only initializes malloc mutex in a safe way (see sequence.c)
147    problem otherwise: scene render will kill of the mutex!
148 */
149
150 void BLI_init_threads(ListBase *threadbase, void *(*do_thread)(void *), int tot)
151 {
152         int a;
153
154         if(threadbase != NULL && tot > 0) {
155                 threadbase->first= threadbase->last= NULL;
156         
157                 if(tot>RE_MAX_THREAD) tot= RE_MAX_THREAD;
158                 else if(tot<1) tot= 1;
159         
160                 for(a=0; a<tot; a++) {
161                         ThreadSlot *tslot= MEM_callocN(sizeof(ThreadSlot), "threadslot");
162                         BLI_addtail(threadbase, tslot);
163                         tslot->do_thread= do_thread;
164                         tslot->avail= 1;
165                 }
166         }
167         
168         if(thread_levels == 0) {
169                 MEM_set_lock_callback(BLI_lock_malloc_thread, BLI_unlock_malloc_thread);
170
171 #if defined(__APPLE__) && (PARALLEL == 1) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 2)
172                 /* workaround for Apple gcc 4.2.1 omp vs background thread bug,
173                    we copy gomp thread local storage pointer to setting it again
174                    inside the thread that we start */
175                 thread_tls_data = pthread_getspecific(gomp_tls_key);
176 #endif
177         }
178
179         thread_levels++;
180 }
181
182 /* amount of available threads */
183 int BLI_available_threads(ListBase *threadbase)
184 {
185         ThreadSlot *tslot;
186         int counter=0;
187         
188         for(tslot= threadbase->first; tslot; tslot= tslot->next) {
189                 if(tslot->avail)
190                         counter++;
191         }
192         return counter;
193 }
194
195 /* returns thread number, for sample patterns or threadsafe tables */
196 int BLI_available_thread_index(ListBase *threadbase)
197 {
198         ThreadSlot *tslot;
199         int counter=0;
200         
201         for(tslot= threadbase->first; tslot; tslot= tslot->next, counter++) {
202                 if(tslot->avail)
203                         return counter;
204         }
205         return 0;
206 }
207
208 static void *tslot_thread_start(void *tslot_p)
209 {
210         ThreadSlot *tslot= (ThreadSlot*)tslot_p;
211
212 #if defined(__APPLE__) && (PARALLEL == 1) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 2)
213         /* workaround for Apple gcc 4.2.1 omp vs background thread bug,
214            set gomp thread local storage pointer which was copied beforehand */
215         pthread_setspecific (gomp_tls_key, thread_tls_data);
216 #endif
217
218         return tslot->do_thread(tslot->callerdata);
219 }
220
221 int BLI_thread_is_main(void) {
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 #       elif defined(__sgi)
322         t = sysconf(_SC_NPROC_ONLN);
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 }
353
354 void BLI_unlock_thread(int type)
355 {
356         if (type==LOCK_IMAGE)
357                 pthread_mutex_unlock(&_image_lock);
358         else if (type==LOCK_PREVIEW)
359                 pthread_mutex_unlock(&_preview_lock);
360         else if (type==LOCK_VIEWER)
361                 pthread_mutex_unlock(&_viewer_lock);
362         else if(type==LOCK_CUSTOM1)
363                 pthread_mutex_unlock(&_custom1_lock);
364         else if(type==LOCK_RCACHE)
365                 pthread_mutex_unlock(&_rcache_lock);
366         else if(type==LOCK_OPENGL)
367                 pthread_mutex_unlock(&_opengl_lock);
368 }
369
370 /* Mutex Locks */
371
372 void BLI_mutex_init(ThreadMutex *mutex)
373 {
374         pthread_mutex_init(mutex, NULL);
375 }
376
377 void BLI_mutex_lock(ThreadMutex *mutex)
378 {
379         pthread_mutex_lock(mutex);
380 }
381
382 void BLI_mutex_unlock(ThreadMutex *mutex)
383 {
384         pthread_mutex_unlock(mutex);
385 }
386
387 void BLI_mutex_end(ThreadMutex *mutex)
388 {
389         pthread_mutex_destroy(mutex);
390 }
391
392 /* Read/Write Mutex Lock */
393
394 void BLI_rw_mutex_init(ThreadRWMutex *mutex)
395 {
396         pthread_rwlock_init(mutex, NULL);
397 }
398
399 void BLI_rw_mutex_lock(ThreadRWMutex *mutex, int mode)
400 {
401         if(mode == THREAD_LOCK_READ)
402                 pthread_rwlock_rdlock(mutex);
403         else
404                 pthread_rwlock_wrlock(mutex);
405 }
406
407 void BLI_rw_mutex_unlock(ThreadRWMutex *mutex)
408 {
409         pthread_rwlock_unlock(mutex);
410 }
411
412 void BLI_rw_mutex_end(ThreadRWMutex *mutex)
413 {
414         pthread_rwlock_destroy(mutex);
415 }
416
417 /* ************************************************ */
418
419 typedef struct ThreadedWorker {
420         ListBase threadbase;
421         void *(*work_fnct)(void *);
422         char     busy[RE_MAX_THREAD];
423         int              total;
424         int              sleep_time;
425 } ThreadedWorker;
426
427 typedef struct WorkParam {
428         ThreadedWorker *worker;
429         void *param;
430         int       index;
431 } WorkParam;
432
433 static void *exec_work_fnct(void *v_param)
434 {
435         WorkParam *p = (WorkParam*)v_param;
436         void *value;
437         
438         value = p->worker->work_fnct(p->param);
439         
440         p->worker->busy[p->index] = 0;
441         MEM_freeN(p);
442         
443         return value;
444 }
445
446 ThreadedWorker *BLI_create_worker(void *(*do_thread)(void *), int tot, int sleep_time)
447 {
448         ThreadedWorker *worker;
449         
450         (void)sleep_time; /* unused */
451         
452         worker = MEM_callocN(sizeof(ThreadedWorker), "threadedworker");
453         
454         if (tot > RE_MAX_THREAD)
455         {
456                 tot = RE_MAX_THREAD;
457         }
458         else if (tot < 1)
459         {
460                 tot= 1;
461         }
462         
463         worker->total = tot;
464         worker->work_fnct = do_thread;
465         
466         BLI_init_threads(&worker->threadbase, exec_work_fnct, tot);
467         
468         return worker;
469 }
470
471 void BLI_end_worker(ThreadedWorker *worker)
472 {
473         BLI_remove_threads(&worker->threadbase);
474 }
475
476 void BLI_destroy_worker(ThreadedWorker *worker)
477 {
478         BLI_end_worker(worker);
479         BLI_freelistN(&worker->threadbase);
480         MEM_freeN(worker);
481 }
482
483 void BLI_insert_work(ThreadedWorker *worker, void *param)
484 {
485         WorkParam *p = MEM_callocN(sizeof(WorkParam), "workparam");
486         int index;
487         
488         if (BLI_available_threads(&worker->threadbase) == 0)
489         {
490                 index = worker->total;
491                 while(index == worker->total)
492                 {
493                         PIL_sleep_ms(worker->sleep_time);
494                         
495                         for (index = 0; index < worker->total; index++)
496                         {
497                                 if (worker->busy[index] == 0)
498                                 {
499                                         BLI_remove_thread_index(&worker->threadbase, index);
500                                         break;
501                                 }
502                         }
503                 }
504         }
505         else
506         {
507                 index = BLI_available_thread_index(&worker->threadbase);
508         }
509         
510         worker->busy[index] = 1;
511         
512         p->param = param;
513         p->index = index;
514         p->worker = worker;
515         
516         BLI_insert_thread(&worker->threadbase, p);
517 }
518
519 /* ************************************************ */
520
521 struct ThreadQueue {
522         GSQueue *queue;
523         pthread_mutex_t mutex;
524         pthread_cond_t cond;
525         int nowait;
526 };
527
528 ThreadQueue *BLI_thread_queue_init(void)
529 {
530         ThreadQueue *queue;
531
532         queue= MEM_callocN(sizeof(ThreadQueue), "ThreadQueue");
533         queue->queue= BLI_gsqueue_new(sizeof(void*));
534
535         pthread_mutex_init(&queue->mutex, NULL);
536         pthread_cond_init(&queue->cond, NULL);
537
538         return queue;
539 }
540
541 void BLI_thread_queue_free(ThreadQueue *queue)
542 {
543         pthread_cond_destroy(&queue->cond);
544         pthread_mutex_destroy(&queue->mutex);
545
546         BLI_gsqueue_free(queue->queue);
547
548         MEM_freeN(queue);
549 }
550
551 void BLI_thread_queue_push(ThreadQueue *queue, void *work)
552 {
553         pthread_mutex_lock(&queue->mutex);
554
555         BLI_gsqueue_push(queue->queue, &work);
556
557         /* signal threads waiting to pop */
558         pthread_cond_signal(&queue->cond);
559         pthread_mutex_unlock(&queue->mutex);
560 }
561
562 void *BLI_thread_queue_pop(ThreadQueue *queue)
563 {
564         void *work= NULL;
565
566         /* wait until there is work */
567         pthread_mutex_lock(&queue->mutex);
568         while(BLI_gsqueue_is_empty(queue->queue) && !queue->nowait)
569                 pthread_cond_wait(&queue->cond, &queue->mutex);
570
571         /* if we have something, pop it */
572         if(!BLI_gsqueue_is_empty(queue->queue))
573                 BLI_gsqueue_pop(queue->queue, &work);
574
575         pthread_mutex_unlock(&queue->mutex);
576
577         return work;
578 }
579
580 static void wait_timeout(struct timespec *timeout, int ms)
581 {
582         ldiv_t div_result;
583         long sec, usec, x;
584
585 #ifdef WIN32
586         {
587                 struct _timeb now;
588                 _ftime(&now);
589                 sec = now.time;
590                 usec = now.millitm*1000; /* microsecond precision would be better */
591         }
592 #else
593         {
594                 struct timeval now;
595                 gettimeofday(&now, NULL);
596                 sec = now.tv_sec;
597                 usec = now.tv_usec;
598         }
599 #endif
600
601         /* add current time + millisecond offset */
602         div_result = ldiv(ms, 1000);
603         timeout->tv_sec = sec + div_result.quot;
604
605         x = usec + (div_result.rem*1000);
606
607         if (x >= 1000000) {
608                 timeout->tv_sec++;
609                 x -= 1000000;
610         }
611
612         timeout->tv_nsec = x*1000;
613 }
614
615 void *BLI_thread_queue_pop_timeout(ThreadQueue *queue, int ms)
616 {
617         double t;
618         void *work= NULL;
619         struct timespec timeout;
620
621         t= PIL_check_seconds_timer();
622         wait_timeout(&timeout, ms);
623
624         /* wait until there is work */
625         pthread_mutex_lock(&queue->mutex);
626         while(BLI_gsqueue_is_empty(queue->queue) && !queue->nowait) {
627                 if(pthread_cond_timedwait(&queue->cond, &queue->mutex, &timeout) == ETIMEDOUT)
628                         break;
629                 else if(PIL_check_seconds_timer() - t >= ms*0.001)
630                         break;
631         }
632
633         /* if we have something, pop it */
634         if(!BLI_gsqueue_is_empty(queue->queue))
635                 BLI_gsqueue_pop(queue->queue, &work);
636
637         pthread_mutex_unlock(&queue->mutex);
638
639         return work;
640 }
641
642 int BLI_thread_queue_size(ThreadQueue *queue)
643 {
644         int size;
645
646         pthread_mutex_lock(&queue->mutex);
647         size= BLI_gsqueue_size(queue->queue);
648         pthread_mutex_unlock(&queue->mutex);
649
650         return size;
651 }
652
653 void BLI_thread_queue_nowait(ThreadQueue *queue)
654 {
655         pthread_mutex_lock(&queue->mutex);
656
657         queue->nowait= 1;
658
659         /* signal threads waiting to pop */
660         pthread_cond_signal(&queue->cond);
661         pthread_mutex_unlock(&queue->mutex);
662 }
663