2011-04-30 15 views
9

पर लिनक्स अवरुद्ध संकेत यह मेरी अन्य पोस्ट Installing signal handler with Python का अनुवर्ती है। संक्षेप में, लिनक्स पीआईडी ​​1 (सिगकिल समेत) के सभी संकेतों को अवरुद्ध करता है जब तक कि इनिट ने किसी विशेष सिग्नल के लिए सिग्नल हैंडलर स्थापित नहीं किया हो; कर्नेल आतंक को रोकने के लिए अगर कोई पीआईडी ​​1 को समाप्ति संकेत भेजना चाहता था। मेरे पास जो मुद्दा है, ऐसा लगता है कि पाइथन में signal मॉड्यूल सिग्नल हैंडलर को सिस्टम पहचानने के तरीके में स्थापित नहीं करता है। मेरी पायथन इनिट स्क्रिप्ट सभी संकेतों को पूरी तरह से अनदेखा कर रही थी, क्योंकि मुझे लगता है कि उन्हें अवरुद्ध किया जा रहा है।पाइथन इनिट

मुझे लगता है कि एक समाधान मिला है; libc में signal() फ़ंक्शन के साथ सिग्नल हैंडलर स्थापित करने के लिए ctypes का उपयोग करके (इस मामले में uClibc)। नीचे एक अजगर आधारित परीक्षण init है। यह टीटीवी 2 पर एक खोल खोलता है जिससे मैं परीक्षण के लिए पीआईडी ​​1 को सिग्नल भेज सकता हूं। यह परीक्षण के लिए उपयोग कर रहे केवीएम आईएम में काम करता है (मैं रुचि रखने वाले किसी के साथ वीएम साझा करने के लिए तैयार हूं)

क्या यह इस मुद्दे के आसपास सबसे अच्छा तरीका है? सिग्नल मॉड्यूल के बिना सिग्नल हैंडलर स्थापित करने के लिए 'बेहतर' तरीका है? (मैं पोर्टेबल से बिल्कुल चिंतित नहीं हूं)

क्या यह पाइथन में एक बग है?

#!/usr/bin/python 

import os 
import sys 
import time 

from ctypes import * 

def SigHUP(): 
    print "Caught SIGHUP" 
    return 0 

def SigCHLD(): 
    print "Caught SIGCHLD" 
    return 0 

SIGFUNC = CFUNCTYPE(c_int) 
SigHUPFunc = SIGFUNC(SigHUP) 
SigCHLDFunc = SIGFUNC(SigCHLD) 

libc = cdll.LoadLibrary('libc.so.0') 
libc.signal(1, SigHUPFunc) # 1 = SIGHUP 
libc.signal(17, SigCHLDFunc) # 17 = SIGCHLD 

print "Mounting Proc: %s" % libc.mount(None, "/proc", "proc", 0, None) 

print "forking for ash" 
cpid = os.fork() 
if cpid == 0: 
    os.closerange(0, 4) 
    sys.stdin = open('/dev/tty2', 'r') 
    sys.stdout = open('/dev/tty2', 'w') 
    sys.stderr = open('/dev/tty2', 'w') 
    os.execv('/bin/ash', ('ash',)) 

print "ash started on tty2" 

print "sleeping" 
while True: 
    time.sleep(0.01) 
+0

यह वास्तव में codereview.SE पर है, लेकिन पाइथन में 'init' को लागू करने के अच्छे विचार के लिए +1 है। –

+0

मैंने सोचा कि शायद मुझे कहां पोस्ट करना चाहिए, लेकिन मैं ऐसा करने के इस तरीके पर सेट नहीं हूं और सोचा कि ऐसे कई विचार हो सकते हैं जिनके बारे में मैंने सोचा था। – tMC

उत्तर

6

मैं केवीएम के तहत डिबगिंग का एक सा था और मैंने पाया कि गिरी 1 pid को पहुंचाने संकेतों जब संकेत संचालकों मानक संकेत मॉड्यूल द्वारा स्थापित कर रहे हैं है। हालांकि, जब संकेत प्राप्त होता है तो "कुछ" अपेक्षित आउटपुट प्रिंट करने की बजाय प्रक्रिया के क्लोन को उत्पन्न करने का कारण बनता है।

