2012-10-15 16 views
8

मैंने एक पुस्तकालय विकसित किया जो सिगिल सिग्नल को संभालता है। चूंकि मैं libc निर्भरता से बचना चाहता हूं, और सीधे लिनक्स सिस्कोल का उपयोग करना चाहता हूं। मैंने देखा कि मेरी लाइब्रेरी कुछ लिनक्स सिस्टम पर लटकती है, और बहुत सारे डिबगिंग के बाद मैंने पाया कि सिस्कोल sigaction की बजाय समस्या हल करती है। हालांकि, मुझे दो सिस्को के बीच अंतर का विवरण नहीं मिला। क्या किसी को भी अंतर्निहित विवरण पता है?लिनक्स में सिग्नल और rt_signal syscalls के बीच क्या अंतर है?

अद्यतन: मैं कुछ एआरएम निर्देश एक्सटेंशन के लिए सीपीयू समर्थन का पता लगाने के लिए सिग्नल हैंडलर का उपयोग करता हूं, उदा। एक्सएसकेले निर्देश MIATT

static uint32_t probe_xscale() { 
    register uint32_t retValue asm("r0") = 0; 
    asm volatile (
     // Equivalent of the following code: 
     // ".arch xscale\n" 
     // "MIATT acc0, r0, r0;" 
     // If the next line raises SIGILL, the signal handle will change r0 to 1 and skip the instruction (4 bytes) 
     "MCR P0, 0x1, r0, c15, c0, 0;" 
     : "+r" (retValue) 
     : 
     : 
    ); 
    return retValue; 
} 

SIGILL हैंडलर में मैं 4 बाइट (इस शिक्षा का आकार) द्वारा PC रजिस्टर अग्रिम, और रजिस्टरों में से एक को बदलने के संकेत मिलता है कि SIGILL हैंडलर बुलाया गया था: यहाँ अनुदेश जांच कार्य है। सिग्नल हैंडलर कोड यहां है।

static void probe_signal_handler(int, siginfo_t *, void* ptr) { 
    ucontext_t* ctx = (ucontext_t*)ptr; 
    ctx->uc_mcontext.arm_pc += 4; 
    ctx->uc_mcontext.arm_r0 = 1; 
} 

यहाँ कैसे मैं जांच (फ़ंक्शन 0 अगर अनुदेश SIGILL, 1 का कारण नहीं करता है, तो SIGILL हैंडलर बुलाया गया था, और 2 यदि sigaction syscall विफल) करना है:

static uint32_t probeInstruction(uint32_t (*ProbeFunction)()) { 
    struct sigaction oldSigillAction; 
    struct sigaction probeSigillAction; 
    memset(&probeSigillAction, 0, sizeof(probeSigillAction)); 
    probeSigillAction.sa_sigaction = &probe_signal_handler; 
    // Needs Linux >= 2.2 
    probeSigillAction.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO; 
    int sigactionResult = _syscall_sigaction(SIGILL, &probeSigillAction, &oldSigillAction); 
    if (sigactionResult == 0) { 
     const uint32_t probeResult = ProbeFunction(); 
     _syscall_sigaction(SIGILL, &oldSigillAction, NULL); 
     return probeResult; 
    } else { 
     return 2; 
    } 
} 

यहाँ

static int _syscall_sigaction(int signum, const struct sigaction *new_action, struct sigaction *old_action) __attribute__((noinline)); 
static int _syscall_sigaction(int signalNumberParameter, const struct sigaction *newActionParameter, struct sigaction *oldActionParameter) { 
    register int result asm ("r0"); 
    register int signalNumber asm ("r0") = signalNumberParameter; 
    register const struct sigaction *newAction asm ("r1") = newActionParameter; 
    register struct sigaction *oldAction asm ("r2") = oldActionParameter; 
    register int syscallNumber asm ("r7") = __NR_rt_sigaction; 
    asm volatile (
     "swi $0;" 
     : "=r" (result) 
     : "r" (signalNumber), "r" (newAction), "r" (oldAction), "r" (syscallNumber) 
     : 
    ); 
    return result; 
} 

मैं एंड्रॉयड एसडीके (qemu) से एमुलेटर में इस कोड का परीक्षण किया है, और Pandaboard चल Ubuntu पर: sigaction syscall ठूंठ समारोह के अपने कार्यान्वयन है। एम्यूलेटर में कोड अच्छी तरह से चलता है (एआरएम 9 और कॉर्टेक्स-ए 8 सीपीयू को अनुकरण करते समय), लेकिन पांडबार्ड पर यह एमआईएटीटी निर्देश पर लटकता है अगर मैं __NR_sigaction का उपयोग करता हूं: ऐसा लगता है कि सिग्नल हैंडलर के बाद कोड 4 बाइट्स को नहीं छोड़ता है, लेकिन रन एक ही निर्देश।

+0

