open_toontown_panda3d/panda/src/pipeline/contextSwitch_ucontext_src.c

142 lines
3.8 KiB
C

/**
* 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 contextSwitch_ucontext_src.c
* @author drose
* @date 2010-04-15
*/
/* This is the implementation of user-space context switching using
getcontext() / setcontext(). This is the preferred implementation,
if these library functions are available; that's what they are
designed for. */
#ifdef __APPLE__
#include <sys/ucontext.h>
#else
#include <ucontext.h>
#endif
const int needs_stack_prealloc = 1;
const int is_os_threads = 0;
struct ThreadContext {
ucontext_t _ucontext;
#ifdef __APPLE__
// Due to a bug in OSX 10.5, the system ucontext_t declaration
// doesn't reserve enough space, and we need to reserve some
// additional space to make room.
#define EXTRA_PADDING_SIZE 4096
char _extra_padding[EXTRA_PADDING_SIZE];
#endif
};
static void
begin_context(ThreadFunction *thread_func, void *data) {
(*thread_func)(data);
}
void
init_thread_context(struct ThreadContext *context,
unsigned char *stack, size_t stack_size,
ThreadFunction *thread_func, void *data) {
if (getcontext(&context->_ucontext) != 0) {
fprintf(stderr, "getcontext failed in init_thread_context!\n");
// Too bad for you.
abort();
}
context->_ucontext.uc_stack.ss_sp = stack;
context->_ucontext.uc_stack.ss_size = stack_size;
context->_ucontext.uc_stack.ss_flags = 0;
context->_ucontext.uc_link = NULL;
makecontext(&context->_ucontext, (void (*)())&begin_context, 2, thread_func, data);
}
void
save_thread_context(struct ThreadContext *context,
ContextFunction *next_context, void *data) {
/* getcontext requires us to use a volatile auto variable to
differentiate between pass 1 (immediate return) and pass 2
(return from setcontext). */
volatile int context_return = 0;
if (getcontext(&context->_ucontext) != 0) {
fprintf(stderr, "getcontext failed!\n");
// Nothing to do here.
abort();
}
if (context_return) {
/* We have just returned from setcontext. In this case, return
from the function. The stack is still good. */
return;
}
context_return = 1;
/* We are still in the calling thread. In this case, we cannot
return from the function without damaging the stack. Insted,
call next_context() and trust the caller to call
switch_to_thread_context() in there somewhere. */
(*next_context)(context, data);
/* We shouldn't get here. */
abort();
}
void
switch_to_thread_context(struct ThreadContext *from_context,
struct ThreadContext *to_context) {
setcontext(&to_context->_ucontext);
/* Shouldn't get here. */
abort();
}
struct ThreadContext *
alloc_thread_context() {
struct ThreadContext *context =
(struct ThreadContext *)malloc(sizeof(struct ThreadContext));
memset(context, 0, sizeof(struct ThreadContext));
#if defined(__APPLE__) && defined(_DEBUG)
{
int p;
// Pre-fill the extra_padding with bytes that we can recognize
// later.
for (p = 0; p < EXTRA_PADDING_SIZE; ++p) {
context->_extra_padding[p] = (p & 0xff);
}
}
#endif // __APPLE__
return context;
}
void
free_thread_context(struct ThreadContext *context) {
#if defined(__APPLE__) && defined(_DEBUG)
{
// Because of the OSX 10.5 bug, we anticipate that the extra_padding
// may have been filled in with junk. Confirm this.
int p = EXTRA_PADDING_SIZE;
while (p > 0) {
--p;
if (context->_extra_padding[p] != (char)(p & 0xff)) {
fprintf(stderr, "Context was mangled at byte %d: %d!\n", p, context->_extra_padding[p]);
break;
}
}
}
#endif // __APPLE__
free(context);
}