Ошибка сегментации с ucontext makecontext на OS X 10.10

#include <stdio.h>
#include <stdlib.h>
#define _XOPEN_SOURCE 600
#include <ucontext.h>

/* Tests creation.
   Should print "Hello World!" */

typedef struct thread_t{
  ucontext_t thread_context;
}thread_t;

void *thr1(void *in) {
  printf("Hello World!\n");
  fflush(stdout);
  return NULL;
}

void *thr2(void *in) {
  printf("goodbye World!\n");
  fflush(stdout);
  return NULL;
}

int main() {
  thread_t t1;
  thread_t t2;

  thread_create( &t1, thr1, NULL);
  // if you comment out the following line, the program will run like a charm. 
  thread_create( &t2, thr2, NULL);
  setcontext(&t1.thread_context);

  return EXIT_SUCCESS;
}

void thread_routine(void *(*start_routine)(void *), void *arg)
{
  start_routine(arg);
  printf("gtthread routine finished\n");
}

int thread_create(thread_t *thread,
        void *(*start_routine)(void *),
        void *arg){
  if (getcontext(&(thread->thread_context)) == -1)
  {
    perror("getcontext");
  }

  thread->thread_context.uc_stack.ss_sp = (char*) malloc(SIGSTKSZ);
  thread->thread_context.uc_stack.ss_size = SIGSTKSZ;
  thread->thread_context.uc_link = NULL;

  makecontext(&(thread->thread_context), thread_routine, 2, (void *)start_routine, arg);
}

Я запускаю свой код в OS X 10.10 с gcc. Я пытаюсь реализовать библиотеку usercontext.

Если я закомментирую thread_create( &t2, thr2, NULL);код даст желаемый эффект. Я понятия не имею, почему линия, связанная с t2 приведет к ошибке сегментации t1,

Авторские заметки

Я с радостью работаю над реализацией библиотеки usercontext после перехода на Ubuntu. Все отлично работает Нет ошибки сегментации больше. И, как и ожидалось, он падает на OS X 10.10.

Я полагаю, что поскольку makecontext(), swapcontext() и т. Д. Устарели в OS X начиная с 10.6, как предупреждено компилятором, я не должен ожидать, что он будет работать.

2 ответа

Решение

У вашей программы есть некоторые недостатки, некоторые из которых приводят к неопределенному поведению. Неопределенное поведение может проявиться именно так, как вы ожидали, но если это произойдет один раз, в какой-то конкретной среде, это не дает никаких оснований ожидать, что это произойдет снова - не в этой среде, и конечно, не в другой среде.

Вот более серьезные проблемы, которые я заметил:

  • thread_routine() не имеет правильного возвращаемого типа или типов аргументов для функции запуска контекста. Ожидается, что функция запуска контекста вернет void (т.е. ничего) нет void *, что совсем другое. Также фактические аргументы, переданные ему, если таковые имеются, будут все типом int, Поэтому, когда эта функция вызывается вашей программой в результате setcontext(), неопределенные результаты поведения. На машине, где указатели функций и указатели объектов имеют одинаковый размер intВы можете сойти с рук, но на других машинах программа, скорее всего, потерпит крах. Это, вероятно, причина сегфоута, который вы наблюдали.

  • В thread_create() вы инициализируете thread->thread_context.uc_link в NULL, Само по себе это не ошибка, но в более широком смысле это приведет к тому, что когда функция запуска контекста вернется, поток (OS), в котором он запущен, завершится. Предположительно, вы бы предпочли иметь возможность поменяться в другом контексте.

  • Ты используешь setcontext() переключиться на t1 контекст. В случае успеха этот вызов не будет возвращен ни тогда, ни позже, и у вас не будет возможности позже переключиться на t2 контекст. На практике, тем не менее, поток и, следовательно, вся программа завершатся в любом случае, когда функция запуска t1 вернется (см. Выше), так что это спорный вопрос для вас. Для чего это стоит, хотя, вы, вероятно, должны использовать swapcontext() вместо.

  • thread_create() объявлено о возвращении int, но это не имеет return заявление.

gcc кстати, должно быть предупреждение о некоторых из этих проблем. Если нет, то увеличьте уровень предупреждения. -Wall уровень должен быть достаточным, но я часто включаю -Wextra а также для поиска вопросов. Иногда есть предупреждения, которые вы можете игнорировать (особенно с -Wextra), но вы должны сделать эту оценку отдельно для каждого.

Я думаю, что вы поставили "thread.h", почему вы используете потоки, если вы можете попробовать это

Другие вопросы по тегам