2013-03-05 11 views
5

का उपयोग कर wiringPi 'सी' पुस्तकालय में एक समारोह नहीं है प्रकारआयात करना हास्केल में 'सी' देरी समारोह FFI

void delay(unsigned int howLong);

इस समारोह howLong मिलीसेकंड के लिए कोड के निष्पादन देरी के साथ delay कहा जाता है। मैंने इस फ़ंक्शन को कॉल करने में सक्षम होने के लिए हैकेल में बाइंडिंग कोड लिखा है। हैकेल कोड निम्नानुसार है,

foreign import ccall "wiringPi.h delay" c_delay :: CUInt -> IO() 
hdelay :: Int -> IO() 
hdelay howlong = c_delay (fromIntegral howlong) 

इसके बाद, मैंने इस फ़ंक्शन को कॉल करने के लिए एक सरल हैकेल प्रोग्राम लिखा था। बस Haskell कोड इस प्रकार मैं

main = wiringPiSetup 
    >> delay 5000 

किया है .. प्रासंगिक पुस्तकालयों का आयात --After

लेकिन देरी नहीं होता है या बल्कि GHC संकलक द्वारा उत्पन्न निष्पादन तुरंत बाहर निकालता है।

क्या कोई मुझे बता सकता है कि यहां संभवतः गलत क्या हो सकता है? सही दिशा में एक छोटा सा झुकाव मदद करेगा।

चीयर्स और सम्मान।

+2

मैं क्या कारण है पता नहीं है, लेकिन (का उपयोग करते हुए 'usleep', के बाद से मैं कोई wiringPi है) GHC के लिए गैर पिरोया आरटीएस के साथ, <= 7.2। *, यह इंतजार कर रहा है जब तक नींद है ऊपर। थ्रेडेड आरटीएस के साथ, या जीएचसी> = 7.4 के साथ, यह तुरंत निकलता है। शायद एक बग, लेकिन मुझे नहीं पता कि पुराने जीएचसी या नए में से कोई एक है या नहीं। –

+0

वायरिंगपी के हेडर वायरिंग नहीं है Pi.h? –

+1

@ डैनियल फिशर: क्या इसे नए जीएचसी/थ्रेडेड आरटीएस में एक बग नहीं होना चाहिए? क्या यह व्यवहार इस बात का तात्पर्य नहीं है कि एक कार्यक्रम में अंतिम कार्रवाई के रूप में सुरक्षित रूप से एक समारोह को कॉल करना असंभव है, क्योंकि इस बात की कोई गारंटी नहीं होगी कि यह समाप्त हो गया है? –

उत्तर

2

ब्लॉक उद्धरण में भाग को अनदेखा करें, और नीचे अपडेट देखें - मैं इसके साथ जुड़े टिप्पणियों के कारण मूल गैर-समाधान को संरक्षित कर रहा हूं।

आप unsafe रूप import निशान के बाद से आप मुख्य धागा, जबकि समारोह निष्पादित हो रहा है ( @carl से नीचे टिप्पणी देखें) ब्लॉक करना चाहते हैं चाहिए। डिफ़ॉल्ट रूप से, आयात safe है, unsafe नहीं।

foreign import ccall unsafe "wiring.h delay" c_delay :: CUInt -> IO() 

इसके अलावा, अगर आप मल्टी-थ्रेडेड कोड लिखने की योजना है, GHC docs for multi-threaded FFI> बहुत उपयोगी: तो, समारोह हस्ताक्षर बदलते इस को मुख्य थ्रेड ब्लॉक बनाना चाहिए। This भी एक अच्छा स्टार्टर लगता है।

अद्यतन

व्यवहार (अगर मैं सही ढंग से याद करते हैं, इस GHC में जोड़ा गया 7.4+ कुछ कीड़े को ठीक करने) का संकेत करने के व्यवधान से निपटने की वजह से हो रहा है। यहां अधिक जानकारी: http://hackage.haskell.org/trac/ghc/wiki/Commentary/Rts/Signals

कृपया उपरोक्त पृष्ठ पर टिप्पणी दें: Signal handling differs between the threaded version of the runtime and the non-threaded version

दृष्टिकोण 1 - एफएफआई कोड में संभाल संकेत संभाल: एक खिलौना कोड नीचे है जो नींद में बाधा को नियंत्रित करता है। मैंने इसे गीक 7.6.1 के साथ लिनक्स 2.6.18 पर परीक्षण किया।