मुझे लगता है कि 'rt_sigaction' संस्करण एक "वास्तविक समय" संस्करण है। मतलब यह है कि यह निर्धारित समय कॉल करने के लिए डिज़ाइन किया गया है। –

+0

ये लगभग उसी कोड हैं, दोनों कर्नेल में do_sigaction() पर जमीन। यदि आपको समस्याएं आ रही हैं, तो शायद यह उन्हें विस्तारित करने में मदद करेगी। –

+0

मैंने प्रश्न में मेरे कोड का अधिक विवरण और प्रासंगिक हिस्सा जोड़ा। –

उत्तर

1

से man sigaction (link) मैं बोली:

मूल लिनक्स सिस्टम कॉल sigaction नामित किया गया था()। हालांकि, के साथ लिनक्स 2.2 में रीयल-टाइम सिग्नल के अतिरिक्त, निश्चित सिस्टम, 32-बिट sigset_t प्रकार उस सिस्टम कॉल द्वारा समर्थित है, उद्देश्य के लिए फिट नहीं था। नतीजतन, एक नया सिस्टम कॉल, rt_sigaction(), एक विस्तारित sigset_t प्रकार का समर्थन करने के लिए जोड़ा गया था। नया सिस्टम कॉल चौथा तर्क लेता है, size_t sigsetsize, जो act.sa_mask और oldact.sa_mask में सिग्नल सेट के बाइट्स में आकार निर्दिष्ट करता है।

+0

'मैन सिग्नेक्शन' से भी, यदि आप ग्लिब का उपयोग कर रहे हैं तो rt_sigaction का उपयोग करने की आवश्यकता नहीं है। "ग्लिब सिग्नेशन() रैपर फ़ंक्शन हमारे द्वारा इन विवरणों को छुपाता है, जब कर्नेल इसे प्रदान करता है तो पारदर्शी रूप से rt_sigaction() को कॉल करता है।" – cooperised

4

मैं एक निश्चित उत्तर नहीं है, लेकिन मैं अभी भी योगदान करने की कोशिश करेंगे:

300SYSCALL_DEFINE3(sigaction, int, sig, const struct sigaction __user *, act, 
301  struct sigaction __user *, oact) 
302{ 
303  struct k_sigaction new_ka, old_ka; 
304  int ret; 
305  int err = 0; 
306 
307  if (act) { 
308    old_sigset_t mask; 
309 
310    if (!access_ok(VERIFY_READ, act, sizeof(*act))) 
311      return -EFAULT; 
312    err |= __get_user(new_ka.sa.sa_handler, &act->sa_handler); 
313    err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); 
314    err |= __get_user(mask, &act->sa_mask.sig[0]); 
315    if (err) 
316      return -EFAULT; 
317 
318    siginitset(&new_ka.sa.sa_mask, mask); 
319  } 
320 
321  ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); 
322 
323  if (!ret && oact) { 
324    if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact))) 
325      return -EFAULT; 
326    err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); 
327    err |= __put_user(old_ka.sa.sa_handler, &oact->sa_handler); 
328    err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig); 
329    err |= __put_user(0, &oact->sa_mask.sig[1]); 
330    err |= __put_user(0, &oact->sa_mask.sig[2]); 
331    err |= __put_user(0, &oact->sa_mask.sig[3]); 
332    if (err) 
333      return -EFAULT; 
334  } 
335 
336  return ret; 
337} 
338#endif 

बनाम

2955SYSCALL_DEFINE4(rt_sigaction, int, sig, 
2956    const struct sigaction __user *, act, 
2957    struct sigaction __user *, oact, 
2958    size_t, sigsetsize) 
2959{ 
2960  struct k_sigaction new_sa, old_sa; 
2961  int ret = -EINVAL; 
2962 
2963  /* XXX: Don't preclude handling different sized sigset_t's. */ 
2964  if (sigsetsize != sizeof(sigset_t)) 
2965    goto out; 
2966 
2967  if (act) { 
2968    if (copy_from_user(&new_sa.sa, act, sizeof(new_sa.sa))) 
2969      return -EFAULT; 
2970  } 
2971 
2972  ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL); 
2973 
2974  if (!ret && oact) { 
2975    if (copy_to_user(oact, &old_sa.sa, sizeof(old_sa.sa))) 
2976      return -EFAULT; 
2977  } 
2978out: 
2979  return ret; 
2980} 

differance के रूप में:

गिरी स्रोत को देखते हुए मुझे लगता है कि यह rt_sigaction पूरे सिग्नेक्शन स्ट्रक्चर की प्रतिलिपि बनाता है, जबकि सिग्नलेशन मेमोरी इनलाइन (प्राप्त/सेट उपयोगकर्ता फ़ंक्शंस का उपयोग करके) को बदल रहा है और बदल रहा है ... मुझे यकीन नहीं है, लेकिन शायद इसमें अधिक समय लगता है अस्थायी प्रति के साथ काम करने के बजाय सीधे उपयोगकर्ता स्पेस मेमोरी तक पहुंचने के लिए।