หากคุณกำลังมองหาการสนับสนุน AIDL โปรดดู FMQ พร้อม AIDL ด้วย
โครงสร้างพื้นฐานการเรียกขั้นตอนระยะไกล (RPC) ของ HIDL ใช้กลไก Binder ซึ่งหมายความว่าการเรียกเกี่ยวข้องกับค่าใช้จ่าย จำเป็นต้องมีการดำเนินการเคอร์เนล และอาจทริกเกอร์การดำเนินการของตัวกำหนดตารางเวลา อย่างไรก็ตาม ในกรณีที่ต้องถ่ายโอนข้อมูลระหว่างกระบวนการที่มีค่าใช้จ่ายน้อยกว่าและไม่เกี่ยวข้องกับเคอร์เนล ระบบจะใช้ระบบ Fast Message Queue (FMQ)
FMQ สร้างคิวข้อความด้วยคุณสมบัติที่ต้องการ อ็อบเจ็กต์ MQDescriptorSync
หรือ MQDescriptorUnsync
สามารถส่งผ่านการเรียก HIDL RPC และใช้โดยกระบวนการรับเพื่อเข้าถึงคิวข้อความ
Fast Message Queues รองรับเฉพาะใน C++ และบนอุปกรณ์ที่ใช้ Android 8.0 ขึ้นไป
ประเภทคิวข้อความ
Android รองรับคิวสองประเภท (เรียกว่า รสชาติ ):
- คิว ที่ไม่ซิง โครไนซ์ได้รับอนุญาตให้ล้น และสามารถมีผู้อ่านได้จำนวนมาก ผู้อ่านแต่ละคนจะต้องอ่านข้อมูลทันเวลาหรือสูญหาย
- คิว ที่ซิงโครไนซ์ ไม่ได้รับอนุญาตให้ล้น และสามารถมีเครื่องอ่านได้เพียงเครื่องเดียวเท่านั้น
คิวทั้งสองประเภทไม่ได้รับอนุญาตให้อันเดอร์โฟลว์ (การอ่านจากคิวว่างจะล้มเหลว) และสามารถมีตัวเขียนได้เพียงคนเดียวเท่านั้น
ไม่ซิงโครไนซ์
คิวที่ไม่ซิงโครไนซ์จะมีตัวเขียนเพียงคนเดียว แต่สามารถมีตัวอ่านจำนวนเท่าใดก็ได้ มีตำแหน่งการเขียนหนึ่งตำแหน่งสำหรับคิว อย่างไรก็ตาม ผู้อ่านแต่ละคนจะติดตามตำแหน่งการอ่านของตนเองอย่างเป็นอิสระ
การเขียนลงในคิวจะสำเร็จเสมอ (ไม่ได้ตรวจสอบโอเวอร์โฟลว์) ตราบใดที่ไม่ใหญ่กว่าความจุของคิวที่กำหนดค่าไว้ (การเขียนที่ใหญ่กว่าความจุของคิวจะล้มเหลวในทันที) เนื่องจากผู้อ่านแต่ละคนอาจมีตำแหน่งการอ่านที่แตกต่างกัน แทนที่จะรอให้ผู้อ่านทุกคนอ่านข้อมูลทุกชิ้น ข้อมูลจึงหลุดออกจากคิวเมื่อใดก็ตามที่การเขียนใหม่ต้องการพื้นที่
ผู้อ่านมีหน้าที่ดึงข้อมูลก่อนที่จะหลุดออกจากจุดสิ้นสุดของคิว การอ่านที่พยายามอ่านข้อมูลมากกว่าที่มีอยู่จะล้มเหลวทันที (หากไม่ได้บล็อก) หรือรอให้มีข้อมูลเพียงพอ (หากบล็อก) การอ่านที่พยายามอ่านข้อมูลมากกว่าความจุของคิวมักจะล้มเหลวในทันที
หากผู้อ่านไม่สามารถติดตามผู้เขียนได้ ดังนั้นปริมาณข้อมูลที่เขียนและยังไม่ได้อ่านโดยผู้อ่านนั้นมีมากกว่าความจุของคิว การอ่านครั้งถัดไปจะไม่ส่งคืนข้อมูล แต่จะรีเซ็ตตำแหน่งการอ่านของผู้อ่านให้เท่ากับตำแหน่งการเขียนล่าสุด จากนั้นจะส่งคืนความล้มเหลว หากข้อมูลที่พร้อมให้อ่านได้รับการตรวจสอบหลังจากการโอเวอร์โฟลว์ แต่ก่อนที่จะอ่านครั้งถัดไป จะแสดงข้อมูลที่พร้อมให้อ่านมากกว่าความจุของคิว ซึ่งบ่งชี้ว่าเกิดการโอเวอร์โฟลว์แล้ว (หากคิวล้นระหว่างการตรวจสอบข้อมูลที่มีอยู่กับการพยายามอ่านข้อมูลนั้น สิ่งเดียวที่บ่งชี้ถึงโอเวอร์โฟลว์คือการอ่านล้มเหลว)
ผู้อ่านคิวที่ไม่ซิงโครไนซ์อาจไม่ต้องการรีเซ็ตตัวชี้การอ่านและเขียนของคิว ดังนั้น เมื่อสร้างคิวจากตัวอธิบาย ผู้อ่านควรใช้อาร์กิวเมนต์ 'false' สำหรับพารามิเตอร์ 'resetPointers'
ซิงโครไนซ์
คิวที่ซิงโครไนซ์มีตัวเขียนหนึ่งตัวและเครื่องอ่านหนึ่งตัวที่มีตำแหน่งการเขียนเดียวและตำแหน่งการอ่านเดียว เป็นไปไม่ได้ที่จะเขียนข้อมูลมากกว่าที่คิวมีพื้นที่ว่างหรืออ่านข้อมูลมากกว่าที่คิวมีอยู่ในปัจจุบัน ขึ้นอยู่กับว่ามีการเรียกใช้ฟังก์ชันการเขียนหรืออ่านการบล็อกหรือไม่บล็อก ความพยายามที่จะเกินพื้นที่ว่างหรือข้อมูลอาจส่งคืนความล้มเหลวทันทีหรือบล็อกจนกว่าการดำเนินการที่ต้องการจะเสร็จสมบูรณ์ ความพยายามที่จะอ่านหรือเขียนข้อมูลมากกว่าความจุของคิวจะล้มเหลวทันทีเสมอ
การตั้งค่า FMQ
คิวข้อความต้องมีออบเจ็กต์ 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>
) ซึ่งรวมถึง ประเภทองค์ประกอบคิวที่กำหนดโดย HIDL และรสชาติของคิว (ซิงโครไนซ์หรือไม่ซิงโครไนซ์)
วัตถุ MQDescriptor
สามารถใช้เพื่อสร้างวัตถุ MessageQueue
:
MessageQueue<T, flavor>::MessageQueue(const MQDescriptor<T, flavor>& Desc, bool resetPointers)
พารามิเตอร์ resetPointers
ระบุว่าจะรีเซ็ตตำแหน่งการอ่านและเขียนเป็น 0 ในขณะที่สร้างวัตถุ MessageQueue
นี้หรือไม่ ในคิวที่ไม่ซิงโครไนซ์ ตำแหน่งการอ่าน (ซึ่งอยู่ในเครื่องของแต่ละออบเจ็กต์ MessageQueue
ในคิวที่ไม่ซิงโครไนซ์) จะถูกตั้งค่าเป็น 0 เสมอในระหว่างการสร้าง โดยทั่วไปแล้ว MQDescriptor
จะเริ่มต้นได้ในระหว่างการสร้างออบเจ็กต์คิวข้อความแรก สำหรับการควบคุมเพิ่มเติมเหนือหน่วยความจำแบบแบ่งใช้ คุณสามารถตั้งค่า MQDescriptor
ด้วยตนเอง ( MQDescriptor
ถูกกำหนดไว้ใน system/libhidl/base/include/hidl/MQDescriptor.h
) จากนั้นสร้างทุกอ็อบเจ็กต์ MessageQueue
ตามที่อธิบายไว้ในส่วนนี้
การบล็อกคิวและแฟล็กเหตุการณ์
ตามค่าเริ่มต้น คิวไม่รองรับการบล็อกการอ่าน/เขียน การบล็อกการโทรอ่าน/เขียนมีสองประเภท:
- รูปแบบสั้น โดยมีพารามิเตอร์ 3 ตัว (ตัวชี้ข้อมูล จำนวนรายการ การหมดเวลา) รองรับการบล็อกการดำเนินการอ่าน/เขียนแต่ละรายการในคิวเดียว เมื่อใช้แบบฟอร์มนี้ คิวจะจัดการแฟล็กเหตุการณ์และบิตมาสก์ภายใน และ ออบเจ็กต์คิวข้อความแรก จะต้องเริ่มต้นด้วยพารามิเตอร์ตัวที่สองเป็น
true
ตัวอย่างเช่น:// For an unsynchronized FMQ that supports blocking mFmqUnsynchronizedBlocking = new (std::nothrow) MessageQueue<uint16_t, kUnsynchronizedWrite> (kNumElementsInQueue, true /* enable blocking operations */);
- รูปแบบยาว โดยมีพารามิเตอร์ 6 ตัว (รวมถึงแฟล็กเหตุการณ์และบิตมาสก์) รองรับการใช้ออบเจ็กต์
EventFlag
ที่ใช้ร่วมกันระหว่างหลายคิว และอนุญาตให้ระบุบิตมาสก์การแจ้งเตือนที่จะใช้ ในกรณีนี้ จะต้องระบุแฟล็กเหตุการณ์และบิตมาสก์ให้กับการเรียกอ่านและเขียนแต่ละครั้ง
สำหรับรูปแบบยาว EventFlag
สามารถระบุได้อย่างชัดเจนในการเรียก readBlocking()
และ writeBlocking()
แต่ละครั้ง หนึ่งในคิวอาจเริ่มต้นได้ด้วยแฟล็กเหตุการณ์ภายใน ซึ่งจะต้องแยกออกจากออบเจ็กต์ MessageQueue
ของคิวนั้นโดยใช้ getEventFlagWord()
และใช้เพื่อสร้างออบเจ็กต์ EventFlag
ในแต่ละกระบวนการเพื่อใช้กับ FMQ อื่น ๆ อีกทางหนึ่ง ออบเจ็กต์ EventFlag
สามารถเตรียมใช้งานด้วยหน่วยความจำที่ใช้ร่วมกันที่เหมาะสมได้
โดยทั่วไป แต่ละคิวควรใช้การบล็อกแบบไม่บล็อก การบล็อกแบบสั้น หรือการบล็อกแบบยาวเพียงรายการเดียวเท่านั้น การผสมสิ่งเหล่านี้ไม่ใช่เรื่องผิดพลาด แต่จำเป็นต้องตั้งโปรแกรมอย่างระมัดระวังเพื่อให้ได้ผลลัพธ์ตามที่ต้องการ
กำลังทำเครื่องหมายหน่วยความจำว่าอ่านอย่างเดียว
ตามค่าเริ่มต้น หน่วยความจำที่ใช้ร่วมกันมีสิทธิ์ในการอ่านและเขียน สำหรับคิวที่ไม่ซิงโครไนซ์ ( kUnsynchronizedWrite
) ผู้เขียนอาจต้องการลบสิทธิ์การเขียนสำหรับผู้อ่านทั้งหมดก่อนที่จะแจกอ็อบเจ็กต์ MQDescriptorUnsync
เพื่อให้แน่ใจว่ากระบวนการอื่นๆ ไม่สามารถเขียนลงในคิวได้ ซึ่งแนะนำเพื่อป้องกันจุดบกพร่องหรือพฤติกรรมที่ไม่ดีในกระบวนการของผู้อ่าน หากผู้เขียนต้องการให้ผู้อ่านสามารถรีเซ็ตคิวเมื่อใดก็ตามที่พวกเขาใช้ MQDescriptorUnsync
เพื่อสร้างด้านการอ่านของคิว หน่วยความจำจะไม่สามารถทำเครื่องหมายเป็นแบบอ่านอย่างเดียวได้ นี่เป็นพฤติกรรมเริ่มต้นของตัวสร้าง `MessageQueue` ดังนั้น หากมีผู้ใช้คิวนี้อยู่แล้ว จะต้องเปลี่ยนรหัสเพื่อสร้างคิวด้วย resetPointer=false
- ผู้เขียน: เรียก
ashmem_set_prot_region
ด้วยตัวอธิบายไฟล์MQDescriptor
และขอบเขตที่ตั้งค่าเป็นแบบอ่านอย่างเดียว (PROT_READ
):int res = ashmem_set_prot_region(mqDesc->handle->data[0], PROT_READ)
- Reader: สร้างคิวข้อความด้วย
resetPointer=false
(ค่าเริ่มต้นคือtrue
):mFmq = new (std::nothrow) MessageQueue(mqDesc, false);
การใช้ MessageQueue
API สาธารณะของวัตถุ 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()
รอจนกว่าการดำเนินการที่ร้องขอจะเสร็จสมบูรณ์ หรือจนกว่าจะหมดเวลา (ค่า timeOutNanos
เป็น 0 หมายถึงไม่หมดเวลา)
การดำเนินการบล็อกจะดำเนินการโดยใช้คำแฟล็กเหตุการณ์ ตามค่าเริ่มต้น แต่ละคิวจะสร้างและใช้คำแฟล็กของตัวเองเพื่อรองรับรูปแบบสั้นของ readBlocking()
และ writeBlocking()
เป็นไปได้ที่หลายคิวจะใช้คำเดียวร่วมกัน เพื่อให้กระบวนการสามารถรอการเขียนหรืออ่านคิวใดๆ ได้ ตัวชี้ไปยังคำแฟล็กเหตุการณ์ของคิวสามารถรับได้โดยการเรียก getEventFlagWord()
และตัวชี้นั้น (หรือตัวชี้ใด ๆ ไปยังตำแหน่งหน่วยความจำที่ใช้ร่วมกันที่เหมาะสม) สามารถใช้เพื่อสร้างออบเจ็กต์ EventFlag
เพื่อส่งผ่านไปยังรูปแบบยาวของ readBlocking()
และ writeBlocking()
สำหรับคิวอื่น พารามิเตอร์ readNotification
และ writeNotification
บอกว่าบิตใดในแฟล็กเหตุการณ์ที่ควรใช้เพื่อส่งสัญญาณการอ่านและเขียนบนคิวนั้น readNotification
และ writeNotification
เป็นบิตมาสก์ 32 บิต
readBlocking()
รอบิต writeNotification
; หากพารามิเตอร์นั้นเป็น 0 การโทรจะล้มเหลวเสมอ ถ้าค่า readNotification
เป็น 0 การเรียกจะไม่ล้มเหลว แต่การอ่านสำเร็จจะไม่ตั้งค่าบิตการแจ้งเตือนใดๆ ในคิวที่ซิงโครไนซ์ หมายความว่าการเรียก writeBlocking()
ที่สอดคล้องกันจะไม่ถูกปลุก เว้นแต่บิตจะถูกตั้งค่าไว้ที่อื่น ในคิวที่ไม่ซิงโครไนซ์ writeBlocking()
จะไม่รอ (ควรใช้เพื่อตั้งค่าบิตการแจ้งเตือนการเขียน) และเหมาะสมที่การอ่านจะไม่ตั้งค่าบิตการแจ้งเตือนใดๆ ในทำนองเดียวกัน writeblocking()
จะล้มเหลวหาก readNotification
เป็น 0 และการเขียนที่สำเร็จจะตั้งค่าบิต writeNotification
ที่ระบุ
หากต้องการรอหลายคิวพร้อมกัน ให้ใช้ wait()
ของวัตถุ EventFlag
เพื่อรอบิตมาสก์ของการแจ้งเตือน wait()
วิธีการส่งกลับคำสถานะพร้อมกับบิตที่ทำให้เกิดการตั้งค่าการปลุก ข้อมูลนี้จะใช้เพื่อตรวจสอบว่าคิวที่เกี่ยวข้องนั้นมีพื้นที่หรือข้อมูลเพียงพอสำหรับการดำเนินการเขียน/อ่านที่ต้องการ และดำเนิน write()
/ read()
หากต้องการรับการแจ้งเตือนหลังการดำเนินการ ให้ใช้การเรียกอีกครั้งไปยัง wake()
ของ EventFlag
สำหรับคำจำกัดความของ EventFlag
abstraction โปรดดูที่ system/libfmq/include/fmq/EventFlag.h
การดำเนินการคัดลอกเป็นศูนย์
API read
/ write
/ readBlocking
/ writeBlocking()
จะนำตัวชี้ไปยังบัฟเฟอร์อินพุต/เอาท์พุตเป็นอาร์กิวเมนต์ และใช้การเรียก memcpy()
ภายในเพื่อคัดลอกข้อมูลระหว่างบัฟเฟอร์เดียวกันและบัฟเฟอร์วงแหวน FMQ เพื่อปรับปรุงประสิทธิภาพ Android 8.0 และสูงกว่าได้รวมชุด API ที่ให้การเข้าถึงตัวชี้โดยตรงไปยังบัฟเฟอร์วงแหวน ทำให้ไม่จำเป็นต้องใช้การเรียก memcpy
ใช้ API สาธารณะต่อไปนี้สำหรับการดำเนินการ FMQ แบบไม่มีสำเนา:
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
จะถูกเติมด้วยพอยน์เตอร์ฐานที่สามารถใช้เพื่อเข้าถึงพอยน์เตอร์โดยตรงในหน่วยความจำแชร์บัฟเฟอร์วงแหวน - โครงสร้าง
MemRegion
ประกอบด้วยรายละเอียดเกี่ยวกับบล็อกหน่วยความจำ รวมถึงตัวชี้ฐาน (ที่อยู่ฐานของบล็อกหน่วยความจำ) และความยาวในรูปของT
(ความยาวของบล็อกหน่วยความจำในแง่ของประเภทคิวข้อความที่กำหนดโดย HIDL) - โครงสร้าง
MemTransaction
มีโครงสร้างMemRegion
สองfirst
และsecond
เมื่ออ่านหรือเขียนลงในบัฟเฟอร์วงแหวนอาจต้องมีการพันรอบจุดเริ่มต้นของคิว นี่หมายความว่าจำเป็นต้องใช้ตัวชี้ฐานสองตัวในการอ่าน/เขียนข้อมูลลงในบัฟเฟอร์วงแหวน FMQ
หากต้องการรับที่อยู่ฐานและความยาวจากโครงสร้าง 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
หากต้องการรับการอ้างอิงถึง MemRegion
ตัวแรกและตัวที่สองภายในวัตถุ MemTransaction
:
const MemRegion& getFirstRegion(); // get a reference to the first MemRegion const MemRegion& getSecondRegion(); // get a reference to the second MemRegion
ตัวอย่างการเขียนไปยัง FMQ โดยใช้ API การคัดลอกเป็นศูนย์:
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);
ส่งกลับตัวชี้ไปยังช่องidx
ภายในMemRegions
ที่เป็นส่วนหนึ่งของวัตถุMemTransaction
นี้ ถ้าวัตถุMemTransaction
เป็นตัวแทนของขอบเขตหน่วยความจำเพื่ออ่าน/เขียน N รายการประเภท T ดังนั้นช่วงที่ถูกต้องของidx
จะอยู่ระหว่าง 0 ถึง N-1 -
bool copyTo(const T* data, size_t startIdx, size_t nMessages = 1);
เขียนรายการnMessages
ประเภท T ลงในพื้นที่หน่วยความจำที่อ็อบเจ็กต์อธิบาย โดยเริ่มจากดัชนีstartIdx
เมธอดนี้ใช้memcpy()
และไม่ได้มีไว้สำหรับการดำเนินการคัดลอกเป็นศูนย์ ถ้าวัตถุMemTransaction
แสดงถึงหน่วยความจำสำหรับอ่าน/เขียน N รายการประเภท T ดังนั้นช่วงที่ถูกต้องของidx
จะอยู่ระหว่าง 0 ถึง N-1 -
bool copyFrom(T* data, size_t startIdx, size_t nMessages = 1);
วิธีการช่วยเหลือในการอ่านรายการnMessages
ประเภท T จากขอบเขตหน่วยความจำที่อธิบายโดยอ็อบเจ็กต์ที่เริ่มต้นจากstartIdx
เมธอดนี้ใช้memcpy()
และไม่ได้มีไว้สำหรับการดำเนินการคัดลอกเป็นศูนย์
การส่งคิวผ่าน HIDL
ในด้านการสร้าง:
- สร้างออบเจ็กต์คิวข้อความตามที่อธิบายไว้ข้างต้น
- ตรวจสอบว่าวัตถุนั้นถูกต้องด้วย
isValid()
- หากคุณกำลังรอหลายคิวโดยส่ง
EventFlag
ไปเป็นรูปแบบยาวของreadBlocking()
/writeBlocking()
คุณสามารถแยกตัวชี้แฟล็กเหตุการณ์ (โดยใช้getEventFlagWord()
) จากอ็อบเจ็กต์MessageQueue
ที่เริ่มต้นเพื่อสร้างแฟล็ก และใช้แฟล็กนั้นเพื่อสร้างออบเจ็กต์EventFlag
ที่จำเป็น - ใช้เมธอด
MessageQueue
getDesc()
เพื่อรับวัตถุ descriptor - ในไฟล์
.hal
ให้กำหนดพารามิเตอร์ประเภทfmq_sync
ให้กับเมธอดหรือ fmq_unsync
โดยที่ T
เป็นประเภทที่กำหนด HIDL ที่เหมาะสม ใช้สิ่งนี้เพื่อส่งอ็อบเจ็กต์ที่ส่งคืนโดยgetDesc()
ไปยังกระบวนการรับ
ทางด้านรับ:
- ใช้วัตถุคำอธิบายเพื่อสร้างวัตถุ
MessageQueue
ตรวจสอบให้แน่ใจว่าใช้คิวรสชาติและประเภทข้อมูลเดียวกัน ไม่เช่นนั้นเทมเพลตจะไม่สามารถคอมไพล์ได้ - ถ้าคุณแยกค่าสถานะเหตุการณ์ แยกค่าสถานะออกจากวัตถุ
MessageQueue
ที่สอดคล้องกันในกระบวนการรับ - ใช้วัตถุ
MessageQueue
เพื่อถ่ายโอนข้อมูล