HIDL का रिमोट प्रोसेस कॉल (आरपीसी) इंफ़्रास्ट्रक्चर, बाइंडर मेकेनिज्म का इस्तेमाल करता है. इसका मतलब है कि कॉल में ओवरहेड शामिल होता है, इसके लिए कर्नेल ऑपरेशन की ज़रूरत होती है, और यह शेड्यूलर ऐक्शन को ट्रिगर कर सकता है. हालांकि, ऐसे मामलों में फ़ास्ट मैसेज क्यू (एफ़एमक्यू) सिस्टम का इस्तेमाल किया जाता है जिनमें कम ओवरहेड वाली प्रोसेस के बीच डेटा ट्रांसफ़र करना ज़रूरी होता है और कर्नेल का कोई जुड़ाव नहीं होता.
FMQ, अपनी पसंद की प्रॉपर्टी के साथ मैसेज की कतारें बनाता है. HIDL आरपीसी कॉल के ज़रिए, MQDescriptorSync
या MQDescriptorUnsync
ऑब्जेक्ट भेजा जा सकता है. मैसेज कतार को ऐक्सेस करने के लिए, मैसेज पाने वाली प्रोसेस में इस ऑब्जेक्ट का इस्तेमाल किया जाता है.
सूची के टाइप
Android, दो तरह की सूची (इन्हें फ़्लेवर कहा जाता है) के साथ काम करता है:
- सिंक नहीं की गई सूचियों को ओवरफ़्लो किया जा सकता है और उनमें कई पाठक हो सकते हैं. हर पाठक को समय पर डेटा पढ़ना होगा या उसे खोना होगा.
- सिंक की गई सूचियों को ओवरफ़्लो नहीं किया जा सकता और इसमें सिर्फ़ एक ही रीडर हो सकता है.
दोनों तरह की सूचियों में डेटा कम नहीं हो सकता. खाली सूची से डेटा पढ़ने की कोशिश करने पर, वह काम नहीं करती. साथ ही, इनमें सिर्फ़ एक व्यक्ति डेटा लिख सकता है.
सिंक नहीं की गई सूचियां
सिंक नहीं की गई सूची में सिर्फ़ एक लेखक होता है, लेकिन उसमें कई लोग हो सकते हैं. सूची के लिए एक लिखने की जगह होती है. हालांकि, हर रीडर अपनी पढ़ने की जगह का ट्रैक रखता है.
सूची में डेटा हमेशा तब तक लिखा जाता है, जब तक कि वह सूची की कॉन्फ़िगर की गई क्षमता से ज़्यादा न हो. सूची की क्षमता से ज़्यादा डेटा लिखने पर, डेटा तुरंत अस्वीकार कर दिया जाता है. हर रीडर के पास डेटा पढ़ने के लिए अलग-अलग पोज़िशन हो सकती है. इसलिए, जब भी नए डेटा को स्टोर करने के लिए जगह की ज़रूरत होती है, तो डेटा सूची से हट जाता है.
डेटा को सूची में सबसे आखिर में शामिल होने से पहले, उसे वापस पाने की ज़िम्मेदारी पाठकों की होती है. कोई रीड जो उपलब्ध डेटा से ज़्यादा डेटा पढ़ने की कोशिश करता है वह तुरंत (अगर ब्लॉक नहीं किया जाता है) या ज़रूरत के मुताबिक डेटा उपलब्ध होने का इंतज़ार करती है (अगर ब्लॉक किया जाता है). अगर कोई रीड, सूची की क्षमता से ज़्यादा डेटा पढ़ने की कोशिश करता है, तो वह हमेशा तुरंत विफल हो जाता है.
अगर कोई पाठक, लेखक से बात नहीं कर पाता है और उसमें पढ़े जाने वाले डेटा की संख्या, सूची में देने की क्षमता से ज़्यादा है, तो अगली रीडिंग में डेटा नहीं दिखेगा. इसके बजाय, वह पाठक की पढ़ने की जगह को लिखने की नई जगह के बराबर रीसेट कर देता है और फिर उसे पढ़ने में गड़बड़ी होती है. अगर पढ़ने के लिए उपलब्ध डेटा की जांच, ओवरफ़्लो के बाद, लेकिन अगली बार पढ़ने से पहले की जाती है, तो यह सूची में मौजूद डेटा की क्षमता से ज़्यादा डेटा दिखाता है. इससे पता चलता है कि ओवरफ़्लो हुआ है. (अगर उपलब्ध डेटा की जांच करने और उस डेटा को पढ़ने के बीच, सूची में डेटा की संख्या तय सीमा से ज़्यादा हो जाती है, तो डेटा पढ़ने में हुई गड़बड़ी ही सूची में डेटा की संख्या तय सीमा से ज़्यादा होने का एकमात्र संकेत है.)
सिंक की गई कतारें
सिंक की गई सूची में एक राइटर और एक रीडर होता है. इसमें एक ही पोज़िशन और पढ़ने की एक पोज़िशन होती है. सूची में जितने डेटा के लिए जगह है उससे ज़्यादा डेटा नहीं लिखा जा सकता. इसके अलावा, सूची में मौजूद डेटा से ज़्यादा डेटा नहीं पढ़ा जा सकता. ब्लॉकिंग या नॉन-ब्लॉकिंग रीड या लिखने वाले फ़ंक्शन को कॉल करने पर, उपलब्ध जगह या डेटा से ज़्यादा डेटा डालने की कोशिश करने पर, तुरंत गड़बड़ी का मैसेज मिलता है या तब तक ब्लॉक किया जाता है, जब तक कि वह कार्रवाई पूरी नहीं हो जाती. सूची की क्षमता से ज़्यादा डेटा पढ़ने या उसमें बदलाव करने की कोशिश हमेशा तुरंत विफल हो जाती है.
एफ़एमक्यू सेट अप करना
मैसेज सूची में एक से ज़्यादा MessageQueue
ऑब्जेक्ट होने चाहिए: एक ऑब्जेक्ट को लिखना होगा और एक या एक से ज़्यादा ऑब्जेक्ट पढ़ने होंगे. इसमें यह साफ़ तौर पर नहीं बताया गया है कि डेटा को पढ़ने या लिखने के लिए किस ऑब्जेक्ट का इस्तेमाल किया जाए. यह पक्का करना उपयोगकर्ता की ज़िम्मेदारी है कि डेटा को पढ़ने और लिखने के लिए, किसी एक ऑब्जेक्ट का इस्तेमाल न किया जाए. साथ ही, सिंक की गई सूचियों के लिए, एक से ज़्यादा पाठक न हों.
पहला MessageQ ऑब्जेक्ट बनाएं
मैसेज सूची को एक ही कॉल से बनाया और कॉन्फ़िगर किया जाता है:
#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 nonblocking 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)
initializer, मैसेज कतार की सुविधा के साथ काम करने वाला ऑब्जेक्ट बनाता और शुरू करता है.MessageQueue<T, flavor>(numElements, configureEventFlagWord)
शुरू करने वाला टूल एक ऐसा ऑब्जेक्ट बनाता और शुरू करता है जो ब्लॉक करने के साथ मैसेज सूची की सुविधा के साथ काम करता है.flavor
, सिंक की गई सूची के लिएkSynchronizedReadWrite
या सिंक नहीं की गई सूची के लिएkUnsynchronizedWrite
हो सकता है.- इस उदाहरण में,
uint16_t
कोई भी HIDL से तय किया गया टाइप हो सकता है. इसमें नेस्ट किए गए बफ़र (string
याvec
टाइप नहीं), हैंडल या इंटरफ़ेस शामिल नहीं होने चाहिए. kNumElementsInQueue
से एंट्री की संख्या की सूची का साइज़ पता चलता है. इससे सूची के लिए तय किए गए, शेयर किए गए मेमोरी बफ़र का साइज़ तय होता है.
दूसरा MessageQueue ऑब्जेक्ट बनाना
मैसेज की सूची का दूसरा हिस्सा, पहले हिस्से से मिले MQDescriptor
ऑब्जेक्ट का इस्तेमाल करके बनाया जाता है. MQDescriptor
ऑब्जेक्ट को HIDL या AIDL आरपीसी कॉल की मदद से, उस प्रोसेस पर भेजा जाता है जिसमें मैसेज कतार का दूसरा हिस्सा होता है. MQDescriptor
में, सूची के बारे में जानकारी होती है. इसमें ये चीज़ें शामिल हैं:
- बफ़र और लिखने वाले पॉइंटर को मैप करने के लिए जानकारी.
- पढ़े गए पॉइंटर को मैप करने के लिए जानकारी (अगर सूची सिंक की गई है).
- इवेंट फ़्लैग वर्ड को मैप करने के लिए जानकारी (अगर कतार ब्लॉक हो रही है).
- ऑब्जेक्ट टाइप (
<T, flavor>
), जिसमें सूची के एलिमेंट का HIDL से तय किया गया टाइप और सूची का फ़्लेवर (सिंक किया गया या सिंक नहीं किया गया) शामिल होता है.
MessageQueue
ऑब्जेक्ट बनाने के लिए, MQDescriptor
ऑब्जेक्ट का इस्तेमाल किया जा सकता है:
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
ऑब्जेक्ट का इस्तेमाल किया जा सकता है. साथ ही, इस्तेमाल किए जाने वाले सूचना बिटमास्क की जानकारी भी दी जा सकती है. इस मामले में, हर रीड और राइट कॉल के लिए इवेंट फ़्लैग और बिटमास्क की जानकारी देना ज़रूरी है.
लंबी अवधि के लिए, हर readBlocking()
और writeBlocking()
कॉल में EventFlag
को साफ़ तौर पर दिया जा सकता है. किसी एक सूची को किसी इंटरनल इवेंट फ़्लैग की मदद से शुरू किया जा सकता है. इसके बाद, getEventFlagWord()
का इस्तेमाल करके उस सूची के MessageQueue
ऑब्जेक्ट से इसे निकाला जाना चाहिए. साथ ही, अन्य एफ़एमक्यू के साथ इस्तेमाल करने के लिए, हर प्रोसेस में 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
ऑब्जेक्ट का सार्वजनिक एपीआई यह है:
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()
को कॉल करके, किसी कतार के इवेंट फ़्लैग वर्ड का पॉइंटर पाया जा सकता है. साथ ही, उस पॉइंटर (या किसी भी सही शेयर की गई मेमोरी लोकेशन के पॉइंटर) का इस्तेमाल करके, किसी EventFlag
ऑब्जेक्ट को बनाया जा सकता है, ताकि उसे किसी दूसरी कतार के readBlocking()
और 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()
कॉल का इस्तेमाल करके, इनपुट-आउटपुट बफ़र और एफ़एमक्यू रिंग बफ़र के बीच डेटा कॉपी किया जाता है. परफ़ॉर्मेंस को बेहतर बनाने के लिए, Android 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
तरीका, FMQ रिंग बफ़र में बेस पॉइंटर उपलब्ध कराता है. डेटा लिखने के बाद,commitWrite()
का इस्तेमाल करके उसे कमिट करें.beginRead
औरcommitRead
, दोनों तरीके एक जैसे काम करते हैं.beginRead
औरWrite
तरीके, पढ़े और लिखे जाने वाले मैसेज की संख्या को इनपुट के तौर पर लेते हैं. साथ ही, एक बूलियन वैल्यू दिखाते हैं, जिससे पता चलता है कि मैसेज पढ़ा या लिखा जा सकता है या नहीं. अगर डेटा पढ़ा या लिखा जा सकता है, तोmemTx
struct में बेस पॉइंटर जोड़े जाते हैं. इनका इस्तेमाल, रिंग बफ़र शेयर की गई मेमोरी में सीधे पॉइंटर ऐक्सेस करने के लिए किया जा सकता है.MemRegion
स्ट्रक्चर में मेमोरी के ब्लॉक की जानकारी होती है. इसमें बेस पॉइंटर (मेमोरी ब्लॉक का बेस पता) औरT
के हिसाब से लंबाई (मैसेज कतार के HIDL से तय किए गए टाइप के हिसाब से मेमोरी ब्लॉक की लंबाई) शामिल होती है.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
स्ट्रक्चर के रेफ़रंस पाने के लिए:
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
ऑब्जेक्ट,T
टाइप के N आइटम पढ़ने और लिखने के लिए, मेमोरी रीजन को दिखा रहा है, तोidx
की मान्य रेंज 0 और N-1 के बीच होगी.bool copyTo(const T* data, size_t startIdx, size_t nMessages = 1);
, ऑब्जेक्ट के बताए गए मेमोरी क्षेत्रों में, इंडेक्सstartIdx
से शुरू करके,T
टाइप केnMessages
आइटम लिखता है. इस तरीके मेंmemcpy()
का इस्तेमाल किया जाता है. इसका इस्तेमाल, ज़ीरो कॉपी ऑपरेशन के लिए नहीं किया जाना चाहिए. अगरMemTransaction
ऑब्जेक्ट,T
टाइप के N आइटम पढ़ने और लिखने के लिए मेमोरी दिखाता है, तोidx
की मान्य रेंज 0 और N-1 के बीच होगी.bool copyFrom(T* data, size_t startIdx, size_t nMessages = 1);
,startIdx
से शुरू होने वाले ऑब्जेक्ट के बताए गए मेमोरी क्षेत्रों से,T
टाइप केnMessages
आइटम पढ़ने के लिए, एक सहायक तरीका है. इस तरीके मेंmemcpy()
का इस्तेमाल किया जाता है. इसका इस्तेमाल, शून्य कॉपी वाले ऑपरेशन के लिए नहीं किया जाना चाहिए.
HIDL के ज़रिए सूची भेजना
वीडियो बनाने वाले के लिए:
- ऊपर बताए गए तरीके से मैसेज क्यू ऑब्जेक्ट बनाएं.
- पुष्टि करें कि ऑब्जेक्ट
isValid()
के साथ मान्य है. - अगर
readBlocking()
याwriteBlocking()
के लंबे फ़ॉर्म मेंEventFlag
पास करके, कई कतारें इंतज़ार में हैं, तोgetEventFlagWord()
का इस्तेमाल करके,MessageQueue
ऑब्जेक्ट से इवेंट फ़्लैग पॉइंटर निकाला जा सकता है. यह ऑब्जेक्ट, फ़्लैग बनाने के लिए शुरू किया गया था. साथ ही, ज़रूरीEventFlag
ऑब्जेक्ट बनाने के लिए, उस फ़्लैग का इस्तेमाल किया जा सकता है. - डिस्क्रिप्टर ऑब्जेक्ट पाने के लिए,
MessageQueue
तरीकेgetDesc()
का इस्तेमाल करें. - HAL फ़ाइल में, तरीके को
fmq_sync
याfmq_unsync
टाइप का पैरामीटर दें, जहांT
सही HIDL-तय टाइप है. इसका इस्तेमालgetDesc()
से मिले ऑब्जेक्ट को पाने की प्रोसेस में भेजने के लिए करें.
दाईं ओर:
MessageQueue
ऑब्जेक्ट बनाने के लिए, डिस्क्रिप्टर ऑब्जेक्ट का इस्तेमाल करें. एक ही फ़्लेवर और डेटा टाइप का इस्तेमाल करें. ऐसा न करने पर, टेंप्लेट को संकलित नहीं किया जा सकेगा.- अगर आपने कोई इवेंट फ़्लैग लिया है, तो इवेंट पाने की प्रोसेस में उससे जुड़े
MessageQueue
ऑब्जेक्ट से फ़्लैग को एक्सट्रैक्ट करें. - डेटा ट्रांसफ़र करने के लिए,
MessageQueue
ऑब्जेक्ट का इस्तेमाल करें.