तेज़ संदेश कतार (एफएमक्यू)

यदि आप एआईडीएल समर्थन की तलाश में हैं, तो एआईडीएल के साथ एफएमक्यू भी देखें।

HIDL का रिमोट प्रोसीजर कॉल (RPC) इंफ्रास्ट्रक्चर बाइंडर तंत्र का उपयोग करता है, जिसका अर्थ है कि कॉल में ओवरहेड शामिल होता है, कर्नेल संचालन की आवश्यकता होती है, और शेड्यूलर कार्रवाई को ट्रिगर कर सकता है। हालाँकि, ऐसे मामलों के लिए जहां डेटा को कम ओवरहेड और बिना कर्नेल भागीदारी वाली प्रक्रियाओं के बीच स्थानांतरित किया जाना चाहिए, फास्ट मैसेज क्यू (एफएमक्यू) प्रणाली का उपयोग किया जाता है।

एफएमक्यू वांछित गुणों के साथ संदेश कतार बनाता है। एक MQDescriptorSync या MQDescriptorUnsync ऑब्जेक्ट को HIDL RPC कॉल पर भेजा जा सकता है और संदेश कतार तक पहुंचने के लिए प्राप्तकर्ता प्रक्रिया द्वारा उपयोग किया जा सकता है।

तेज़ संदेश कतारें केवल C++ और Android 8.0 और उच्चतर चलाने वाले उपकरणों पर समर्थित हैं।

MessageQueue प्रकार

एंड्रॉइड दो कतार प्रकारों का समर्थन करता है (जिन्हें फ्लेवर के रूप में जाना जाता है):

  • अनसिंक्रनाइज़्ड कतारों को अतिप्रवाह की अनुमति है, और उनके कई पाठक हो सकते हैं; प्रत्येक पाठक को समय पर डेटा पढ़ना होगा या इसे खोना होगा।
  • सिंक्रोनाइज़्ड कतारों को अतिप्रवाह की अनुमति नहीं है, और उनमें केवल एक रीडर हो सकता है।

दोनों कतार प्रकारों को अंडरफ्लो होने की अनुमति नहीं है (खाली कतार से पढ़ना विफल हो जाएगा) और केवल एक लेखक हो सकता है।

अनसिंक्रनाइज़्ड

एक अनसिंक्रनाइज़्ड कतार में केवल एक लेखक होता है, लेकिन इसमें पाठकों की संख्या कोई भी हो सकती है। कतार के लिए एक लिखने की स्थिति है; हालाँकि, प्रत्येक पाठक अपनी स्वतंत्र पठन स्थिति पर नज़र रखता है।

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

कतार के अंत से गिरने से पहले डेटा को पुनः प्राप्त करने के लिए पाठक जिम्मेदार हैं। एक रीड जो उपलब्ध डेटा से अधिक डेटा पढ़ने का प्रयास करता है वह या तो तुरंत विफल हो जाता है (यदि ब्लॉक नहीं किया जा रहा है) या पर्याप्त डेटा उपलब्ध होने की प्रतीक्षा करता है (यदि ब्लॉक कर रहा है)। एक रीड जो कतार क्षमता से अधिक डेटा पढ़ने का प्रयास करता है वह हमेशा तुरंत विफल हो जाता है।

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

अनसिंक्रनाइज़्ड कतार के पाठक संभवतः कतार के पढ़ने और लिखने वाले पॉइंटर्स को रीसेट नहीं करना चाहते हैं। इसलिए, डिस्क्रिप्टर से कतार बनाते समय पाठकों को `resetPointers` पैरामीटर के लिए `गलत` तर्क का उपयोग करना चाहिए।

सिंक्रनाइज़

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

एफएमक्यू की स्थापना

एक संदेश कतार के लिए कई MessageQueue ऑब्जेक्ट की आवश्यकता होती है: एक को लिखा जाना चाहिए, और एक या अधिक से पढ़ा जाना चाहिए। लिखने या पढ़ने के लिए किस वस्तु का उपयोग किया जाता है इसका कोई स्पष्ट विन्यास नहीं है; यह सुनिश्चित करना उपयोगकर्ता पर निर्भर है कि पढ़ने और लिखने दोनों के लिए किसी ऑब्जेक्ट का उपयोग नहीं किया जाता है, अधिकतम एक लेखक होता है, और, सिंक्रनाइज़ कतारों के लिए, अधिकतम एक पाठक होता है।

