ফাস্ট মেসেজ কিউ (FMQ)

আপনি যদি এআইডিএল সমর্থন খুঁজছেন তবে এআইডিএল-এর সাথে এফএমকিউও দেখুন।

HIDL এর রিমোট প্রসিডিওর কল (RPC) পরিকাঠামো বাইন্ডার মেকানিজম ব্যবহার করে, যার অর্থ কলগুলি ওভারহেড জড়িত, কার্নেল অপারেশনের প্রয়োজন এবং শিডিউলার অ্যাকশন ট্রিগার করতে পারে। যাইহোক, যেসব ক্ষেত্রে কম ওভারহেড এবং কোনো কার্নেল জড়িত না থাকা প্রসেসের মধ্যে ডেটা স্থানান্তর করতে হবে, ফাস্ট মেসেজ কিউ (FMQ) সিস্টেম ব্যবহার করা হয়।

FMQ পছন্দসই বৈশিষ্ট্য সহ বার্তা সারি তৈরি করে। একটি MQDescriptorSync বা MQDescriptorUnsync অবজেক্ট একটি HIDL RPC কলের মাধ্যমে পাঠানো যেতে পারে এবং বার্তা সারিতে অ্যাক্সেস করার জন্য গ্রহণ প্রক্রিয়া দ্বারা ব্যবহার করা যেতে পারে।

ফাস্ট মেসেজ সারিগুলি শুধুমাত্র C++ এবং Android 8.0 এবং উচ্চতর সংস্করণে চালিত ডিভাইসগুলিতে সমর্থিত।

বার্তা সারি প্রকার

অ্যান্ড্রয়েড দুটি সারি ধরনের সমর্থন করে ( স্বাদ নামে পরিচিত):

  • আনসিঙ্ক্রোনাইজড সারিগুলিকে ওভারফ্লো করার অনুমতি দেওয়া হয় এবং অনেক পাঠক থাকতে পারে; প্রতিটি পাঠকের অবশ্যই সময়মতো ডেটা পড়তে হবে বা এটি হারাতে হবে।
  • সিঙ্ক্রোনাইজড সারিগুলিকে ওভারফ্লো করার অনুমতি দেওয়া হয় না এবং শুধুমাত্র একজন পাঠক থাকতে পারে৷

উভয় সারির ধরনকে আন্ডারফ্লো করার অনুমতি দেওয়া হয় না (একটি খালি সারি থেকে পড়া ব্যর্থ হবে) এবং শুধুমাত্র একজন লেখক থাকতে পারে।

আনসিঙ্ক্রোনাইজড

একটি অসিঙ্ক্রোনাইজড সারিতে শুধুমাত্র একজন লেখক আছে, কিন্তু পাঠকদের সংখ্যা যেকোনও থাকতে পারে। সারির জন্য একটি লেখার অবস্থান আছে; যাইহোক, প্রতিটি পাঠক তার নিজস্ব স্বাধীন পঠন অবস্থানের উপর নজর রাখে।

সারিতে লেখা সবসময় সফল হয় (ওভারফ্লো পরীক্ষা করা হয় না) যতক্ষণ না তারা কনফিগার করা সারির ক্ষমতার চেয়ে বড় না হয় (সারি ধারণক্ষমতার চেয়ে বড় লেখা অবিলম্বে ব্যর্থ হয়)। যেহেতু প্রতিটি পাঠকের আলাদা পড়ার অবস্থান থাকতে পারে, প্রতিটি পাঠকের প্রতিটি ডেটা পড়ার জন্য অপেক্ষা করার পরিবর্তে, যখনই নতুন লেখার জন্য স্থানের প্রয়োজন হয় তখন ডেটা সারিতে পড়ে যাওয়ার অনুমতি দেওয়া হয়।

সারির শেষ থেকে পড়ে যাওয়ার আগে ডেটা পুনরুদ্ধার করার জন্য পাঠকদের দায়বদ্ধ। একটি রিড যা উপলব্ধ থেকে বেশি ডেটা পড়ার চেষ্টা করে তা হয় অবিলম্বে ব্যর্থ হয় (যদি অবরোধ না করা হয়) বা পর্যাপ্ত ডেটা উপলব্ধ হওয়ার জন্য অপেক্ষা করে (যদি ব্লক করা হয়)। একটি পঠন যা সারির ক্ষমতার চেয়ে বেশি ডেটা পড়ার চেষ্টা করে তা অবিলম্বে ব্যর্থ হয়।

