330 lines
9.1 KiB
Text
330 lines
9.1 KiB
Text
/**
|
|
* PANDA 3D SOFTWARE
|
|
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
|
*
|
|
* All use of this software is subject to the terms of the revised BSD
|
|
* license. You should have received a copy of this license along
|
|
* with this source code in a file named "LICENSE."
|
|
*
|
|
* @file thread.I
|
|
* @author drose
|
|
* @date 2002-08-08
|
|
*/
|
|
|
|
/**
|
|
* Returns the sync name of the thread. This name collects threads into "sync
|
|
* groups", which are expected to run synchronously. This is mainly used for
|
|
* the benefit of PStats; threads with the same sync name can be ticked all at
|
|
* once via the thread_tick() call.
|
|
*/
|
|
INLINE const std::string &Thread::
|
|
get_sync_name() const {
|
|
return _sync_name;
|
|
}
|
|
|
|
/**
|
|
* Returns the PStats index associated with this thread, or -1 if no index has
|
|
* yet been associated with this thread. This is used internally by the
|
|
* PStatClient; you should not need to call this directly.
|
|
*/
|
|
INLINE int Thread::
|
|
get_pstats_index() const {
|
|
return _pstats_index;
|
|
}
|
|
|
|
/**
|
|
* Returns the Python index associated with this thread, or -1 if no index has
|
|
* yet been associated with this thread. This is used internally by the
|
|
* direct.stdpy.thread module; you should not need to call this directly.
|
|
*/
|
|
INLINE int Thread::
|
|
get_python_index() const {
|
|
return _python_index;
|
|
}
|
|
|
|
/**
|
|
* Returns a string that is guaranteed to be unique to this thread, across all
|
|
* processes on the machine, during at least the lifetime of this process.
|
|
*/
|
|
INLINE std::string Thread::
|
|
get_unique_id() const {
|
|
return _impl.get_unique_id();
|
|
}
|
|
|
|
/**
|
|
* Returns the Pipeline stage number associated with this thread. The default
|
|
* stage is 0 if no stage is specified otherwise. See set_pipeline_stage().
|
|
*/
|
|
INLINE int Thread::
|
|
get_pipeline_stage() const {
|
|
#if !defined(_DEBUG) && defined(__has_builtin) && __has_builtin(__builtin_assume)
|
|
// Because this is a signed int, this results in a sign extend on x86-64.
|
|
// However, since we guarantee that this is never less than zero, clang
|
|
// offers a nice way to avoid that.
|
|
int pipeline_stage = _pipeline_stage;
|
|
__builtin_assume(pipeline_stage >= 0);
|
|
return pipeline_stage;
|
|
#else
|
|
return _pipeline_stage;
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Sets this thread's pipeline stage number to at least the indicated value,
|
|
* unless it is already larger. See set_pipeline_stage().
|
|
*/
|
|
INLINE void Thread::
|
|
set_min_pipeline_stage(int min_pipeline_stage) {
|
|
set_pipeline_stage(std::max(_pipeline_stage, min_pipeline_stage));
|
|
}
|
|
|
|
/**
|
|
* Returns a pointer to the "main" Thread object--this is the Thread that
|
|
* started the whole process.
|
|
*/
|
|
INLINE Thread *Thread::
|
|
get_main_thread() {
|
|
if (_main_thread == nullptr) {
|
|
init_main_thread();
|
|
}
|
|
return _main_thread;
|
|
}
|
|
|
|
/**
|
|
* Returns a pointer to the "external" Thread object--this is a special Thread
|
|
* object that corresponds to any thread spawned outside of Panda's threading
|
|
* interface. Note that multiple different threads may share this same
|
|
* pointer.
|
|
*/
|
|
INLINE Thread *Thread::
|
|
get_external_thread() {
|
|
if (_external_thread == nullptr) {
|
|
init_external_thread();
|
|
}
|
|
return _external_thread;
|
|
}
|
|
|
|
/**
|
|
* Returns a pointer to the currently-executing Thread object. If this is
|
|
* called from the main thread, this will return the same value as
|
|
* get_main_thread().
|
|
*
|
|
* This will always return some valid Thread pointer. It will never return
|
|
* NULL, even if the current thread was spawned outside of Panda's threading
|
|
* system, although all non-Panda threads will return the exact same Thread
|
|
* pointer.
|
|
*/
|
|
INLINE Thread *Thread::
|
|
get_current_thread() {
|
|
TAU_PROFILE("Thread *Thread::get_current_thread()", " ", TAU_USER);
|
|
#ifndef HAVE_THREADS
|
|
return get_main_thread();
|
|
#else // HAVE_THREADS
|
|
Thread *thread = ThreadImpl::get_current_thread();
|
|
if (thread == nullptr) {
|
|
return Thread::get_external_thread();
|
|
}
|
|
return thread;
|
|
#endif // HAVE_THREADS
|
|
}
|
|
|
|
/**
|
|
* Returns the integer pipeline stage associated with the current thread.
|
|
* This is the same thing as get_current_thread()->get_pipeline_stage(), but
|
|
* it may be faster to retrieve in some contexts.
|
|
*/
|
|
INLINE int Thread::
|
|
get_current_pipeline_stage() {
|
|
TAU_PROFILE("int Thread::get_current_pipeline_stage()", " ", TAU_USER);
|
|
#ifndef THREADED_PIPELINE
|
|
// Without threaded pipelining, the result is always 0.
|
|
return 0;
|
|
#else
|
|
return get_current_thread()->get_pipeline_stage();
|
|
#endif // !THREADED_PIPELINE
|
|
}
|
|
|
|
/**
|
|
* Returns true if threading support has been compiled in and enabled, or
|
|
* false if no threading is available (and Thread::start() will always fail).
|
|
*/
|
|
INLINE bool Thread::
|
|
is_threading_supported() {
|
|
if (!support_threads) {
|
|
return false;
|
|
}
|
|
return ThreadImpl::is_threading_supported();
|
|
}
|
|
|
|
/**
|
|
* Returns true if a real threading library is available that supports actual
|
|
* OS-implemented threads, or false if the only threading we can provide is
|
|
* simulated user-space threading.
|
|
*/
|
|
INLINE bool Thread::
|
|
is_true_threads() {
|
|
if (!support_threads) {
|
|
return false;
|
|
}
|
|
return ThreadImpl::is_true_threads();
|
|
}
|
|
|
|
/**
|
|
* Returns true if Panda is currently compiled for "simple threads", which is
|
|
* to say, cooperative context switching only, reducing the need for quite so
|
|
* many critical section protections. This is not necessarily the opposite of
|
|
* "true threads", since one possible implementation of simple threads is via
|
|
* true threads with mutex protection to ensure only one runs at a time.
|
|
*/
|
|
INLINE bool Thread::
|
|
is_simple_threads() {
|
|
if (!support_threads) {
|
|
return false;
|
|
}
|
|
return ThreadImpl::is_simple_threads();
|
|
}
|
|
|
|
/**
|
|
* Suspends the current thread for at least the indicated amount of time. It
|
|
* might be suspended for longer.
|
|
*/
|
|
INLINE void Thread::
|
|
sleep(double seconds) {
|
|
TAU_PROFILE("void Thread::sleep(double)", " ", TAU_USER);
|
|
ThreadImpl::sleep(seconds);
|
|
}
|
|
|
|
/**
|
|
* Suspends the current thread for the rest of the current epoch.
|
|
*/
|
|
INLINE void Thread::
|
|
force_yield() {
|
|
TAU_PROFILE("void Thread::yield()", " ", TAU_USER);
|
|
ThreadImpl::yield();
|
|
}
|
|
|
|
/**
|
|
* Possibly suspends the current thread for the rest of the current epoch, if
|
|
* it has run for enough this epoch. This is especially important for the
|
|
* simple thread implementation, which relies on cooperative yields like this.
|
|
*/
|
|
INLINE void Thread::
|
|
consider_yield() {
|
|
TAU_PROFILE("void Thread::consider_yield()", " ", TAU_USER);
|
|
ThreadImpl::consider_yield();
|
|
}
|
|
|
|
/**
|
|
* Returns true if the thread has been started, false if it has not, or if
|
|
* join() has already been called.
|
|
*/
|
|
INLINE bool Thread::
|
|
is_started() const {
|
|
return _started;
|
|
}
|
|
|
|
/**
|
|
* Returns the value of joinable that was passed to the start() call.
|
|
*/
|
|
INLINE bool Thread::
|
|
is_joinable() const {
|
|
return _joinable;
|
|
}
|
|
|
|
/**
|
|
* Blocks the calling process until the thread terminates. If the thread has
|
|
* already terminated, this returns immediately.
|
|
*/
|
|
INLINE void Thread::
|
|
join() {
|
|
TAU_PROFILE("void Thread::join()", " ", TAU_USER);
|
|
if (_started) {
|
|
_impl.join();
|
|
_started = false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Indicates that this thread should run as soon as possible, preemptying any
|
|
* other threads that may be scheduled to run. This may not be implemented on
|
|
* every platform.
|
|
*/
|
|
INLINE void Thread::
|
|
preempt() {
|
|
if (_started) {
|
|
_impl.preempt();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the task currently executing on this thread (via the
|
|
* AsyncTaskManager), if any, or NULL if the thread is not currently servicing
|
|
* a task.
|
|
*/
|
|
INLINE TypedReferenceCount *Thread::
|
|
get_current_task() const {
|
|
return (TypedReferenceCount *)_current_task;
|
|
}
|
|
|
|
/**
|
|
* Stores a Python index to be associated with this thread. This is used
|
|
* internally by the thread module; you should not need to call this directly.
|
|
*/
|
|
INLINE void Thread::
|
|
set_python_index(int python_index) {
|
|
_python_index = python_index;
|
|
}
|
|
|
|
/**
|
|
* Should be called by the main thread just before exiting the program, this
|
|
* blocks until any remaining thread cleanup has finished.
|
|
*/
|
|
INLINE void Thread::
|
|
prepare_for_exit() {
|
|
ThreadImpl::prepare_for_exit();
|
|
}
|
|
|
|
#ifdef ANDROID
|
|
/**
|
|
* Enables interaction with the Java VM on Android. Returns null if the
|
|
* thread is not attached to the Java VM (or bind_thread was not called).
|
|
*/
|
|
INLINE JNIEnv *Thread::
|
|
get_jni_env() const {
|
|
return _impl.get_jni_env();
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* Stores a PStats index to be associated with this thread. This is used
|
|
* internally by the PStatClient; you should not need to call this directly.
|
|
*/
|
|
INLINE void Thread::
|
|
set_pstats_index(int pstats_index) {
|
|
_pstats_index = pstats_index;
|
|
}
|
|
|
|
/**
|
|
* Stores a PStats callback to be associated with this thread. This is used
|
|
* internally by the PStatClient; you should not need to call this directly.
|
|
*/
|
|
INLINE void Thread::
|
|
set_pstats_callback(Thread::PStatsCallback *pstats_callback) {
|
|
_pstats_callback = pstats_callback;
|
|
}
|
|
|
|
/**
|
|
* Returns the PStats callback associated with this thread, or NULL if no
|
|
* callback has yet been associated with this thread. This is used internally
|
|
* by the PStatClient; you should not need to call this directly.
|
|
*/
|
|
INLINE Thread::PStatsCallback *Thread::
|
|
get_pstats_callback() const {
|
|
return _pstats_callback;
|
|
}
|
|
|
|
INLINE std::ostream &
|
|
operator << (std::ostream &out, const Thread &thread) {
|
|
thread.output(out);
|
|
return out;
|
|
}
|