पहला MessageQueue ऑब्जेक्ट बनाना

एक संदेश कतार एक ही कॉल से बनाई और कॉन्फ़िगर की जाती है:

#include <fmq/MessageQueue.h>
using android::hardware::kSynchronizedReadWrite;
using android::hardware::kUnsynchronizedWrite;
using android::hardware::MQDescriptorSync;
using android::hardware::MQDescriptorUnsync;
using android::hardware::MessageQueue;
....
// For a synchronized non-blocking FMQ
mFmqSynchronized =
  new (std::nothrow) MessageQueue<uint16_t, kSynchronizedReadWrite>
      (kNumElementsInQueue);
// For an unsynchronized FMQ that supports blocking
mFmqUnsynchronizedBlocking =
  new (std::nothrow) MessageQueue<uint16_t, kUnsynchronizedWrite>
      (kNumElementsInQueue, true /* enable blocking operations */);
  • MessageQueue<T, flavor>(numElements) इनिशियलाइज़र एक ऑब्जेक्ट बनाता है और आरंभ करता है जो संदेश कतार कार्यक्षमता का समर्थन करता है।
  • MessageQueue<T, flavor>(numElements, configureEventFlagWord) इनिशियलाइज़र एक ऑब्जेक्ट बनाता है और प्रारंभ करता है जो ब्लॉकिंग के साथ संदेश कतार कार्यक्षमता का समर्थन करता है।
  • flavor या तो सिंक्रनाइज़ कतार के लिए kSynchronizedReadWrite या अनसिंक्रोनाइज्ड कतार के लिए kUnsynchronizedWrite हो सकता है।
  • uint16_t (इस उदाहरण में) कोई भी HIDL-परिभाषित प्रकार हो सकता है जिसमें नेस्टेड बफ़र्स (कोई string या vec प्रकार नहीं), हैंडल या इंटरफ़ेस शामिल नहीं है।
  • kNumElementsInQueue प्रविष्टियों की संख्या में कतार के आकार को इंगित करता है; यह साझा मेमोरी बफ़र का आकार निर्धारित करता है जिसे कतार के लिए आवंटित किया जाएगा।

दूसरा MessageQueue ऑब्जेक्ट बनाना

संदेश कतार का दूसरा पक्ष पहली ओर से प्राप्त MQDescriptor ऑब्जेक्ट का उपयोग करके बनाया गया है। MQDescriptor ऑब्जेक्ट को HIDL या AIDL RPC कॉल पर उस प्रक्रिया में भेजा जाता है जो संदेश कतार के दूसरे छोर को होल्ड करेगी। MQDescriptor कतार के बारे में जानकारी शामिल है, जिसमें शामिल हैं:

  • बफ़र को मैप करने और पॉइंटर लिखने की जानकारी।
  • रीड पॉइंटर को मैप करने की जानकारी (यदि कतार सिंक्रनाइज़ है)।
  • इवेंट फ़्लैग शब्द को मैप करने की जानकारी (यदि कतार अवरुद्ध हो रही है)।
  • ऑब्जेक्ट प्रकार ( <T, flavor> ), जिसमें एचआईडीएल-परिभाषित प्रकार के कतार तत्व और कतार फ्लेवर (सिंक्रनाइज़ या अनसिंक्रनाइज़्ड) शामिल हैं।

MQDescriptor ऑब्जेक्ट का उपयोग MessageQueue ऑब्जेक्ट बनाने के लिए किया जा सकता है:

MessageQueue<T, flavor>::MessageQueue(const MQDescriptor<T, flavor>& Desc, bool resetPointers)

