1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
|
// This code contains NVIDIA Confidential Information and is disclosed to you
// under a form of NVIDIA software license agreement provided separately to you.
//
// Notice
// NVIDIA Corporation and its licensors retain all intellectual property and
// proprietary rights in and to this software and related documentation and
// any modifications thereto. Any use, reproduction, disclosure, or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA Corporation is strictly prohibited.
//
// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
//
// Information and code furnished is believed to be accurate and reliable.
// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
// information or for any infringement of patents or other rights of third parties that may
// result from its use. No license is granted by implication or otherwise under any patent
// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
// This code supersedes and replaces all information previously supplied.
// NVIDIA Corporation products are not authorized for use as critical
// components in life support devices or systems without express written approval of
// NVIDIA Corporation.
//
// Copyright (c) 2008-2017 NVIDIA Corporation. All rights reserved.
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
#ifndef PSFOUNDATION_PSTHREAD_H
#define PSFOUNDATION_PSTHREAD_H
#include "PsUserAllocated.h"
// dsequeira: according to existing comment here (David Black would be my guess)
// "This is useful to reduce bus contention on tight spin locks. And it needs
// to be a macro as the xenon compiler often ignores even __forceinline." What's not
// clear is why a pause function needs inlining...? (TODO: check with XBox team)
// todo: these need to go somewhere else
#if PX_WINDOWS_FAMILY || PX_XBOXONE
#define PxSpinLockPause() __asm pause
#elif PX_LINUX || PX_ANDROID || PX_PS4 || PX_APPLE_FAMILY || PX_SWITCH
#define PxSpinLockPause() asm("nop")
#else
#error "Platform not supported!"
#endif
namespace physx
{
namespace shdfnd
{
struct ThreadPriority // todo: put in some other header file
{
enum Enum
{
/**
\brief High priority
*/
eHIGH = 0,
/**
\brief Above Normal priority
*/
eABOVE_NORMAL = 1,
/**
\brief Normal/default priority
*/
eNORMAL = 2,
/**
\brief Below Normal priority
*/
eBELOW_NORMAL = 3,
/**
\brief Low priority.
*/
eLOW = 4,
eFORCE_DWORD = 0xffFFffFF
};
};
class Runnable
{
public:
Runnable()
{
}
virtual ~Runnable()
{
}
virtual void execute(void)
{
}
};
class PX_FOUNDATION_API ThreadImpl
{
public:
typedef size_t Id; // space for a pointer or an integer
typedef void* (*ExecuteFn)(void*);
static uint32_t getDefaultStackSize();
static Id getId();
/**
Construct (but do not start) the thread object. The OS thread object will not be created
until start() is called. Executes in the context
of the spawning thread.
*/
ThreadImpl();
/**
Construct and start the the thread, passing the given arg to the given fn. (pthread style)
*/
ThreadImpl(ExecuteFn fn, void* arg);
/**
Deallocate all resources associated with the thread. Should be called in the
context of the spawning thread.
*/
~ThreadImpl();
/**
Create the OS thread and start it running. Called in the context of the spawning thread.
If an affinity mask has previously been set then it will be applied after the
thread has been created.
*/
void start(uint32_t stackSize, Runnable* r);
/**
Violently kill the current thread. Blunt instrument, not recommended since
it can leave all kinds of things unreleased (stack, memory, mutexes...) Should
be called in the context of the spawning thread.
*/
void kill();
/**
Stop the thread. Signals the spawned thread that it should stop, so the
thread should check regularly
*/
void signalQuit();
/**
Wait for a thread to stop. Should be called in the context of the spawning
thread. Returns false if the thread has not been started.
*/
bool waitForQuit();
/**
check whether the thread is signalled to quit. Called in the context of the
spawned thread.
*/
bool quitIsSignalled();
/**
Cleanly shut down this thread. Called in the context of the spawned thread.
*/
void quit();
/**
Change the affinity mask for this thread. The mask is a platform
specific value.
On Windows, Linux, PS4, XboxOne and Switch platforms, each set mask bit represents
the index of a logical processor that the OS may schedule thread execution on.
Bits outside the range of valid logical processors may be ignored or cause
the function to return an error.
On Apple platforms, this function has no effect.
If the thread has not yet been started then the mask is stored
and applied when the thread is started.
If the thread has already been started then this method returns the
previous affinity mask on success, otherwise it returns zero.
*/
uint32_t setAffinityMask(uint32_t mask);
static ThreadPriority::Enum getPriority(Id threadId);
/** Set thread priority. */
void setPriority(ThreadPriority::Enum prio);
/** set the thread's name */
void setName(const char* name);
/** Put the current thread to sleep for the given number of milliseconds */
static void sleep(uint32_t ms);
/** Yield the current thread's slot on the CPU */
static void yield();
/** Return the number of physical cores (does not include hyper-threaded cores), returns 0 on failure */
static uint32_t getNbPhysicalCores();
/**
Size of this class.
*/
static uint32_t getSize();
};
/**
Thread abstraction API
*/
template <typename Alloc = ReflectionAllocator<ThreadImpl> >
class ThreadT : protected Alloc, public UserAllocated, public Runnable
{
public:
typedef ThreadImpl::Id Id; // space for a pointer or an integer
/**
Construct (but do not start) the thread object. Executes in the context
of the spawning thread
*/
ThreadT(const Alloc& alloc = Alloc()) : Alloc(alloc)
{
mImpl = reinterpret_cast<ThreadImpl*>(Alloc::allocate(ThreadImpl::getSize(), __FILE__, __LINE__));
PX_PLACEMENT_NEW(mImpl, ThreadImpl)();
}
/**
Construct and start the the thread, passing the given arg to the given fn. (pthread style)
*/
ThreadT(ThreadImpl::ExecuteFn fn, void* arg, const Alloc& alloc = Alloc()) : Alloc(alloc)
{
mImpl = reinterpret_cast<ThreadImpl*>(Alloc::allocate(ThreadImpl::getSize(), __FILE__, __LINE__));
PX_PLACEMENT_NEW(mImpl, ThreadImpl)(fn, arg);
}
/**
Deallocate all resources associated with the thread. Should be called in the
context of the spawning thread.
*/
virtual ~ThreadT()
{
mImpl->~ThreadImpl();
Alloc::deallocate(mImpl);
}
/**
start the thread running. Called in the context of the spawning thread.
*/
void start(uint32_t stackSize = ThreadImpl::getDefaultStackSize())
{
mImpl->start(stackSize, this);
}
/**
Violently kill the current thread. Blunt instrument, not recommended since
it can leave all kinds of things unreleased (stack, memory, mutexes...) Should
be called in the context of the spawning thread.
*/
void kill()
{
mImpl->kill();
}
/**
The virtual execute() method is the user defined function that will
run in the new thread. Called in the context of the spawned thread.
*/
virtual void execute(void)
{
}
/**
stop the thread. Signals the spawned thread that it should stop, so the
thread should check regularly
*/
void signalQuit()
{
mImpl->signalQuit();
}
/**
Wait for a thread to stop. Should be called in the context of the spawning
thread. Returns false if the thread has not been started.
*/
bool waitForQuit()
{
return mImpl->waitForQuit();
}
/**
check whether the thread is signalled to quit. Called in the context of the
spawned thread.
*/
bool quitIsSignalled()
{
return mImpl->quitIsSignalled();
}
/**
Cleanly shut down this thread. Called in the context of the spawned thread.
*/
void quit()
{
mImpl->quit();
}
uint32_t setAffinityMask(uint32_t mask)
{
return mImpl->setAffinityMask(mask);
}
static ThreadPriority::Enum getPriority(ThreadImpl::Id threadId)
{
return ThreadImpl::getPriority(threadId);
}
/** Set thread priority. */
void setPriority(ThreadPriority::Enum prio)
{
mImpl->setPriority(prio);
}
/** set the thread's name */
void setName(const char* name)
{
mImpl->setName(name);
}
/** Put the current thread to sleep for the given number of milliseconds */
static void sleep(uint32_t ms)
{
ThreadImpl::sleep(ms);
}
/** Yield the current thread's slot on the CPU */
static void yield()
{
ThreadImpl::yield();
}
static uint32_t getDefaultStackSize()
{
return ThreadImpl::getDefaultStackSize();
}
static ThreadImpl::Id getId()
{
return ThreadImpl::getId();
}
static uint32_t getNbPhysicalCores()
{
return ThreadImpl::getNbPhysicalCores();
}
private:
class ThreadImpl* mImpl;
};
typedef ThreadT<> Thread;
PX_FOUNDATION_API uint32_t TlsAlloc();
PX_FOUNDATION_API void TlsFree(uint32_t index);
PX_FOUNDATION_API void* TlsGet(uint32_t index);
PX_FOUNDATION_API uint32_t TlsSet(uint32_t index, void* value);
} // namespace shdfnd
} // namespace physx
#endif // #ifndef PSFOUNDATION_PSTHREAD_H
|