Воссоздать мертвые темы после разветвления - PullRequest
7 голосов
/ 27 октября 2011

Как вы, возможно, знаете, все потоки в приложении умирают в разветвленном процессе, кроме потока, выполняющего разветвление. Однако я планирую восстановить эти потоки в разветвленном процессе, вызвав pthread_create и используя pthread_attr_setstack , чтобы назначить вновь созданные потоки тому же стеку, что и мертвые потоки. Что-то вроде следующего.

// stackAddr and stacksize taken from the dead thread    
pthread_attr_setstack(&attr, stackAddr, stacksize);
rc = pthread_create(&thread, &attr, threadRoutine, NULL); 

Однако мне все равно нужно получить значения регистра ЦП, такие как указатель стека, указатель базы, указатель инструкции и т. Д., Чтобы перезапустить потоки из той же точки. Как я могу это сделать? И что еще мне нужно сделать, чтобы успешно достичь своей цели?

Также обратите внимание, что я использую 64-битную архитектуру. Какие дополнительные трудности это будет иметь по сравнению с 32-битным?

Ответы [ 3 ]

3 голосов
/ 27 октября 2011

Я вижу два возможных способа выстрелить себе в ногу и потерять волосы. ^ W ^ W ^ W ^ W ^ W ^ W ^ W ^ Пробуйте сделать это:

  • Попробуйте заставить каждогопоток в вызов getcontext() до fork(), а затем восстановить контекст каждого потока через setcontext().Вероятно, не сработает, но вы можете попробовать для удовольствия.
  • Сохраните ptrace(PTRACE_GETREGS), ptrace(PTRACE_GETFPREGS) и восстановите с помощью ptrace(PTRACE_SETREGS), ptrace(PTRACE_SETFPREGS).
2 голосов
/ 27 октября 2011

Другие потоки в текущем процессе не уничтожаются вилкой - они все еще там и работают в родительском. Кажется, проблема в том, что fork разветвляет только ОДИН поток в текущих процессах, создавая новый процесс, запускающий один поток, с копией всех ресурсов, не относящихся к потокам, в родительском объекте.

То, что вы, очевидно, хотите, это способ дублирования всей многопоточной задачи, разветвления всех потоков в ней и создания нового процесса / задачи с тем же числом потоков.

Чтобы сделать ЭТО, вам нужно будет найти и приостановить все остальные потоки в процессе, сбросить их текущее состояние (включая все блокировки, которые они удерживают), разветвить новый процесс, а затем (заново) создать каждый из них. другие потоки в дочернем процессе, переназначая состояние блокировки для ссылки на новые дочерние потоки, где это необходимо.

К сожалению, pthread-интерфейс POSIX безнадежно недооценен и не позволяет этого сделать. В частности, в нем отсутствует какой-либо отражающий интерфейс, позволяющий выяснить, какие потоки действительно выполняются.

Если вы все равно хотите попытаться сделать это, я вижу два способа попытаться подойти к этому:

  • покопайтесь в / proc / self / task, чтобы выяснить, какие потоки выполняются в вашем процессе, эффективно получая этот отражающий интерфейс в очень непереносимой форме. Скорее всего, вам придется в конечном итоге выполнить ptrace (2) для других потоков, чтобы получить их внутреннее состояние. Это будет очень сложно.

  • оберните библиотеку pthreads - вместо непосредственного использования библиотеки перехватывайте каждый вызов и отслеживайте все созданные потоки / мьютексы / блокировки, чтобы иметь эту информацию доступной, когда вы хотите выполнить форк. Это будет работать нормально, если вы не хотите использовать сторонние библиотеки, использующие pthreads

Второй вариант намного проще (и несколько переносим), но работает хорошо, только если у вас есть доступ ко всему исходному коду всего вашего приложения, и вы можете изменить его для правильного использования ваших оболочек.

0 голосов
/ 27 октября 2011

Просто погуглив, я обнаружил, что у Solaris есть вызов forkall (), который делает именно то, что вы хотите, смотрите документацию здесь:

http://download.oracle.com/docs/cd/E19963-01/html/821-1601/gen-1.html

Я предполагаю, что вы работаете в Linux, но возможно запустить Solaris на оборудовании x86. Так что, возможно, это вариант для вас.

...