mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 10:54:24 -04:00
linux
This commit is contained in:
parent
050541c214
commit
16562fc4e5
@ -22,6 +22,12 @@
|
|||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[]) {
|
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;
|
jmp_buf buf1, buf2;
|
||||||
char * volatile scratch;
|
char * volatile scratch;
|
||||||
|
|
||||||
@ -39,6 +45,7 @@ main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
cerr << "scratch = " << (void *)scratch << "\n";
|
cerr << "scratch = " << (void *)scratch << "\n";
|
||||||
cerr << "scratch end = " << (void *)(scratch + 1024) << "\n";
|
cerr << "scratch end = " << (void *)(scratch + 1024) << "\n";
|
||||||
|
#endif // HAVE_UCONTEXT_H
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -196,11 +196,34 @@ yield_this() {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: ThreadSimpleImpl::setup_context
|
// Function: ThreadSimpleImpl::setup_context
|
||||||
// Access: Private
|
// 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.
|
// and an appropriate stack reserved for the thread.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void ThreadSimpleImpl::
|
void ThreadSimpleImpl::
|
||||||
setup_context() {
|
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;
|
jmp_buf orig_stack;
|
||||||
if (setjmp(orig_stack) == 0) {
|
if (setjmp(orig_stack) == 0) {
|
||||||
// First, switch to the new stack. This requires temporarily saving
|
// 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.
|
// By now we are back to the original stack.
|
||||||
|
#endif // HAVE_UCONTEXT_H
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: ThreadSimpleImpl::setup_context_3
|
// Function: ThreadSimpleImpl::setup_context_3
|
||||||
// Access: Private
|
// Access: Private, Static
|
||||||
// Description: More continuation of setup_context(). Again, making
|
// Description: More continuation of setup_context(). Again, making
|
||||||
// this a separate function helps defeat the compiler
|
// this a separate function helps defeat the compiler
|
||||||
// optimizer.
|
// optimizer.
|
||||||
|
@ -35,9 +35,24 @@
|
|||||||
|
|
||||||
#endif // HAVE_PYTHON
|
#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>
|
#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
|
// We have determined this value empirically, via test_setjmp.cxx in
|
||||||
// this directory.
|
// this directory.
|
||||||
#define JB_SP 9
|
#define JB_SP 9
|
||||||
@ -49,6 +64,10 @@
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif // JB_SP
|
||||||
|
|
||||||
|
#endif // HAVE_UCONTEXT_H
|
||||||
|
|
||||||
class Thread;
|
class Thread;
|
||||||
class ThreadSimpleManager;
|
class ThreadSimpleManager;
|
||||||
class MutexSimpleImpl;
|
class MutexSimpleImpl;
|
||||||
@ -102,7 +121,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void setup_context();
|
void setup_context();
|
||||||
static void setup_context_2(ThreadSimpleImpl *self);
|
static void *setup_context_2(ThreadSimpleImpl *self);
|
||||||
void setup_context_3();
|
void setup_context_3();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -126,7 +145,12 @@ private:
|
|||||||
// should wake up.
|
// should wake up.
|
||||||
double _start_time;
|
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;
|
unsigned char *_stack;
|
||||||
size_t _stack_size;
|
size_t _stack_size;
|
||||||
|
|
||||||
|
@ -31,24 +31,23 @@
|
|||||||
// disable optimizations globally on the command line,
|
// disable optimizations globally on the command line,
|
||||||
// not via pragmas).
|
// not via pragmas).
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void ThreadSimpleImpl::
|
void *ThreadSimpleImpl::
|
||||||
setup_context_2(ThreadSimpleImpl *self) {
|
setup_context_2(ThreadSimpleImpl *self) {
|
||||||
ThreadSimpleImpl *volatile v_self = 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.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#endif // HAVE_UCONTEXT_H
|
||||||
|
|
||||||
// Here we are executing within the thread.
|
// Here we are executing within the thread.
|
||||||
v_self->setup_context_3();
|
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();
|
abort();
|
||||||
|
return v_self;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // THREAD_SIMPLE_IMPL
|
#endif // THREAD_SIMPLE_IMPL
|
||||||
|
@ -38,9 +38,9 @@ ThreadSimpleManager *ThreadSimpleManager::_global_ptr;
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
ThreadSimpleManager::
|
ThreadSimpleManager::
|
||||||
ThreadSimpleManager() {
|
ThreadSimpleManager() {
|
||||||
|
_current_thread = NULL;
|
||||||
_clock = TrueClock::get_global_ptr();
|
_clock = TrueClock::get_global_ptr();
|
||||||
_waiting_for_exit = NULL;
|
_waiting_for_exit = NULL;
|
||||||
nassertv(_current_thread == NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -49,7 +49,7 @@ ThreadSimpleManager() {
|
|||||||
// Description: Adds the indicated thread to the ready queue. The
|
// Description: Adds the indicated thread to the ready queue. The
|
||||||
// thread will be executed when its turn comes. If the
|
// thread will be executed when its turn comes. If the
|
||||||
// thread is not the currently executing thread, its
|
// thread is not the currently executing thread, its
|
||||||
// _context should be filled appropriately.
|
// _jmp_context should be filled appropriately.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void ThreadSimpleManager::
|
void ThreadSimpleManager::
|
||||||
enqueue_ready(ThreadSimpleImpl *thread) {
|
enqueue_ready(ThreadSimpleImpl *thread) {
|
||||||
@ -173,7 +173,7 @@ preempt(ThreadSimpleImpl *thread) {
|
|||||||
// re-enqueued itself with a call to enqueue(), if it
|
// re-enqueued itself with a call to enqueue(), if it
|
||||||
// intends to run again.
|
// 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
|
// member appropriately, and then change the global
|
||||||
// current_thread pointer.
|
// current_thread pointer.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -187,7 +187,29 @@ next_context() {
|
|||||||
PyThreadState_Swap(_current_thread->_python_state);
|
PyThreadState_Swap(_current_thread->_python_state);
|
||||||
#endif // HAVE_PYTHON
|
#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
|
// We have returned from a longjmp, and are now resuming the
|
||||||
// current thread.
|
// current thread.
|
||||||
#ifdef HAVE_PYTHON
|
#ifdef HAVE_PYTHON
|
||||||
@ -196,6 +218,7 @@ next_context() {
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#endif // HAVE_UCONTEXT_H
|
||||||
|
|
||||||
while (!_finished.empty() && _finished.front() != _current_thread) {
|
while (!_finished.empty() && _finished.front() != _current_thread) {
|
||||||
ThreadSimpleImpl *finished_thread = _finished.front();
|
ThreadSimpleImpl *finished_thread = _finished.front();
|
||||||
@ -261,7 +284,12 @@ next_context() {
|
|||||||
thread_cat.spam()
|
thread_cat.spam()
|
||||||
<< "Switching to " << *_current_thread->_parent_obj << "\n";
|
<< "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.
|
// Shouldn't get here.
|
||||||
nassertv(false);
|
nassertv(false);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user