2010-03-01 17 views
6

में किसी ने कहा कि Wikipedia "ptrace" article में जोड़ा गया है कि लिनक्स पर, एक छेड़छाड़ की प्रक्रिया स्वयं एक और प्रक्रिया को छीन नहीं सकती है। मैं यह निर्धारित करने की कोशिश कर रहा हूं कि (और यदि ऐसा है तो) यह मामला है। नीचे एक सरल कार्यक्रम है जिसे मैंने परीक्षण करने के लिए प्रेरित किया है। मेरा प्रोग्राम विफल रहता है (उप उप प्रक्रिया ठीक से नहीं चलती है) लेकिन मुझे पूरा विश्वास है कि यह मेरी त्रुटि है और कुछ मौलिक नहीं है।एक छिद्रित लिनक्स प्रक्रिया

संक्षेप में प्रारंभिक प्रक्रिया एक कांटे बी जो बारी कांटे में सी की प्रक्रिया। अपने बच्चे को बी, बी अपने बच्चे को सी को छेड़छाड़ करता है। एक बार वे सेट अप हो जाने के बाद, सभी तीन प्रक्रियाएं केवल A, B, या C प्रिंट करने के लिए लिखी जाती हैं ताकि प्रत्येक सेकेंड में एक बार स्टडआउट हो सके।

अभ्यास क्या होता है कि एक और बी काम ठीक है, लेकिन सी प्रिंट केवल एक बार और फिर अटक जाती है है। ps -eo pid,cmd,wchan के साथ जांच सी कर्नेल फ़ंक्शन ptrace_stop में फंस गया है जबकि शेष hrtimer_nanosleep में हैं जहां मैं सभी तीनों की अपेक्षा करता हूं।

कभी-कभी तीनों काम करते हैं (इसलिए प्रोग्राम सीएस के साथ-साथ एएस और बीएस प्रिंट करता है), जो मुझे विश्वास दिलाता है कि शुरुआती सेटअप में कुछ दौड़ की स्थिति है।

मेरे अनुमान क्या गलत हो सकता है के रूप में कर रहे हैं: एक देखकर से कोई लेना देना

  • कुछ एक SIGCHLD संबंधित एक SIGCHLD देखकर के लिए एक संकेत के साथ क्या करना सी करने के लिए बी, और प्रतीक्षा करें (2) बी से आने वाले दोनों की रिपोर्टिंग (लेकिन दोनों पीड्स में PTRACE_CONT की एक हैकी कॉल चीजों को ठीक नहीं करती है)?
  • सीबी द्वारा ptraced जाना चाहिए - सी (बी की कॉल ptrace को और न errored है और न ही इस अधिलेखित कर दिया) एक बजाय द्वारा ptrace विरासत में मिला है?

क्या कोई यह पता लगा सकता है कि मैं क्या गलत कर रहा हूं? धन्यवाद।

#include <stdio.h> 
#include <string.h> 
#include <unistd.h> 
#include <signal.h> 
#include <sys/ptrace.h> 
#include <sys/wait.h> 

static void a(){ 
    while(1){ 
    printf ("A\n"); 
    fflush(stdout); 
    sleep(1); 
    } 
} 

static void b(){ 
    while(1){ 
    printf ("B\n"); 
    fflush(stdout); 
    sleep(1); 
    } 
} 

static void c(){ 
    while(1){ 
    printf ("C\n"); 
    fflush(stdout); 
    sleep(1); 
    } 
} 

static void sigchld_handler(int sig){ 
    int result; 
    pid_t child_pid = wait(NULL); // find who send us this SIGCHLD 

    printf("SIGCHLD on %d\n", child_pid); 
    result=ptrace(PTRACE_CONT, child_pid, sig, NULL); 
    if(result) { 
    perror("continuing after SIGCHLD"); 
    } 
} 

