2014-04-24 8 views
5

पर लिखने के दौरान पावरफेल अनुक्रम का डेडलॉक मैं वर्तमान में एआरएम कॉर्टेक्स एम 3 माइक्रोकंट्रोलर का उपयोग कर एक एम्बेडेड प्रोजेक्ट पर काम कर रहा हूं जिसमें फ्री ओएस के साथ फ्रीआरटीओएस है। कोड एक पूर्व सहयोगी द्वारा लिखा गया था और दुख की बात है कि इस परियोजना में कुछ अजीब बग हैं जिन्हें मुझे जल्द से जल्द ढूंढना और ठीक करना है।फ्लैश पेज

संक्षिप्त विवरण: डिवाइस को वाहनों में एकीकृत किया गया है और एक दूरस्थ सर्वर पर एक एकीकृत मॉडेम का उपयोग करके कुछ "विशेष" डेटा भेजता है।

मुख्य समस्या: चूंकि डिवाइस को वाहन में एकीकृत किया गया है, डिवाइस की बिजली आपूर्ति किसी भी समय खो जा सकती है। इसलिए डिवाइस "विशेष" डेटा के कुछ हिस्सों को दो आरक्षित फ़्लैश पृष्ठों पर संग्रहीत करता है। यह कोड मॉड्यूल दो फ़्लैश पृष्ठों पर एक ईप्राम इम्यूलेशन के रूप में रखा गया है (पहनने के स्तर और एक फ्लैश पेज से दूसरे डेटा स्थानांतरण के लिए)। eeprom इम्यूलेशन तथाकथित "आभासी पते" के साथ काम करता है, जहां आप वर्तमान में सक्रिय/मान्य फ़्लैश पृष्ठ पर किसी भी आकार के डेटा ब्लॉक लिख सकते हैं और उन वर्चुअल पतों का उपयोग करके इसे वापस पढ़ सकते हैं। पूर्व सहयोगी ने एप्राम इम्यूलेशन को मल्टीटास्किंग मॉड्यूल के रूप में कार्यान्वित किया, जहां आप एप्लिकेशन में प्रत्येक कार्य से फ़्लैश पृष्ठों को पढ़/लिख सकते हैं। पहली नजर में सबकुछ ठीक लगता है।

लेकिन मेरे प्रोजेक्ट मैनेजर ने मुझे बताया कि डिवाइस हमेशा कुछ खास "विशेष" डेटा खो देता है, जहां वाहन में बिजली की आपूर्ति का स्तर कुछ वोल्ट तक चला जाता है और डिवाइस डेटा को फ्लैश करने की कोशिश करता है। आम तौर पर बिजली की आपूर्ति लगभग 10-18 वोल्ट होती है, लेकिन यदि यह 7 वोल्ट से कम हो जाती है, तो डिवाइस को powerwarn नामक एक इंटरप्ट प्राप्त होता है और यह powerfail task नामक एक कार्य को ट्रिगर करता है। powerfail task में सभी कार्यों की सर्वोच्च प्राथमिकता है और कुछ कॉलबैक निष्पादित करता है जहां उदा। मॉडेम बंद हो गया है और जहां फ़्लैश पेज में "विशेष" डेटा संग्रहीत किया जाता है। मैं कोड समझने की कोशिश की और दिन/सप्ताह के लिए डिबग और अब मैं काफी यकीन है कि मैं इस समस्या पाया हूँ:

उन कॉलबैक जो powerfail कार्य निष्पादित (powerfail कॉलबैक कहा जाता है) के भीतर, देखते हैं RTOS कहता है, जहां अन्य कार्यों को निलंबित कर दिया जाता है। लेकिन दुर्भाग्य से उन प्रस्तावित कार्य में पावरवार्न इंटरप्ट प्राप्त होने से ठीक पहले एक अधूरा EEPROM_WriteBlock() कॉल भी हो सकता है। इसलिए पावरफेल कार्य कॉलबैक निष्पादित करता है और कॉलबैक में से एक में EE_WriteBlock() कॉल होता है जहां कार्य EE_WriteBlock() में म्यूटेक्स नहीं ले सकता है क्योंकि एक अन्य कार्य (जिसे निलंबित कर दिया गया था) ने इसे पहले से ही लिया है -> डेडलॉक!