resetPointers पैरामीटर इंगित करता है कि इस MessageQueue ऑब्जेक्ट को बनाते समय पढ़ने और लिखने की स्थिति को 0 पर रीसेट करना है या नहीं। एक अनसिंक्रनाइज़्ड कतार में, पढ़ने की स्थिति (जो अनसिंक्रनाइज़्ड कतारों में प्रत्येक MessageQueue ऑब्जेक्ट के लिए स्थानीय है) निर्माण के दौरान हमेशा 0 पर सेट होती है। आमतौर पर, MQDescriptor पहली संदेश कतार ऑब्जेक्ट के निर्माण के दौरान प्रारंभ किया जाता है। साझा मेमोरी पर अतिरिक्त नियंत्रण के लिए, आप MQDescriptor मैन्युअल रूप से सेट कर सकते हैं ( MQDescriptor system/libhidl/base/include/hidl/MQDescriptor.h में परिभाषित किया गया है) फिर इस अनुभाग में वर्णित प्रत्येक MessageQueue ऑब्जेक्ट बनाएं।

कतारों और इवेंट झंडों को अवरुद्ध करना

डिफ़ॉल्ट रूप से, कतारें पढ़ने/लिखने को अवरुद्ध करने का समर्थन नहीं करती हैं। पढ़ने/लिखने की कॉल को ब्लॉक करने के दो प्रकार हैं:

  • संक्षिप्त रूप , तीन मापदंडों (डेटा सूचक, वस्तुओं की संख्या, टाइमआउट) के साथ। एकल कतार पर व्यक्तिगत पढ़ने/लिखने के संचालन को अवरुद्ध करने का समर्थन करता है। इस फॉर्म का उपयोग करते समय, कतार ईवेंट ध्वज और बिटमास्क को आंतरिक रूप से संभाल लेगी, और पहली संदेश कतार ऑब्जेक्ट को true के दूसरे पैरामीटर के साथ प्रारंभ किया जाना चाहिए। उदाहरण के लिए:
    // For an unsynchronized FMQ that supports blocking
    mFmqUnsynchronizedBlocking =
      new (std::nothrow) MessageQueue<uint16_t, kUnsynchronizedWrite>
          (kNumElementsInQueue, true /* enable blocking operations */);
    
  • छह मापदंडों के साथ लंबा फॉर्म (ईवेंट ध्वज और बिटमास्क शामिल हैं)। कई कतारों के बीच एक साझा EventFlag ऑब्जेक्ट का उपयोग करने का समर्थन करता है और अधिसूचना बिट मास्क का उपयोग करने के लिए निर्दिष्ट करने की अनुमति देता है। इस मामले में, प्रत्येक पढ़ने और लिखने की कॉल के लिए इवेंट फ़्लैग और बिटमास्क की आपूर्ति की जानी चाहिए।

लंबे फॉर्म के लिए, EventFlag प्रत्येक readBlocking() और writeBlocking() कॉल में स्पष्ट रूप से प्रदान किया जा सकता है। कतारों में से एक को आंतरिक ईवेंट ध्वज के साथ आरंभ किया जा सकता है, जिसे getEventFlagWord() का उपयोग करके उस कतार के MessageQueue ऑब्जेक्ट से निकाला जाना चाहिए और अन्य FMQ के साथ उपयोग के लिए प्रत्येक प्रक्रिया में EventFlag ऑब्जेक्ट बनाने के लिए उपयोग किया जाना चाहिए। वैकल्पिक रूप से, EventFlag ऑब्जेक्ट को किसी भी उपयुक्त साझा मेमोरी के साथ प्रारंभ किया जा सकता है।

सामान्य तौर पर, प्रत्येक कतार को नॉन-ब्लॉकिंग, शॉर्ट-फॉर्म ब्लॉकिंग, या लॉन्ग-फॉर्म ब्लॉकिंग में से केवल एक का उपयोग करना चाहिए। उन्हें मिश्रित करना कोई त्रुटि नहीं है, लेकिन वांछित परिणाम प्राप्त करने के लिए सावधानीपूर्वक प्रोग्रामिंग की आवश्यकता होती है।

स्मृति को केवल पढ़ने योग्य के रूप में चिह्नित करना

