Blocking API that farms out count jobs to a thread pool. It may return with some work undone if func_ptr() returns a non-zero result. This function obviously has its shortcommings. Only one call to ThreadPool_Do can be running at a time. It is not intended for general purpose use. If clEnqueueNativeKernelFn, out of order queues and a CL_DEVICE_TYPE_CPU were all available then it would make more s
| 770 | // If clEnqueueNativeKernelFn, out of order queues and a CL_DEVICE_TYPE_CPU were |
| 771 | // all available then it would make more sense to use those features. |
| 772 | cl_int ThreadPool_Do(TPFuncPtr func_ptr, cl_uint count, void *userInfo) |
| 773 | { |
| 774 | #ifndef _WIN32 |
| 775 | cl_int newErr; |
| 776 | #endif |
| 777 | cl_int err = 0; |
| 778 | // Lazily set up our threads |
| 779 | #if defined(_MSC_VER) && (_WIN32_WINNT >= 0x600) |
| 780 | err = !_InitOnceExecuteOnce(&threadpool_init_control, _ThreadPool_Init, |
| 781 | NULL, NULL); |
| 782 | #elif defined(_WIN32) |
| 783 | if (threadpool_init_control == 0) |
| 784 | { |
| 785 | #warning This is buggy and race prone. Find a better way. |
| 786 | ThreadPool_Init(); |
| 787 | threadpool_init_control = 1; |
| 788 | } |
| 789 | #else // posix platform |
| 790 | err = pthread_once(&threadpool_init_control, ThreadPool_Init); |
| 791 | if (err) |
| 792 | { |
| 793 | log_error("Error %d from pthread_once. Unable to init threads. " |
| 794 | "ThreadPool_Do failed.\n", |
| 795 | err); |
| 796 | return err; |
| 797 | } |
| 798 | #endif |
| 799 | // Single threaded code to handle case where threadpool wasn't allocated or |
| 800 | // was disabled by environment variable |
| 801 | if (threadPoolInitErr) |
| 802 | { |
| 803 | cl_uint currentJob = 0; |
| 804 | cl_int result = CL_SUCCESS; |
| 805 | |
| 806 | #if defined(__APPLE__) && defined(__arm__) |
| 807 | // On most platforms which support denorm, default is FTZ off. However, |
| 808 | // on some hardware where the reference is computed, default might be |
| 809 | // flush denorms to zero e.g. arm. This creates issues in result |
| 810 | // verification. Since spec allows the implementation to either flush or |
| 811 | // not flush denorms to zero, an implementation may choose not be flush |
| 812 | // i.e. return denorm result whereas reference result may be zero |
| 813 | // (flushed denorm). Hence we need to disable denorm flushing on host |
| 814 | // side where reference is being computed to make sure we get |
| 815 | // non-flushed reference result. If implementation returns flushed |
| 816 | // result, we correctly take care of that in verification code. |
| 817 | FPU_mode_type oldMode; |
| 818 | DisableFTZ(&oldMode); |
| 819 | #endif |
| 820 | for (currentJob = 0; currentJob < count; currentJob++) |
| 821 | if ((result = func_ptr(currentJob, 0, userInfo))) |
| 822 | { |
| 823 | #if defined(__APPLE__) && defined(__arm__) |
| 824 | // Restore FP state before leaving |
| 825 | RestoreFPState(&oldMode); |
| 826 | #endif |
| 827 | return result; |
| 828 | } |
| 829 |