यह दिनचर्या फ्लैश के लिए डेटा लिखने के लिए है:

uint16_t 
EE_WriteBlock (EE_TypeDef *EE, uint16_t VirtAddress, const void *Data, uint16_t Size) 
{ 
    . 
    . 
    xSemaphoreTakeRecursive(EE->rw_mutex, portMAX_DELAY); 
    /* Write the variable virtual address and value in the EEPROM */ 
    . 
    . 
    . 
    xSemaphoreGiveRecursive(EE->rw_mutex); 
    return Status; 
} 

इस RTOS विशिष्ट कोड जब 'xSemaphoreTakeRecursive()' कहा जाता है:

portBASE_TYPE xQueueTakeMutexRecursive(xQueueHandle pxMutex, portTickType xBlockTime) 
{ 
    portBASE_TYPE xReturn; 

    /* Comments regarding mutual exclusion as per those within 
     xQueueGiveMutexRecursive(). */ 
    traceTAKE_MUTEX_RECURSIVE(pxMutex); 

    if(pxMutex->pxMutexHolder == xTaskGetCurrentTaskHandle()) 
    { 
     (pxMutex->uxRecursiveCallCount)++; 
     xReturn = pdPASS; 
    } 
    else 
    { 
     xReturn = xQueueGenericReceive(pxMutex, NULL, xBlockTime, pdFALSE); 

     /* pdPASS will only be returned if we successfully obtained the mutex, 
      we may have blocked to reach here. */ 
     if(xReturn == pdPASS) 
     { 
      (pxMutex->uxRecursiveCallCount)++; 
     } 
     else 
     { 
      traceTAKE_MUTEX_RECURSIVE_FAILED(pxMutex); 
     } 
    } 

    return xReturn; 
} 

मेरे परियोजना प्रबंधक खुश है कि मैं मुझे बग मिला है लेकिन वह मुझे जितनी जल्दी हो सके एक फिक्स बनाने के लिए मजबूर करता है, लेकिन जो मैं वास्तव में चाहता हूं वह कोड का पुनर्लेखन है। शायद आप में से एक सोच सकता है, बस अन्य कार्यों के निलंबन से बचें और आप कर चुके हैं, लेकिन यह एक संभावित समाधान नहीं है, क्योंकि यह एक और बग ट्रिगर कर सकता है। क्या किसी के पास त्वरित समाधान/विचार है कि मैं इस डेडलॉक समस्या को कैसे ठीक कर सकता हूं? शायद में xTaskGetCurrentTaskHandle() का उपयोग यह निर्धारित करने के लिए कर सकता है कि म्यूटेक्स का स्वामित्व किसके पास है और फिर यह कार्य तब नहीं चल रहा है जब कार्य अब नहीं चल रहा है।

Thx

उत्तर

5

लेखन फ्लैश, कई सिस्टम पर, बीच में आता है की आवश्यकता है लिखने की अवधि के लिए अक्षम होने तो मुझे यकीन है कि कैसे powerFail जबकि कार्य प्रगति पर है एक लिखने चल बनाया जा सकता है नहीं कर रहा हूँ, लेकिन वैसे भी:

सीधे म्यूटेक्स के साथ आरक्षित फ़्लैश पृष्ठों तक पहुंच को नियंत्रित न करें - इसके बजाय अवरुद्ध निर्माता-उपभोक्ता कतार का उपयोग करें।

उन सभी को एक 'फ्लैशवाइटर' धागे को लिखने के अनुरोधों को अस्वीकार कर दें। यदि लिखने का अनुरोध करने वाले थ्रेड सिंक्रोनस एक्सेस की आवश्यकता होती है, तो अनुरोध अनुरोध में एक ईवेंट या सेमफोर शामिल करें कि अनुरोध थ्रेड इसके अनुरोध को दबाए जाने के बाद प्रतीक्षा करता है। फ्लैशवाइटर इसे पूरा करने पर संकेत दे सकता है, (या त्रुटि संकेत के साथ संरचना लोड करने के बाद :)।