डिफ़ॉल्ट रूप से, साझा मेमोरी में पढ़ने और लिखने की अनुमति होती है। अनसिंक्रनाइज़्ड कतारों ( kUnsynchronizedWrite ) के लिए, लेखक MQDescriptorUnsync ऑब्जेक्ट सौंपने से पहले सभी पाठकों के लिए लेखन अनुमतियाँ हटाना चाह सकता है। यह सुनिश्चित करता है कि अन्य प्रक्रियाएँ कतार में नहीं लिख सकती हैं, जिसे रीडर प्रक्रियाओं में बग या बुरे व्यवहार से बचाने के लिए अनुशंसित किया जाता है। यदि लेखक चाहता है कि पाठक जब भी कतार के पठन पक्ष को बनाने के लिए MQDescriptorUnsync का उपयोग करें तो कतार को रीसेट करने में सक्षम हों, तो मेमोरी को केवल-पढ़ने के लिए चिह्नित नहीं किया जा सकता है। यह `MessageQueue` कंस्ट्रक्टर का डिफ़ॉल्ट व्यवहार है। इसलिए, यदि इस कतार में पहले से ही उपयोगकर्ता मौजूद हैं, तो resetPointer=false के साथ कतार बनाने के लिए उनके कोड को बदलना होगा।

  • लेखक: MQDescriptor फ़ाइल डिस्क्रिप्टर और क्षेत्र को केवल पढ़ने के लिए सेट ( PROT_READ ) के साथ ashmem_set_prot_region को कॉल करें:
    int res = ashmem_set_prot_region(mqDesc->handle->data[0], PROT_READ)
  • रीडर: resetPointer=false (डिफ़ॉल्ट true है) के साथ संदेश कतार बनाएं:
    mFmq = new (std::nothrow) MessageQueue(mqDesc, false);

MessageQueue का उपयोग करना

MessageQueue ऑब्जेक्ट का सार्वजनिक API है:

size_t availableToWrite()  // Space available (number of elements).
size_t availableToRead()  // Number of elements available.
size_t getQuantumSize()  // Size of type T in bytes.
size_t getQuantumCount() // Number of items of type T that fit in the FMQ.
bool isValid() // Whether the FMQ is configured correctly.
const MQDescriptor<T, flavor>* getDesc()  // Return info to send to other process.

bool write(const T* data)  // Write one T to FMQ; true if successful.
bool write(const T* data, size_t count) // Write count T's; no partial writes.

bool read(T* data);  // read one T from FMQ; true if successful.
bool read(T* data, size_t count);  // Read count T's; no partial reads.

bool writeBlocking(const T* data, size_t count, int64_t timeOutNanos = 0);
bool readBlocking(T* data, size_t count, int64_t timeOutNanos = 0);

// Allows multiple queues to share a single event flag word
std::atomic<uint32_t>* getEventFlagWord();

bool writeBlocking(const T* data, size_t count, uint32_t readNotification,
uint32_t writeNotification, int64_t timeOutNanos = 0,
android::hardware::EventFlag* evFlag = nullptr); // Blocking write operation for count Ts.

bool readBlocking(T* data, size_t count, uint32_t readNotification,
uint32_t writeNotification, int64_t timeOutNanos = 0,
android::hardware::EventFlag* evFlag = nullptr) // Blocking read operation for count Ts;

//APIs to allow zero copy read/write operations
bool beginWrite(size_t nMessages, MemTransaction* memTx) const;
bool commitWrite(size_t nMessages);
bool beginRead(size_t nMessages, MemTransaction* memTx) const;
bool commitRead(size_t nMessages);

एक ही ऑपरेशन में कितना डेटा स्थानांतरित किया जा सकता है यह निर्धारित करने के लिए availableToWrite() और availableToRead() उपयोग किया जा सकता है। एक असिंक्रनाइज़्ड कतार में:

  • availableToWrite() हमेशा कतार की क्षमता लौटाता है।
  • प्रत्येक पाठक की अपनी पढ़ने की स्थिति होती है और वह availableToRead() के लिए अपनी गणना स्वयं करता है।
  • धीमे पाठक के दृष्टिकोण से, कतार को ओवरफ्लो होने दिया जाता है; इसके परिणामस्वरूप availableToRead() कतार के आकार से बड़ा मान लौटा सकता है। ओवरफ्लो के बाद पहला रीड विफल हो जाएगा और परिणामस्वरूप उस रीडर के लिए पढ़ने की स्थिति वर्तमान लेखन सूचक के बराबर सेट हो जाएगी, चाहे ओवरफ्लो को availableToRead() के माध्यम से रिपोर्ट किया गया था या नहीं।

