Maak dode draden opnieuw na een vork

Zoals je misschien weet, sterven alle draden in de applicatie in een gevorkte procedure, behalve de draad die de vork doet. Ik ben echter van plan om die threads in het gevorkte proces opnieuw tot leven te brengen door pthread_create aan te roepen en pthread_attr_setstack te gebruiken, om de nieuw gemaakte threads dezelfde stapel toe te wijzen als de dode threads. Iets als als volgt.

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

Ik zou echter nog steeds de CPU-registerwaarden moeten ophalen, zoals stack pointer, base pointer, instructie pointer enz. Om threads opnieuw vanaf hetzelfde punt te starten. Hoe kan ik dat doen? En wat moet ik nog meer doen om mijn doel te bereiken?

Merk ook op dat ik een 64-bits architectuur gebruik. Welke extra problemen zou het hebben in vergelijking met een 32-bits exemplaar?

7
Heb je gekeken naar pthread_atfork ? Ik zie niet in hoe je mutexes, condvars enz. Vermijdt om corrupt te worden zonder dat soort faciliteiten. Zelfs bij hen lijkt dit behoorlijk behaard en fragiel.
toegevoegd de auteur Duck, de bron
Ik dacht dat ik ergens had gelezen dat het mixen van draad en vork een slecht idee was. Doen herleven draden na een vork (denk ik) neemt slechte ideeën naar een geheel nieuw niveau. Ik weet niet of het mogelijk is, ik denk niet dat het een goed idee is, zelfs als dat zo is, en ik durf te wedden dat er een veel betere manier is om te doen wat je echt wilt doen.
toegevoegd de auteur Kevin, de bron
Ik denk dat hij een Solaris-app probeert te porten naar linux. Solaris heeft een forkall-call, dus hij komt waarschijnlijk met een architectuur die daarop vertrouwt.
toegevoegd de auteur Kevin, de bron
@denniston: misschien kun je hier een beetje helpen :)!
toegevoegd de auteur MetallicPriest, de bron
@ denniston.t, controlepunten!
toegevoegd de auteur MetallicPriest, de bron
"Zoals je misschien weet, sterven alle threads in de applicatie in een gevorkte procedure" - is dat zo? Voor zover ik weet, roept pthread_create alleen kloon aan (met een combinatie van vlaggen, zoals CLONE_VM | CLONE_THREAD | CLONE_SIGHAND of vergelijkbaar), waardoor effectief een andere wordt gemaakt proces met gedeeld geheugen, dezelfde threadgroep, enz. fork anderzijds, roept kloon zonder die vlaggen, creëert een ander proces met "alles scheiden", maar raakt niets aan van de bestaande processen überhaupt (dwz een proces met 5 threads-forking heeft nog steeds 5 thread-processen en er zal nog een ander proces zijn).
toegevoegd de auteur Damon, de bron
Net zo moeilijk op 64 bit als 32 bit.
toegevoegd de auteur David Heffernan, de bron
Om het te verduidelijken, praat u over processen die zijn gemarkeerd als EXIT_DEAD of als EXIT_ZOMBIE? Ik neem aan EXIT_ZOMBIE omdat dit niet mogelijk zou moeten zijn voor EXIT_DEAD.
toegevoegd de auteur gnometorule, de bron
@MetallicPriest Ik wist het! Haha, een groot deel van mijn onderzoek ligt in het controleren van applicaties. Gewoon mijn vermoedens bevestigen :-). Bedankt.
toegevoegd de auteur proc-self-maps, de bron
Dit lijkt een ongewone taak. Zou je ons willen ophelderen met een beetje motivatie om dit te doen? Ik zeg niet dat je je ontwerp moet verlaten, maar ik ben erg benieuwd wat de use case is voor deze functionaliteit.
toegevoegd de auteur proc-self-maps, de bron

3 antwoord

Ik zie twee mogelijke manieren om jezelf in de voet te schieten en haar te verliezen ^ W ^ W ^ W ^ W ^ W ^ W ^ Wtry om dit te doen:

  • Probeer elke thread te dwingen om getcontext() aan te roepen vóór de fork() en herstel vervolgens de context van elke thread via setcontext() . Waarschijnlijk zal het niet werken, maar je kunt het proberen voor de lol.
  • Bewaar ptrace (PTRACE_GETREGS) , ptrace (PTRACE_GETFPREGS) en herstel met ptrace (PTRACE_SETREGS) , ptrace (PTRACE_SETFPREGS) .
