historical/toontown-classic.git/panda/include/thread.I
2024-01-16 11:20:27 -06:00

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;
}