mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 10:22:45 -04:00
linux
This commit is contained in:
parent
050541c214
commit
16562fc4e5
@ -22,6 +22,12 @@
|
||||
|
||||
int
|
||||
main(int argc, char *argv[]) {
|
||||
|
||||
// If we have ucontext.h, we don't need to use setjmp, so don't
|
||||
// bother trying to compile this program (it may not compile
|
||||
// anyway).
|
||||
|
||||
#ifndef HAVE_UCONTEXT_H
|
||||
jmp_buf buf1, buf2;
|
||||
char * volatile scratch;
|
||||
|
||||
@ -39,6 +45,7 @@ main(int argc, char *argv[]) {
|
||||
}
|
||||
cerr << "scratch = " << (void *)scratch << "\n";
|
||||
cerr << "scratch end = " << (void *)(scratch + 1024) << "\n";
|
||||
#endif // HAVE_UCONTEXT_H
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -196,11 +196,34 @@ yield_this() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ThreadSimpleImpl::setup_context
|
||||
// Access: Private
|
||||
// Description: Fills the _context with an appropriate context buffer
|
||||
// Description: Fills the _jmp_context with an appropriate context buffer
|
||||
// and an appropriate stack reserved for the thread.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void ThreadSimpleImpl::
|
||||
setup_context() {
|
||||
#ifdef HAVE_UCONTEXT_H
|
||||
// Set up a unique thread context using makecontext().
|
||||
getcontext(&_ucontext);
|
||||
|
||||
_ucontext.uc_stack.ss_sp = _stack;
|
||||
_ucontext.uc_stack.ss_size = _stack_size;
|
||||
_ucontext.uc_stack.ss_flags = 0;
|
||||
_ucontext.uc_link = NULL;
|
||||
|
||||
makecontext(&_ucontext, (void (*)())setup_context_2, 1, this);
|
||||
|
||||
#else // HAVE_UCONTEXT_H
|
||||
// The setjmp hack for setting up a unique thread context is a bit
|
||||
// more complicated. The approach is: hack our way onto the new
|
||||
// stack pointer right now, then call setjmp() to record that stack
|
||||
// pointer in the _jmp_context. Then restore back to the original
|
||||
// stack pointer.
|
||||
|
||||
// This requires jumping through a couple of different functions.
|
||||
// One of these functions, setup_context_2(), is defined in a
|
||||
// different file, so we can easily disable compiler optimizations
|
||||
// on that one function.
|
||||
|
||||
jmp_buf orig_stack;
|
||||
if (setjmp(orig_stack) == 0) {
|
||||
// First, switch to the new stack. This requires temporarily saving
|
||||
@ -234,11 +257,12 @@ setup_context() {
|
||||
}
|
||||
|
||||
// By now we are back to the original stack.
|
||||
#endif // HAVE_UCONTEXT_H
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ThreadSimpleImpl::setup_context_3
|
||||
// Access: Private
|
||||
// Access: Private, Static
|
||||
// Description: More continuation of setup_context(). Again, making
|
||||
// this a separate function helps defeat the compiler
|
||||
// optimizer.
|
||||
|
@ -35,9 +35,24 @@
|
||||
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
#ifdef HAVE_UCONTEXT_H
|
||||
// We'd prefer to use getcontext() / setcontext() to portably change
|
||||
// execution contexts within C code. That's what these library
|
||||
// functions are designed for.
|
||||
#include <ucontext.h>
|
||||
|
||||
#else
|
||||
// Unfortunately, setcontext() is not defined everywhere (even though
|
||||
// it claims to be adopted by Posix). So we have to fall back to
|
||||
// setjmp() / longjmp() in its absence. This is a hackier solution.
|
||||
#include <setjmp.h>
|
||||
|
||||
#if !defined(JB_SP) && defined(IS_OSX) && defined(__i386__)
|
||||
// Ideally, setjmp.h would have defined JB_SP, which will tell us
|
||||
// where in the context structure we can muck with the stack pointer.
|
||||
// If it didn't define this symbol, we have to guess it.
|
||||
#ifndef JB_SP
|
||||
|
||||
#if defined(IS_OSX) && defined(__i386__)
|
||||
// We have determined this value empirically, via test_setjmp.cxx in
|
||||
// this directory.
|
||||
#define JB_SP 9
|
||||
@ -49,6 +64,10 @@
|
||||
|
||||
#endif
|
||||
|
||||
#endif // JB_SP
|
||||
|
||||
#endif // HAVE_UCONTEXT_H
|
||||
|
||||
class Thread;
|
||||
class ThreadSimpleManager;
|
||||
class MutexSimpleImpl;
|
||||
@ -102,7 +121,7 @@ public:
|
||||
|
||||
private:
|
||||
void setup_context();
|
||||
static void setup_context_2(ThreadSimpleImpl *self);
|
||||
static void *setup_context_2(ThreadSimpleImpl *self);
|
||||
void setup_context_3();
|
||||
|
||||
private:
|
||||
@ -126,7 +145,12 @@ private:
|
||||
// should wake up.
|
||||
double _start_time;
|
||||
|
||||
jmp_buf _context;
|
||||
#ifdef HAVE_UCONTEXT_H
|
||||
ucontext_t _ucontext;
|
||||
#else
|
||||
jmp_buf _jmp_context;
|
||||
#endif // HAVE_UCONTEXT_H
|
||||
|
||||
unsigned char *_stack;
|
||||
size_t _stack_size;
|
||||
|
||||
|
@ -31,24 +31,23 @@
|
||||
// disable optimizations globally on the command line,
|
||||
// not via pragmas).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void ThreadSimpleImpl::
|
||||
void *ThreadSimpleImpl::
|
||||
setup_context_2(ThreadSimpleImpl *self) {
|
||||
ThreadSimpleImpl *volatile v_self = self;
|
||||
if (setjmp(self->_context) == 0) {
|
||||
// The _context is now set up and ready to run. Now we can
|
||||
|
||||
#ifndef HAVE_UCONTEXT_H
|
||||
if (setjmp(self->_jmp_context) == 0) {
|
||||
// The _jmp_context is now set up and ready to run. Now we can
|
||||
// return.
|
||||
return;
|
||||
}
|
||||
#endif // HAVE_UCONTEXT_H
|
||||
|
||||
// Here we are executing within the thread.
|
||||
v_self->setup_context_3();
|
||||
|
||||
// This code will never run, but we need to have some real code
|
||||
// here, to force the compiler to build an appropriate stack frame
|
||||
// for the above call (otherwise it might optimize the stack frame
|
||||
// away).
|
||||
*v_self = 0;
|
||||
abort();
|
||||
return v_self;
|
||||
}
|
||||
|
||||
#endif // THREAD_SIMPLE_IMPL
|
||||
|
@ -38,9 +38,9 @@ ThreadSimpleManager *ThreadSimpleManager::_global_ptr;
|
||||
////////////////////////////////////////////////////////////////////
|
||||
ThreadSimpleManager::
|
||||
ThreadSimpleManager() {
|
||||
_current_thread = NULL;
|
||||
_clock = TrueClock::get_global_ptr();
|
||||
_waiting_for_exit = NULL;
|
||||
nassertv(_current_thread == NULL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -49,7 +49,7 @@ ThreadSimpleManager() {
|
||||
// Description: Adds the indicated thread to the ready queue. The
|
||||
// thread will be executed when its turn comes. If the
|
||||
// thread is not the currently executing thread, its
|
||||
// _context should be filled appropriately.
|
||||
// _jmp_context should be filled appropriately.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void ThreadSimpleManager::
|
||||
enqueue_ready(ThreadSimpleImpl *thread) {
|
||||
@ -173,7 +173,7 @@ preempt(ThreadSimpleImpl *thread) {
|
||||
// re-enqueued itself with a call to enqueue(), if it
|
||||
// intends to run again.
|
||||
//
|
||||
// This will fill in the current thread's _context
|
||||
// This will fill in the current thread's _jmp_context
|
||||
// member appropriately, and then change the global
|
||||
// current_thread pointer.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -187,7 +187,29 @@ next_context() {
|
||||
PyThreadState_Swap(_current_thread->_python_state);
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
if (setjmp(_current_thread->_context) != 0) {
|
||||
#ifdef HAVE_UCONTEXT_H
|
||||
// The setcontext() implementation.
|
||||
|
||||
volatile bool context_return = false;
|
||||
|
||||
getcontext(&_current_thread->_ucontext);
|
||||
if (context_return) {
|
||||
// We have returned from a setcontext, and are now resuming the
|
||||
// current thread.
|
||||
#ifdef HAVE_PYTHON
|
||||
PyThreadState_Swap(_current_thread->_python_state);
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Set this flag so that we can differentiate between getcontext()
|
||||
// returning the first time and the second time.
|
||||
context_return = true;
|
||||
|
||||
#else
|
||||
// The longjmp() implementation.
|
||||
if (setjmp(_current_thread->_jmp_context) != 0) {
|
||||
// We have returned from a longjmp, and are now resuming the
|
||||
// current thread.
|
||||
#ifdef HAVE_PYTHON
|
||||
@ -196,6 +218,7 @@ next_context() {
|
||||
|
||||
return;
|
||||
}
|
||||
#endif // HAVE_UCONTEXT_H
|
||||
|
||||
while (!_finished.empty() && _finished.front() != _current_thread) {
|
||||
ThreadSimpleImpl *finished_thread = _finished.front();
|
||||
@ -261,7 +284,12 @@ next_context() {
|
||||
thread_cat.spam()
|
||||
<< "Switching to " << *_current_thread->_parent_obj << "\n";
|
||||
}
|
||||
longjmp(_current_thread->_context, 1);
|
||||
|
||||
#ifdef HAVE_UCONTEXT_H
|
||||
setcontext(&_current_thread->_ucontext);
|
||||
#else
|
||||
longjmp(_current_thread->_jmp_context, 1);
|
||||
#endif
|
||||
|
||||
// Shouldn't get here.
|
||||
nassertv(false);
|
||||
|
Loading…
x
Reference in New Issue
Block a user