यदि सभी अनुरोधित डेटा को कतार में/से स्थानांतरित किया जा सकता है (और था) तो read() और write() विधियां true हो जाती हैं। ये विधियाँ अवरुद्ध नहीं करतीं; वे या तो सफल होते हैं (और true लौटाते हैं), या तुरंत विफलता ( false ) लौटाते हैं।

readBlocking() और writeBlocking() विधियां तब तक प्रतीक्षा करती हैं जब तक कि अनुरोधित ऑपरेशन पूरा नहीं हो जाता है, या जब तक वे टाइमआउट नहीं हो जाते (0 के timeOutNanos मान का मतलब कभी भी टाइमआउट नहीं होता है)।

इवेंट फ़्लैग शब्द का उपयोग करके ब्लॉकिंग ऑपरेशन कार्यान्वित किए जाते हैं। डिफ़ॉल्ट रूप से, प्रत्येक कतार readBlocking() और writeBlocking() के संक्षिप्त रूप का समर्थन करने के लिए अपना स्वयं का ध्वज शब्द बनाती है और उसका उपयोग करती है। एकाधिक कतारों के लिए एक ही शब्द को साझा करना संभव है, ताकि एक प्रक्रिया किसी भी कतार में लिखने या पढ़ने की प्रतीक्षा कर सके। कतार के ईवेंट फ़्लैग शब्द के लिए एक सूचक getEventFlagWord() को कॉल करके प्राप्त किया जा सकता है, और उस सूचक (या उपयुक्त साझा मेमोरी स्थान के लिए कोई सूचक) का उपयोग readBlocking() के लंबे रूप में पास करने के लिए एक EventFlag ऑब्जेक्ट बनाने के लिए किया जा सकता है और एक अलग कतार के लिए writeBlocking()readNotification और writeNotification पैरामीटर बताते हैं कि इवेंट फ़्लैग में कौन से बिट्स का उपयोग उस कतार पर पढ़ने और लिखने के संकेत के लिए किया जाना चाहिए। readNotification और writeNotification 32-बिट बिटमास्क हैं।

readBlocking() writeNotification बिट्स पर प्रतीक्षा करता है; यदि वह पैरामीटर 0 है, तो कॉल हमेशा विफल हो जाती है। यदि readNotification मान 0 है, तो कॉल विफल नहीं होगी, लेकिन एक सफल रीड कोई अधिसूचना बिट्स सेट नहीं करेगा। एक सिंक्रनाइज़ कतार में, इसका मतलब यह होगा कि संबंधित writeBlocking() कॉल तब तक नहीं उठेगी जब तक कि बिट कहीं और सेट न हो। एक अनसिंक्रनाइज़्ड कतार में, writeBlocking() प्रतीक्षा नहीं करेगा (इसे अभी भी राइट नोटिफिकेशन बिट सेट करने के लिए उपयोग किया जाना चाहिए), और रीड्स के लिए किसी भी नोटिफिकेशन बिट्स को सेट न करना उचित है। इसी तरह, यदि readNotification 0 है तो writeblocking() विफल हो जाएगी, और एक सफल लेखन निर्दिष्ट writeNotification बिट्स सेट करता है।