यहाँ strace उत्पादन होता है जब मैं करने के लिए HUP भेज गैर काम init.sig-आधुनिक:

strace output

कौन सा एक नई प्रक्रिया में जो परिणाम चल (पीआईडी ​​23) जो init का क्लोन है हस्ताक्षर-आधुनिक:

clone of init as pid 23

मैं कारण में गहरी खुदाई करने के लिए समय नहीं था, लेकिन यह बातें आगे सीमित कर देता है। शायद पाइथन के सिग्नल डिलीवरी तर्क के साथ कुछ करने के लिए (यह एक सी हुक पंजीकृत करता है जो आपके बाइटकोड फ़ंक्शन को बुलाता है)। Ctypes तकनीक इसे छोड़ देता है। यदि आप नज़दीकी रूप से देखना चाहते हैं तो प्रासंगिक पायथन स्रोत फ़ाइलें Python/pythonrun.c और Modules/signalmodule.c हैं।

पुरानी जानकारी - मुझे यकीन नहीं है कि यह आपकी समस्या का समाधान करेगा, लेकिन आपको करीब मिल सकता है। I इन विभिन्न तरीकों की तुलना में सिग्नल हैंडलर स्थापित हैं:

  • पायथन के सिग्नल मॉड्यूल के माध्यम से एक हैंडलर स्थापित करना।
  • अपस्टार्ट के सिग्नल हैंडलर।
  • signal() सिस्कोल को सीधे कॉल करने के लिए ctypes का उपयोग करना।
  • सी

दोनों में कुछ त्वरित परीक्षण ctypes-लागू signal() सिस्टम कॉल और कल का नवाब के sigaction() syscalls जब हैंडलर पंजीकृत है SA_RESTART ध्वज सेट। सेट करने से यह ध्वज इंगित करता है कि जब सिग्नल हैंडलर पूरा हो जाता है तो सिग्नल स्वचालित रूप से पुनरारंभ होने के बाद प्रक्रिया को निष्पादित या अवरुद्ध करने के दौरान एक सिग्नल प्राप्त होता है (पढ़ना, लिखना, प्रतीक्षा करना, नैनोस्लीप आदि)। आवेदन इस से अवगत नहीं होगा।

जब पायथन का सिग्नल मॉड्यूल एक हैंडलर पंजीकृत करता है, तो यह siginterrupt(signum, 1) पर कॉल करके SA_RESTART ध्वज को शून्य करता है। यह सिस्टम को कहता है "जब सिस्टम कॉल सिग्नल द्वारा बाधित होता है, सिग्नल हैंडलर को EINTR को इरनो सेट करता है और सिस्कल से वापस लौटाता है"। यह इसे पर डेवलपर तक छोड़ देता है और यह तय करता है कि सिस्टम कॉल को पुनरारंभ करना है या नहीं।

आप अपने संकेत इस तरह से पंजीकरण से SA_RESTART ध्वज सेट कर सकते हैं:

import signal 
signal.signal(signal.SIGHUP, handler) 
signal.siginterrupt(signal.SIGHUP, False) 
+0

मैं इसे आजमाने की चिंतित हूं- भले ही यह इस समस्या को हल न करे, यह बहुत अच्छा संदर्भ है! एक बार मुझे परीक्षण करने का मौका मिलने के बाद मैं फिर से टिप्पणी करूंगा। – tMC

+0

यह काम नहीं करता- हालांकि विचार के लिए धन्यवाद, बहुत अंतर्दृष्टि – tMC

+0

ठीक है, लेकिन यह स्पष्ट करने के लिए: आपके ctypes- आधारित init कोड काम कर रहा है, है ना? – samplebias

1

मुद्दा वर्ष linux धागे के साथ uclibc 0.9.31 के खिलाफ संकलित अजगर के साथ एक संगतता मुद्दा था। 0.9.32-आरसी 3 के खिलाफ संकलन और एनपीटीएल का उपयोग करने से इस मुद्दे को ठीक किया गया है।

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