যদি একজন পাঠক লেখকের সাথে তাল মিলিয়ে চলতে ব্যর্থ হয়, যাতে সেই পাঠকের দ্বারা লেখা এবং এখনও পড়া হয়নি এমন ডেটার পরিমাণ সারির ক্ষমতার চেয়ে বড় হয়, পরবর্তী পঠিত ডেটা ফেরত দেয় না; পরিবর্তে, এটি পাঠকের পঠিত অবস্থানকে সর্বশেষ লেখার অবস্থানের সমান করতে পুনরায় সেট করে তারপর ব্যর্থতা ফিরিয়ে দেয়। যদি পড়ার জন্য উপলব্ধ ডেটা ওভারফ্লো হওয়ার পরে চেক করা হয় তবে পরবর্তী পড়ার আগে, এটি সারির ক্ষমতার চেয়ে পড়ার জন্য উপলব্ধ আরও ডেটা দেখায়, ওভারফ্লো হয়েছে তা নির্দেশ করে। (যদি উপলভ্য ডেটা চেক করা এবং সেই ডেটা পড়ার চেষ্টা করার মধ্যে সারিটি ওভারফ্লো হয়, তবে ওভারফ্লো হওয়ার একমাত্র ইঙ্গিত হল পঠন ব্যর্থ হয়।)

একটি আনসিঙ্ক্রোনাইজড সারির পাঠকরা সম্ভবত সারির পঠন এবং লেখার পয়েন্টারগুলি পুনরায় সেট করতে চান না। সুতরাং, বর্ণনাকারী পাঠকদের থেকে সারি তৈরি করার সময় `resetPointers` প্যারামিটারের জন্য একটি `false` যুক্তি ব্যবহার করা উচিত।

সিঙ্ক্রোনাইজড

একটি সিঙ্ক্রোনাইজড সারিতে একজন লেখক এবং একজন পাঠক একটি একক লেখার অবস্থান এবং একটি একক পঠিত অবস্থান রয়েছে৷ সারিতে যে স্থান রয়েছে তার চেয়ে বেশি ডেটা লেখা বা সারিতে বর্তমানে যে ডেটা রয়েছে তার চেয়ে বেশি পড়া অসম্ভব৷ ব্লকিং বা ননব্লকিং রাইট বা রিড ফাংশন বলা হয় কিনা তার উপর নির্ভর করে, উপলব্ধ স্থান বা ডেটা অতিক্রম করার প্রচেষ্টা হয় অবিলম্বে ব্যর্থতা ফিরিয়ে দেয় বা পছন্দসই অপারেশন সম্পূর্ণ না হওয়া পর্যন্ত ব্লক করে। সারির ক্ষমতার চেয়ে বেশি ডেটা পড়ার বা লেখার প্রচেষ্টা সর্বদা অবিলম্বে ব্যর্থ হবে।

একটি 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 অথবা একটি unsynchronized সারির জন্য 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 প্যারামিটার নির্দেশ করে যে এই 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 স্পষ্টভাবে সরবরাহ করা যেতে পারে। সারিগুলির মধ্যে একটি একটি অভ্যন্তরীণ ইভেন্ট ফ্ল্যাগ দিয়ে শুরু করা যেতে পারে, যা অবশ্যই সেই সারির MessageQueue অবজেক্টগুলি থেকে getEventFlagWord() ব্যবহার করে বের করতে হবে এবং অন্যান্য FMQ এর সাথে ব্যবহারের জন্য প্রতিটি প্রক্রিয়াতে EventFlag অবজেক্ট তৈরি করতে ব্যবহার করা হবে। বিকল্পভাবে, EventFlag অবজেক্টগুলি যেকোনো উপযুক্ত শেয়ার করা মেমরির সাথে আরম্ভ করা যেতে পারে।

সাধারণভাবে, প্রতিটি সারিতে শুধুমাত্র একটি নন-ব্লকিং, শর্ট-ফর্ম ব্লকিং বা লং-ফর্ম ব্লকিং ব্যবহার করা উচিত। এগুলি মিশ্রিত করা কোনও ত্রুটি নয়, তবে পছন্দসই ফলাফল পেতে যত্নশীল প্রোগ্রামিং প্রয়োজন।

মেমরিটিকে শুধুমাত্র পঠিত হিসাবে চিহ্নিত করা হচ্ছে

