P4 to Git Change 1398097 by lmoriche@lmoriche_opencl_dev2 on 2017/04/13 13:01:56
SWDEV-102733 - [OCL-LC-ROCm] Cmake build Write CMakeLists.txt to enable building with and without the DK environment
- Change the coding convention of the runtime files. Use Google's Style (https://google.github.io/styleguide/cppguide.html).
Affected files ...
... //depot/stg/opencl/drivers/opencl/.clang-format#1 add
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_agent_amd.h#2 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_command.cpp#13 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_context.cpp#53 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_counter.cpp#2 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_d3d10.cpp#15 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_d3d11.cpp#22 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_d3d9.cpp#32 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_debugger_amd.cpp#8 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_debugger_amd.h#7 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_device.cpp#61 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_event.cpp#10 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_execute.cpp#23 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_gl.cpp#53 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_icd.cpp#27 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_icd_amd.h#18 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_kernel.h#24 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_kernel_info_amd.cpp#3 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_kernel_info_amd.h#4 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_lqdflash_amd.cpp#17 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_lqdflash_amd.h#6 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_memobj.cpp#81 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_object.cpp#3 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_pipe.cpp#6 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_platform_amd.cpp#2 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_platform_amd.h#2 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_profile_amd.cpp#3 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_profile_amd.h#2 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_program.cpp#41 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_sampler.cpp#6 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_sdi_amd.cpp#3 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_sdi_amd.h#2 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_semaphore_amd.h#3 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_svm.cpp#20 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_thread_trace_amd.cpp#8 edit
... //depot/stg/opencl/drivers/opencl/api/opencl/amdocl/cl_thread_trace_amd.h#4 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/appprofile.cpp#17 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/appprofile.hpp#12 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/blit.cpp#4 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/blit.hpp#4 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/blitcl.cpp#11 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/cpu/cpubinary.cpp#11 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/cpu/cpubinary.hpp#4 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/cpu/cpubuiltins.cpp#13 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/cpu/cpubuiltins.hpp#4 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/cpu/cpucommand.cpp#66 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/cpu/cpucommand.hpp#40 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/cpu/cpudevice.cpp#280 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/cpu/cpudevice.hpp#96 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/cpu/cpufeat.hpp#3 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/cpu/cpukernel.hpp#8 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/cpu/cpumapping.cpp#6 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/cpu/cpumapping.hpp#4 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/cpu/cpuprogram.cpp#70 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/cpu/cpuprogram.hpp#14 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/cpu/cpusettings.cpp#33 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/cpu/cpusettings.hpp#2 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/cpu/cputables.hpp#5 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/cpu/cpuvirtual.cpp#26 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/cpu/cpuvirtual.hpp#13 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/device.cpp#209 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/device.hpp#284 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpuappprofile.cpp#12 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpuappprofile.hpp#7 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpubinary.cpp#58 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpubinary.hpp#27 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpublit.cpp#126 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpublit.hpp#41 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpucompiler.cpp#156 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpuconstbuf.cpp#10 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpuconstbuf.hpp#7 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpucounters.cpp#12 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpucounters.hpp#9 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpudebugger.hpp#7 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpudebugmanager.cpp#10 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpudebugmanager.hpp#6 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpudefs.hpp#147 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpudevice.cpp#567 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpudevice.hpp#163 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpukernel.cpp#318 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpukernel.hpp#126 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpumemory.cpp#131 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpumemory.hpp#50 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpuprintf.cpp#44 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpuprintf.hpp#15 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpuprogram.cpp#232 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpuprogram.hpp#69 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpuresource.cpp#238 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpuresource.hpp#87 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpusched.hpp#19 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpuschedcl.cpp#35 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpuscsi.cpp#37 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpusettings.cpp#350 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpusettings.hpp#98 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gputhreadtrace.cpp#9 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gputhreadtrace.hpp#7 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gputimestamp.cpp#27 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gputimestamp.hpp#16 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gputrap.hpp#4 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpuvirtual.cpp#410 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpuvirtual.hpp#140 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpuwavelimiter.cpp#13 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/gpu/gpuwavelimiter.hpp#9 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/hwdebug.cpp#7 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/hwdebug.hpp#8 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palappprofile.cpp#2 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palappprofile.hpp#3 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palbinary.cpp#2 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palbinary.hpp#3 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palblit.cpp#13 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palblit.hpp#5 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palcompiler.cpp#15 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palconstbuf.cpp#2 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palconstbuf.hpp#3 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palcounters.cpp#11 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palcounters.hpp#9 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/paldebugger.hpp#3 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/paldebugmanager.cpp#2 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/paldebugmanager.hpp#3 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/paldefs.hpp#16 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/paldevice.cpp#45 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/paldevice.hpp#16 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/paldeviced3d10.cpp#2 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/paldeviced3d11.cpp#2 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/paldeviced3d9.cpp#2 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/paldevicegl.cpp#4 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palkernel.cpp#34 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palkernel.hpp#11 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palmemory.cpp#13 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palmemory.hpp#3 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palprintf.cpp#5 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palprintf.hpp#3 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palprogram.cpp#39 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palprogram.hpp#17 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palresource.cpp#28 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palresource.hpp#12 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palsched.hpp#3 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palschedcl.cpp#4 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palsettings.cpp#24 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palsettings.hpp#10 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palthreadtrace.cpp#3 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palthreadtrace.hpp#5 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/paltimestamp.cpp#2 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/paltimestamp.hpp#3 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/paltrap.hpp#2 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palvirtual.cpp#48 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palvirtual.hpp#21 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palwavelimiter.cpp#3 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/pal/palwavelimiter.hpp#4 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/rocm/mesa_glinterop.h#4 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/rocm/rocappprofile.cpp#6 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/rocm/rocappprofile.hpp#4 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/rocm/rocbinary.hpp#4 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/rocm/rocblit.cpp#17 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/rocm/rocblit.hpp#8 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/rocm/roccompiler.cpp#32 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/rocm/roccompilerlib.cpp#6 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/rocm/roccompilerlib.hpp#5 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/rocm/rocdefs.hpp#10 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/rocm/rocdevice.cpp#48 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/rocm/rocdevice.hpp#20 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/rocm/rocglinterop.cpp#4 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/rocm/rocglinterop.hpp#4 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/rocm/rockernel.cpp#22 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/rocm/rockernel.hpp#16 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/rocm/rocmemory.cpp#15 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/rocm/rocmemory.hpp#8 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/rocm/rocprintf.cpp#7 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/rocm/rocprintf.hpp#5 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/rocm/rocprogram.cpp#64 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/rocm/rocprogram.hpp#23 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/rocm/rocregisters.hpp#4 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/rocm/rocsettings.cpp#17 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/rocm/rocsettings.hpp#8 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/rocm/rocvirtual.cpp#34 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/rocm/rocvirtual.hpp#10 edit
... //depot/stg/opencl/drivers/opencl/runtime/os/alloc.cpp#7 edit
... //depot/stg/opencl/drivers/opencl/runtime/os/alloc.hpp#4 edit
... //depot/stg/opencl/drivers/opencl/runtime/os/os.cpp#8 edit
... //depot/stg/opencl/drivers/opencl/runtime/os/os.hpp#30 edit
... //depot/stg/opencl/drivers/opencl/runtime/os/os_posix.cpp#42 edit
... //depot/stg/opencl/drivers/opencl/runtime/os/os_win32.cpp#47 edit
... //depot/stg/opencl/drivers/opencl/runtime/platform/agent.cpp#8 edit
... //depot/stg/opencl/drivers/opencl/runtime/platform/agent.hpp#6 edit
... //depot/stg/opencl/drivers/opencl/runtime/platform/command.cpp#78 edit
... //depot/stg/opencl/drivers/opencl/runtime/platform/command.hpp#83 edit
... //depot/stg/opencl/drivers/opencl/runtime/platform/commandqueue.cpp#23 edit
... //depot/stg/opencl/drivers/opencl/runtime/platform/commandqueue.hpp#18 edit
... //depot/stg/opencl/drivers/opencl/runtime/platform/context.cpp#42 edit
... //depot/stg/opencl/drivers/opencl/runtime/platform/context.hpp#26 edit
... //depot/stg/opencl/drivers/opencl/runtime/platform/counter.hpp#4 edit
... //depot/stg/opencl/drivers/opencl/runtime/platform/interop.hpp#12 edit
... //depot/stg/opencl/drivers/opencl/runtime/platform/kernel.cpp#23 edit
... //depot/stg/opencl/drivers/opencl/runtime/platform/kernel.hpp#18 edit
... //depot/stg/opencl/drivers/opencl/runtime/platform/memory.cpp#127 edit
... //depot/stg/opencl/drivers/opencl/runtime/platform/memory.hpp#100 edit
... //depot/stg/opencl/drivers/opencl/runtime/platform/ndrange.cpp#8 edit
... //depot/stg/opencl/drivers/opencl/runtime/platform/ndrange.hpp#9 edit
... //depot/stg/opencl/drivers/opencl/runtime/platform/object.cpp#2 edit
... //depot/stg/opencl/drivers/opencl/runtime/platform/object.hpp#17 edit
... //depot/stg/opencl/drivers/opencl/runtime/platform/perfctr.hpp#5 edit
... //depot/stg/opencl/drivers/opencl/runtime/platform/program.cpp#86 edit
... //depot/stg/opencl/drivers/opencl/runtime/platform/program.hpp#41 edit
... //depot/stg/opencl/drivers/opencl/runtime/platform/runtime.cpp#35 edit
... //depot/stg/opencl/drivers/opencl/runtime/platform/runtime.hpp#4 edit
... //depot/stg/opencl/drivers/opencl/runtime/platform/sampler.hpp#8 edit
... //depot/stg/opencl/drivers/opencl/runtime/platform/threadtrace.hpp#6 edit
... //depot/stg/opencl/drivers/opencl/runtime/thread/atomic.hpp#7 edit
... //depot/stg/opencl/drivers/opencl/runtime/thread/monitor.cpp#7 edit
... //depot/stg/opencl/drivers/opencl/runtime/thread/monitor.hpp#8 edit
... //depot/stg/opencl/drivers/opencl/runtime/thread/semaphore.cpp#10 edit
... //depot/stg/opencl/drivers/opencl/runtime/thread/semaphore.hpp#7 edit
... //depot/stg/opencl/drivers/opencl/runtime/thread/thread.cpp#14 edit
... //depot/stg/opencl/drivers/opencl/runtime/thread/thread.hpp#15 edit
... //depot/stg/opencl/drivers/opencl/runtime/top.hpp#26 edit
... //depot/stg/opencl/drivers/opencl/runtime/utils/concurrent.hpp#8 edit
... //depot/stg/opencl/drivers/opencl/runtime/utils/debug.cpp#5 edit
... //depot/stg/opencl/drivers/opencl/runtime/utils/debug.hpp#7 edit
... //depot/stg/opencl/drivers/opencl/runtime/utils/flags.cpp#16 edit
... //depot/stg/opencl/drivers/opencl/runtime/utils/flags.hpp#271 edit
... //depot/stg/opencl/drivers/opencl/runtime/utils/macros.hpp#8 edit
... //depot/stg/opencl/drivers/opencl/runtime/utils/util.hpp#12 edit
... //depot/stg/opencl/drivers/opencl/runtime/utils/versions.hpp#2150 edit
[ROCm/clr commit: 465c1c0287]
Tento commit je obsažen v:
@@ -17,11 +17,11 @@
|
||||
#include <type_traits>
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <intrin.h>
|
||||
#include <intrin.h>
|
||||
#elif defined(ATI_ARCH_X86)
|
||||
# include <emmintrin.h>
|
||||
# include <xmmintrin.h>
|
||||
#endif // !_WIN32
|
||||
#include <emmintrin.h>
|
||||
#include <xmmintrin.h>
|
||||
#endif // !_WIN32
|
||||
|
||||
#include <atomic>
|
||||
#include <utility>
|
||||
@@ -37,135 +37,111 @@ namespace amd {
|
||||
|
||||
/*! \brief Static functions for atomic operations.
|
||||
*/
|
||||
class AtomicOperation : AllStatic
|
||||
{
|
||||
private:
|
||||
|
||||
//! Template to specialize atomic intrinsics on register size.
|
||||
template <int N>
|
||||
struct Intrinsics {
|
||||
/*! \brief %Atomic add.
|
||||
*
|
||||
* Atomically add \a inc to \a *dest and return the prior value.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T add(T increment, volatile T* dest);
|
||||
|
||||
/*! \brief %Atomic exchange.
|
||||
*
|
||||
* Atomically exchange value with *dest and return the prior value.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T swap(T value, volatile T* dest);
|
||||
|
||||
/*! \brief %Atomic compare and exchange.
|
||||
*
|
||||
* Atomically compare and xchge value with *dest if *dest == compare.
|
||||
* Return the prior value.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T compareAndSwap(T compare, volatile T* dest, T value);
|
||||
|
||||
/*! \brief %Atomic increment.
|
||||
*
|
||||
* Atomically increment *dest and return the prior value.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T increment(volatile T* dest);
|
||||
|
||||
/*! \brief %Atomic exchange.
|
||||
*
|
||||
* Atomically decrement *dest and return the prior value.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T decrement(volatile T* dest);
|
||||
|
||||
/*! \brief %Atomic or.
|
||||
*
|
||||
* Atomically or \a mask to \a *dest and return the prior value.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T _or(T mask, volatile T* dest);
|
||||
|
||||
/*! \brief %Atomic and.
|
||||
*
|
||||
* Atomically and \a mask to \a *dest and return the prior value.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T _and(T mask, volatile T* dest);
|
||||
};
|
||||
|
||||
public:
|
||||
class AtomicOperation : AllStatic {
|
||||
private:
|
||||
//! Template to specialize atomic intrinsics on register size.
|
||||
template <int N> struct Intrinsics {
|
||||
/*! \brief %Atomic add.
|
||||
*
|
||||
* Atomically add \a inc to \a *dest and return the prior value.
|
||||
*/
|
||||
template <typename T>
|
||||
static T add(T inc, volatile T* dest)
|
||||
{
|
||||
return Intrinsics<sizeof(T)>::add((T) inc, dest);
|
||||
}
|
||||
template <typename T> static inline T add(T increment, volatile T* dest);
|
||||
|
||||
/*! \brief %Atomic exchange.
|
||||
*
|
||||
* Atomically exchange value with *dest and return the prior value.
|
||||
*/
|
||||
template <typename T>
|
||||
static T swap(T value, volatile T* dest)
|
||||
{
|
||||
return Intrinsics<sizeof(T)>::swap(value, dest);
|
||||
}
|
||||
template <typename T> static inline T swap(T value, volatile T* dest);
|
||||
|
||||
/*! \brief %Atomic compare and exchange.
|
||||
*
|
||||
* Atomically compare and exchange value with *dest if *dest == compare.
|
||||
* Atomically compare and xchge value with *dest if *dest == compare.
|
||||
* Return the prior value.
|
||||
*/
|
||||
template <typename T>
|
||||
static T compareAndSwap(T compare, volatile T* dest, T value)
|
||||
{
|
||||
return Intrinsics<sizeof(T)>::compareAndSwap(compare, dest, value);
|
||||
}
|
||||
template <typename T> static inline T compareAndSwap(T compare, volatile T* dest, T value);
|
||||
|
||||
/*! \brief %Atomic increment.
|
||||
*
|
||||
* Atomically increment *dest and return the prior value.
|
||||
*/
|
||||
template <typename T>
|
||||
static T increment(volatile T* dest)
|
||||
{
|
||||
return Intrinsics<sizeof(T)>::increment(dest);
|
||||
}
|
||||
template <typename T> static inline T increment(volatile T* dest);
|
||||
|
||||
/*! \brief %Atomic decrement.
|
||||
/*! \brief %Atomic exchange.
|
||||
*
|
||||
* Atomically decrement *dest and return the prior value.
|
||||
*/
|
||||
template <typename T>
|
||||
static T decrement(volatile T* dest)
|
||||
{
|
||||
return Intrinsics<sizeof(T)>::decrement(dest);
|
||||
}
|
||||
template <typename T> static inline T decrement(volatile T* dest);
|
||||
|
||||
/*! \brief %Atomic or.
|
||||
*
|
||||
* Atomically or \a mask to \a *dest and return the prior value.
|
||||
*/
|
||||
template <typename T>
|
||||
static T _or(T mask, volatile T* dest)
|
||||
{
|
||||
return Intrinsics<sizeof(T)>::_or((T) mask, dest);
|
||||
}
|
||||
template <typename T> static inline T _or(T mask, volatile T* dest);
|
||||
|
||||
/*! \brief %Atomic and.
|
||||
*
|
||||
* Atomically or \a mask to \a *dest and return the prior value.
|
||||
* Atomically and \a mask to \a *dest and return the prior value.
|
||||
*/
|
||||
template <typename T>
|
||||
static T _and(T mask, volatile T* dest)
|
||||
{
|
||||
return Intrinsics<sizeof(T)>::_and((T) mask, dest);
|
||||
}
|
||||
template <typename T> static inline T _and(T mask, volatile T* dest);
|
||||
};
|
||||
|
||||
public:
|
||||
/*! \brief %Atomic add.
|
||||
*
|
||||
* Atomically add \a inc to \a *dest and return the prior value.
|
||||
*/
|
||||
template <typename T> static T add(T inc, volatile T* dest) {
|
||||
return Intrinsics<sizeof(T)>::add((T)inc, dest);
|
||||
}
|
||||
|
||||
/*! \brief %Atomic exchange.
|
||||
*
|
||||
* Atomically exchange value with *dest and return the prior value.
|
||||
*/
|
||||
template <typename T> static T swap(T value, volatile T* dest) {
|
||||
return Intrinsics<sizeof(T)>::swap(value, dest);
|
||||
}
|
||||
|
||||
/*! \brief %Atomic compare and exchange.
|
||||
*
|
||||
* Atomically compare and exchange value with *dest if *dest == compare.
|
||||
* Return the prior value.
|
||||
*/
|
||||
template <typename T> static T compareAndSwap(T compare, volatile T* dest, T value) {
|
||||
return Intrinsics<sizeof(T)>::compareAndSwap(compare, dest, value);
|
||||
}
|
||||
|
||||
/*! \brief %Atomic increment.
|
||||
*
|
||||
* Atomically increment *dest and return the prior value.
|
||||
*/
|
||||
template <typename T> static T increment(volatile T* dest) {
|
||||
return Intrinsics<sizeof(T)>::increment(dest);
|
||||
}
|
||||
|
||||
/*! \brief %Atomic decrement.
|
||||
*
|
||||
* Atomically decrement *dest and return the prior value.
|
||||
*/
|
||||
template <typename T> static T decrement(volatile T* dest) {
|
||||
return Intrinsics<sizeof(T)>::decrement(dest);
|
||||
}
|
||||
|
||||
/*! \brief %Atomic or.
|
||||
*
|
||||
* Atomically or \a mask to \a *dest and return the prior value.
|
||||
*/
|
||||
template <typename T> static T _or(T mask, volatile T* dest) {
|
||||
return Intrinsics<sizeof(T)>::_or((T)mask, dest);
|
||||
}
|
||||
|
||||
/*! \brief %Atomic and.
|
||||
*
|
||||
* Atomically or \a mask to \a *dest and return the prior value.
|
||||
*/
|
||||
template <typename T> static T _and(T mask, volatile T* dest) {
|
||||
return Intrinsics<sizeof(T)>::_and((T)mask, dest);
|
||||
}
|
||||
};
|
||||
|
||||
/*@}*/
|
||||
@@ -174,193 +150,139 @@ public:
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<4>::add(T increment, volatile T* dest)
|
||||
{
|
||||
return (T)_InterlockedExchangeAdd(
|
||||
(volatile long*)dest, (long)increment);
|
||||
inline T AtomicOperation::Intrinsics<4>::add(T increment, volatile T* dest) {
|
||||
return (T)_InterlockedExchangeAdd((volatile long*)dest, (long)increment);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<4>::swap(T value, volatile T* dest)
|
||||
{
|
||||
return (T)_InterlockedExchange(
|
||||
(volatile long*)dest, (long)value);
|
||||
inline T AtomicOperation::Intrinsics<4>::swap(T value, volatile T* dest) {
|
||||
return (T)_InterlockedExchange((volatile long*)dest, (long)value);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<4>::compareAndSwap(
|
||||
T compare, volatile T* dest, T value)
|
||||
{
|
||||
return (T)_InterlockedCompareExchange(
|
||||
(volatile long*)dest, (long)value, (long)compare);
|
||||
inline T AtomicOperation::Intrinsics<4>::compareAndSwap(T compare, volatile T* dest, T value) {
|
||||
return (T)_InterlockedCompareExchange((volatile long*)dest, (long)value, (long)compare);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<4>::increment(volatile T* dest)
|
||||
{
|
||||
return (T)(_InterlockedIncrement((volatile long*)dest) - 1L);
|
||||
inline T AtomicOperation::Intrinsics<4>::increment(volatile T* dest) {
|
||||
return (T)(_InterlockedIncrement((volatile long*)dest) - 1L);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<4>::decrement(volatile T* dest)
|
||||
{
|
||||
return (T)(_InterlockedDecrement((volatile long*)dest) + 1L);
|
||||
inline T AtomicOperation::Intrinsics<4>::decrement(volatile T* dest) {
|
||||
return (T)(_InterlockedDecrement((volatile long*)dest) + 1L);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<4>::_or(T mask, volatile T* dest)
|
||||
{
|
||||
return (T)_InterlockedOr(
|
||||
(volatile long*)dest, (long)mask);
|
||||
inline T AtomicOperation::Intrinsics<4>::_or(T mask, volatile T* dest) {
|
||||
return (T)_InterlockedOr((volatile long*)dest, (long)mask);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<4>::_and(T mask, volatile T* dest)
|
||||
{
|
||||
return (T)_InterlockedAnd(
|
||||
(volatile long*)dest, (long)mask);
|
||||
inline T AtomicOperation::Intrinsics<4>::_and(T mask, volatile T* dest) {
|
||||
return (T)_InterlockedAnd((volatile long*)dest, (long)mask);
|
||||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<8>::add(T increment, volatile T* dest)
|
||||
{
|
||||
return (T)_InterlockedExchangeAdd64(
|
||||
(volatile __int64*)dest, (__int64)increment);
|
||||
inline T AtomicOperation::Intrinsics<8>::add(T increment, volatile T* dest) {
|
||||
return (T)_InterlockedExchangeAdd64((volatile __int64*)dest, (__int64)increment);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<8>::swap(T value, volatile T* dest)
|
||||
{
|
||||
return (T)_InterlockedExchange64(
|
||||
(volatile __int64*)dest, (__int64)value);
|
||||
inline T AtomicOperation::Intrinsics<8>::swap(T value, volatile T* dest) {
|
||||
return (T)_InterlockedExchange64((volatile __int64*)dest, (__int64)value);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<8>::compareAndSwap(
|
||||
T compare, volatile T* dest, T value)
|
||||
{
|
||||
return (T)_InterlockedCompareExchange64(
|
||||
(volatile __int64*)dest, (__int64)value, (__int64)compare);
|
||||
inline T AtomicOperation::Intrinsics<8>::compareAndSwap(T compare, volatile T* dest, T value) {
|
||||
return (T)_InterlockedCompareExchange64((volatile __int64*)dest, (__int64)value,
|
||||
(__int64)compare);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<8>::increment(volatile T* dest)
|
||||
{
|
||||
return (T)(_InterlockedIncrement64((volatile __int64*)dest) - 1LL);
|
||||
inline T AtomicOperation::Intrinsics<8>::increment(volatile T* dest) {
|
||||
return (T)(_InterlockedIncrement64((volatile __int64*)dest) - 1LL);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<8>::decrement(volatile T* dest)
|
||||
{
|
||||
return (T)(_InterlockedDecrement64((volatile __int64*)dest) + 1LL);
|
||||
inline T AtomicOperation::Intrinsics<8>::decrement(volatile T* dest) {
|
||||
return (T)(_InterlockedDecrement64((volatile __int64*)dest) + 1LL);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<8>::_or(T mask, volatile T* dest)
|
||||
{
|
||||
return (T)_InterlockedOr64(
|
||||
(volatile long*)dest, (long)mask);
|
||||
inline T AtomicOperation::Intrinsics<8>::_or(T mask, volatile T* dest) {
|
||||
return (T)_InterlockedOr64((volatile long*)dest, (long)mask);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<8>::_and(T mask, volatile T* dest)
|
||||
{
|
||||
return (T)_InterlockedAnd64(
|
||||
(volatile long*)dest, (long)mask);
|
||||
inline T AtomicOperation::Intrinsics<8>::_and(T mask, volatile T* dest) {
|
||||
return (T)_InterlockedAnd64((volatile long*)dest, (long)mask);
|
||||
}
|
||||
|
||||
#endif // _LP64
|
||||
#endif // _LP64
|
||||
|
||||
#elif defined(__GNUC__)
|
||||
|
||||
template <int N>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<N>::add(T inc, volatile T* dest)
|
||||
{
|
||||
return __sync_fetch_and_add(dest, inc);
|
||||
}
|
||||
|
||||
template<int N>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<N>::swap(T value, volatile T* dest)
|
||||
{
|
||||
return __sync_lock_test_and_set(dest, value);
|
||||
inline T AtomicOperation::Intrinsics<N>::add(T inc, volatile T* dest) {
|
||||
return __sync_fetch_and_add(dest, inc);
|
||||
}
|
||||
|
||||
template <int N>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<N>::compareAndSwap(
|
||||
T compare, volatile T* dest, T value)
|
||||
{
|
||||
return __sync_val_compare_and_swap(dest, compare, value);
|
||||
}
|
||||
|
||||
template<int N>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<N>::increment(volatile T* dest)
|
||||
{
|
||||
return add(T(1), dest);
|
||||
}
|
||||
|
||||
template<int N>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<N>::decrement(volatile T* dest)
|
||||
{
|
||||
return add(T(-1), dest);
|
||||
inline T AtomicOperation::Intrinsics<N>::swap(T value, volatile T* dest) {
|
||||
return __sync_lock_test_and_set(dest, value);
|
||||
}
|
||||
|
||||
template <int N>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<N>::_or(T mask, volatile T* dest)
|
||||
{
|
||||
return __sync_fetch_and_or(dest, mask);
|
||||
inline T AtomicOperation::Intrinsics<N>::compareAndSwap(T compare, volatile T* dest, T value) {
|
||||
return __sync_val_compare_and_swap(dest, compare, value);
|
||||
}
|
||||
|
||||
template <int N>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<N>::_and(T mask, volatile T* dest)
|
||||
{
|
||||
return __sync_fetch_and_and(dest, mask);
|
||||
inline T AtomicOperation::Intrinsics<N>::increment(volatile T* dest) {
|
||||
return add(T(1), dest);
|
||||
}
|
||||
|
||||
template <int N>
|
||||
template <typename T>
|
||||
inline T AtomicOperation::Intrinsics<N>::decrement(volatile T* dest) {
|
||||
return add(T(-1), dest);
|
||||
}
|
||||
|
||||
template <int N>
|
||||
template <typename T>
|
||||
inline T AtomicOperation::Intrinsics<N>::_or(T mask, volatile T* dest) {
|
||||
return __sync_fetch_and_or(dest, mask);
|
||||
}
|
||||
|
||||
template <int N>
|
||||
template <typename T>
|
||||
inline T AtomicOperation::Intrinsics<N>::_and(T mask, volatile T* dest) {
|
||||
return __sync_fetch_and_and(dest, mask);
|
||||
}
|
||||
|
||||
#else
|
||||
# error Unimplemented
|
||||
#error Unimplemented
|
||||
#endif
|
||||
|
||||
/*! \addtogroup Atomic Atomic Operations
|
||||
@@ -369,180 +291,151 @@ AtomicOperation::Intrinsics<N>::_and(T mask, volatile T* dest)
|
||||
|
||||
/*! \brief A variable of type T with atomic properties.
|
||||
*/
|
||||
template <typename T>
|
||||
class Atomic
|
||||
{
|
||||
private:
|
||||
template <typename T> class Atomic {
|
||||
private:
|
||||
typedef typename std::remove_volatile<
|
||||
typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::type value_type;
|
||||
typename std::add_volatile<T>::type value_; //!< \brief The variable.
|
||||
|
||||
typedef typename std::remove_volatile<typename std::remove_pointer<
|
||||
typename std::remove_reference<T>::type>::type>::type value_type;
|
||||
typename std::add_volatile<T>::type value_; //!< \brief The variable.
|
||||
public:
|
||||
//! Construct a new %Atomic variable of type T.
|
||||
Atomic() : value_(T(0)) {}
|
||||
//! Construct a new %Atomic variable of type T from \a value.
|
||||
Atomic(T value) : value_(value) {}
|
||||
//! Construct a new %Atomic variable of type T from another %Atomic.
|
||||
Atomic(const Atomic<T>& atomic) : value_(atomic.value_) {}
|
||||
//! Copy value into this %Atomic variable.
|
||||
Atomic<T>& operator=(T value) {
|
||||
value_ = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
//! Construct a new %Atomic variable of type T.
|
||||
Atomic() : value_(T(0)) {}
|
||||
//! Construct a new %Atomic variable of type T from \a value.
|
||||
Atomic(T value) : value_(value) {}
|
||||
//! Construct a new %Atomic variable of type T from another %Atomic.
|
||||
Atomic(const Atomic<T>& atomic) : value_(atomic.value_) { }
|
||||
//! Copy value into this %Atomic variable.
|
||||
Atomic<T>& operator = (T value)
|
||||
{
|
||||
value_ = value;
|
||||
return *this;
|
||||
//! Return the %Atomic variable value.
|
||||
operator T() const { return T(value_); }
|
||||
//! Return the %Atomic variable value.
|
||||
T operator->() const { return T(value_); }
|
||||
//! Return the %Atomic variable's address.
|
||||
typename std::add_pointer<typename std::add_volatile<value_type>::type>::type operator&() {
|
||||
return &value_;
|
||||
}
|
||||
|
||||
//! Atomically add \a inc to this variable.
|
||||
Atomic<T>& operator+=(value_type inc) {
|
||||
if (std::is_pointer<T>::value) {
|
||||
inc *= sizeof(typename std::remove_pointer<T>::type);
|
||||
}
|
||||
AtomicOperation::add(inc, &value_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Return the %Atomic variable value.
|
||||
operator T () const { return T(value_); }
|
||||
//! Return the %Atomic variable value.
|
||||
T operator ->() const { return T(value_); }
|
||||
//! Return the %Atomic variable's address.
|
||||
typename std::add_pointer<typename std::add_volatile<value_type>::type>::
|
||||
type operator &() { return &value_; }
|
||||
|
||||
//! Atomically add \a inc to this variable.
|
||||
Atomic<T>& operator += (value_type inc)
|
||||
{
|
||||
if (std::is_pointer<T>::value) {
|
||||
inc *= sizeof(typename std::remove_pointer<T>::type);
|
||||
}
|
||||
AtomicOperation::add(inc, &value_);
|
||||
return *this;
|
||||
//! Atomically subtract \a inc to this variable.
|
||||
Atomic<T>& operator-=(value_type inc) {
|
||||
value_type modifier = 0;
|
||||
if (std::is_pointer<T>::value) {
|
||||
inc *= sizeof(typename std::remove_pointer<T>::type);
|
||||
}
|
||||
AtomicOperation::add(modifier - inc, &value_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Atomically subtract \a inc to this variable.
|
||||
Atomic<T>& operator -= (value_type inc)
|
||||
{
|
||||
value_type modifier = 0;
|
||||
if (std::is_pointer<T>::value) {
|
||||
inc *= sizeof(typename std::remove_pointer<T>::type);
|
||||
}
|
||||
AtomicOperation::add(modifier - inc, &value_);
|
||||
return *this;
|
||||
}
|
||||
//! Atomically OR \a value to this variable.
|
||||
Atomic<T>& operator|=(value_type mask) {
|
||||
AtomicOperation::_or(mask, &value_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Atomically OR \a value to this variable.
|
||||
Atomic<T>& operator |= (value_type mask)
|
||||
{
|
||||
AtomicOperation::_or(mask, &value_);
|
||||
return *this;
|
||||
}
|
||||
//! Atomically AND \a value to this variable.
|
||||
Atomic<T>& operator&=(value_type mask) {
|
||||
AtomicOperation::_and(mask, &value_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Atomically AND \a value to this variable.
|
||||
Atomic<T>& operator &= (value_type mask)
|
||||
{
|
||||
AtomicOperation::_and(mask, &value_);
|
||||
return *this;
|
||||
//! Atomically increment this variable and return its new value.
|
||||
typename std::remove_reference<T>::type operator++() {
|
||||
if (std::is_pointer<T>::value) {
|
||||
value_type inc = static_cast<value_type>(sizeof(typename std::remove_pointer<T>::type));
|
||||
return AtomicOperation::add(inc, &value_) + 1;
|
||||
} else {
|
||||
return AtomicOperation::increment(&value_) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
//! Atomically increment this variable and return its new value.
|
||||
typename std::remove_reference<T>::type operator ++ ()
|
||||
{
|
||||
if (std::is_pointer<T>::value) {
|
||||
value_type inc = static_cast<value_type>(
|
||||
sizeof(typename std::remove_pointer<T>::type));
|
||||
return AtomicOperation::add(inc, &value_) + 1;
|
||||
}
|
||||
else {
|
||||
return AtomicOperation::increment(&value_) + 1;
|
||||
}
|
||||
//! Atomically decrement this variable and return its new value.
|
||||
typename std::remove_reference<T>::type operator--() {
|
||||
if (std::is_pointer<T>::value) {
|
||||
value_type inc =
|
||||
static_cast<value_type>(-static_cast<typename std::make_signed<value_type>::type>(
|
||||
sizeof(typename std::remove_pointer<T>::type)));
|
||||
return AtomicOperation::add(inc, &value_) - 1;
|
||||
} else {
|
||||
return AtomicOperation::decrement(&value_) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
//! Atomically decrement this variable and return its new value.
|
||||
typename std::remove_reference<T>::type operator -- ()
|
||||
{
|
||||
if (std::is_pointer<T>::value) {
|
||||
value_type inc = static_cast<value_type>(-
|
||||
static_cast<typename std::make_signed<value_type>::type>(
|
||||
sizeof(typename std::remove_pointer<T>::type)));
|
||||
return AtomicOperation::add(inc, &value_) - 1;
|
||||
}
|
||||
else {
|
||||
return AtomicOperation::decrement(&value_) - 1;
|
||||
}
|
||||
//! Atomically increment this variable and return its previous value.
|
||||
typename std::remove_reference<T>::type operator++(int) {
|
||||
if (std::is_pointer<T>::value) {
|
||||
value_type inc = static_cast<value_type>(sizeof(typename std::remove_pointer<T>::type));
|
||||
return AtomicOperation::add(inc, &value_);
|
||||
} else {
|
||||
return AtomicOperation::increment(&value_);
|
||||
}
|
||||
}
|
||||
|
||||
//! Atomically increment this variable and return its previous value.
|
||||
typename std::remove_reference<T>::type operator ++ (int)
|
||||
{
|
||||
if (std::is_pointer<T>::value) {
|
||||
value_type inc = static_cast<value_type>(
|
||||
sizeof(typename std::remove_pointer<T>::type));
|
||||
return AtomicOperation::add(inc, &value_);
|
||||
}
|
||||
else {
|
||||
return AtomicOperation::increment(&value_);
|
||||
}
|
||||
//! Atomically decrement this variable and return its previous value.
|
||||
T operator--(int) {
|
||||
if (std::is_pointer<T>::value) {
|
||||
value_type inc =
|
||||
static_cast<value_type>(-static_cast<typename std::make_signed<value_type>::type>(
|
||||
sizeof(typename std::remove_pointer<T>::type)));
|
||||
return AtomicOperation::add(inc, &value_);
|
||||
} else {
|
||||
return AtomicOperation::decrement(&value_);
|
||||
}
|
||||
}
|
||||
|
||||
//! Atomically decrement this variable and return its previous value.
|
||||
T operator -- (int)
|
||||
{
|
||||
if (std::is_pointer<T>::value) {
|
||||
value_type inc = static_cast<value_type>(-
|
||||
static_cast<typename std::make_signed<value_type>::type>(
|
||||
sizeof(typename std::remove_pointer<T>::type)));
|
||||
return AtomicOperation::add(inc, &value_);
|
||||
}
|
||||
else {
|
||||
return AtomicOperation::decrement(&value_);
|
||||
}
|
||||
}
|
||||
/*! \brief Atomically compare this variable with \a compare and set
|
||||
* to value if equals
|
||||
*/
|
||||
bool compareAndSet(T compare, T value) {
|
||||
return compare == AtomicOperation::compareAndSwap(compare, &value_, value);
|
||||
}
|
||||
|
||||
/*! \brief Atomically compare this variable with \a compare and set
|
||||
* to value if equals
|
||||
*/
|
||||
bool compareAndSet(T compare, T value)
|
||||
{
|
||||
return compare == AtomicOperation::compareAndSwap(
|
||||
compare, &value_, value);
|
||||
}
|
||||
//! Atomically set this variable to \a value and return its previous value.
|
||||
T swap(T value) { return AtomicOperation::swap(value, &value_); }
|
||||
|
||||
//! Atomically set this variable to \a value and return its previous value.
|
||||
T swap(T value)
|
||||
{
|
||||
return AtomicOperation::swap(value, &value_);
|
||||
}
|
||||
/*! \brief Execute a stores fence followed by a store to this variable.
|
||||
*
|
||||
* This storeRelease operation ensures that all store to memory operations
|
||||
* preceding this function will be globally visible before the update to
|
||||
* this variable's value.
|
||||
*/
|
||||
void storeRelease(T value) {
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
value_ = value;
|
||||
}
|
||||
|
||||
/*! \brief Execute a stores fence followed by a store to this variable.
|
||||
*
|
||||
* This storeRelease operation ensures that all store to memory operations
|
||||
* preceding this function will be globally visible before the update to
|
||||
* this variable's value.
|
||||
*/
|
||||
void storeRelease(T value)
|
||||
{
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
value_ = value;
|
||||
}
|
||||
|
||||
/*! \brief Execute a load from this variable followed by a loads fence.
|
||||
*
|
||||
* This loadAcquire operation ensures that all load from memory operations
|
||||
* following this function will be globally visible after the read from
|
||||
* this variable's value.
|
||||
*/
|
||||
T loadAcquire() const
|
||||
{
|
||||
T value = value_;
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
return value;
|
||||
}
|
||||
/*! \brief Execute a load from this variable followed by a loads fence.
|
||||
*
|
||||
* This loadAcquire operation ensures that all load from memory operations
|
||||
* following this function will be globally visible after the read from
|
||||
* this variable's value.
|
||||
*/
|
||||
T loadAcquire() const {
|
||||
T value = value_;
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
//! Helper function to tie an Atomic<T&> to a variable of type T.
|
||||
template <typename T>
|
||||
inline Atomic<T&>
|
||||
make_atomic(T& t)
|
||||
{
|
||||
return Atomic<T&>(t);
|
||||
}
|
||||
template <typename T> inline Atomic<T&> make_atomic(T& t) { return Atomic<T&>(t); }
|
||||
|
||||
|
||||
/*! @}
|
||||
* @}
|
||||
*/
|
||||
|
||||
} // namespace amd
|
||||
} // namespace amd
|
||||
|
||||
#endif /*ATOMIC_HPP_*/
|
||||
|
||||
@@ -14,308 +14,287 @@
|
||||
|
||||
namespace amd {
|
||||
|
||||
Monitor::Monitor(const char* name, bool recursive) :
|
||||
contendersList_(0), onDeck_(0), waitersList_(NULL),
|
||||
owner_(NULL), recursive_(recursive)
|
||||
{
|
||||
const size_t maxNameLen = sizeof(name_);
|
||||
if (name == NULL) {
|
||||
const char* unknownName = "@unknown@";
|
||||
assert(sizeof(unknownName) < maxNameLen && "just checking");
|
||||
strcpy(name_, unknownName);
|
||||
Monitor::Monitor(const char* name, bool recursive)
|
||||
: contendersList_(0), onDeck_(0), waitersList_(NULL), owner_(NULL), recursive_(recursive) {
|
||||
const size_t maxNameLen = sizeof(name_);
|
||||
if (name == NULL) {
|
||||
const char* unknownName = "@unknown@";
|
||||
assert(sizeof(unknownName) < maxNameLen && "just checking");
|
||||
strcpy(name_, unknownName);
|
||||
} else {
|
||||
strncpy(name_, name, maxNameLen - 1);
|
||||
name_[maxNameLen - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
bool Monitor::trySpinLock() {
|
||||
if (tryLock()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int s = kMaxSpinIter; s > 0; --s) {
|
||||
// First, be SMT friendly
|
||||
if (s >= (kMaxSpinIter - kMaxReadSpinIter)) {
|
||||
Os::spinPause();
|
||||
}
|
||||
// and then SMP friendly
|
||||
else {
|
||||
strncpy(name_, name, maxNameLen - 1);
|
||||
name_[maxNameLen - 1] = '\0';
|
||||
Thread::yield();
|
||||
}
|
||||
if (!isLocked()) {
|
||||
return tryLock();
|
||||
}
|
||||
}
|
||||
|
||||
// We could not acquire the lock in the spin loop.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
Monitor::trySpinLock()
|
||||
{
|
||||
void Monitor::finishLock() {
|
||||
Thread* thread = Thread::current();
|
||||
assert(thread != NULL && "cannot lock() from (null)");
|
||||
|
||||
if (trySpinLock()) {
|
||||
return; // We succeeded, we are done.
|
||||
}
|
||||
|
||||
/* The lock is contended. Push the thread's semaphore onto
|
||||
* the contention list.
|
||||
*/
|
||||
Semaphore& semaphore = thread->lockSemaphore();
|
||||
semaphore.reset();
|
||||
|
||||
LinkedNode newHead;
|
||||
newHead.setItem(&semaphore);
|
||||
|
||||
intptr_t head = contendersList_.load(std::memory_order_acquire);
|
||||
for (;;) {
|
||||
// The assumption is that lockWord is locked. Make sure we do not
|
||||
// continue unless the lock bit is set.
|
||||
if ((head & kLockBit) == 0) {
|
||||
if (tryLock()) {
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set the new contention list head if lockWord is unchanged.
|
||||
newHead.setNext(reinterpret_cast<LinkedNode*>(head & ~kLockBit));
|
||||
if (contendersList_.compare_exchange_weak(head, reinterpret_cast<intptr_t>(&newHead) | kLockBit,
|
||||
std::memory_order_acq_rel,
|
||||
std::memory_order_acquire)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// We failed the CAS. yield/pause before trying again.
|
||||
Thread::yield();
|
||||
}
|
||||
|
||||
int32_t spinCount = 0;
|
||||
// Go to sleep until we become the on-deck thread.
|
||||
while ((onDeck_ & ~kLockBit) != reinterpret_cast<intptr_t>(&semaphore)) {
|
||||
// First, be SMT friendly
|
||||
if (spinCount < kMaxReadSpinIter) {
|
||||
Os::spinPause();
|
||||
}
|
||||
// and then SMP friendly
|
||||
else if (spinCount < kMaxSpinIter) {
|
||||
Thread::yield();
|
||||
}
|
||||
// now go to sleep
|
||||
else {
|
||||
semaphore.wait();
|
||||
}
|
||||
spinCount++;
|
||||
}
|
||||
|
||||
spinCount = 0;
|
||||
//
|
||||
// From now-on, we are the on-deck thread. It will stay that way until
|
||||
// we successfuly acquire the lock.
|
||||
//
|
||||
for (;;) {
|
||||
assert((onDeck_ & ~kLockBit) == reinterpret_cast<intptr_t>(&semaphore) && "just checking");
|
||||
if (tryLock()) {
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
for (int s = kMaxSpinIter; s > 0; --s) {
|
||||
// First, be SMT friendly
|
||||
if (s >= (kMaxSpinIter - kMaxReadSpinIter)) {
|
||||
Os::spinPause();
|
||||
}
|
||||
// and then SMP friendly
|
||||
else {
|
||||
Thread::yield();
|
||||
}
|
||||
if (!isLocked()) {
|
||||
return tryLock();
|
||||
}
|
||||
// Somebody beat us to it. Since we are on-deck, we can just go
|
||||
// back to sleep.
|
||||
// First, be SMT friendly
|
||||
if (spinCount < kMaxReadSpinIter) {
|
||||
Os::spinPause();
|
||||
}
|
||||
// and then SMP friendly
|
||||
else if (spinCount < kMaxSpinIter) {
|
||||
Thread::yield();
|
||||
}
|
||||
// now go to sleep
|
||||
else {
|
||||
semaphore.wait();
|
||||
}
|
||||
spinCount++;
|
||||
}
|
||||
|
||||
// We could not acquire the lock in the spin loop.
|
||||
return false;
|
||||
assert(newHead.next() == NULL && "Should not be linked");
|
||||
onDeck_ = 0;
|
||||
}
|
||||
|
||||
void
|
||||
Monitor::finishLock()
|
||||
{
|
||||
Thread* thread = Thread::current();
|
||||
assert(thread != NULL && "cannot lock() from (null)");
|
||||
void Monitor::finishUnlock() {
|
||||
// If we get here, it means that there might be a thread in the contention
|
||||
// list waiting to acquire the lock. We need to select a successor and
|
||||
// place it on-deck.
|
||||
|
||||
if (trySpinLock()) {
|
||||
return; // We succeeded, we are done.
|
||||
for (;;) {
|
||||
// Grab the onDeck_ microlock to protect the next loop (make sure only
|
||||
// one semaphore is removed from the contention list).
|
||||
//
|
||||
intptr_t ptr = 0;
|
||||
if (!onDeck_.compare_exchange_strong(ptr, ptr | kLockBit, std::memory_order_acq_rel,
|
||||
std::memory_order_acquire)) {
|
||||
return; // Somebody else has the microlock, let him select onDeck_
|
||||
}
|
||||
|
||||
/* The lock is contended. Push the thread's semaphore onto
|
||||
* the contention list.
|
||||
*/
|
||||
Semaphore& semaphore = thread->lockSemaphore();
|
||||
semaphore.reset();
|
||||
|
||||
LinkedNode newHead;
|
||||
newHead.setItem(&semaphore);
|
||||
|
||||
intptr_t head = contendersList_.load(std::memory_order_acquire);
|
||||
for (;;) {
|
||||
// The assumption is that lockWord is locked. Make sure we do not
|
||||
// continue unless the lock bit is set.
|
||||
if ((head & kLockBit) == 0) {
|
||||
if (tryLock()) {
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (head == 0) {
|
||||
break; // There's nothing else to do.
|
||||
}
|
||||
|
||||
// Set the new contention list head if lockWord is unchanged.
|
||||
newHead.setNext(reinterpret_cast<LinkedNode*>(head & ~kLockBit));
|
||||
if (contendersList_.compare_exchange_weak(head,
|
||||
reinterpret_cast<intptr_t>(&newHead) | kLockBit,
|
||||
std::memory_order_acq_rel, std::memory_order_acquire)) {
|
||||
break;
|
||||
}
|
||||
if ((head & kLockBit) != 0) {
|
||||
// Somebody could have acquired then released the lock
|
||||
// and failed to grab the onDeck_ microlock.
|
||||
head = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// We failed the CAS. yield/pause before trying again.
|
||||
Thread::yield();
|
||||
if (contendersList_.compare_exchange_weak(
|
||||
head, reinterpret_cast<intptr_t>(reinterpret_cast<LinkedNode*>(head)->next()),
|
||||
std::memory_order_acq_rel, std::memory_order_acquire)) {
|
||||
#ifdef ASSERT
|
||||
reinterpret_cast<LinkedNode*>(head)->setNext(NULL);
|
||||
#endif // ASSERT
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t spinCount = 0;
|
||||
// Go to sleep until we become the on-deck thread.
|
||||
while ((onDeck_ & ~kLockBit) != reinterpret_cast<intptr_t>(&semaphore)) {
|
||||
// First, be SMT friendly
|
||||
if (spinCount < kMaxReadSpinIter) {
|
||||
Os::spinPause();
|
||||
}
|
||||
// and then SMP friendly
|
||||
else if (spinCount < kMaxSpinIter) {
|
||||
Thread::yield();
|
||||
}
|
||||
// now go to sleep
|
||||
else {
|
||||
semaphore.wait();
|
||||
}
|
||||
spinCount++;
|
||||
}
|
||||
Semaphore* semaphore = (head != 0) ? reinterpret_cast<LinkedNode*>(head)->item() : NULL;
|
||||
|
||||
spinCount = 0;
|
||||
onDeck_.store(reinterpret_cast<intptr_t>(semaphore), std::memory_order_release);
|
||||
//
|
||||
// From now-on, we are the on-deck thread. It will stay that way until
|
||||
// we successfuly acquire the lock.
|
||||
//
|
||||
for (;;) {
|
||||
assert((onDeck_ & ~kLockBit) == reinterpret_cast<intptr_t>(&semaphore)
|
||||
&& "just checking");
|
||||
if (tryLock()) {
|
||||
break;
|
||||
}
|
||||
// Release the onDeck_ microlock (end of critical region);
|
||||
|
||||
// Somebody beat us to it. Since we are on-deck, we can just go
|
||||
// back to sleep.
|
||||
// First, be SMT friendly
|
||||
if (spinCount < kMaxReadSpinIter) {
|
||||
Os::spinPause();
|
||||
}
|
||||
// and then SMP friendly
|
||||
else if (spinCount < kMaxSpinIter) {
|
||||
Thread::yield();
|
||||
}
|
||||
// now go to sleep
|
||||
else {
|
||||
semaphore.wait();
|
||||
}
|
||||
spinCount++;
|
||||
if (semaphore != NULL) {
|
||||
semaphore->post();
|
||||
return;
|
||||
}
|
||||
|
||||
assert(newHead.next() == NULL && "Should not be linked");
|
||||
onDeck_ = 0;
|
||||
// We do not have an on-deck thread (semaphore == NULL). Return if
|
||||
// the contention list is empty or if the lock got acquired again.
|
||||
head = contendersList_;
|
||||
if (head == 0 || (head & kLockBit) != 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Monitor::finishUnlock()
|
||||
{
|
||||
// If we get here, it means that there might be a thread in the contention
|
||||
// list waiting to acquire the lock. We need to select a successor and
|
||||
// place it on-deck.
|
||||
void Monitor::wait() {
|
||||
Thread* thread = Thread::current();
|
||||
assert(isLocked() && owner_ == thread && "just checking");
|
||||
|
||||
for (;;) {
|
||||
// Grab the onDeck_ microlock to protect the next loop (make sure only
|
||||
// one semaphore is removed from the contention list).
|
||||
//
|
||||
intptr_t ptr = 0;
|
||||
if (!onDeck_.compare_exchange_strong(ptr, ptr | kLockBit,
|
||||
std::memory_order_acq_rel, std::memory_order_acquire)) {
|
||||
return; // Somebody else has the microlock, let him select onDeck_
|
||||
}
|
||||
// Add the thread's resume semaphore to the list.
|
||||
Semaphore& suspend = thread->suspendSemaphore();
|
||||
suspend.reset();
|
||||
|
||||
intptr_t head = contendersList_.load(std::memory_order_acquire);
|
||||
for (;;) {
|
||||
if (head == 0) {
|
||||
break; // There's nothing else to do.
|
||||
}
|
||||
LinkedNode newHead;
|
||||
newHead.setItem(&suspend);
|
||||
newHead.setNext(waitersList_);
|
||||
waitersList_ = &newHead;
|
||||
|
||||
if ((head & kLockBit) != 0) {
|
||||
// Somebody could have acquired then released the lock
|
||||
// and failed to grab the onDeck_ microlock.
|
||||
head = 0;
|
||||
break;
|
||||
}
|
||||
// Preserve the lock count (for recursive mutexes)
|
||||
uint32_t lockCount = lockCount_;
|
||||
lockCount_ = 1;
|
||||
|
||||
if (contendersList_.compare_exchange_weak(
|
||||
head, reinterpret_cast<intptr_t>(
|
||||
reinterpret_cast<LinkedNode*>(head)->next()),
|
||||
std::memory_order_acq_rel, std::memory_order_acquire)) {
|
||||
#ifdef ASSERT
|
||||
reinterpret_cast<LinkedNode*>(head)->setNext(NULL);
|
||||
#endif // ASSERT
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Release the lock and go to sleep.
|
||||
unlock();
|
||||
|
||||
Semaphore* semaphore = (head != 0)
|
||||
? reinterpret_cast<LinkedNode*>(head)->item()
|
||||
: NULL;
|
||||
|
||||
onDeck_.store(reinterpret_cast<intptr_t>(semaphore),
|
||||
std::memory_order_release);
|
||||
//
|
||||
// Release the onDeck_ microlock (end of critical region);
|
||||
|
||||
if (semaphore != NULL) {
|
||||
semaphore->post();
|
||||
return;
|
||||
}
|
||||
|
||||
// We do not have an on-deck thread (semaphore == NULL). Return if
|
||||
// the contention list is empty or if the lock got acquired again.
|
||||
head = contendersList_;
|
||||
if (head == 0 || (head & kLockBit) != 0) {
|
||||
return;
|
||||
}
|
||||
// Go to sleep until we become the on-deck thread.
|
||||
int32_t spinCount = 0;
|
||||
while ((onDeck_ & ~kLockBit) != reinterpret_cast<intptr_t>(&suspend)) {
|
||||
// First, be SMT friendly
|
||||
if (spinCount < kMaxReadSpinIter) {
|
||||
Os::spinPause();
|
||||
}
|
||||
// and then SMP friendly
|
||||
else if (spinCount < kMaxSpinIter) {
|
||||
Thread::yield();
|
||||
}
|
||||
// now go to sleep
|
||||
else {
|
||||
suspend.wait();
|
||||
}
|
||||
spinCount++;
|
||||
}
|
||||
|
||||
spinCount = 0;
|
||||
for (;;) {
|
||||
assert((onDeck_ & ~kLockBit) == reinterpret_cast<intptr_t>(&suspend) && "just checking");
|
||||
|
||||
if (trySpinLock()) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Somebody beat us to it. Since we are on-deck, we can just go
|
||||
// back to sleep.
|
||||
// First, be SMT friendly
|
||||
if (spinCount < kMaxReadSpinIter) {
|
||||
Os::spinPause();
|
||||
}
|
||||
// and then SMP friendly
|
||||
else if (spinCount < kMaxSpinIter) {
|
||||
Thread::yield();
|
||||
}
|
||||
// now go to sleep
|
||||
else {
|
||||
suspend.wait();
|
||||
}
|
||||
spinCount++;
|
||||
}
|
||||
|
||||
// Restore the lock count (for recursive mutexes)
|
||||
lockCount_ = lockCount;
|
||||
|
||||
onDeck_.store(0, std::memory_order_release);
|
||||
}
|
||||
|
||||
void
|
||||
Monitor::wait()
|
||||
{
|
||||
Thread* thread = Thread::current();
|
||||
assert(isLocked() && owner_ == thread && "just checking");
|
||||
void Monitor::notify() {
|
||||
assert(isLocked() && owner_ == Thread::current() && "just checking");
|
||||
|
||||
// Add the thread's resume semaphore to the list.
|
||||
Semaphore& suspend = thread->suspendSemaphore();
|
||||
suspend.reset();
|
||||
LinkedNode* waiter = waitersList_;
|
||||
if (waiter == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
LinkedNode newHead;
|
||||
newHead.setItem(&suspend);
|
||||
newHead.setNext(waitersList_);
|
||||
waitersList_ = &newHead;
|
||||
// Dequeue a waiter from the wait list and add it to the contention list.
|
||||
waitersList_ = waiter->next();
|
||||
|
||||
// Preserve the lock count (for recursive mutexes)
|
||||
uint32_t lockCount = lockCount_;
|
||||
lockCount_ = 1;
|
||||
|
||||
// Release the lock and go to sleep.
|
||||
unlock();
|
||||
|
||||
// Go to sleep until we become the on-deck thread.
|
||||
int32_t spinCount = 0;
|
||||
while ((onDeck_ & ~kLockBit) != reinterpret_cast<intptr_t>(&suspend)) {
|
||||
// First, be SMT friendly
|
||||
if (spinCount < kMaxReadSpinIter) {
|
||||
Os::spinPause();
|
||||
}
|
||||
// and then SMP friendly
|
||||
else if (spinCount < kMaxSpinIter) {
|
||||
Thread::yield();
|
||||
}
|
||||
// now go to sleep
|
||||
else {
|
||||
suspend.wait();
|
||||
}
|
||||
spinCount++;
|
||||
intptr_t node = contendersList_.load(std::memory_order_acquire);
|
||||
for (;;) {
|
||||
waiter->setNext(reinterpret_cast<LinkedNode*>(node & ~kLockBit));
|
||||
if (contendersList_.compare_exchange_weak(node, reinterpret_cast<intptr_t>(waiter) | kLockBit,
|
||||
std::memory_order_acq_rel,
|
||||
std::memory_order_acquire)) {
|
||||
break;
|
||||
}
|
||||
|
||||
spinCount = 0;
|
||||
for (;;) {
|
||||
assert((onDeck_ & ~kLockBit) == reinterpret_cast<intptr_t>(&suspend)
|
||||
&& "just checking");
|
||||
|
||||
if (trySpinLock()) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Somebody beat us to it. Since we are on-deck, we can just go
|
||||
// back to sleep.
|
||||
// First, be SMT friendly
|
||||
if (spinCount < kMaxReadSpinIter) {
|
||||
Os::spinPause();
|
||||
}
|
||||
// and then SMP friendly
|
||||
else if (spinCount < kMaxSpinIter) {
|
||||
Thread::yield();
|
||||
}
|
||||
// now go to sleep
|
||||
else {
|
||||
suspend.wait();
|
||||
}
|
||||
spinCount++;
|
||||
}
|
||||
|
||||
// Restore the lock count (for recursive mutexes)
|
||||
lockCount_ = lockCount;
|
||||
|
||||
onDeck_.store(0, std::memory_order_release);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Monitor::notify()
|
||||
{
|
||||
assert(isLocked() && owner_ == Thread::current() && "just checking");
|
||||
|
||||
LinkedNode* waiter = waitersList_;
|
||||
if (waiter == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Dequeue a waiter from the wait list and add it to the contention list.
|
||||
waitersList_ = waiter->next();
|
||||
|
||||
intptr_t node = contendersList_.load(std::memory_order_acquire);
|
||||
for (;;) {
|
||||
waiter->setNext(reinterpret_cast<LinkedNode*>(node & ~kLockBit));
|
||||
if (contendersList_.compare_exchange_weak(node,
|
||||
reinterpret_cast<intptr_t>(waiter) | kLockBit,
|
||||
std::memory_order_acq_rel, std::memory_order_acquire)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
void Monitor::notifyAll() {
|
||||
// NOTE: We could CAS the whole list in 1 shot but this is
|
||||
// not critical code. Optimize this if it becomes hot.
|
||||
while (waitersList_ != NULL) {
|
||||
notify();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Monitor::notifyAll()
|
||||
{
|
||||
// NOTE: We could CAS the whole list in 1 shot but this is
|
||||
// not critical code. Optimize this if it becomes hot.
|
||||
while (waitersList_ != NULL) {
|
||||
notify();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace amd
|
||||
} // namespace amd
|
||||
|
||||
@@ -25,239 +25,221 @@ namespace amd {
|
||||
|
||||
namespace details {
|
||||
|
||||
template <class T, class AllocClass = HeapObject>
|
||||
struct SimplyLinkedNode : public AllocClass
|
||||
{
|
||||
typedef SimplyLinkedNode<T, AllocClass> Node;
|
||||
template <class T, class AllocClass = HeapObject> struct SimplyLinkedNode : public AllocClass {
|
||||
typedef SimplyLinkedNode<T, AllocClass> Node;
|
||||
|
||||
protected:
|
||||
std::atomic<Node*> next_; /*!< \brief The next element. */
|
||||
T volatile item_;
|
||||
protected:
|
||||
std::atomic<Node*> next_; /*!< \brief The next element. */
|
||||
T volatile item_;
|
||||
|
||||
public:
|
||||
//! \brief Return the next element in the linked-list.
|
||||
Node* next() const { return next_; }
|
||||
//! \brief Return the item.
|
||||
T item() const { return item_; }
|
||||
public:
|
||||
//! \brief Return the next element in the linked-list.
|
||||
Node* next() const { return next_; }
|
||||
//! \brief Return the item.
|
||||
T item() const { return item_; }
|
||||
|
||||
//! \brief Set the next element pointer.
|
||||
void setNext(Node* next) { next_ = next; }
|
||||
//! \brief Set the item.
|
||||
void setItem(T item) { item_ = item; }
|
||||
//! \brief Set the next element pointer.
|
||||
void setNext(Node* next) { next_ = next; }
|
||||
//! \brief Set the item.
|
||||
void setItem(T item) { item_ = item; }
|
||||
|
||||
//! \brief Swap the next element pointer.
|
||||
Node* swapNext(Node* next) { return next_.swap(next); }
|
||||
//! \brief Swap the next element pointer.
|
||||
Node* swapNext(Node* next) { return next_.swap(next); }
|
||||
|
||||
//! \brief Compare and set the next element pointer.
|
||||
bool compareAndSetNext(Node* compare, Node* next)
|
||||
{
|
||||
return next_.compare_exchange_strong(compare, next);
|
||||
}
|
||||
//! \brief Compare and set the next element pointer.
|
||||
bool compareAndSetNext(Node* compare, Node* next) {
|
||||
return next_.compare_exchange_strong(compare, next);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
} // namespace details
|
||||
|
||||
class Monitor : public HeapObject
|
||||
{
|
||||
typedef details::SimplyLinkedNode<Semaphore*,StackObject> LinkedNode;
|
||||
class Monitor : public HeapObject {
|
||||
typedef details::SimplyLinkedNode<Semaphore*, StackObject> LinkedNode;
|
||||
|
||||
private:
|
||||
static const intptr_t kLockBit = 0x1;
|
||||
private:
|
||||
static const intptr_t kLockBit = 0x1;
|
||||
|
||||
static const int kMaxSpinIter = 55; //!< Total number of spin iterations.
|
||||
static const int kMaxReadSpinIter = 50; //!< Read iterations before yielding
|
||||
static const int kMaxSpinIter = 55; //!< Total number of spin iterations.
|
||||
static const int kMaxReadSpinIter = 50; //!< Read iterations before yielding
|
||||
|
||||
/*! Linked list of semaphores the contending threads are waiting on
|
||||
* and main lock.
|
||||
*/
|
||||
std::atomic_intptr_t contendersList_;
|
||||
//! The Mutex's name
|
||||
char name_[64];
|
||||
/*! Linked list of semaphores the contending threads are waiting on
|
||||
* and main lock.
|
||||
*/
|
||||
std::atomic_intptr_t contendersList_;
|
||||
//! The Mutex's name
|
||||
char name_[64];
|
||||
|
||||
//! Semaphore of the next thread to contend for the lock.
|
||||
std::atomic_intptr_t onDeck_;
|
||||
//! Linked list of the suspended threads resume semaphores.
|
||||
LinkedNode* volatile waitersList_;
|
||||
//! Semaphore of the next thread to contend for the lock.
|
||||
std::atomic_intptr_t onDeck_;
|
||||
//! Linked list of the suspended threads resume semaphores.
|
||||
LinkedNode* volatile waitersList_;
|
||||
|
||||
//! Thread owning this monitor.
|
||||
Thread* volatile owner_;
|
||||
//! The amount of times this monitor was acquired by the owner.
|
||||
uint32_t lockCount_;
|
||||
//! True if this is a recursive mutex, false otherwise.
|
||||
const bool recursive_;
|
||||
//! Thread owning this monitor.
|
||||
Thread* volatile owner_;
|
||||
//! The amount of times this monitor was acquired by the owner.
|
||||
uint32_t lockCount_;
|
||||
//! True if this is a recursive mutex, false otherwise.
|
||||
const bool recursive_;
|
||||
|
||||
private:
|
||||
//! Finish locking the mutex (contented case).
|
||||
void finishLock();
|
||||
//! Finish unlocking the mutex (contented case).
|
||||
void finishUnlock();
|
||||
private:
|
||||
//! Finish locking the mutex (contented case).
|
||||
void finishLock();
|
||||
//! Finish unlocking the mutex (contented case).
|
||||
void finishUnlock();
|
||||
|
||||
protected:
|
||||
//! Try to spin-acquire the lock, return true if successful.
|
||||
bool trySpinLock();
|
||||
protected:
|
||||
//! Try to spin-acquire the lock, return true if successful.
|
||||
bool trySpinLock();
|
||||
|
||||
/*! \brief Return true if the lock is owned.
|
||||
*
|
||||
* \note The user is responsible for the memory ordering.
|
||||
*/
|
||||
bool isLocked() const { return (contendersList_ & kLockBit) != 0; }
|
||||
/*! \brief Return true if the lock is owned.
|
||||
*
|
||||
* \note The user is responsible for the memory ordering.
|
||||
*/
|
||||
bool isLocked() const { return (contendersList_ & kLockBit) != 0; }
|
||||
|
||||
//! Return this monitor's owner thread (NULL if unlocked).
|
||||
Thread* owner() const { return owner_; }
|
||||
//! Return this monitor's owner thread (NULL if unlocked).
|
||||
Thread* owner() const { return owner_; }
|
||||
|
||||
//! Set the owner.
|
||||
void setOwner(Thread* thread) { owner_ = thread; }
|
||||
//! Set the owner.
|
||||
void setOwner(Thread* thread) { owner_ = thread; }
|
||||
|
||||
public:
|
||||
explicit Monitor(const char* name = NULL, bool recursive = false);
|
||||
~Monitor() {}
|
||||
public:
|
||||
explicit Monitor(const char* name = NULL, bool recursive = false);
|
||||
~Monitor() {}
|
||||
|
||||
//! Try to acquire the lock, return true if successful.
|
||||
inline bool tryLock();
|
||||
//! Try to acquire the lock, return true if successful.
|
||||
inline bool tryLock();
|
||||
|
||||
//! Acquire the lock or suspend the calling thread.
|
||||
inline void lock();
|
||||
//! Acquire the lock or suspend the calling thread.
|
||||
inline void lock();
|
||||
|
||||
//! Release the lock and wake a single waiting thread if any.
|
||||
inline void unlock();
|
||||
//! Release the lock and wake a single waiting thread if any.
|
||||
inline void unlock();
|
||||
|
||||
/*! \brief Give up the lock and go to sleep.
|
||||
*
|
||||
* Calling wait() causes the current thread to go to sleep until
|
||||
* another thread calls notify()/notifyAll().
|
||||
*
|
||||
* \note The monitor must be owned before calling wait().
|
||||
*/
|
||||
void wait();
|
||||
/*! \brief Wake up a single thread waiting on this monitor.
|
||||
*
|
||||
* \note The monitor must be owned before calling notify().
|
||||
*/
|
||||
void notify();
|
||||
/*! \brief Wake up all threads that are waiting on this monitor.
|
||||
*
|
||||
* \note The monitor must be owned before calling notifyAll().
|
||||
*/
|
||||
void notifyAll();
|
||||
/*! \brief Give up the lock and go to sleep.
|
||||
*
|
||||
* Calling wait() causes the current thread to go to sleep until
|
||||
* another thread calls notify()/notifyAll().
|
||||
*
|
||||
* \note The monitor must be owned before calling wait().
|
||||
*/
|
||||
void wait();
|
||||
/*! \brief Wake up a single thread waiting on this monitor.
|
||||
*
|
||||
* \note The monitor must be owned before calling notify().
|
||||
*/
|
||||
void notify();
|
||||
/*! \brief Wake up all threads that are waiting on this monitor.
|
||||
*
|
||||
* \note The monitor must be owned before calling notifyAll().
|
||||
*/
|
||||
void notifyAll();
|
||||
|
||||
//! Return this lock's name.
|
||||
const char* name() const { return name_; }
|
||||
//! Return this lock's name.
|
||||
const char* name() const { return name_; }
|
||||
};
|
||||
|
||||
class ScopedLock : StackObject
|
||||
{
|
||||
private:
|
||||
Monitor* lock_;
|
||||
class ScopedLock : StackObject {
|
||||
private:
|
||||
Monitor* lock_;
|
||||
|
||||
public:
|
||||
ScopedLock(Monitor& lock)
|
||||
: lock_(&lock)
|
||||
{
|
||||
lock_->lock();
|
||||
}
|
||||
public:
|
||||
ScopedLock(Monitor& lock) : lock_(&lock) { lock_->lock(); }
|
||||
|
||||
ScopedLock(Monitor* lock)
|
||||
: lock_(lock)
|
||||
{
|
||||
if (lock_) lock_->lock();
|
||||
}
|
||||
ScopedLock(Monitor* lock) : lock_(lock) {
|
||||
if (lock_) lock_->lock();
|
||||
}
|
||||
|
||||
~ScopedLock()
|
||||
{
|
||||
if (lock_) lock_->unlock();
|
||||
}
|
||||
~ScopedLock() {
|
||||
if (lock_) lock_->unlock();
|
||||
}
|
||||
};
|
||||
|
||||
/*! @}
|
||||
* @}
|
||||
*/
|
||||
|
||||
inline bool
|
||||
Monitor::tryLock()
|
||||
{
|
||||
Thread* thread = Thread::current();
|
||||
assert(thread != NULL && "cannot lock() from (null)");
|
||||
inline bool Monitor::tryLock() {
|
||||
Thread* thread = Thread::current();
|
||||
assert(thread != NULL && "cannot lock() from (null)");
|
||||
|
||||
intptr_t ptr = contendersList_.load(std::memory_order_acquire);
|
||||
intptr_t ptr = contendersList_.load(std::memory_order_acquire);
|
||||
|
||||
if (unlikely((ptr & kLockBit) != 0)) {
|
||||
if (recursive_ && thread == owner_) {
|
||||
// Recursive lock: increment the lock count and return.
|
||||
++lockCount_;
|
||||
return true;
|
||||
}
|
||||
return false; // Already locked!
|
||||
if (unlikely((ptr & kLockBit) != 0)) {
|
||||
if (recursive_ && thread == owner_) {
|
||||
// Recursive lock: increment the lock count and return.
|
||||
++lockCount_;
|
||||
return true;
|
||||
}
|
||||
return false; // Already locked!
|
||||
}
|
||||
|
||||
if (unlikely(!contendersList_.compare_exchange_weak(ptr, ptr | kLockBit,
|
||||
std::memory_order_acq_rel, std::memory_order_acquire))) {
|
||||
return false; // We failed the CAS from unlocked to locked.
|
||||
}
|
||||
if (unlikely(!contendersList_.compare_exchange_weak(
|
||||
ptr, ptr | kLockBit, std::memory_order_acq_rel, std::memory_order_acquire))) {
|
||||
return false; // We failed the CAS from unlocked to locked.
|
||||
}
|
||||
|
||||
setOwner(thread); // cannot move above the CAS.
|
||||
lockCount_ = 1;
|
||||
setOwner(thread); // cannot move above the CAS.
|
||||
lockCount_ = 1;
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void
|
||||
Monitor::lock()
|
||||
{
|
||||
if (unlikely(!tryLock())) {
|
||||
// The lock is contented.
|
||||
finishLock();
|
||||
}
|
||||
inline void Monitor::lock() {
|
||||
if (unlikely(!tryLock())) {
|
||||
// The lock is contented.
|
||||
finishLock();
|
||||
}
|
||||
|
||||
// This is the beginning of the critical region. From now-on, everything
|
||||
// executes single-threaded!
|
||||
//
|
||||
// This is the beginning of the critical region. From now-on, everything
|
||||
// executes single-threaded!
|
||||
//
|
||||
}
|
||||
|
||||
inline void
|
||||
Monitor::unlock()
|
||||
{
|
||||
assert(isLocked() && owner_ == Thread::current() && "invariant");
|
||||
inline void Monitor::unlock() {
|
||||
assert(isLocked() && owner_ == Thread::current() && "invariant");
|
||||
|
||||
if (recursive_ && --lockCount_ > 0) {
|
||||
// was a recursive lock case, simply return.
|
||||
return;
|
||||
if (recursive_ && --lockCount_ > 0) {
|
||||
// was a recursive lock case, simply return.
|
||||
return;
|
||||
}
|
||||
|
||||
setOwner(NULL);
|
||||
|
||||
// Clear the lock bit.
|
||||
intptr_t ptr = contendersList_.load(std::memory_order_acquire);
|
||||
while (!contendersList_.compare_exchange_weak(ptr, ptr & ~kLockBit, std::memory_order_acq_rel,
|
||||
std::memory_order_acquire))
|
||||
;
|
||||
//
|
||||
// We succeeded the CAS from locked to unlocked.
|
||||
// This is the end of the critical region.
|
||||
|
||||
// Check if we have an on-deck thread that needs signaling.
|
||||
intptr_t onDeck = onDeck_;
|
||||
if (onDeck != 0) {
|
||||
if ((onDeck & kLockBit) == 0) {
|
||||
// Only signal if it is unmarked.
|
||||
reinterpret_cast<Semaphore*>(onDeck)->post();
|
||||
}
|
||||
return; // We are done.
|
||||
}
|
||||
|
||||
setOwner(NULL);
|
||||
// We do not have an on-deck thread yet, we might have to walk the list in
|
||||
// order to select the next onDeck_. Only one thread needs to fill onDeck_,
|
||||
// so return if the list is empty or if the lock got acquired again (it's
|
||||
// somebody else's problem now!)
|
||||
|
||||
// Clear the lock bit.
|
||||
intptr_t ptr = contendersList_.load(std::memory_order_acquire);
|
||||
while (!contendersList_.compare_exchange_weak(ptr, ptr & ~kLockBit,
|
||||
std::memory_order_acq_rel, std::memory_order_acquire))
|
||||
;
|
||||
//
|
||||
// We succeeded the CAS from locked to unlocked.
|
||||
// This is the end of the critical region.
|
||||
intptr_t head = contendersList_;
|
||||
if (head == 0 || (head & kLockBit) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we have an on-deck thread that needs signaling.
|
||||
intptr_t onDeck = onDeck_;
|
||||
if (onDeck != 0) {
|
||||
if ((onDeck & kLockBit) == 0) {
|
||||
// Only signal if it is unmarked.
|
||||
reinterpret_cast<Semaphore*>(onDeck)->post();
|
||||
}
|
||||
return; // We are done.
|
||||
}
|
||||
|
||||
// We do not have an on-deck thread yet, we might have to walk the list in
|
||||
// order to select the next onDeck_. Only one thread needs to fill onDeck_,
|
||||
// so return if the list is empty or if the lock got acquired again (it's
|
||||
// somebody else's problem now!)
|
||||
|
||||
intptr_t head = contendersList_;
|
||||
if (head == 0 || (head & kLockBit) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Finish the unlock operation: find a thread to wake up.
|
||||
finishUnlock();
|
||||
// Finish the unlock operation: find a thread to wake up.
|
||||
finishUnlock();
|
||||
}
|
||||
|
||||
} // namespace amd
|
||||
} // namespace amd
|
||||
|
||||
#endif /*MONITOR_HPP_*/
|
||||
|
||||
@@ -6,90 +6,82 @@
|
||||
#include "thread/thread.hpp"
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
# include <windows.h>
|
||||
#else // !_WIN32
|
||||
# include <semaphore.h>
|
||||
# include <errno.h>
|
||||
#endif // !_WIN32
|
||||
#include <windows.h>
|
||||
#else // !_WIN32
|
||||
#include <semaphore.h>
|
||||
#include <errno.h>
|
||||
#endif // !_WIN32
|
||||
|
||||
namespace amd {
|
||||
|
||||
Semaphore::Semaphore()
|
||||
: state_(0)
|
||||
{
|
||||
Semaphore::Semaphore() : state_(0) {
|
||||
#ifdef _WIN32
|
||||
handle_ = static_cast<void*>(CreateSemaphore(NULL, 0, LONG_MAX, NULL));
|
||||
assert(handle_ != NULL && "CreateSemaphore failed");
|
||||
#else // !_WIN32
|
||||
if (sem_init(&sem_, 0, 0) != 0) {
|
||||
fatal("sem_init() failed");
|
||||
}
|
||||
#endif // !_WIN32
|
||||
handle_ = static_cast<void*>(CreateSemaphore(NULL, 0, LONG_MAX, NULL));
|
||||
assert(handle_ != NULL && "CreateSemaphore failed");
|
||||
#else // !_WIN32
|
||||
if (sem_init(&sem_, 0, 0) != 0) {
|
||||
fatal("sem_init() failed");
|
||||
}
|
||||
#endif // !_WIN32
|
||||
}
|
||||
|
||||
Semaphore::~Semaphore()
|
||||
{
|
||||
Semaphore::~Semaphore() {
|
||||
#ifdef _WIN32
|
||||
if (!CloseHandle(static_cast<HANDLE>(handle_))) {
|
||||
fatal("CloseHandle() failed");
|
||||
}
|
||||
#else // !_WIN32
|
||||
if (sem_destroy(&sem_) != 0) {
|
||||
fatal("sem_destroy() failed");
|
||||
}
|
||||
#endif // !WIN32
|
||||
if (!CloseHandle(static_cast<HANDLE>(handle_))) {
|
||||
fatal("CloseHandle() failed");
|
||||
}
|
||||
#else // !_WIN32
|
||||
if (sem_destroy(&sem_) != 0) {
|
||||
fatal("sem_destroy() failed");
|
||||
}
|
||||
#endif // !WIN32
|
||||
}
|
||||
|
||||
void
|
||||
Semaphore::post()
|
||||
{
|
||||
int state = state_.load(std::memory_order_relaxed);
|
||||
for (;;) {
|
||||
if (state > 0) {
|
||||
int newstate = state_.load(std::memory_order_acquire);
|
||||
if (state == newstate) {
|
||||
return;
|
||||
}
|
||||
state = newstate;
|
||||
continue;
|
||||
}
|
||||
if (state_.compare_exchange_weak(state, state+1,
|
||||
std::memory_order_acq_rel, std::memory_order_acquire)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (state < 0) {
|
||||
// We have threads waiting on this event.
|
||||
#ifdef _WIN32
|
||||
ReleaseSemaphore(static_cast<HANDLE>(handle_), 1, NULL);
|
||||
#else // !_WIN32
|
||||
if (0 != sem_post(&sem_)) {
|
||||
fatal("sem_post() failed");
|
||||
}
|
||||
#endif // !_WIN32
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Semaphore::wait()
|
||||
{
|
||||
if (state_-- > 0) {
|
||||
void Semaphore::post() {
|
||||
int state = state_.load(std::memory_order_relaxed);
|
||||
for (;;) {
|
||||
if (state > 0) {
|
||||
int newstate = state_.load(std::memory_order_acquire);
|
||||
if (state == newstate) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (WAIT_OBJECT_0 != WaitForSingleObject(
|
||||
static_cast<HANDLE>(handle_), INFINITE)) {
|
||||
fatal("WaitForSingleObject failed");
|
||||
}
|
||||
#else // !_WIN32
|
||||
while (0 != sem_wait(&sem_)) {
|
||||
if (EINTR != errno) {
|
||||
fatal("sem_wait() failed");
|
||||
}
|
||||
state = newstate;
|
||||
continue;
|
||||
}
|
||||
#endif // !_WIN32
|
||||
if (state_.compare_exchange_weak(state, state + 1, std::memory_order_acq_rel,
|
||||
std::memory_order_acquire)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (state < 0) {
|
||||
// We have threads waiting on this event.
|
||||
#ifdef _WIN32
|
||||
ReleaseSemaphore(static_cast<HANDLE>(handle_), 1, NULL);
|
||||
#else // !_WIN32
|
||||
if (0 != sem_post(&sem_)) {
|
||||
fatal("sem_post() failed");
|
||||
}
|
||||
#endif // !_WIN32
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace amd
|
||||
void Semaphore::wait() {
|
||||
if (state_-- > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (WAIT_OBJECT_0 != WaitForSingleObject(static_cast<HANDLE>(handle_), INFINITE)) {
|
||||
fatal("WaitForSingleObject failed");
|
||||
}
|
||||
#else // !_WIN32
|
||||
while (0 != sem_wait(&sem_)) {
|
||||
if (EINTR != errno) {
|
||||
fatal("sem_wait() failed");
|
||||
}
|
||||
}
|
||||
#endif // !_WIN32
|
||||
}
|
||||
|
||||
} // namespace amd
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#include <atomic>
|
||||
#if defined(__linux__)
|
||||
# include <semaphore.h>
|
||||
#include <semaphore.h>
|
||||
#endif /*linux*/
|
||||
|
||||
|
||||
@@ -26,40 +26,36 @@ namespace amd {
|
||||
class Thread;
|
||||
|
||||
//! \brief Counting semaphore
|
||||
class Semaphore : public HeapObject
|
||||
{
|
||||
private:
|
||||
std::atomic_int state_; //!< This semaphore's value.
|
||||
class Semaphore : public HeapObject {
|
||||
private:
|
||||
std::atomic_int state_; //!< This semaphore's value.
|
||||
|
||||
#ifdef _WIN32
|
||||
void* handle_; //!< The semaphore object's handle.
|
||||
char padding_[64-sizeof(void*)-sizeof(std::atomic_int)];
|
||||
#else // !_WIN32
|
||||
sem_t sem_; //!< The semaphore object's identifier.
|
||||
char padding_[64-sizeof(sem_t)-sizeof(std::atomic_int)];
|
||||
void* handle_; //!< The semaphore object's handle.
|
||||
char padding_[64 - sizeof(void*) - sizeof(std::atomic_int)];
|
||||
#else // !_WIN32
|
||||
sem_t sem_; //!< The semaphore object's identifier.
|
||||
char padding_[64 - sizeof(sem_t) - sizeof(std::atomic_int)];
|
||||
#endif /*!_WIN32*/
|
||||
|
||||
public:
|
||||
Semaphore();
|
||||
~Semaphore();
|
||||
public:
|
||||
Semaphore();
|
||||
~Semaphore();
|
||||
|
||||
//! \brief Decrement this semaphore
|
||||
void wait();
|
||||
//! \brief Decrement this semaphore
|
||||
void wait();
|
||||
|
||||
//! \brief Increment this semaphore
|
||||
void post();
|
||||
//! \brief Increment this semaphore
|
||||
void post();
|
||||
|
||||
//! \brief Reset this semaphore.
|
||||
void reset()
|
||||
{
|
||||
state_.store(0, std::memory_order_release);
|
||||
}
|
||||
//! \brief Reset this semaphore.
|
||||
void reset() { state_.store(0, std::memory_order_release); }
|
||||
};
|
||||
|
||||
/*! @}
|
||||
* @}
|
||||
*/
|
||||
|
||||
} // namespace amd
|
||||
} // namespace amd
|
||||
|
||||
#endif /*SEMAPHORE_HPP_*/
|
||||
|
||||
@@ -8,109 +8,97 @@
|
||||
#include "os/os.hpp"
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
# include <windows.h>
|
||||
#endif // _WIN32
|
||||
#include <windows.h>
|
||||
#endif // _WIN32
|
||||
|
||||
namespace amd {
|
||||
|
||||
HostThread::HostThread()
|
||||
: Thread("HostThread", 0, false)
|
||||
{
|
||||
setCurrent();
|
||||
Os::currentStackInfo(&stackBase_, &stackSize_);
|
||||
setState(RUNNABLE);
|
||||
HostThread::HostThread() : Thread("HostThread", 0, false) {
|
||||
setCurrent();
|
||||
Os::currentStackInfo(&stackBase_, &stackSize_);
|
||||
setState(RUNNABLE);
|
||||
}
|
||||
|
||||
void
|
||||
Thread::create()
|
||||
{
|
||||
created_ = new Semaphore();
|
||||
lock_ = new Semaphore();
|
||||
suspend_ = new Semaphore();
|
||||
void Thread::create() {
|
||||
created_ = new Semaphore();
|
||||
lock_ = new Semaphore();
|
||||
suspend_ = new Semaphore();
|
||||
|
||||
selfSuspendLock_ = new Monitor();
|
||||
selfSuspendLock_ = new Monitor();
|
||||
|
||||
data_ = NULL;
|
||||
handle_ = NULL;
|
||||
setState(CREATED);
|
||||
data_ = NULL;
|
||||
handle_ = NULL;
|
||||
setState(CREATED);
|
||||
}
|
||||
|
||||
Thread::Thread(const std::string& name, size_t stackSize, bool spawn)
|
||||
: handle_(NULL), name_(name), stackSize_(stackSize)
|
||||
{
|
||||
create();
|
||||
: handle_(NULL), name_(name), stackSize_(stackSize) {
|
||||
create();
|
||||
|
||||
if (!spawn) return;
|
||||
if (!spawn) return;
|
||||
|
||||
if ((handle_ = Os::createOsThread(this))) {
|
||||
// Now we need to wait for Thread::main to report back.
|
||||
while (state() != Thread::INITIALIZED) {
|
||||
created_->wait();
|
||||
}
|
||||
if ((handle_ = Os::createOsThread(this))) {
|
||||
// Now we need to wait for Thread::main to report back.
|
||||
while (state() != Thread::INITIALIZED) {
|
||||
created_->wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Thread::~Thread()
|
||||
{
|
||||
Thread::~Thread() {
|
||||
#if defined(_WIN32)
|
||||
if (handle_ != NULL) {
|
||||
::CloseHandle((HANDLE) handle_);
|
||||
}
|
||||
if (handle_ != NULL) {
|
||||
::CloseHandle((HANDLE)handle_);
|
||||
}
|
||||
#endif
|
||||
delete created_;
|
||||
delete lock_;
|
||||
delete suspend_;
|
||||
delete created_;
|
||||
delete lock_;
|
||||
delete suspend_;
|
||||
|
||||
delete selfSuspendLock_;
|
||||
delete selfSuspendLock_;
|
||||
}
|
||||
|
||||
void*
|
||||
Thread::main()
|
||||
{
|
||||
void* Thread::main() {
|
||||
#ifdef DEBUG
|
||||
Os::setCurrentThreadName(name().c_str());
|
||||
#endif // DEBUG
|
||||
Os::currentStackInfo(&stackBase_, &stackSize_);
|
||||
setCurrent();
|
||||
Os::setCurrentThreadName(name().c_str());
|
||||
#endif // DEBUG
|
||||
Os::currentStackInfo(&stackBase_, &stackSize_);
|
||||
setCurrent();
|
||||
|
||||
// Notify the parent thread that we are up and running.
|
||||
{
|
||||
ScopedLock sl(selfSuspendLock_);
|
||||
setState(INITIALIZED);
|
||||
created_->post();
|
||||
selfSuspendLock_->wait();
|
||||
}
|
||||
|
||||
if (state() == RUNNABLE) {
|
||||
run(data_);
|
||||
}
|
||||
|
||||
setState(FINISHED);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
Thread::start(void* data)
|
||||
{
|
||||
if (state() != INITIALIZED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
data_ = data;
|
||||
{
|
||||
ScopedLock sl(selfSuspendLock_);
|
||||
setState(RUNNABLE);
|
||||
selfSuspendLock_->notify();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Thread::resume()
|
||||
{
|
||||
// Notify the parent thread that we are up and running.
|
||||
{
|
||||
ScopedLock sl(selfSuspendLock_);
|
||||
setState(INITIALIZED);
|
||||
created_->post();
|
||||
selfSuspendLock_->wait();
|
||||
}
|
||||
|
||||
if (state() == RUNNABLE) {
|
||||
run(data_);
|
||||
}
|
||||
|
||||
setState(FINISHED);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool Thread::start(void* data) {
|
||||
if (state() != INITIALIZED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
data_ = data;
|
||||
{
|
||||
ScopedLock sl(selfSuspendLock_);
|
||||
setState(RUNNABLE);
|
||||
selfSuspendLock_->notify();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Thread::resume() {
|
||||
ScopedLock sl(selfSuspendLock_);
|
||||
selfSuspendLock_->notify();
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
@@ -119,19 +107,13 @@ namespace details {
|
||||
|
||||
__thread Thread* thread_ __attribute__((tls_model("initial-exec")));
|
||||
|
||||
} // namespace details
|
||||
} // namespace details
|
||||
|
||||
void
|
||||
Thread::registerStack(address base, address top)
|
||||
{
|
||||
// Nothing to do.
|
||||
void Thread::registerStack(address base, address top) {
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
void
|
||||
Thread::setCurrent()
|
||||
{
|
||||
details::thread_ = this;
|
||||
}
|
||||
void Thread::setCurrent() { details::thread_ = this; }
|
||||
|
||||
#elif defined(_WIN32)
|
||||
|
||||
@@ -139,53 +121,45 @@ namespace details {
|
||||
|
||||
#if defined(USE_DECLSPEC_THREAD)
|
||||
__declspec(thread) Thread* thread_;
|
||||
#else // !USE_DECLSPEC_THREAD
|
||||
#else // !USE_DECLSPEC_THREAD
|
||||
DWORD threadIndex_ = TlsAlloc();
|
||||
#endif // !USE_DECLSPEC_THREAD
|
||||
#endif // !USE_DECLSPEC_THREAD
|
||||
|
||||
} // namespace details
|
||||
} // namespace details
|
||||
|
||||
void
|
||||
Thread::registerStack(address base, address top)
|
||||
{
|
||||
// Nothing to do.
|
||||
void Thread::registerStack(address base, address top) {
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
void
|
||||
Thread::setCurrent()
|
||||
{
|
||||
void Thread::setCurrent() {
|
||||
#if defined(USE_DECLSPEC_THREAD)
|
||||
details::thread_ = this;
|
||||
#else // !USE_DECLSPEC_THREAD
|
||||
TlsSetValue(details::threadIndex_, this);
|
||||
#endif // !USE_DECLSPEC_THREAD
|
||||
details::thread_ = this;
|
||||
#else // !USE_DECLSPEC_THREAD
|
||||
TlsSetValue(details::threadIndex_, this);
|
||||
#endif // !USE_DECLSPEC_THREAD
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool
|
||||
Thread::init()
|
||||
{
|
||||
static bool initialized_ = false;
|
||||
bool Thread::init() {
|
||||
static bool initialized_ = false;
|
||||
|
||||
// We could use InitOnceExecuteOnce/pthread_once here:
|
||||
if (initialized_) {
|
||||
return true;
|
||||
}
|
||||
initialized_ = true;
|
||||
// We could use InitOnceExecuteOnce/pthread_once here:
|
||||
if (initialized_) {
|
||||
return true;
|
||||
}
|
||||
initialized_ = true;
|
||||
|
||||
// Register the main thread
|
||||
return NULL != new HostThread();
|
||||
// Register the main thread
|
||||
return NULL != new HostThread();
|
||||
}
|
||||
|
||||
void
|
||||
Thread::tearDown()
|
||||
{
|
||||
void Thread::tearDown() {
|
||||
#if defined(_WIN32) && !defined(USE_DECLSPEC_THREAD)
|
||||
if (details::threadIndex_ != TLS_OUT_OF_INDEXES) {
|
||||
TlsFree(threadIndex_);
|
||||
}
|
||||
#endif // _WIN32 && !USE_DECLSPEC_THREAD
|
||||
if (details::threadIndex_ != TLS_OUT_OF_INDEXES) {
|
||||
TlsFree(threadIndex_);
|
||||
}
|
||||
#endif // _WIN32 && !USE_DECLSPEC_THREAD
|
||||
}
|
||||
|
||||
} // namespace amd
|
||||
} // namespace amd
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
#include <string>
|
||||
|
||||
#if defined(_WIN32)
|
||||
# define USE_DECLSPEC_THREAD 1
|
||||
# if !defined(USE_DECLSPEC_THREAD)
|
||||
# include <windows.h>
|
||||
# endif /*!USE_DECLSPEC_THREAD*/
|
||||
#define USE_DECLSPEC_THREAD 1
|
||||
#if !defined(USE_DECLSPEC_THREAD)
|
||||
#include <windows.h>
|
||||
#endif /*!USE_DECLSPEC_THREAD*/
|
||||
#endif /*_WIN32*/
|
||||
|
||||
namespace amd {
|
||||
@@ -29,157 +29,137 @@ namespace amd {
|
||||
|
||||
class Monitor;
|
||||
|
||||
class Thread : public HeapObject
|
||||
{
|
||||
friend const void* Os::createOsThread(Thread*);
|
||||
class Thread : public HeapObject {
|
||||
friend const void* Os::createOsThread(Thread*);
|
||||
|
||||
public:
|
||||
enum ThreadState
|
||||
{
|
||||
CREATED,
|
||||
INITIALIZED,
|
||||
RUNNABLE,
|
||||
SUSPENDED,
|
||||
FINISHED,
|
||||
FAILED
|
||||
};
|
||||
public:
|
||||
enum ThreadState { CREATED, INITIALIZED, RUNNABLE, SUSPENDED, FINISHED, FAILED };
|
||||
|
||||
private:
|
||||
//! System thread handle.
|
||||
const void* handle_;
|
||||
//! The thread's name.
|
||||
const std::string name_;
|
||||
//! Current running state.
|
||||
volatile ThreadState state_;
|
||||
//! The argument passed to run()
|
||||
void* data_;
|
||||
private:
|
||||
//! System thread handle.
|
||||
const void* handle_;
|
||||
//! The thread's name.
|
||||
const std::string name_;
|
||||
//! Current running state.
|
||||
volatile ThreadState state_;
|
||||
//! The argument passed to run()
|
||||
void* data_;
|
||||
|
||||
//! \cond ignore
|
||||
Semaphore* created_; //!< To notify the parent thread.
|
||||
Semaphore* lock_; //!< For mutex support (during contention).
|
||||
Semaphore* suspend_; //!< For wait/suspend support.
|
||||
//! \endcond
|
||||
//! \cond ignore
|
||||
Semaphore* created_; //!< To notify the parent thread.
|
||||
Semaphore* lock_; //!< For mutex support (during contention).
|
||||
Semaphore* suspend_; //!< For wait/suspend support.
|
||||
//! \endcond
|
||||
|
||||
Monitor* selfSuspendLock_; //!< For self suspend/resume.
|
||||
Monitor* selfSuspendLock_; //!< For self suspend/resume.
|
||||
|
||||
protected:
|
||||
address stackBase_; //!< Main stack base.
|
||||
size_t stackSize_; //!< Main stack size.
|
||||
protected:
|
||||
address stackBase_; //!< Main stack base.
|
||||
size_t stackSize_; //!< Main stack size.
|
||||
|
||||
private:
|
||||
private:
|
||||
/*! \brief The start wrapper for all newly create threads.
|
||||
* This is called from the pthread_create start_thread.
|
||||
*/
|
||||
static void* entry(Thread* thread);
|
||||
|
||||
/*! \brief The start wrapper for all newly create threads.
|
||||
* This is called from the pthread_create start_thread.
|
||||
*/
|
||||
static void* entry(Thread* thread);
|
||||
/*! \brief Thread main (called from the main function).
|
||||
* Setup the thread for running and wait for the semaphore to be signaled.
|
||||
*/
|
||||
void* main();
|
||||
|
||||
/*! \brief Thread main (called from the main function).
|
||||
* Setup the thread for running and wait for the semaphore to be signaled.
|
||||
*/
|
||||
void* main();
|
||||
//! The entry point for this thread.
|
||||
virtual void run(void* data) = 0;
|
||||
|
||||
//! The entry point for this thread.
|
||||
virtual void run(void* data) = 0;
|
||||
protected:
|
||||
//! Bring this thread to the created state.
|
||||
void create();
|
||||
|
||||
protected:
|
||||
//! Bring this thread to the created state.
|
||||
void create();
|
||||
//! Set the current thread state.
|
||||
void setState(ThreadState state) { state_ = state; }
|
||||
|
||||
//! Set the current thread state.
|
||||
void setState(ThreadState state) { state_ = state; }
|
||||
//! Set the thread-local _thread variable (used by current()).
|
||||
void setCurrent();
|
||||
|
||||
//! Set the thread-local _thread variable (used by current()).
|
||||
void setCurrent();
|
||||
//! Register the given memory region as a valid stack.
|
||||
void registerStack(address base, address top);
|
||||
|
||||
//! Register the given memory region as a valid stack.
|
||||
void registerStack(address base, address top);
|
||||
/*! \brief Construct a new thread.
|
||||
* If \a spawn is false, do not create a new OS thread, instead,
|
||||
* bind to the currently running on.
|
||||
*/
|
||||
explicit Thread(const std::string& name, size_t stackSize = 0 /*use system default*/,
|
||||
bool spawn = true /* create a new Os::thread */);
|
||||
|
||||
/*! \brief Construct a new thread.
|
||||
* If \a spawn is false, do not create a new OS thread, instead,
|
||||
* bind to the currently running on.
|
||||
*/
|
||||
explicit Thread(
|
||||
const std::string& name,
|
||||
size_t stackSize = 0 /*use system default*/,
|
||||
bool spawn = true /* create a new Os::thread */);
|
||||
public:
|
||||
//! Return the currently running thread instance.
|
||||
static inline Thread* current();
|
||||
|
||||
public:
|
||||
//! Return the currently running thread instance.
|
||||
static inline Thread* current();
|
||||
//! Initialize the OsThread package.
|
||||
static bool init();
|
||||
|
||||
//! Initialize the OsThread package.
|
||||
static bool init();
|
||||
//! Tear down the OsThread package.
|
||||
static void tearDown();
|
||||
|
||||
//! Tear down the OsThread package.
|
||||
static void tearDown();
|
||||
//! Destroy this thread.
|
||||
virtual ~Thread();
|
||||
|
||||
//! Destroy this thread.
|
||||
virtual ~Thread();
|
||||
//! Return the thread's name
|
||||
const std::string& name() const { return name_; }
|
||||
|
||||
//! Return the thread's name
|
||||
const std::string& name() const { return name_; }
|
||||
//! Get the system thread handle.
|
||||
const void* handle() const { return handle_; }
|
||||
|
||||
//! Get the system thread handle.
|
||||
const void* handle() const { return handle_; }
|
||||
//! Start the thread execution
|
||||
bool start(void* data = NULL);
|
||||
|
||||
//! Start the thread execution
|
||||
bool start(void *data = NULL);
|
||||
//! Resume the thread
|
||||
void resume();
|
||||
|
||||
//! Resume the thread
|
||||
void resume();
|
||||
//! Return true is this is the host thread.
|
||||
virtual bool isHostThread() const { return false; }
|
||||
|
||||
//! Return true is this is the host thread.
|
||||
virtual bool isHostThread() const { return false; }
|
||||
//! Return true if this is a worker thread.
|
||||
virtual bool isWorkerThread() const { return false; }
|
||||
|
||||
//! Return true if this is a worker thread.
|
||||
virtual bool isWorkerThread() const { return false; }
|
||||
//! Get the current thread state.
|
||||
ThreadState state() const { return state_; }
|
||||
|
||||
//! Get the current thread state.
|
||||
ThreadState state() const { return state_; }
|
||||
//! Return this thread's stack base.
|
||||
address stackBase() const { return stackBase_; }
|
||||
//! Return this thread's stack size.
|
||||
size_t stackSize() const { return stackSize_; }
|
||||
//! Return this thread's stack bottom.
|
||||
address stackBottom() const { return stackBase() - stackSize(); }
|
||||
|
||||
//! Return this thread's stack base.
|
||||
address stackBase() const { return stackBase_; }
|
||||
//! Return this thread's stack size.
|
||||
size_t stackSize() const { return stackSize_; }
|
||||
//! Return this thread's stack bottom.
|
||||
address stackBottom() const { return stackBase() - stackSize(); }
|
||||
//! Return this thread's contend semaphore.
|
||||
Semaphore& lockSemaphore() const { return *lock_; }
|
||||
//! Return this thread's resume semaphore.
|
||||
Semaphore& suspendSemaphore() const { return *suspend_; }
|
||||
|
||||
//! Return this thread's contend semaphore.
|
||||
Semaphore& lockSemaphore() const { return *lock_; }
|
||||
//! Return this thread's resume semaphore.
|
||||
Semaphore& suspendSemaphore() const { return *suspend_; }
|
||||
//! Set this thread's affinity to the given cpu.
|
||||
void setAffinity(uint cpu_id) const { Os::setThreadAffinity(handle_, cpu_id); }
|
||||
|
||||
//! Set this thread's affinity to the given cpu.
|
||||
void setAffinity(uint cpu_id) const
|
||||
{
|
||||
Os::setThreadAffinity(handle_, cpu_id);
|
||||
}
|
||||
//! Set this thread's affinity to the given cpu mask.
|
||||
void setAffinity(const Os::ThreadAffinityMask& mask) const {
|
||||
Os::setThreadAffinity(handle_, mask);
|
||||
}
|
||||
|
||||
//! Set this thread's affinity to the given cpu mask.
|
||||
void setAffinity(const Os::ThreadAffinityMask& mask) const
|
||||
{
|
||||
Os::setThreadAffinity(handle_, mask);
|
||||
}
|
||||
|
||||
//! Yield to threads of the same priority of higher
|
||||
static void yield()
|
||||
{
|
||||
Os::yield();
|
||||
}
|
||||
//! Yield to threads of the same priority of higher
|
||||
static void yield() { Os::yield(); }
|
||||
};
|
||||
|
||||
class HostThread : public Thread
|
||||
{
|
||||
private:
|
||||
//! A HostThread does not have a run function
|
||||
virtual void run(void* data) { ShouldNotCallThis(); }
|
||||
class HostThread : public Thread {
|
||||
private:
|
||||
//! A HostThread does not have a run function
|
||||
virtual void run(void* data) { ShouldNotCallThis(); }
|
||||
|
||||
public:
|
||||
//! Construct a new HostThread
|
||||
HostThread();
|
||||
public:
|
||||
//! Construct a new HostThread
|
||||
HostThread();
|
||||
|
||||
//! Return true is this is the host thread.
|
||||
bool isHostThread() const { return true; };
|
||||
//! Return true is this is the host thread.
|
||||
bool isHostThread() const { return true; };
|
||||
};
|
||||
|
||||
/*! @}
|
||||
@@ -192,40 +172,30 @@ namespace details {
|
||||
|
||||
extern __thread Thread* thread_ __attribute__((tls_model("initial-exec")));
|
||||
|
||||
static inline Thread*
|
||||
currentThread()
|
||||
{
|
||||
return thread_;
|
||||
}
|
||||
static inline Thread* currentThread() { return thread_; }
|
||||
|
||||
#elif defined(_WIN32)
|
||||
|
||||
#if defined(USE_DECLSPEC_THREAD)
|
||||
extern __declspec(thread) Thread* thread_;
|
||||
#else // !USE_DECLSPEC_THREAD
|
||||
#else // !USE_DECLSPEC_THREAD
|
||||
extern DWORD threadIndex_;
|
||||
#endif // !USE_DECLSPEC_THREAD
|
||||
#endif // !USE_DECLSPEC_THREAD
|
||||
|
||||
static inline Thread*
|
||||
currentThread()
|
||||
{
|
||||
static inline Thread* currentThread() {
|
||||
#if defined(USE_DECLSPEC_THREAD)
|
||||
return thread_;
|
||||
#else // !USE_DECLSPEC_THREAD
|
||||
return (Thread*) TlsGetValue(threadIndex_);
|
||||
#endif // !USE_DECLSPEC_THREAD
|
||||
return thread_;
|
||||
#else // !USE_DECLSPEC_THREAD
|
||||
return (Thread*)TlsGetValue(threadIndex_);
|
||||
#endif // !USE_DECLSPEC_THREAD
|
||||
}
|
||||
|
||||
#endif // _WIN32
|
||||
#endif // _WIN32
|
||||
|
||||
} // namespace details
|
||||
} // namespace details
|
||||
|
||||
inline Thread*
|
||||
Thread::current()
|
||||
{
|
||||
return details::currentThread();
|
||||
}
|
||||
inline Thread* Thread::current() { return details::currentThread(); }
|
||||
|
||||
} // namespace amd
|
||||
} // namespace amd
|
||||
|
||||
#endif /*THREAD_HPP_*/
|
||||
|
||||
Odkázat v novém úkolu
Zablokovat Uživatele