3
toegevoegd
In plaats van getcontext/setcontext, kan ik dan setjmp/longjmp gebruiken? Ik zat erover te denken om dat te doen.
toegevoegd de auteur MetallicPriest, de bron
@MetallicPriest: Mogelijk, maar zoals ik al zei voor setcontext() , heb ik niet veel hoop in die aanpak.
toegevoegd de auteur ninjalj, de bron
toegevoegd de auteur ninjalj, de bron

De andere threads in het huidige proces worden niet door een vork gedood - ze zijn er nog steeds en lopen in de ouder. Het probleem dat u lijkt te hebben is dat fork slechts één SINGLE thread in de huidige procces doorzoekt, waardoor een nieuw proces wordt gecreëerd met één thread met een kopie van alle niet-thread bronnen in de bovenliggende.

Wat je blijkbaar wilt, is een manier om een ​​volledige multithreaded-taak te dupliceren, alle threads erin te schrijven en een nieuw proces/nieuwe taak met hetzelfde aantal threads te maken.

Om dat te doen, zou je alle andere threads in het proces moeten zoeken en pauzeren, hun huidige status (inclusief alle vergrendelingen die ze bevatten) dumpen, een nieuw proces vorkten en vervolgens elk van die andere threads in (opnieuw) maken het kind, waarbij de vergrendelingsmodus opnieuw wordt bedraad om waar nodig naar de nieuwe child-threads te verwijzen.

Helaas is de POSTX pthread-interface hopeloos ondergespecificeerd en biedt geen mogelijkheid om dat te doen. In het bijzonder mist het een soort reflectieve interface waarmee je kunt achterhalen welke threads daadwerkelijk worden uitgevoerd.

Als je dit toch wilt proberen, zie ik twee manieren om dit te benaderen:

  • snuffel rond in/proc/self/task om erachter te komen welke threads worden uitgevoerd in uw proces, waardoor die reflecterende interface op een zeer niet-draagbare manier wordt verkregen. Je zult waarschijnlijk uiteindelijk de andere threads moeten ptrace (2) om hun interne status te krijgen. Dit zal heel moeilijk zijn.

  • verpak de pthreads-bibliotheek - in plaats van rechtstreeks bibliotheek te gebruiken, onderschep elke oproep en houd alle threads/mutexes/locks bij die worden aangemaakt, zodat je die informatie beschikbaar hebt wanneer je wilt splitten. Dit werkt prima, zolang u geen bibliotheken van derden wilt gebruiken die pthreads gebruiken

De tweede optie is veel eenvoudiger (en enigszins draagbaar), maar werkt alleen goed als je toegang hebt tot alle broncode van je hele applicatie en deze kunt aanpassen om je wrappers juist te gebruiken.

2
toegevoegd
kan ik mijn bovenstaande benadering combineren met setjmp/longjmp. Ga er maar van uit dat ik vork wanneer er geen sloten worden vastgehouden, zoals op barrièrepunten. Zou het niet mogelijk zijn. Het lijkt erop dat ik.
toegevoegd de auteur MetallicPriest, de bron
Het 'hopeloos ondergespecificeerde' van een man is 'netjes geabstraheerd' van een ander. Door geen dingen als de interne sloten te specificeren, hebben uitvoerders de vrijheid om dingen op de beste manier voor hun omgeving te doen.
toegevoegd de auteur caf, de bron
@caf: met een juiste specificatie kun je dingen zoals het gedrag van sloten specificeren op een manier die een programma in staat stelt om ze te beheren, terwijl ze de uitvoerders nog de vrijheid geven om dingen de beste manier voor hun omgeving te doen.
toegevoegd de auteur Chris Dodd, de bron
@MatallicPriest - als u een manier hebt om threads af te stemmen (zodat ze naar een punt kunnen lopen waar ze geen vergrendeling hebben en ze vervolgens te onderbreken), kunt u dat gebruiken om het probleem met het vergrendelingsbeheer op te lossen.
toegevoegd de auteur Chris Dodd, de bron

Gewoon rond googlen vond ik dat solaris een forkall() -aanroep heeft die precies doet wat je wilt, zie de documentatie hier:

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

Ik neem aan dat je op Linux werkt, maar het is mogelijk om Solaris op x86-hardware uit te voeren. Dus misschien is dat een optie voor jou.

0
toegevoegd
oh, ha ... je porteert waarschijnlijk een solaris-programma naar Linux.
toegevoegd de auteur Kevin, de bron
Ja, ik weet het, ik heb het al in mijn programma gebruikt, maar nu wil ik het in Linux doen.
toegevoegd de auteur MetallicPriest, de bron