ডিফল্টরূপে, শেয়ার করা মেমরিতে পড়ার এবং লেখার অনুমতি রয়েছে। আনসিঙ্ক্রোনাইজড সারিগুলির জন্য ( kUnsynchronizedWrite ), লেখক MQDescriptorUnsync অবজেক্টগুলি হস্তান্তর করার আগে সমস্ত পাঠকদের জন্য লেখার অনুমতিগুলি সরাতে চাইতে পারেন। এটি নিশ্চিত করে যে অন্যান্য প্রক্রিয়াগুলি সারিতে লিখতে পারে না, যা পাঠক প্রক্রিয়াগুলিতে বাগ বা খারাপ আচরণ থেকে রক্ষা করার জন্য সুপারিশ করা হয়। লেখক যদি চান যে পাঠকরা যখনই সারির পঠিত দিক তৈরি করতে MQDescriptorUnsync ব্যবহার করে তখনই সারিটি পুনরায় সেট করতে সক্ষম হন, তাহলে মেমরিটি কেবল-পঠন হিসাবে চিহ্নিত করা যাবে না। এটি `MessageQueue` কনস্ট্রাক্টরের ডিফল্ট আচরণ। সুতরাং, যদি এই সারির ইতিমধ্যেই বিদ্যমান ব্যবহারকারীরা থাকে, তাহলে resetPointer=false দিয়ে সারি তৈরি করতে তাদের কোড পরিবর্তন করতে হবে।

  • লেখক: একটি MQDescriptor ফাইল বর্ণনাকারী সহ ashmem_set_prot_region কে কল করুন এবং অঞ্চলটি শুধুমাত্র পঠনযোগ্য ( PROT_READ ):
    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() কল করে প্রাপ্ত করা যেতে পারে, এবং সেই পয়েন্টারটি (অথবা একটি উপযুক্ত শেয়ার করা মেমরি অবস্থানের যে কোনো পয়েন্টার) একটি 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() এপিআই একটি ইনপুট/আউটপুট বাফারে একটি আর্গুমেন্ট হিসাবে একটি পয়েন্টার নেয় এবং একই এবং FMQ রিং বাফারের মধ্যে ডেটা কপি করতে অভ্যন্তরীণভাবে memcpy() কল ব্যবহার করে। কর্মক্ষমতা উন্নত করতে, অ্যান্ড্রয়েড 8.0 এবং উচ্চতর এপিআইগুলির একটি সেট অন্তর্ভুক্ত করে যা রিং বাফারে সরাসরি পয়েন্টার অ্যাক্সেস প্রদান করে, memcpy কল ব্যবহার করার প্রয়োজনীয়তা দূর করে।

শূন্য কপি FMQ অপারেশনের জন্য নিম্নলিখিত পাবলিক API ব্যবহার করুন:

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 struct-এ দুটি MemRegion স্ট্রাকট রয়েছে, first এবং second রিং বাফারে পড়া বা লেখার জন্য সারির শুরুতে মোড়ানোর প্রয়োজন হতে পারে। এর অর্থ হল FMQ রিং বাফারে ডেটা পড়তে/লিখতে দুটি বেস পয়েন্টার প্রয়োজন।

একটি MemRegion struct থেকে বেস ঠিকানা এবং দৈর্ঘ্য পেতে:

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

শূন্য অনুলিপি API ব্যবহার করে FMQ-তে উদাহরণ লিখুন:

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);
    এই MemTransaction অবজেক্টের অংশ MemRegions মধ্যে স্লট idx এ একটি পয়েন্টার ফেরত দেয়। যদি 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 এর উপর সারি পাঠানো হচ্ছে

সৃষ্টির দিকে:

  1. উপরে বর্ণিত হিসাবে বার্তা সারি অবজেক্ট তৈরি করুন।
  2. isValid() দিয়ে বস্তুটি বৈধ কিনা তা যাচাই করুন।
  3. আপনি যদি readBlocking() / writeBlocking() এর দীর্ঘ আকারে একটি EventFlag পাস করে একাধিক সারিতে অপেক্ষা করেন, তাহলে আপনি একটি MessageQueue অবজেক্ট থেকে ইভেন্ট ফ্ল্যাগ পয়েন্টার ( getEventFlagWord() ব্যবহার করে ) বের করতে পারেন যা পতাকা তৈরি করতে শুরু করা হয়েছিল, এবং প্রয়োজনীয় EventFlag অবজেক্ট তৈরি করতে সেই পতাকাটি ব্যবহার করুন।
  4. একটি বর্ণনাকারী বস্তু পেতে MessageQueue getDesc() পদ্ধতি ব্যবহার করুন।
  5. .hal ফাইলে, পদ্ধতিটিকে fmq_sync টাইপের একটি প্যারামিটার দিন অথবা fmq_unsync যেখানে T একটি উপযুক্ত HIDL-সংজ্ঞায়িত প্রকার। getDesc() দ্বারা প্রত্যাবর্তিত বস্তুটি গ্রহণ প্রক্রিয়ায় পাঠাতে এটি ব্যবহার করুন।

প্রাপ্তির দিকে:

  1. একটি MessageQueue অবজেক্ট তৈরি করতে বর্ণনাকারী অবজেক্ট ব্যবহার করুন। একই সারি স্বাদ এবং ডেটা টাইপ ব্যবহার করতে ভুলবেন না, নতুবা টেমপ্লেট কম্পাইল করতে ব্যর্থ হবে।
  2. আপনি যদি একটি ইভেন্ট পতাকা বের করে থাকেন, তাহলে রিসিভিং প্রক্রিয়ায় সংশ্লিষ্ট MessageQueue অবজেক্ট থেকে পতাকাটি বের করুন।
  3. ডেটা স্থানান্তর করতে MessageQueue অবজেক্ট ব্যবহার করুন।