Revert "Fix T67040: Undo crashes after renaming"
[blender.git] / source / blender / blenlib / intern / threads.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2006 Blender Foundation
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup bli
22  */
23
24 #include <stdlib.h>
25 #include <errno.h>
26 #include <string.h>
27
28 #include "MEM_guardedalloc.h"
29
30 #include "BLI_listbase.h"
31 #include "BLI_gsqueue.h"
32 #include "BLI_system.h"
33 #include "BLI_task.h"
34 #include "BLI_threads.h"
35
36 #include "PIL_time.h"
37
38 /* for checking system threads - BLI_system_thread_count */
39 #ifdef WIN32
40 #  include <windows.h>
41 #  include <sys/timeb.h>
42 #elif defined(__APPLE__)
43 #  include <sys/types.h>
44 #  include <sys/sysctl.h>
45 #else
46 #  include <unistd.h>
47 #  include <sys/time.h>
48 #endif
49
50 #include "atomic_ops.h"
51 #include "numaapi.h"
52
53 #if defined(__APPLE__) && defined(_OPENMP) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 2) && \
54     !defined(__clang__)
55 #  define USE_APPLE_OMP_FIX
56 #endif
57
58 #ifdef USE_APPLE_OMP_FIX
59 /* ************** libgomp (Apple gcc 4.2.1) TLS bug workaround *************** */
60 extern pthread_key_t gomp_tls_key;
61 static void *thread_tls_data;
62 #endif
63
64 /* We're using one global task scheduler for all kind of tasks. */
65 static TaskScheduler *task_scheduler = NULL;
66
67 /* ********** basic thread control API ************
68  *
69  * Many thread cases have an X amount of jobs, and only an Y amount of
70  * threads are useful (typically amount of cpus)
71  *
72  * This code can be used to start a maximum amount of 'thread slots', which
73  * then can be filled in a loop with an idle timer.
74  *
75  * A sample loop can look like this (pseudo c);
76  *
77  *     ListBase lb;
78  *     int maxthreads = 2;
79  *     int cont = 1;
80  *
81  *     BLI_threadpool_init(&lb, do_something_func, maxthreads);
82  *
83  *     while (cont) {
84  *         if (BLI_available_threads(&lb) && !(escape loop event)) {
85  *             // get new job (data pointer)
86  *             // tag job 'processed
87  *             BLI_threadpool_insert(&lb, job);
88  *         }
89  *         else PIL_sleep_ms(50);
90  *
91  *         // find if a job is ready, this the do_something_func() should write in job somewhere
92  *         cont = 0;
93  *         for (go over all jobs)
94  *             if (job is ready) {
95  *                 if (job was not removed) {
96  *                     BLI_threadpool_remove(&lb, job);
97  *                 }
98  *             }
99  *             else cont = 1;
100  *         }
101  *         // conditions to exit loop
102  *         if (if escape loop event) {
103  *             if (BLI_available_threadslots(&lb) == maxthreads) {
104  *                 break;
105  *             }
106  *         }
107  *     }
108  *
109  *     BLI_threadpool_end(&lb);
110  *
111  ************************************************ */
112 static SpinLock _malloc_lock;
113 static pthread_mutex_t _image_lock = PTHREAD_MUTEX_INITIALIZER;
114 static pthread_mutex_t _image_draw_lock = PTHREAD_MUTEX_INITIALIZER;
115 static pthread_mutex_t _viewer_lock = PTHREAD_MUTEX_INITIALIZER;
116 static pthread_mutex_t _custom1_lock = PTHREAD_MUTEX_INITIALIZER;
117 static pthread_mutex_t _rcache_lock = PTHREAD_MUTEX_INITIALIZER;
118 static pthread_mutex_t _opengl_lock = PTHREAD_MUTEX_INITIALIZER;
119 static pthread_mutex_t _nodes_lock = PTHREAD_MUTEX_INITIALIZER;
120 static pthread_mutex_t _movieclip_lock = PTHREAD_MUTEX_INITIALIZER;
121 static pthread_mutex_t _colormanage_lock = PTHREAD_MUTEX_INITIALIZER;
122 static pthread_mutex_t _fftw_lock = PTHREAD_MUTEX_INITIALIZER;
123 static pthread_mutex_t _view3d_lock = PTHREAD_MUTEX_INITIALIZER;
124 static pthread_t mainid;
125 static bool is_numa_available = false;
126 static unsigned int thread_levels = 0; /* threads can be invoked inside threads */
127 static int num_threads_override = 0;
128
129 /* just a max for security reasons */
130 #define RE_MAX_THREAD BLENDER_MAX_THREADS
131
132 typedef struct ThreadSlot {
133   struct ThreadSlot *next, *prev;
134   void *(*do_thread)(void *);
135   void *callerdata;
136   pthread_t pthread;
137   int avail;
138 } ThreadSlot;
139
140 static void BLI_lock_malloc_thread(void)
141 {
142   BLI_spin_lock(&_malloc_lock);
143 }
144
145 static void BLI_unlock_malloc_thread(void)
146 {
147   BLI_spin_unlock(&_malloc_lock);
148 }
149
150 void BLI_threadapi_init(void)
151 {
152   mainid = pthread_self();
153
154   BLI_spin_init(&_malloc_lock);
155   if (numaAPI_Initialize() == NUMAAPI_SUCCESS) {
156     is_numa_available = true;
157   }
158 }
159
160 void BLI_threadapi_exit(void)
161 {
162   if (task_scheduler) {
163     BLI_task_scheduler_free(task_scheduler);
164     task_scheduler = NULL;
165   }
166   BLI_spin_end(&_malloc_lock);
167 }
168
169 TaskScheduler *BLI_task_scheduler_get(void)
170 {
171   if (task_scheduler == NULL) {
172     int tot_thread = BLI_system_thread_count();
173
174     /* Do a lazy initialization, so it happens after
175      * command line arguments parsing
176      */
177     task_scheduler = BLI_task_scheduler_create(tot_thread);
178   }
179
180   return task_scheduler;
181 }
182
183 /* tot = 0 only initializes malloc mutex in a safe way (see sequence.c)
184  * problem otherwise: scene render will kill of the mutex!
185  */
186
187 void BLI_threadpool_init(ListBase *threadbase, void *(*do_thread)(void *), int tot)
188 {
189   int a;
190
191   if (threadbase != NULL && tot > 0) {
192     BLI_listbase_clear(threadbase);
193
194     if (tot > RE_MAX_THREAD) {
195       tot = RE_MAX_THREAD;
196     }
197     else if (tot < 1) {
198       tot = 1;
199     }
200
201     for (a = 0; a < tot; a++) {
202       ThreadSlot *tslot = MEM_callocN(sizeof(ThreadSlot), "threadslot");
203       BLI_addtail(threadbase, tslot);
204       tslot->do_thread = do_thread;
205       tslot->avail = 1;
206     }
207   }
208
209   unsigned int level = atomic_fetch_and_add_u(&thread_levels, 1);
210   if (level == 0) {
211     MEM_set_lock_callback(BLI_lock_malloc_thread, BLI_unlock_malloc_thread);
212
213 #ifdef USE_APPLE_OMP_FIX
214     /* workaround for Apple gcc 4.2.1 omp vs background thread bug,
215      * we copy gomp thread local storage pointer to setting it again
216      * inside the thread that we start */
217     thread_tls_data = pthread_getspecific(gomp_tls_key);
218 #endif
219   }
220 }
221
222 /* amount of available threads */
223 int BLI_available_threads(ListBase *threadbase)
224 {
225   ThreadSlot *tslot;
226   int counter = 0;
227
228   for (tslot = threadbase->first; tslot; tslot = tslot->next) {
229     if (tslot->avail) {
230       counter++;
231     }
232   }
233   return counter;
234 }
235
236 /* returns thread number, for sample patterns or threadsafe tables */
237 int BLI_threadpool_available_thread_index(ListBase *threadbase)
238 {
239   ThreadSlot *tslot;
240   int counter = 0;
241
242   for (tslot = threadbase->first; tslot; tslot = tslot->next, counter++) {
243     if (tslot->avail) {
244       return counter;
245     }
246   }
247   return 0;
248 }
249
250 static void *tslot_thread_start(void *tslot_p)
251 {
252   ThreadSlot *tslot = (ThreadSlot *)tslot_p;
253
254 #ifdef USE_APPLE_OMP_FIX
255   /* workaround for Apple gcc 4.2.1 omp vs background thread bug,
256    * set gomp thread local storage pointer which was copied beforehand */
257   pthread_setspecific(gomp_tls_key, thread_tls_data);
258 #endif
259
260   return tslot->do_thread(tslot->callerdata);
261 }
262
263 int BLI_thread_is_main(void)
264 {
265   return pthread_equal(pthread_self(), mainid);
266 }
267
268 void BLI_threadpool_insert(ListBase *threadbase, void *callerdata)
269 {
270   ThreadSlot *tslot;
271
272   for (tslot = threadbase->first; tslot; tslot = tslot->next) {
273     if (tslot->avail) {
274       tslot->avail = 0;
275       tslot->callerdata = callerdata;
276       pthread_create(&tslot->pthread, NULL, tslot_thread_start, tslot);
277       return;
278     }
279   }
280   printf("ERROR: could not insert thread slot\n");
281 }
282
283 void BLI_threadpool_remove(ListBase *threadbase, void *callerdata)
284 {
285   ThreadSlot *tslot;
286
287   for (tslot = threadbase->first; tslot; tslot = tslot->next) {
288     if (tslot->callerdata == callerdata) {
289       pthread_join(tslot->pthread, NULL);
290       tslot->callerdata = NULL;
291       tslot->avail = 1;
292     }
293   }
294 }
295
296 void BLI_threadpool_remove_index(ListBase *threadbase, int index)
297 {
298   ThreadSlot *tslot;
299   int counter = 0;
300
301   for (tslot = threadbase->first; tslot; tslot = tslot->next, counter++) {
302     if (counter == index && tslot->avail == 0) {
303       pthread_join(tslot->pthread, NULL);
304       tslot->callerdata = NULL;
305       tslot->avail = 1;
306       break;
307     }
308   }
309 }
310
311 void BLI_threadpool_clear(ListBase *threadbase)
312 {
313   ThreadSlot *tslot;
314
315   for (tslot = threadbase->first; tslot; tslot = tslot->next) {
316     if (tslot->avail == 0) {
317       pthread_join(tslot->pthread, NULL);
318       tslot->callerdata = NULL;
319       tslot->avail = 1;
320     }
321   }
322 }
323
324 void BLI_threadpool_end(ListBase *threadbase)
325 {
326   ThreadSlot *tslot;
327
328   /* only needed if there's actually some stuff to end
329    * this way we don't end up decrementing thread_levels on an empty threadbase
330    * */
331   if (threadbase && (BLI_listbase_is_empty(threadbase) == false)) {
332     for (tslot = threadbase->first; tslot; tslot = tslot->next) {
333       if (tslot->avail == 0) {
334         pthread_join(tslot->pthread, NULL);
335       }
336     }
337     BLI_freelistN(threadbase);
338   }
339
340   unsigned int level = atomic_sub_and_fetch_u(&thread_levels, 1);
341   if (level == 0) {
342     MEM_set_lock_callback(NULL, NULL);
343   }
344 }
345
346 /* System Information */
347
348 /* how many threads are native on this system? */
349 int BLI_system_thread_count(void)
350 {
351   static int t = -1;
352
353   if (num_threads_override != 0) {
354     return num_threads_override;
355   }
356   else if (LIKELY(t != -1)) {
357     return t;
358   }
359
360   {
361 #ifdef WIN32
362     SYSTEM_INFO info;
363     GetSystemInfo(&info);
364     t = (int)info.dwNumberOfProcessors;
365 #else
366 #  ifdef __APPLE__
367     int mib[2];
368     size_t len;
369
370     mib[0] = CTL_HW;
371     mib[1] = HW_NCPU;
372     len = sizeof(t);
373     sysctl(mib, 2, &t, &len, NULL, 0);
374 #  else
375     t = (int)sysconf(_SC_NPROCESSORS_ONLN);
376 #  endif
377 #endif
378   }
379
380   CLAMP(t, 1, RE_MAX_THREAD);
381
382   return t;
383 }
384
385 void BLI_system_num_threads_override_set(int num)
386 {
387   num_threads_override = num;
388 }
389
390 int BLI_system_num_threads_override_get(void)
391 {
392   return num_threads_override;
393 }
394
395 /* Global Mutex Locks */
396
397 static ThreadMutex *global_mutex_from_type(const int type)
398 {
399   switch (type) {
400     case LOCK_IMAGE:
401       return &_image_lock;
402     case LOCK_DRAW_IMAGE:
403       return &_image_draw_lock;
404     case LOCK_VIEWER:
405       return &_viewer_lock;
406     case LOCK_CUSTOM1:
407       return &_custom1_lock;
408     case LOCK_RCACHE:
409       return &_rcache_lock;
410     case LOCK_OPENGL:
411       return &_opengl_lock;
412     case LOCK_NODES:
413       return &_nodes_lock;
414     case LOCK_MOVIECLIP:
415       return &_movieclip_lock;
416     case LOCK_COLORMANAGE:
417       return &_colormanage_lock;
418     case LOCK_FFTW:
419       return &_fftw_lock;
420     case LOCK_VIEW3D:
421       return &_view3d_lock;
422     default:
423       BLI_assert(0);
424       return NULL;
425   }
426 }
427
428 void BLI_thread_lock(int type)
429 {
430   pthread_mutex_lock(global_mutex_from_type(type));
431 }
432
433 void BLI_thread_unlock(int type)
434 {
435   pthread_mutex_unlock(global_mutex_from_type(type));
436 }
437
438 /* Mutex Locks */
439
440 void BLI_mutex_init(ThreadMutex *mutex)
441 {
442   pthread_mutex_init(mutex, NULL);
443 }
444
445 void BLI_mutex_lock(ThreadMutex *mutex)
446 {
447   pthread_mutex_lock(mutex);
448 }
449
450 void BLI_mutex_unlock(ThreadMutex *mutex)
451 {
452   pthread_mutex_unlock(mutex);
453 }
454
455 bool BLI_mutex_trylock(ThreadMutex *mutex)
456 {
457   return (pthread_mutex_trylock(mutex) == 0);
458 }
459
460 void BLI_mutex_end(ThreadMutex *mutex)
461 {
462   pthread_mutex_destroy(mutex);
463 }
464
465 ThreadMutex *BLI_mutex_alloc(void)
466 {
467   ThreadMutex *mutex = MEM_callocN(sizeof(ThreadMutex), "ThreadMutex");
468   BLI_mutex_init(mutex);
469   return mutex;
470 }
471
472 void BLI_mutex_free(ThreadMutex *mutex)
473 {
474   BLI_mutex_end(mutex);
475   MEM_freeN(mutex);
476 }
477
478 /* Spin Locks */
479
480 void BLI_spin_init(SpinLock *spin)
481 {
482 #if defined(__APPLE__)
483   *spin = OS_SPINLOCK_INIT;
484 #elif defined(_MSC_VER)
485   *spin = 0;
486 #else
487   pthread_spin_init(spin, 0);
488 #endif
489 }
490
491 void BLI_spin_lock(SpinLock *spin)
492 {
493 #if defined(__APPLE__)
494   OSSpinLockLock(spin);
495 #elif defined(_MSC_VER)
496   while (InterlockedExchangeAcquire(spin, 1)) {
497     while (*spin) {
498       /* Spin-lock hint for processors with hyperthreading. */
499       YieldProcessor();
500     }
501   }
502 #else
503   pthread_spin_lock(spin);
504 #endif
505 }
506
507 void BLI_spin_unlock(SpinLock *spin)
508 {
509 #if defined(__APPLE__)
510   OSSpinLockUnlock(spin);
511 #elif defined(_MSC_VER)
512   _ReadWriteBarrier();
513   *spin = 0;
514 #else
515   pthread_spin_unlock(spin);
516 #endif
517 }
518
519 #if defined(__APPLE__) || defined(_MSC_VER)
520 void BLI_spin_end(SpinLock *UNUSED(spin))
521 {
522 }
523 #else
524 void BLI_spin_end(SpinLock *spin)
525 {
526   pthread_spin_destroy(spin);
527 }
528 #endif
529
530 /* Read/Write Mutex Lock */
531
532 void BLI_rw_mutex_init(ThreadRWMutex *mutex)
533 {
534   pthread_rwlock_init(mutex, NULL);
535 }
536
537 void BLI_rw_mutex_lock(ThreadRWMutex *mutex, int mode)
538 {
539   if (mode == THREAD_LOCK_READ) {
540     pthread_rwlock_rdlock(mutex);
541   }
542   else {
543     pthread_rwlock_wrlock(mutex);
544   }
545 }
546
547 void BLI_rw_mutex_unlock(ThreadRWMutex *mutex)
548 {
549   pthread_rwlock_unlock(mutex);
550 }
551
552 void BLI_rw_mutex_end(ThreadRWMutex *mutex)
553 {
554   pthread_rwlock_destroy(mutex);
555 }
556
557 ThreadRWMutex *BLI_rw_mutex_alloc(void)
558 {
559   ThreadRWMutex *mutex = MEM_callocN(sizeof(ThreadRWMutex), "ThreadRWMutex");
560   BLI_rw_mutex_init(mutex);
561   return mutex;
562 }
563
564 void BLI_rw_mutex_free(ThreadRWMutex *mutex)
565 {
566   BLI_rw_mutex_end(mutex);
567   MEM_freeN(mutex);
568 }
569
570 /* Ticket Mutex Lock */
571
572 struct TicketMutex {
573   pthread_cond_t cond;
574   pthread_mutex_t mutex;
575   unsigned int queue_head, queue_tail;
576 };
577
578 TicketMutex *BLI_ticket_mutex_alloc(void)
579 {
580   TicketMutex *ticket = MEM_callocN(sizeof(TicketMutex), "TicketMutex");
581
582   pthread_cond_init(&ticket->cond, NULL);
583   pthread_mutex_init(&ticket->mutex, NULL);
584
585   return ticket;
586 }
587
588 void BLI_ticket_mutex_free(TicketMutex *ticket)
589 {
590   pthread_mutex_destroy(&ticket->mutex);
591   pthread_cond_destroy(&ticket->cond);
592   MEM_freeN(ticket);
593 }
594
595 void BLI_ticket_mutex_lock(TicketMutex *ticket)
596 {
597   unsigned int queue_me;
598
599   pthread_mutex_lock(&ticket->mutex);
600   queue_me = ticket->queue_tail++;
601
602   while (queue_me != ticket->queue_head) {
603     pthread_cond_wait(&ticket->cond, &ticket->mutex);
604   }
605
606   pthread_mutex_unlock(&ticket->mutex);
607 }
608
609 void BLI_ticket_mutex_unlock(TicketMutex *ticket)
610 {
611   pthread_mutex_lock(&ticket->mutex);
612   ticket->queue_head++;
613   pthread_cond_broadcast(&ticket->cond);
614   pthread_mutex_unlock(&ticket->mutex);
615 }
616
617 /* ************************************************ */
618
619 /* Condition */
620
621 void BLI_condition_init(ThreadCondition *cond)
622 {
623   pthread_cond_init(cond, NULL);
624 }
625
626 void BLI_condition_wait(ThreadCondition *cond, ThreadMutex *mutex)
627 {
628   pthread_cond_wait(cond, mutex);
629 }
630
631 void BLI_condition_wait_global_mutex(ThreadCondition *cond, const int type)
632 {
633   pthread_cond_wait(cond, global_mutex_from_type(type));
634 }
635
636 void BLI_condition_notify_one(ThreadCondition *cond)
637 {
638   pthread_cond_signal(cond);
639 }
640
641 void BLI_condition_notify_all(ThreadCondition *cond)
642 {
643   pthread_cond_broadcast(cond);
644 }
645
646 void BLI_condition_end(ThreadCondition *cond)
647 {
648   pthread_cond_destroy(cond);
649 }
650
651 /* ************************************************ */
652
653 struct ThreadQueue {
654   GSQueue *queue;
655   pthread_mutex_t mutex;
656   pthread_cond_t push_cond;
657   pthread_cond_t finish_cond;
658   volatile int nowait;
659   volatile int canceled;
660 };
661
662 ThreadQueue *BLI_thread_queue_init(void)
663 {
664   ThreadQueue *queue;
665
666   queue = MEM_callocN(sizeof(ThreadQueue), "ThreadQueue");
667   queue->queue = BLI_gsqueue_new(sizeof(void *));
668
669   pthread_mutex_init(&queue->mutex, NULL);
670   pthread_cond_init(&queue->push_cond, NULL);
671   pthread_cond_init(&queue->finish_cond, NULL);
672
673   return queue;
674 }
675
676 void BLI_thread_queue_free(ThreadQueue *queue)
677 {
678   /* destroy everything, assumes no one is using queue anymore */
679   pthread_cond_destroy(&queue->finish_cond);
680   pthread_cond_destroy(&queue->push_cond);
681   pthread_mutex_destroy(&queue->mutex);
682
683   BLI_gsqueue_free(queue->queue);
684
685   MEM_freeN(queue);
686 }
687
688 void BLI_thread_queue_push(ThreadQueue *queue, void *work)
689 {
690   pthread_mutex_lock(&queue->mutex);
691
692   BLI_gsqueue_push(queue->queue, &work);
693
694   /* signal threads waiting to pop */
695   pthread_cond_signal(&queue->push_cond);
696   pthread_mutex_unlock(&queue->mutex);
697 }
698
699 void *BLI_thread_queue_pop(ThreadQueue *queue)
700 {
701   void *work = NULL;
702
703   /* wait until there is work */
704   pthread_mutex_lock(&queue->mutex);
705   while (BLI_gsqueue_is_empty(queue->queue) && !queue->nowait) {
706     pthread_cond_wait(&queue->push_cond, &queue->mutex);
707   }
708
709   /* if we have something, pop it */
710   if (!BLI_gsqueue_is_empty(queue->queue)) {
711     BLI_gsqueue_pop(queue->queue, &work);
712
713     if (BLI_gsqueue_is_empty(queue->queue)) {
714       pthread_cond_broadcast(&queue->finish_cond);
715     }
716   }
717
718   pthread_mutex_unlock(&queue->mutex);
719
720   return work;
721 }
722
723 static void wait_timeout(struct timespec *timeout, int ms)
724 {
725   ldiv_t div_result;
726   long sec, usec, x;
727
728 #ifdef WIN32
729   {
730     struct _timeb now;
731     _ftime(&now);
732     sec = now.time;
733     usec = now.millitm * 1000; /* microsecond precision would be better */
734   }
735 #else
736   {
737     struct timeval now;
738     gettimeofday(&now, NULL);
739     sec = now.tv_sec;
740     usec = now.tv_usec;
741   }
742 #endif
743
744   /* add current time + millisecond offset */
745   div_result = ldiv(ms, 1000);
746   timeout->tv_sec = sec + div_result.quot;
747
748   x = usec + (div_result.rem * 1000);
749
750   if (x >= 1000000) {
751     timeout->tv_sec++;
752     x -= 1000000;
753   }
754
755   timeout->tv_nsec = x * 1000;
756 }
757
758 void *BLI_thread_queue_pop_timeout(ThreadQueue *queue, int ms)
759 {
760   double t;
761   void *work = NULL;
762   struct timespec timeout;
763
764   t = PIL_check_seconds_timer();
765   wait_timeout(&timeout, ms);
766
767   /* wait until there is work */
768   pthread_mutex_lock(&queue->mutex);
769   while (BLI_gsqueue_is_empty(queue->queue) && !queue->nowait) {
770     if (pthread_cond_timedwait(&queue->push_cond, &queue->mutex, &timeout) == ETIMEDOUT) {
771       break;
772     }
773     else if (PIL_check_seconds_timer() - t >= ms * 0.001) {
774       break;
775     }
776   }
777
778   /* if we have something, pop it */
779   if (!BLI_gsqueue_is_empty(queue->queue)) {
780     BLI_gsqueue_pop(queue->queue, &work);
781
782     if (BLI_gsqueue_is_empty(queue->queue)) {
783       pthread_cond_broadcast(&queue->finish_cond);
784     }
785   }
786
787   pthread_mutex_unlock(&queue->mutex);
788
789   return work;
790 }
791
792 int BLI_thread_queue_len(ThreadQueue *queue)
793 {
794   int size;
795
796   pthread_mutex_lock(&queue->mutex);
797   size = BLI_gsqueue_len(queue->queue);
798   pthread_mutex_unlock(&queue->mutex);
799
800   return size;
801 }
802
803 bool BLI_thread_queue_is_empty(ThreadQueue *queue)
804 {
805   bool is_empty;
806
807   pthread_mutex_lock(&queue->mutex);
808   is_empty = BLI_gsqueue_is_empty(queue->queue);
809   pthread_mutex_unlock(&queue->mutex);
810
811   return is_empty;
812 }
813
814 void BLI_thread_queue_nowait(ThreadQueue *queue)
815 {
816   pthread_mutex_lock(&queue->mutex);
817
818   queue->nowait = 1;
819
820   /* signal threads waiting to pop */
821   pthread_cond_broadcast(&queue->push_cond);
822   pthread_mutex_unlock(&queue->mutex);
823 }
824
825 void BLI_thread_queue_wait_finish(ThreadQueue *queue)
826 {
827   /* wait for finish condition */
828   pthread_mutex_lock(&queue->mutex);
829
830   while (!BLI_gsqueue_is_empty(queue->queue)) {
831     pthread_cond_wait(&queue->finish_cond, &queue->mutex);
832   }
833
834   pthread_mutex_unlock(&queue->mutex);
835 }
836
837 /* ************************************************ */
838
839 void BLI_threaded_malloc_begin(void)
840 {
841   unsigned int level = atomic_fetch_and_add_u(&thread_levels, 1);
842   if (level == 0) {
843     MEM_set_lock_callback(BLI_lock_malloc_thread, BLI_unlock_malloc_thread);
844     /* There is a little chance that two threads will need to access to a
845      * scheduler which was not yet created from main thread. which could
846      * cause scheduler created multiple times.
847      */
848     BLI_task_scheduler_get();
849   }
850 }
851
852 void BLI_threaded_malloc_end(void)
853 {
854   unsigned int level = atomic_sub_and_fetch_u(&thread_levels, 1);
855   if (level == 0) {
856     MEM_set_lock_callback(NULL, NULL);
857   }
858 }
859
860 /* **** Special functions to help performance on crazy NUMA setups. **** */
861
862 #if 0  /* UNUSED */
863 static bool check_is_threadripper2_alike_topology(void)
864 {
865   /* NOTE: We hope operating system does not support CPU hotswap to
866    * a different brand. And that SMP of different types is also not
867    * encouraged by the system. */
868   static bool is_initialized = false;
869   static bool is_threadripper2 = false;
870   if (is_initialized) {
871     return is_threadripper2;
872   }
873   is_initialized = true;
874   char *cpu_brand = BLI_cpu_brand_string();
875   if (cpu_brand == NULL) {
876     return false;
877   }
878   if (strstr(cpu_brand, "Threadripper")) {
879     /* NOTE: We consider all Thread-rippers having similar topology to
880      * the second one. This is because we are trying to utilize NUMA node
881      * 0 as much as possible. This node does exist on earlier versions of
882      * thread-ripper and setting affinity to it should not have negative
883      * effect.
884      * This allows us to avoid per-model check, making the code more
885      * reliable for the CPUs which are not yet released.
886      */
887     if (strstr(cpu_brand, "2990WX") || strstr(cpu_brand, "2950X")) {
888       is_threadripper2 = true;
889     }
890   }
891   /* NOTE: While all dies of EPYC has memory controller, only two f them
892    * has access to a lower-indexed DDR slots. Those dies are same as on
893    * Threadripper2 with the memory controller.
894    * Now, it is rather likely that reasonable amount of users don't max
895    * up their DR slots, making it only two dies connected to a DDR slot
896    * with actual memory in it. */
897   if (strstr(cpu_brand, "EPYC")) {
898     /* NOTE: Similarly to Thread-ripper we do not do model check. */
899     is_threadripper2 = true;
900   }
901   MEM_freeN(cpu_brand);
902   return is_threadripper2;
903 }
904
905 static void threadripper_put_process_on_fast_node(void)
906 {
907   if (!is_numa_available) {
908     return;
909   }
910   /* NOTE: Technically, we can use NUMA nodes 0 and 2 and using both of
911    * them in the affinity mask will allow OS to schedule threads more
912    * flexible,possibly increasing overall performance when multiple apps
913    * are crunching numbers.
914    *
915    * However, if scene fits into memory adjacent to a single die we don't
916    * want OS to re-schedule the process to another die since that will make
917    * it further away from memory allocated for .blend file. */
918   /* NOTE: Even if NUMA is available in the API but is disabled in BIOS on
919    * this workstation we still process here. If NUMA is disabled it will be a
920    * single node, so our action is no-visible-changes, but allows to keep
921    * things simple and unified. */
922   numaAPI_RunProcessOnNode(0);
923 }
924
925 static void threadripper_put_thread_on_fast_node(void)
926 {
927   if (!is_numa_available) {
928     return;
929   }
930   /* NOTE: This is where things becomes more interesting. On the one hand
931    * we can use nodes 0 and 2 and allow operating system to do balancing
932    * of processes/threads for the maximum performance when multiple apps
933    * are running.
934    * On another hand, however, we probably want to use same node as the
935    * main thread since that's where the memory of .blend file is likely
936    * to be allocated.
937    * Since the main thread is currently on node 0, we also put thread on
938    * same node. */
939   /* See additional note about NUMA disabled in BIOS above. */
940   numaAPI_RunThreadOnNode(0);
941 }
942 #endif /* UNUSED */
943
944 void BLI_thread_put_process_on_fast_node(void)
945 {
946   /* Disabled for now since this causes only 16 threads to be used on a
947    * thread-ripper for computations like sculpting and fluid sim. The problem
948    * is that all threads created as children from this thread will inherit
949    * the NUMA node and so will end up on the same node. This can be fixed
950    * case-by-case by assigning the NUMA node for every child thread, however
951    * this is difficult for external libraries and OpenMP, and out of our
952    * control for plugins like external renderers. */
953 #if 0
954   if (check_is_threadripper2_alike_topology()) {
955     threadripper_put_process_on_fast_node();
956   }
957 #endif
958 }
959
960 void BLI_thread_put_thread_on_fast_node(void)
961 {
962   /* Disabled for now, see comment above. */
963 #if 0
964   if (check_is_threadripper2_alike_topology()) {
965     threadripper_put_thread_on_fast_node();
966   }
967 #endif
968 }