एक साथ कई कतारों पर प्रतीक्षा करने के लिए, सूचनाओं के बिटमास्क पर प्रतीक्षा करने के लिए EventFlag ऑब्जेक्ट की wait() विधि का उपयोग करें। wait() विधि उन बिट्स के साथ एक स्थिति शब्द लौटाती है जो वेक अप सेट का कारण बनती है। इस जानकारी का उपयोग यह सत्यापित करने के लिए किया जाता है कि संबंधित कतार में वांछित लिखने/पढ़ने के ऑपरेशन के लिए पर्याप्त जगह या डेटा है और एक नॉनब्लॉकिंग write() / read() निष्पादित करें। पोस्ट ऑपरेशन अधिसूचना प्राप्त करने के लिए, EventFlag की wake() विधि पर किसी अन्य कॉल का उपयोग करें। EventFlag एब्स्ट्रैक्शन की परिभाषा के लिए, system/libfmq/include/fmq/EventFlag.h देखें।

शून्य प्रतिलिपि संचालन

read / write / readBlocking / writeBlocking() एपीआई एक इनपुट/आउटपुट बफर के लिए एक पॉइंटर को एक तर्क के रूप में लेते हैं और उसी और एफएमक्यू रिंग बफर के बीच डेटा कॉपी करने के लिए आंतरिक रूप से memcpy() कॉल का उपयोग करते हैं। प्रदर्शन में सुधार करने के लिए, एंड्रॉइड 8.0 और उच्चतर में एपीआई का एक सेट शामिल है जो रिंग बफर में सीधे पॉइंटर एक्सेस प्रदान करता है, जिससे memcpy कॉल का उपयोग करने की आवश्यकता समाप्त हो जाती है।

शून्य प्रतिलिपि एफएमक्यू संचालन के लिए निम्नलिखित सार्वजनिक एपीआई का उपयोग करें:

bool beginWrite(size_t nMessages, MemTransaction* memTx) const;
bool commitWrite(size_t nMessages);

bool beginRead(size_t nMessages, MemTransaction* memTx) const;
bool commitRead(size_t nMessages);
  • beginWrite विधि एफएमक्यू रिंग बफर में बेस पॉइंटर्स प्रदान करती है। डेटा लिखे जाने के बाद, इसे commitWrite() उपयोग करके कमिट करें। beginRead / commitRead विधियाँ उसी तरह कार्य करती हैं।
  • beginRead / Write तरीके इनपुट के रूप में पढ़े/लिखे जाने वाले संदेशों की संख्या लेते हैं और एक बूलियन लौटाते हैं जो दर्शाता है कि पढ़ना/लिखना संभव है या नहीं। यदि पढ़ना या लिखना संभव है तो memTx संरचना बेस पॉइंटर्स से भर जाती है जिसका उपयोग रिंग बफर साझा मेमोरी में सीधे पॉइंटर एक्सेस के लिए किया जा सकता है।
  • MemRegion संरचना में मेमोरी के एक ब्लॉक के बारे में विवरण शामिल है, जिसमें बेस पॉइंटर (मेमोरी ब्लॉक का आधार पता) और T के संदर्भ में लंबाई (एचआईडीएल-परिभाषित प्रकार के संदेश कतार के संदर्भ में मेमोरी ब्लॉक की लंबाई) शामिल है।
  • MemTransaction संरचना में दो MemRegion संरचनाएं शामिल हैं, first और second रिंग बफर में पढ़ने या लिखने के लिए कतार की शुरुआत में लपेटने की आवश्यकता हो सकती है। इसका मतलब यह होगा कि एफएमक्यू रिंग बफर में डेटा को पढ़ने/लिखने के लिए दो बेस पॉइंटर्स की आवश्यकता होती है।

MemRegion संरचना से आधार पता और लंबाई प्राप्त करने के लिए:

T* getAddress(); // gets the base address
size_t getLength(); // gets the length of the memory region in terms of T
size_t getLengthInBytes(); // gets the length of the memory region in bytes

MemTransaction ऑब्जेक्ट के भीतर पहले और दूसरे MemRegion s का संदर्भ प्राप्त करने के लिए:

const MemRegion& getFirstRegion(); // get a reference to the first MemRegion
const MemRegion& getSecondRegion(); // get a reference to the second MemRegion

शून्य प्रतिलिपि एपीआई का उपयोग करके एफएमक्यू को उदाहरण लिखें:

