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