int main(int argc, 
     char **argv){ 

    pid_t mychild_pid; 
    int result; 

    printf("pidA = %d\n", getpid()); 

    signal(SIGCHLD, sigchld_handler); 

    mychild_pid = fork(); 

    if (mychild_pid) { 
    printf("pidB = %d\n", mychild_pid); 
    result = ptrace(PTRACE_ATTACH, mychild_pid, NULL, NULL); 
    if(result==-1){ 
     perror("outer ptrace"); 
    } 
    a(); 
    } 
    else { 
    mychild_pid = fork(); 

    if (mychild_pid) { 
     printf("pidC = %d\n", mychild_pid); 

     result = ptrace(PTRACE_ATTACH, mychild_pid, NULL, NULL); 
     if(result==-1){ 
     perror("inner ptrace"); 
     } 
     b(); 
    } 
    else { 
     c(); 
    } 
    } 

    return 0; 
} 
+0

मदद नहीं कर सकता है लेकिन 'ptrace (PTRACE_CONT, child_pid, sig, nULL) 'नोटिस ... आप शायद' ptrace (PTRACE_CONT, child_pid, NULL, sig) '(data = sig) – remram

उत्तर

4

आप वास्तव में दौड़ की स्थिति देख रहे हैं। सेकंडfork() कॉल से पहले sleep(1); डालने से आप इसे दोहरा सकते हैं।

रेस स्थिति क्योंकि प्रक्रिया एक सही ढंग से प्रक्रिया बी करने के लिए पर संकेत गुजर नहीं है के कारण होता है इसका मतलब है कि अगर प्रक्रिया बी प्रक्रिया सी अनुरेखण शुरू होता है के बाद प्रक्रिया एक प्रक्रिया बी अनुरेखण शुरू कर दिया है, इस प्रक्रिया को बी SIGCHLD संकेत है कि यह दर्शाता है हो जाता है कभी नहीं प्रक्रिया सी बंद कर दिया गया है, इसलिए यह इसे कभी जारी नहीं रख सकता है।

static void sigchld_handler(int sig){ 
    int result, status; 
    pid_t child_pid = wait(&status); // find who send us this SIGCHLD 

    printf("%d received SIGCHLD on %d\n", getpid(), child_pid); 
    if (WIFSTOPPED(status)) 
    { 
     result=ptrace(PTRACE_CONT, child_pid, 0, WSTOPSIG(status)); 
     if(result) { 
      perror("continuing after SIGCHLD"); 
     } 
    } 
} 
+0

हां, यह बिल्कुल ठीक है । आपके सुंदर स्पष्ट स्पष्टीकरण के लिए बहुत बहुत धन्यवाद। –

+0

@caf क्या यह संभव है कि सी ptrace ए? –

0

यह "संभव" है एक बच्चे प्रक्रिया है कि ptrace ही आह्वान पर कुछ ptrace कार्यक्षमताओं प्रदर्शन करने के लिए:

समस्या को ठीक करने के लिए, आप बस अपने SIGCHLD हैंडलर ठीक करना होगा। वास्तविक कठिनाई यह है कि बाद में संलग्न होने पर एक ट्रैसर प्रक्रिया ट्रेस के पैरेंट बन जाती है। और यदि आपकी ट्रेसर प्रक्रिया सभी (प्रत्यक्ष और अप्रत्यक्ष) बाल प्रक्रियाओं (यानी जब एक डीबगर प्रोग्राम को बहु-थ्रेडेड प्रोग्राम डीबग करने की आवश्यकता होती है) से सभी व्यवहारों का पता लगाना चाहता है, तो यह स्वाभाविक रूप से मूल प्रक्रिया पदानुक्रम को तोड़ देता है, और सभी इंटर-प्रोसेस/इंटर-थ्रेड संचार (यानी थ्रेड सिंक्रनाइज़ेशन, सिग्नल भेजना/प्राप्त करना, ...) सभी बाल प्रक्रियाओं में ट्रेसर प्रक्रिया द्वारा नकली/मल्टीप्लेक्स की आवश्यकता होती है। यह अभी भी "संभव" है, लेकिन अधिक कठिन और अक्षम है।

संबंधित मुद्दे