move setjmp etc. into contextSwitch.c
This commit is contained in:
parent
69766d382d
commit
03ef026f09
|
|
@ -11,7 +11,7 @@
|
|||
#define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx
|
||||
|
||||
#define SOURCES \
|
||||
threadSimpleImpl_no_opt_.cxx \
|
||||
contextSwitch.c contextSwitch.h \
|
||||
blockerSimple.h blockerSimple.I \
|
||||
conditionVar.h conditionVar.I \
|
||||
conditionVarDebug.h conditionVarDebug.I \
|
||||
|
|
@ -110,6 +110,7 @@
|
|||
threadWin32Impl.cxx
|
||||
|
||||
#define INSTALL_HEADERS \
|
||||
contextSwitch.h \
|
||||
blockerSimple.h blockerSimple.I \
|
||||
conditionVar.h conditionVar.I \
|
||||
conditionVarDebug.h conditionVarDebug.I \
|
||||
|
|
|
|||
|
|
@ -0,0 +1,166 @@
|
|||
/* Filename: contextSwitch.c
|
||||
* Created by: drose (21Jun07)
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* PANDA 3D SOFTWARE
|
||||
* Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
*
|
||||
* All use of this software is subject to the terms of the Panda 3d
|
||||
* Software license. You should have received a copy of this license
|
||||
* along with this source code; you will also find a current copy of
|
||||
* the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
*
|
||||
* To contact the maintainers of this program write to
|
||||
* panda3d-general@lists.sourceforge.net .
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "contextSwitch.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef THREAD_SIMPLE_IMPL
|
||||
|
||||
#ifdef HAVE_UCONTEXT_H
|
||||
|
||||
/* The getcontext() / setcontext() implementation. Easy-peasy. */
|
||||
|
||||
static void *
|
||||
begin_context(ContextFunction *main_func, void *data) {
|
||||
(*main_func)(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
void
|
||||
init_thread_context(struct ThreadContext *context,
|
||||
unsigned char *stack, size_t stack_size,
|
||||
ContextFunction *main_func, void *data) {
|
||||
getcontext(&context->_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(&context->_ucontext, begin_context, 2, main_func, this);
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
/* The setjmp() / longjmp() implementation. A bit hackier. */
|
||||
|
||||
/* 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. */
|
||||
|
||||
|
||||
/* Ideally, including 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
|
||||
|
||||
#elif defined(WIN32)
|
||||
/* We have determined this value empirically, via test_setjmp.cxx in
|
||||
this directory. */
|
||||
#define JB_SP 4
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* JB_SP */
|
||||
|
||||
static struct ThreadContext *st_context;
|
||||
static unsigned char *st_stack;
|
||||
static size_t st_stack_size;
|
||||
static ContextFunction *st_main_func;
|
||||
static void *st_data;
|
||||
|
||||
static jmp_buf orig_stack;
|
||||
|
||||
static void
|
||||
setup_context_2(void) {
|
||||
/* Here we are running on the new stack. Copy the key data onto our
|
||||
new stack. */
|
||||
ContextFunction *volatile main_func = st_main_func;
|
||||
void *volatile data = st_data;
|
||||
|
||||
if (setjmp(st_context->_jmp_context) == 0) {
|
||||
/* The _jmp_context is set up and ready to run. Now restore the
|
||||
original stack and return. We can't simply return from this
|
||||
function, since it might overwrite some of the stack data on
|
||||
the way out. */
|
||||
longjmp(orig_stack, 1);
|
||||
|
||||
/* Shouldn't get here. */
|
||||
abort();
|
||||
}
|
||||
|
||||
/* We come here the first time the thread starts. */
|
||||
(*main_func)(data);
|
||||
|
||||
/* We shouldn't get here, since we don't expect the main_func to
|
||||
return. */
|
||||
abort();
|
||||
}
|
||||
|
||||
static void
|
||||
setup_context_1(void) {
|
||||
/* Save the current stack frame so we can return to it (at the end
|
||||
of setup_context_2()). */
|
||||
if (setjmp(orig_stack) == 0) {
|
||||
/* First, switch to the new stack. Save the current context using
|
||||
setjmp(). This saves out all of the processor register values,
|
||||
though it doesn't muck with the stack. */
|
||||
static jmp_buf temp;
|
||||
if (setjmp(temp) == 0) {
|
||||
/* This is the initial return from setjmp. Still the original
|
||||
stack. */
|
||||
|
||||
/* Now we overwrite the stack pointer value in the saved
|
||||
register context. This doesn't work with all implementations
|
||||
of setjmp/longjmp. */
|
||||
(*(void **)&temp[JB_SP]) = (st_stack + st_stack_size);
|
||||
|
||||
/* And finally, we place ourselves on the new stack by using
|
||||
longjmp() to reload the modified context. */
|
||||
longjmp(temp, 1);
|
||||
|
||||
/* Shouldn't get here. */
|
||||
abort();
|
||||
}
|
||||
|
||||
/* This is the second return from setjmp. Now we're on the new
|
||||
stack. */
|
||||
setup_context_2();
|
||||
|
||||
/* Shouldn't get here. */
|
||||
abort();
|
||||
}
|
||||
|
||||
/* By now we are back to the original stack. */
|
||||
}
|
||||
|
||||
void
|
||||
init_thread_context(struct ThreadContext *context,
|
||||
unsigned char *stack, size_t stack_size,
|
||||
ContextFunction *main_func, void *data) {
|
||||
/* Copy all of the input parameters to static variables, then begin
|
||||
the stack-switching process. */
|
||||
st_context = context;
|
||||
st_stack = stack;
|
||||
st_stack_size = stack_size;
|
||||
st_main_func = main_func;
|
||||
st_data = data;
|
||||
|
||||
setup_context_1();
|
||||
}
|
||||
|
||||
#endif /* HAVE_UCONTEXT_H */
|
||||
#endif /* THREAD_SIMPLE_IMPL */
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
/* Filename: contextSwitch.h
|
||||
* Created by: drose (21Jun07)
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* PANDA 3D SOFTWARE
|
||||
* Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
*
|
||||
* All use of this software is subject to the terms of the Panda 3d
|
||||
* Software license. You should have received a copy of this license
|
||||
* along with this source code; you will also find a current copy of
|
||||
* the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
*
|
||||
* To contact the maintainers of this program write to
|
||||
* panda3d-general@lists.sourceforge.net .
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef CONTEXTSWITCH_H
|
||||
#define CONTEXTSWITCH_H
|
||||
|
||||
#include "pandabase.h"
|
||||
#include "selectThreadImpl.h"
|
||||
|
||||
/* This file defines the code to perform fundamental context switches
|
||||
between different threads of execution within user space code. It
|
||||
does this by saving and restoring the register state, including
|
||||
transferring to a new stack. */
|
||||
|
||||
/* The code in this file is all written in C code, rather than C++, to
|
||||
reduce possible conflicts from longjmp implementations that attempt
|
||||
to be smart with respect to C++ destructors and exception
|
||||
handling. */
|
||||
|
||||
#ifdef THREAD_SIMPLE_IMPL
|
||||
|
||||
#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>
|
||||
|
||||
struct ThreadContext {
|
||||
ucontext_t _ucontext;
|
||||
};
|
||||
|
||||
#define save_thread_context(switched, context) \
|
||||
{ \
|
||||
volatile int context_return = 0; \
|
||||
getcontext(&context->_ucontext); \
|
||||
if (context_return) { \
|
||||
(*(switched)) = 1; \
|
||||
} \
|
||||
|
||||
context_return = 1; \
|
||||
(*(switched)) = 0; \
|
||||
}
|
||||
|
||||
#define switch_to_thread_context(context) \
|
||||
setcontext(&(context)->_ucontext)
|
||||
|
||||
#else /* HAVE_UCONTEXT_H */
|
||||
/* 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>
|
||||
|
||||
struct ThreadContext {
|
||||
jmp_buf _jmp_context;
|
||||
};
|
||||
|
||||
#define save_thread_context(switched, context) \
|
||||
{ \
|
||||
(*(switched)) = setjmp((context)->_jmp_context); \
|
||||
}
|
||||
|
||||
#define switch_to_thread_context(context) \
|
||||
longjmp((context)->_jmp_context, 1)
|
||||
|
||||
#endif /* HAVE_UCONTEXT_H */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void ContextFunction(void *);
|
||||
|
||||
void init_thread_context(struct ThreadContext *context,
|
||||
unsigned char *stack, size_t stack_size,
|
||||
ContextFunction *main_func, void *data);
|
||||
|
||||
/* These two functions are defined as macros, above. */
|
||||
/* void save_thread_context(int *switched, struct ThreadContext *context); */
|
||||
/* void switch_to_thread_context(struct ThreadContext *context); */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* THREAD_SIMPLE_IMPL */
|
||||
|
||||
#endif /* CONTEXTSWITCH_H */
|
||||
|
||||
|
|
@ -126,7 +126,7 @@ start(ThreadPriority priority, bool joinable) {
|
|||
PyThreadState_Swap(_python_state);
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
setup_context();
|
||||
init_thread_context(&_context, _stack, _stack_size, st_begin_thread, this);
|
||||
|
||||
_manager->enqueue_ready(this);
|
||||
return true;
|
||||
|
|
@ -194,81 +194,25 @@ yield_this() {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ThreadSimpleImpl::setup_context
|
||||
// Access: Private
|
||||
// Description: Fills the _jmp_context with an appropriate context buffer
|
||||
// and an appropriate stack reserved for the thread.
|
||||
// Function: ThreadSimpleImpl::st_begin_thread
|
||||
// Access: Private, Static
|
||||
// Description: This method is called as the first introduction to a
|
||||
// new 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
|
||||
// the this pointer as a static.
|
||||
_st_this = this;
|
||||
|
||||
// Save the current context using setjmp(). This saves out all of
|
||||
// the processor register values, though it doesn't muck with the
|
||||
// stack.
|
||||
jmp_buf temp;
|
||||
if (setjmp(temp) == 0) {
|
||||
// This is the initial return from setjmp. Still the original
|
||||
// stack.
|
||||
|
||||
// Now we overwrite the stack pointer value in the saved
|
||||
// register context. This doesn't work with all implementations
|
||||
// of setjmp/longjmp.
|
||||
((void *&)temp[JB_SP]) = (_st_this->_stack + _st_this->_stack_size);
|
||||
|
||||
// And finally, we place ourselves on the new stack by using
|
||||
// longjmp() to reload the saved (and modified) context.
|
||||
longjmp(temp, 1);
|
||||
}
|
||||
|
||||
// This is the second return from setjmp. Now we're on the new
|
||||
// stack.
|
||||
setup_context_2(_st_this);
|
||||
|
||||
// Now restore the original stack and return.
|
||||
longjmp(orig_stack, 1);
|
||||
}
|
||||
|
||||
// By now we are back to the original stack.
|
||||
#endif // HAVE_UCONTEXT_H
|
||||
st_begin_thread(void *data) {
|
||||
ThreadSimpleImpl *self = (ThreadSimpleImpl *)data;
|
||||
self->begin_thread();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ThreadSimpleImpl::setup_context_3
|
||||
// Access: Private, Static
|
||||
// Description: More continuation of setup_context(). Again, making
|
||||
// this a separate function helps defeat the compiler
|
||||
// optimizer.
|
||||
// Function: ThreadSimpleImpl::begin_thread
|
||||
// Access: Private
|
||||
// Description: This method is called as the first introduction to a
|
||||
// new thread.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void ThreadSimpleImpl::
|
||||
setup_context_3() {
|
||||
begin_thread() {
|
||||
#ifdef HAVE_PYTHON
|
||||
PyThreadState_Swap(_python_state);
|
||||
#endif // HAVE_PYTHON
|
||||
|
|
@ -276,7 +220,7 @@ setup_context_3() {
|
|||
// Here we are executing within the thread. Run the thread_main
|
||||
// function defined for this thread.
|
||||
_parent_obj->thread_main();
|
||||
|
||||
|
||||
// Now we have completed the thread.
|
||||
_status = S_finished;
|
||||
|
||||
|
|
@ -291,6 +235,7 @@ setup_context_3() {
|
|||
_manager->next_context();
|
||||
|
||||
// Shouldn't get here.
|
||||
nassertv(false);
|
||||
abort();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "pnotify.h"
|
||||
#include "threadPriority.h"
|
||||
#include "pvector.h"
|
||||
#include "contextSwitch.h"
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
|
||||
|
|
@ -35,39 +36,6 @@
|
|||
|
||||
#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>
|
||||
|
||||
// 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
|
||||
|
||||
#elif defined(WIN32)
|
||||
// We have determined this value empirically, via test_setjmp.cxx in
|
||||
// this directory.
|
||||
#define JB_SP 4
|
||||
|
||||
#endif
|
||||
|
||||
#endif // JB_SP
|
||||
|
||||
#endif // HAVE_UCONTEXT_H
|
||||
|
||||
class Thread;
|
||||
class ThreadSimpleManager;
|
||||
class MutexSimpleImpl;
|
||||
|
|
@ -120,9 +88,8 @@ public:
|
|||
INLINE double get_start_time() const;
|
||||
|
||||
private:
|
||||
void setup_context();
|
||||
static void *setup_context_2(ThreadSimpleImpl *self);
|
||||
void setup_context_3();
|
||||
static void st_begin_thread(void *data);
|
||||
void begin_thread();
|
||||
|
||||
private:
|
||||
enum Status {
|
||||
|
|
@ -145,12 +112,7 @@ private:
|
|||
// should wake up.
|
||||
double _start_time;
|
||||
|
||||
#ifdef HAVE_UCONTEXT_H
|
||||
ucontext_t _ucontext;
|
||||
#else
|
||||
jmp_buf _jmp_context;
|
||||
#endif // HAVE_UCONTEXT_H
|
||||
|
||||
ThreadContext _context;
|
||||
unsigned char *_stack;
|
||||
size_t _stack_size;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,59 +0,0 @@
|
|||
// Filename: threadSimpleImpl_setup_context.cxx
|
||||
// Created by: drose (20Jun07)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "threadSimpleImpl.h"
|
||||
|
||||
#ifdef THREAD_SIMPLE_IMPL
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ThreadSimpleImpl::setup_context_2
|
||||
// Access: Private, Static
|
||||
// Description: Continuation of setup_context(). We have this as a
|
||||
// separate method so we can ensure that the stack gets
|
||||
// set up with our this pointer properly. It is defined
|
||||
// in a separate file so we can disable compiler
|
||||
// optimizations on this one method (gcc prefers to
|
||||
// disable optimizations globally on the command line,
|
||||
// not via pragmas).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void *ThreadSimpleImpl::
|
||||
setup_context_2(ThreadSimpleImpl *self) {
|
||||
ThreadSimpleImpl *volatile v_self = self;
|
||||
|
||||
#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 v_self;
|
||||
}
|
||||
#endif // HAVE_UCONTEXT_H
|
||||
|
||||
// Here we are executing within the thread.
|
||||
v_self->setup_context_3();
|
||||
|
||||
// We shouldn't get here.
|
||||
abort();
|
||||
|
||||
// Even though this line should never be executed, setting it here
|
||||
// seems to help the compiler figure out not to optimize away
|
||||
// v_self.
|
||||
*v_self = 0;
|
||||
return v_self;
|
||||
}
|
||||
|
||||
#endif // THREAD_SIMPLE_IMPL
|
||||
|
|
@ -66,6 +66,12 @@ enqueue_ready(ThreadSimpleImpl *thread) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void ThreadSimpleManager::
|
||||
enqueue_sleep(ThreadSimpleImpl *thread, double seconds) {
|
||||
if (thread_cat.is_debug()) {
|
||||
thread_cat.debug()
|
||||
<< *_current_thread->_parent_obj << " sleeping for "
|
||||
<< seconds << " seconds\n";
|
||||
}
|
||||
|
||||
double now = get_current_time();
|
||||
thread->_start_time = now + seconds;
|
||||
_sleeping.push_back(thread);
|
||||
|
|
@ -186,38 +192,18 @@ next_context() {
|
|||
_current_thread->_python_state = PyThreadState_Swap(NULL);
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
#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.
|
||||
int switched;
|
||||
save_thread_context(&switched, &_current_thread->_context);
|
||||
if (switched) {
|
||||
// Pass 2: we have returned into the context, 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
|
||||
PyThreadState_Swap(_current_thread->_python_state);
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
return;
|
||||
}
|
||||
#endif // HAVE_UCONTEXT_H
|
||||
// Pass 1: we have saved the context successfully.
|
||||
|
||||
while (!_finished.empty() && _finished.front() != _current_thread) {
|
||||
ThreadSimpleImpl *finished_thread = _finished.front();
|
||||
|
|
@ -264,9 +250,9 @@ next_context() {
|
|||
|
||||
double wait = _sleeping.front()->_start_time - now;
|
||||
if (wait > 0.0) {
|
||||
if (thread_cat.is_spam()) {
|
||||
thread_cat.spam()
|
||||
<< "Sleeping " << wait << " seconds\n";
|
||||
if (thread_cat.is_debug()) {
|
||||
thread_cat.debug()
|
||||
<< "Sleeping all threads " << wait << " seconds\n";
|
||||
}
|
||||
system_sleep(wait);
|
||||
}
|
||||
|
|
@ -293,14 +279,11 @@ next_context() {
|
|||
<< " blocked, " << _sleeping.size() << " sleeping)\n";
|
||||
}
|
||||
|
||||
#ifdef HAVE_UCONTEXT_H
|
||||
setcontext(&_current_thread->_ucontext);
|
||||
#else
|
||||
longjmp(_current_thread->_jmp_context, 1);
|
||||
#endif
|
||||
switch_to_thread_context(&_current_thread->_context);
|
||||
|
||||
// Shouldn't get here.
|
||||
nassertv(false);
|
||||
abort();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
Loading…
Reference in New Issue