contextSwitch_ucontext_src.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. /* Filename: contextSwitch_ucontext_src.c
  2. * Created by: drose (15Apr10)
  3. *
  4. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  5. *
  6. * PANDA 3D SOFTWARE
  7. * Copyright (c) Carnegie Mellon University. All rights reserved.
  8. *
  9. * All use of this software is subject to the terms of the revised BSD
  10. * license. You should have received a copy of this license along
  11. * with this source code in a file named "LICENSE."
  12. *
  13. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  14. /* This is the implementation of user-space context switching using
  15. getcontext() / setcontext(). This is the preferred implementation,
  16. if these library functions are available; that's what they are
  17. designed for. */
  18. #ifdef __APPLE__
  19. #include <sys/ucontext.h>
  20. #else
  21. #include <ucontext.h>
  22. #endif
  23. const int needs_stack_prealloc = 1;
  24. const int is_os_threads = 0;
  25. struct ThreadContext {
  26. ucontext_t _ucontext;
  27. #ifdef __APPLE__
  28. // Due to a bug in OSX 10.5, the system ucontext_t declaration
  29. // doesn't reserve enough space, and we need to reserve some
  30. // additional space to make room.
  31. #define EXTRA_PADDING_SIZE 4096
  32. char _extra_padding[EXTRA_PADDING_SIZE];
  33. #endif
  34. };
  35. static void
  36. begin_context(ThreadFunction *thread_func, void *data) {
  37. (*thread_func)(data);
  38. }
  39. void
  40. init_thread_context(struct ThreadContext *context,
  41. unsigned char *stack, size_t stack_size,
  42. ThreadFunction *thread_func, void *data) {
  43. if (getcontext(&context->_ucontext) != 0) {
  44. fprintf(stderr, "getcontext failed in init_thread_context!\n");
  45. // Too bad for you.
  46. abort();
  47. }
  48. context->_ucontext.uc_stack.ss_sp = stack;
  49. context->_ucontext.uc_stack.ss_size = stack_size;
  50. context->_ucontext.uc_stack.ss_flags = 0;
  51. context->_ucontext.uc_link = NULL;
  52. makecontext(&context->_ucontext, (void (*)())&begin_context, 2, thread_func, data);
  53. }
  54. void
  55. save_thread_context(struct ThreadContext *context,
  56. ContextFunction *next_context, void *data) {
  57. /* getcontext requires us to use a volatile auto variable to
  58. differentiate between pass 1 (immediate return) and pass 2
  59. (return from setcontext). */
  60. volatile int context_return = 0;
  61. if (getcontext(&context->_ucontext) != 0) {
  62. fprintf(stderr, "getcontext failed!\n");
  63. // Nothing to do here.
  64. abort();
  65. }
  66. if (context_return) {
  67. /* We have just returned from setcontext. In this case, return
  68. from the function. The stack is still good. */
  69. return;
  70. }
  71. context_return = 1;
  72. /* We are still in the calling thread. In this case, we cannot
  73. return from the function without damaging the stack. Insted,
  74. call next_context() and trust the caller to call
  75. switch_to_thread_context() in there somewhere. */
  76. (*next_context)(context, data);
  77. /* We shouldn't get here. */
  78. abort();
  79. }
  80. void
  81. switch_to_thread_context(struct ThreadContext *from_context,
  82. struct ThreadContext *to_context) {
  83. setcontext(&to_context->_ucontext);
  84. /* Shouldn't get here. */
  85. abort();
  86. }
  87. struct ThreadContext *
  88. alloc_thread_context() {
  89. struct ThreadContext *context =
  90. (struct ThreadContext *)malloc(sizeof(struct ThreadContext));
  91. memset(context, 0, sizeof(struct ThreadContext));
  92. #if defined(__APPLE__) && defined(_DEBUG)
  93. {
  94. int p;
  95. // Pre-fill the extra_padding with bytes that we can recognize
  96. // later.
  97. for (p = 0; p < EXTRA_PADDING_SIZE; ++p) {
  98. context->_extra_padding[p] = (p & 0xff);
  99. }
  100. }
  101. #endif // __APPLE__
  102. return context;
  103. }
  104. void
  105. free_thread_context(struct ThreadContext *context) {
  106. #if defined(__APPLE__) && defined(_DEBUG)
  107. {
  108. // Because of the OSX 10.5 bug, we anticipate that the extra_padding
  109. // may have been filled in with junk. Confirm this.
  110. int p = EXTRA_PADDING_SIZE;
  111. while (p > 0) {
  112. --p;
  113. if (context->_extra_padding[p] != (char)(p & 0xff)) {
  114. fprintf(stderr, "Context was mangled at byte %d: %d!\n", p, context->_extra_padding[p]);
  115. break;
  116. }
  117. }
  118. }
  119. #endif // __APPLE__
  120. free(context);
  121. }