MessageQueueSync::MemTransaction tx;
if (mQueue->beginRead(dataLen, &tx)) {
    auto first = tx.getFirstRegion();
    auto second = tx.getSecondRegion();

    foo(first.getAddress(), first.getLength()); // method that performs the data write
    foo(second.getAddress(), second.getLength()); // method that performs the data write

    if(commitWrite(dataLen) == false) {
       // report error
    }
} else {
   // report error
}

निम्नलिखित सहायक विधियाँ भी MemTransaction का हिस्सा हैं:

  • T* getSlot(size_t idx);
    MemRegions के भीतर स्लॉट idx के लिए एक पॉइंटर लौटाता है जो इस MemTransaction ऑब्जेक्ट का हिस्सा है। यदि MemTransaction ऑब्जेक्ट प्रकार टी के एन आइटम को पढ़ने/लिखने के लिए मेमोरी क्षेत्रों का प्रतिनिधित्व कर रहा है, तो idx की वैध सीमा 0 और एन-1 के बीच है।
  • bool copyTo(const T* data, size_t startIdx, size_t nMessages = 1);
    इंडेक्स startIdx से शुरू करके, ऑब्जेक्ट द्वारा वर्णित मेमोरी क्षेत्रों में टी प्रकार के nMessages आइटम लिखें। यह विधि memcpy() का उपयोग करती है और इसका उपयोग शून्य प्रतिलिपि ऑपरेशन के लिए नहीं किया जाता है। यदि MemTransaction ऑब्जेक्ट प्रकार टी के एन आइटम को पढ़ने/लिखने के लिए मेमोरी का प्रतिनिधित्व करता है, तो idx की वैध सीमा 0 और एन-1 के बीच है।
  • bool copyFrom(T* data, size_t startIdx, size_t nMessages = 1);
    startIdx से शुरू होने वाले ऑब्जेक्ट द्वारा वर्णित स्मृति क्षेत्रों से टी प्रकार के nMessages आइटम को पढ़ने के लिए सहायक विधि। यह विधि memcpy() का उपयोग करती है और इसका उपयोग शून्य प्रतिलिपि ऑपरेशन के लिए नहीं किया जाता है।

HIDL पर कतार भेज रहा हूँ

सृजन पक्ष पर:

  1. ऊपर बताए अनुसार संदेश कतार ऑब्जेक्ट बनाएं।
  2. सत्यापित करें कि ऑब्जेक्ट isValid() के साथ मान्य है।
  3. यदि आप EventFlag readBlocking() / writeBlocking() के लंबे रूप में पास करके एकाधिक कतारों पर प्रतीक्षा कर रहे हैं, तो आप MessageQueue ऑब्जेक्ट से ईवेंट फ़्लैग पॉइंटर ( getEventFlagWord() का उपयोग करके) निकाल सकते हैं, जिसे ध्वज बनाने के लिए प्रारंभ किया गया था, और आवश्यक EventFlag ऑब्जेक्ट बनाने के लिए उस ध्वज का उपयोग करें।
  4. डिस्क्रिप्टर ऑब्जेक्ट प्राप्त करने के लिए MessageQueue getDesc() विधि का उपयोग करें।
  5. .hal फ़ाइल में, विधि को fmq_sync प्रकार का एक पैरामीटर दें या fmq_unsync जहां T एक उपयुक्त HIDL-परिभाषित प्रकार है। getDesc() द्वारा लौटाए गए ऑब्जेक्ट को प्राप्त करने की प्रक्रिया में भेजने के लिए इसका उपयोग करें।

प्राप्तकर्ता पक्ष पर:

  1. MessageQueue ऑब्जेक्ट बनाने के लिए डिस्क्रिप्टर ऑब्जेक्ट का उपयोग करें। समान कतार स्वाद और डेटा प्रकार का उपयोग करना सुनिश्चित करें, अन्यथा टेम्पलेट संकलित करने में विफल हो जाएगा।
  2. यदि आपने कोई ईवेंट फ़्लैग निकाला है, तो प्राप्त करने की प्रक्रिया में संबंधित MessageQueue ऑब्जेक्ट से फ़्लैग निकालें।
  3. डेटा स्थानांतरित करने के लिए MessageQueue ऑब्जेक्ट का उपयोग करें।