सी कोड:

/** ctest.c **/ 
#include <unistd.h> 
#include <stdio.h> 
#include <time.h> 

unsigned delay(unsigned sec) 
{ 
    struct timespec req={0}; 
    req.tv_sec = sec; 
    req.tv_nsec = 0; 

    while (nanosleep(&req, &req) == -1) { 
    printf("Got interrupt, continuing\n"); 
    continue; 
    } 
    return 1; 
} 

हास्केल कोड:

{-# LANGUAGE ForeignFunctionInterface #-} 
-- Filename Test.hs 
module Main (main) where 
import Foreign.C.Types 

foreign import ccall safe "delay" delay :: CUInt -> IO CUInt 

main = do 
    putStrLn "Sleeping" 
    n <- delay 2000 
    putStrLn $ "Got return code from sleep: " ++ show n 

अब, GHC 7.6 के साथ संकलन के बाद।1 (आदेश: ghc Test.hs ctest.c), यह नींद खत्म होने तक इंतजार कर रहा है, और संदेश हर बार नींद के समय व्यवधान संकेत हो जाता है प्रिंट:

./Test 
Sleeping 
Got interrupt, continuing 
Got interrupt, continuing 
Got interrupt, continuing 
Got interrupt, continuing 
.... 
.... 
Got return code from sleep: 1 

दृष्टिकोण 2 - अक्षम SIGVTALRM FFI कोड कॉल करने से पहले, और पुन: सक्षम :

मुझे यकीन नहीं है कि SIGVTALRM को अक्षम करने के लिए क्या प्रभाव हैं। यह वैकल्पिक दृष्टिकोण है जो एफएफआई कॉल के दौरान एसआईजीवीटीएएलआरएम को अक्षम करता है, अगर आप एफएफआई कोड को बदल नहीं सकते हैं। इसलिए, नींद के दौरान एफएफआई कोड बाधित नहीं होता है (माना जाता है कि यह सिग्वाल्ट्रम है जो बाधा उत्पन्न कर रहा है)।

{-# LANGUAGE ForeignFunctionInterface #-} 
-- Test.hs 
module Main (main) where 
import Foreign.C.Types 
import System.Posix.Signals 

foreign import ccall safe "delay" delay :: CUInt -> IO CUInt 

main = do 
    putStrLn "Sleeping" 
    -- Block SIGVTALRM temporarily to avoid interrupts while sleeping 
    blockSignals $ addSignal sigVTALRM emptySignalSet 
    n <- delay 2 
    putStrLn $ "Got return code from sleep: " ++ show n 
    -- Unblock SIGVTALRM 
    unblockSignals $ addSignal sigVTALRM emptySignalSet 
    return() 
+2

क्या कहें? जो चीजें ब्लॉक करती हैं उन्हें 'सुरक्षित' होना चाहिए, न कि 'असुरक्षित'। चीजें जो 'असुरक्षित' हैं, निष्पादन संदर्भ को अवरुद्ध करते समय अन्य धागे पर स्विच करने से रोकती हैं। साइड इफेक्ट के रूप में, इसका मतलब यह है कि वे जीसी ऑपरेशंस को ब्लॉक करते समय भी चलने से रोकते हैं, जिसका मतलब है कि वे आरटीएस में * सभी * थ्रेड रोक सकते हैं। – Carl

+1

@ करल, निष्पादन संदर्भ स्विचिंग के बारे में अच्छा बिंदु। जैसा कि मैं इसे समझता हूं, 'सुरक्षित' और 'असुरक्षित' कॉल के बीच मुख्य अंतर यह है कि किसी भी कोड के लिए 'सुरक्षित' का उपयोग किया जाना चाहिए जो वापस कॉल कर सकता है। मैं निष्पादन संदर्भ स्विच का उपयोग करने के लिए शब्द को अद्यतन कर दूंगा। – Sal

+1

जीएचसी दस्तावेज कहता है: इसका मतलब है कि यदि आपको किसी ऐसे फ़ंक्शन पर विदेशी कॉल करने की आवश्यकता है जो अनिश्चित काल तक लंबे समय तक या ब्लॉक करता है, तो आपको इसे 'सुरक्षित' चिह्नित करना चाहिए और '-थ्रेडेड' का उपयोग करना चाहिए। इसलिए मुझे नहीं लगता कि 'असुरक्षित' का उपयोग किया जाना चाहिए। – nymk

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