थीम पर भिन्नताएं हैं - यदि सभी लिखने वाले थ्रेडों को केवल सिंक्रोनस एक्सेस की आवश्यकता होती है, तो हो सकता है कि वे अपने स्वयं के सैमफोर के साथ अपनी स्थिर अनुरोध संरचना रख सकें और बस इसके लिए एक पॉइंटर कतार दें।

एक निर्माता-उपभोक्ता कतार वर्ग का उपयोग करें जो कतार के सिर पर उच्च प्राथमिकता वाले धक्का की अनुमति देता है, और जब पावरफेल चलता है, तो कतार के सामने 'स्टॉपवाइटिंग' अनुरोध दबाएं। फ्लैशवाइटर फिर प्रगति पर किसी भी लेखन ऑपरेशन को पूरा करेगा, स्टॉप लिखने के अनुरोध को पॉप करें और इसलिए स्वयं को निलंबित करने का निर्देश दिया जाए, (या आप 'स्टॉप' अस्थिर बूलियन का उपयोग कर सकते हैं कि फ्लैशवाइटर कतार को पॉप करने का प्रयास करने से पहले हर बार जांचता है)।

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

संपादित करें: मैं सिर्फ दो और कॉफी किया है और, इस के बारे में सोच, 'flashWriter' धागा आसानी से 'FlashWriterAndPowerFail' धागा बन सकता है:

तुम एक वापस जाने के लिए अपने निर्माता-उपभोक्त कतार की व्यवस्था कर सकता है पॉप() नल का नतीजा अगर अस्थिर 'स्टॉप' बूलियन सेट किया गया है, इससे कोई फर्क नहीं पड़ता कि कतार या नहीं पर प्रविष्टियां थीं। 'एफडब्ल्यूएपीएफ' थ्रेड में, प्रत्येक पॉप() रिटर्न के बाद एक नल-चेक करें और पावरफेल क्रियाएं शून्य या फ्लैश पर क्रियाएं करें, अगर नहीं।

जब पावरफेल बाधा उत्पन्न होती है, तो स्टॉप बूल सेट करें और कतार में 'गिनती' सेमफोर को सिग्नल करें ताकि यह सुनिश्चित किया जा सके कि FWAPF थ्रेड चल रहा है यदि यह वर्तमान में कतार पर अवरुद्ध है।

इस तरह, आपको एक अलग 'पावरफेल' थ्रेड और स्टैक की आवश्यकता नहीं है - एक धागा फ्लैशवाइट और पावरफेल कर सकता है जबकि अभी भी यह सुनिश्चित कर रहा है कि कोई म्यूटेक्स डेडलॉक्स नहीं है।

+0

+1 यही वही है जो मैं प्रस्तावित करता हूं। लेखन एक ही बाधा में किया जाना चाहिए, अन्य सभी स्तरों को केवल कतार अनुरोध करना चाहिए। यदि आप उन्हें प्राथमिकता देने की अनुमति भी देते हैं, तो अन्य लोगों के सामने एक "महत्वपूर्ण" अनुरोध निष्पादित किया जा सकता है। – Groo

+0

क्षमा करें, मैं उल्लेख करना भूल गया: जब मुझे पावरवॉर्न इंटरप्ट को पावरफेल कार्यों को कॉलबैक निष्पादित करना प्रारंभ होता है, लेकिन इंटरप्ट/इंटरप्ट अक्षम होते हैं। – arge

+0

@arge - हाँ, मैंने अनुमान लगाया :) मेरा पहला विचार था कि 'अन्य कार्यों को निलंबित न करें ताकि वे म्यूटेक्स को छोड़ दें', लेकिन यह हस्तक्षेप के साथ काम नहीं कर सकता है :(फिर मैंने बेहतर विचार के बारे में सोचा .. –

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