الخلاصة

  • كانت العمليات الطويلة في TinyOS مقسمة المراحل: يبدأ الأمر الطلب أو يرفضه ثم يعود فورا، بينما يبلغ حدث لاحق عن الاكتمال ضمن حدود المكوّن المقدم للخدمة.
  • وفر هذا التصميم المكدسات والطاقة، لكنه نقل التسلسل وحيازة المخزن المؤقت والمهل والتعافي إلى آلة حالات صريحة.
  • كان sendDone قادرا على إثبات إمكان إعادة استخدام الرسالة محليا من دون أن يثبت أن التطبيق البعيد استلمها أو قبلها أو نفذ معناها.

ما الذي تقوله المهلة فعلا

حين ينتظر برنامج حدثا ولا يصل، يسهل أن يكتب كلمة «فشل». لكن غياب الإشعار ليس بالضرورة دليلا على غياب الفعل. ربما لم يبدأ العمل، وربما اكتمل وضاع إشعاره، وربما ما زال الجهاز ينفذه. هذه الحالات متشابهة لمن يراقب الصمت، ومختلفة تماما لمن سيقرر إعادة المحاولة.

جعل TinyOS هذه المشكلة مرئية لأن العملية الطويلة لم تكن تختبئ داخل استدعاء متزامن. يصدر التطبيق send، فيقبل مكوّن الراديو الطلب أو يرفضه، ثم يعيد الأمر التحكم. إذا قبل الطلب، يبقى التزام لم يحسم. يأتي sendDone لاحقا ليغلق الجزء الذي يعرفه ذلك المكوّن.

ورقة NSDI لعام 2004، The Emergence of Networking Abstractions and Techniques in TinyOS، كتبها Philip Levis وSam Madden وDavid Gay وJoseph Polastre وRobert Szewczyk وAlec Woo وEric Brewer وDavid Culler. تصف الأوامر بأنها طلبات لبدء أفعال، والأحداث بأنها إما إكمال لطلبات أو وقائع منشؤها البيئة. ويمكن للخطين أن يحملا أخطاء.

بهذا يصبح لكل سجل سؤال خاص. تسجيل الأمر يثبت أن نية قدمت. والنتيجة الفورية قد تثبت الرفض أو القبول. وحدث الاكتمال يثبت الانتقال الذي يسيطر عليه مصدره. أما تأكيد الوصلة، والاستلام البعيد، ومعالجة التطبيق، والأثر المادي فتحتاج إلى أصوات أخرى.

لماذا لم يكن الانتظار المتزامن ممكنا

عملت وحدات الاستشعار المبكرة بذاكرة تقاس ببضعة كيلوبايت، وبطارية يجب حمايتها من فترات النشاط التي لا تنتج حسابا مفيدا. تخصيص خيط محجوب ومكدس مستقل لكل إرسال أو تحويل حساس كان سيستهلك المورد الأندر. إبقاء المعالج مستيقظا حتى ينتهي العتاد كان سيستهلك الطاقة.

اعتمد TinyOS المهام للحساب المؤجل والأحداث للتغيرات غير المتزامنة. عندما تفرغ قائمة المهام يستطيع المعالج النوم، ثم تعيده مقاطعة تحمل عملا جديدا.

لذلك قسمت العملية الطويلة إلى مرحلتين. يطلب الأمر الفعل ثم يحرر المكدس. وعندما يغير العتاد حالته، يدفع الحدث آلة الحالات إلى الخطوة التالية. يمكن لتدفقات كثيرة أن تتقدم بمكدس واحد صغير.

لكن الحالة المنطقية لم تختف؛ انتقلت إلى التطبيق. وجب عليه أن يتذكر أي طلب ما زال معلقا، وأي مخزن مؤقت تحت حيازة الراديو، وأي حدث ينتظره، وماذا يفعل إذا رفض الطلب أو لم يظهر الحدث. لم يلغ التصميم الانتظار، بل منعه من التخفي.

مخزن مؤقت واحد وحيازة مؤقتة

كان تجنب النسخ مهما لأن نسخ الحزم يستهلك الذاكرة والدورات والطاقة. غالبا ما مررت المكوّنات مؤشرا إلى المخزن المؤقت نفسه. بعد قبول الإرسال يحتاج الراديو إلى بقاء البايتات من دون تغيير إلى أن ينتهي من دوره.

يبقى المخزن في ذاكرة التطبيق، لكن حق تعديله ينتقل مؤقتا. يعلن sendDone أن هذه الحيازة المحلية انتهت ويمكن استخدام المورد من جديد.

إذا أعاد التطبيق كتابة المخزن قبل الحدث فقد يفسد الحزمة وهي في الطريق. وإذا لم يصل الحدث فقد تتجمد ذاكرة نادرة إلى أجل غير معلوم. وإذا فقدت المطابقة بين الحدث والطلب فقد يحرر البرنامج المخزن الخطأ. ومع حدث مكرر قد يغلق الالتزام نفسه مرتين.

لهذا لم يكن حدث الاكتمال مجرد استدعاء رجعي للراحة البرمجية؛ كان إيصال حيازة. قوته محددة بحدوده. قد يثبت انتهاء محاولة الإرسال المحلية، وقد يتضمن نتيجة على مستوى الوصلة بحسب التنفيذ. لكنه لا يثبت باسمه وحده أن التطبيق البعيد تلقى الرسالة أو خزنها أو نفذها.

واجهة تسير في اتجاهين

أعطت nesC هذا التبادل شكلا ثابتا. تنتقل الأوامر من مستخدم الواجهة إلى مقدمها، وتعود الأحداث من المقدم إلى المستخدم. كان send وsendDone جزءين من عقد واحد، وكان الربط الساكن يصل الاتجاهين.

استطاع المصرّف رؤية تركيب البرنامج كله، والتحقق من علاقات المكوّنات، واكتشاف كثير من احتمالات التنافس، وتقليل الكلفة الديناميكية. على جهاز صغير، كانت الوقاية في وقت الترجمة أثمن من آليات حماية تستهلك موارد أثناء التشغيل.

غير أن الربط يثبت التركيب لا سلطة البرنامج على العالم. هو يعرف أن مكوّنا مترجما متصل بدالة محددة. لا يصادق على الحساس المادي، ولا يثبت هوية جار الراديو، ولا يحول القياس إلى حقيقة لمجرد أن نوع الواجهة صحيح.

كذلك ليست كل الأحداث إيصالات. قد يكمل الحدث طلبا سابقا، أو يبدأ من البيئة بوصول رسالة أو انتهاء مؤقت أو تغير حساس. وصف كل حدث بأنه رد يمحو الفرق بين الاستجابة والملاحظة. يجب أن يسمى الدور الدلالي قبل استعمال الحدث كدليل.

القبول ليس نصرا نهائيا

عندما تكون الخدمة مشغولة يستطيع المكوّن رفض طلب متزامن فورا، أو وضعه في قائمة للمعالجة لاحقا. القراران ينشئان واقعين مختلفين.

بعد الرفض لا ينبغي اختراع عملية معلقة. يحتفظ الطالب بالمخزن ويقرر الانتظار أو الإسقاط أو إعادة المحاولة. بعد القبول ينشأ التزام على المقدم، وتنتقل الحيازة المؤقتة إلى أن يصل الحدث أو مسار خطأ محدد.

تضغط واجهات كثيرة اليوم التقديم والتحقق والقبول والتنفيذ والنتيجة النهائية في حالة واحدة اسمها «نجاح». يفصل النموذج المقسم هذه المراحل لأن كل واحدة تجيب عن سؤال في وقت مختلف.

حتى الوسيط success داخل sendDone(message, success) يحتاج إلى نطاق. يمكن أن يكون كافيا لتحرير الرسالة ومتابعة آلة الحالات. وربما يشمل معلومة من طبقة الوصلة. لكنه لا يتحدث تلقائيا باسم تطبيق بعيد لم يصدر إيصالا.

الدليل الضيق ليس دليلا ضعيفا. إنه دليل صالح لإجراء بعينه، وخطورته تبدأ عندما ينسب إليه أثر طرف لم يتكلم.

عندما يتعطل طريق حدث الاكتمال

يوضح تقرير T2 أن مسار الإيصال نفسه يستهلك موارد. كانت الطبقة العليا تنتظر الراديو قبل إعادة استعمال المخزن. وعادة ينشر مكدس الراديو مهمة في القائمة كي ترسل sendDone. إلا أن قائمة المهام محدودة.

إذا تعذر نشر المهمة، قد ينتظر الطالب إلى الأبد. لجأ TinyOS أحيانا إلى إرسال sendDone مباشرة في سياق المقاطعة. أعاد ذلك التقدم، لكنه خالف افتراض التنفيذ المعتاد: كود كتب لبيئة مهمة قد يعمل الآن بصورة غير متزامنة ويحدث تنافسا أو فسادا في الذاكرة.

يشير المؤلفون إلى أن هذا الشكل لا يخص مكدس راديو واحدا. أي مكوّن مقسم المراحل يعتمد على نشر مهمة لإبلاغ الاكتمال قد يفقد الإشارة تحت ضغط القائمة. إما أن تضيع النهاية فتعطل الطبقات العليا، أو تصل في سياق غير متوقع فتكسر سلامة التزامن.

لا تبرر هذه الملاحظة الادعاء بأن كل نشر لـTinyOS شهد الخلل نفسه. كان T2 استجابة تصميمية من فريق كبير، لا إحصاء للحوادث. الدرس الذي تسنده المصادر أضيق: نقل دليل الاكتمال عملية تنفيذية معرضة لحدود القائمة والسياق مثل أي عملية أخرى.

آلة الحالات كسجل للانتقالات

بعد إلغاء التسلسل المحجوب، كان على البرنامج أن يمثل الخطوات كآلة حالات. يصدر الطلب، يسجل التعليق، ينتظر الحدث المطابق، ثم ينتقل بناء على النتيجة.

يمكن للسجل أن يميز الخمول، والطلب، والرفض، والقبول، وعمل العتاد، والاكتمال المحلي، وانتهاء المهلة، والإلغاء. لا يلزم أن تتحول المهلة إلى حكم بأن الفعل لم يقع؛ يمكنها أن تبقى حالة غير محسومة. ويمكن لحدث متأخر أن يعود إلى طلبه إذا بقي معرف العملية.

إعادة المحاولة هي الأخرى تحتاج إلى معنى. قد تستخدم الهوية نفسها للمصالحة، أو تنشئ فعلا جديدا بقصد واضح. من دون الهوية يصبح من السهل تكرار أثر وقع بالفعل أو ربط الإيصال القديم بطلب جديد.

ولا تجعل آلة الحالات البرنامج صادقا تلقائيا. يمكنها إهمال انتقال، أو إعادة استخدام معرف، أو إخفاء امتلاء القائمة. يقلل التحليل الساكن بعض السباقات لكنه لا يثبت صحة المعنى التجاري. يصبح السجل مفيدا فقط عندما تقابل حالاته وقائع يمكن ملاحظتها في التشغيل.

توفر أولوية الكود العامل لدى Heng Lu عدسة معاصرة لهذه الفكرة. إعلان الأمر نية، أما المكوّن العامل والحدث اللاحق فيقدمان دليلا أقوى. لكن الحدث لا يصبح ذا سيادة مطلقة؛ ينتهي معناه عند الانتقال الذي يسيطر عليه باعثه. هذه مقارنة تحريرية لاحقة، وليست نسبة عقيدة حديثة إلى مؤلفي TinyOS تاريخيا.

Culler داخل منظومة من المؤلفين

تضع صفحة Berkeley الرسمية TinyOS وBerkeley Motes بين الأنظمة المحورية في مسيرة David Culler. ودوره في بناء البيئة البحثية وتطوير العمارة يجعله مركزا مناسبا لسرد شخصي، لا مؤلفا منفردا للنظام.

ورقة NSDI لها ثمانية مؤلفين. وورقة nesC كتبها David Gay وPhilip Levis وRobert von Behren وMatt Welsh وEric Brewer وCuller. أما T2 فحمل أسماء فريق أوسع من Stanford وBerkeley وIntel Research وTechnische Universität Berlin وUCLA وCrossbow وArch Rock وMoteiv وWashington University. وكتب Philip Levis مراجعة العقد في 2012.

الإسناد الجماعي جزء من المعنى، لا حاشية مجاملة. نشأ TinyOS من تفاعل اللغة ونظام التشغيل والراديو والعتاد والتجارب والمجتمع. وتاريخ الأفكار فيه مركب مثل مكوّناته.

الكلفة التي ظهرت بعد النجاح

ذكر Levis في مراجعة 2012 أن TinyOS كان في ذلك الوقت منصة بحثية بارزة وظهر في منتجات تجارية. لكنه لم يكتب نهاية احتفالية فقط. أتاحت nesC والمكوّنات الدقيقة وتقليل الموارد للخبراء بناء أنظمة معقدة؛ ومع النضج، جعلت اللغة المتخصصة وتوزع المنطق بين مكوّنات كثيرة دخول المستخدمين الجدد وفهم الكود القائم أكثر صعوبة.

تلك الملاحظات وأرقام التبني تاريخية تخص زمنها، وليست قياسا راهنا. قيمتها أنها تكشف مقايضة طويلة الأجل: قد تكون الواجهة أنيقة محليا، ثم تنتج كلفة تعلم وتنسيق على مستوى المجتمع. يوفر الاختيار الساكن ذاكرة التشغيل، وقد يستهلك وقت البشر لاحقا.

يبقى فصل الطلب عن الاكتمال صالحا رغم هذا النقد. تستخدم الأنظمة الحديثة الوعود والمستقبليات وقوائم الإكمال وحالات الوظائف الدائمة. تتغير الأسماء ولا تتغير المسؤولية: التعليمات ليست نتيجة، والنتيجة المحلية ليست حقيقة من طرف إلى طرف.

الإيصال المفيد يقف عند حد صاحبه

لم يكن الأمر الذي عاد مبكرا ناقصا؛ كان دقيقا. قال إن حدود الطلب اجتيزت وإن مكوّنا آخر أصبح مسؤولا عن الحقيقة التالية. ولم يكن حدث الاكتمال كلي المعرفة؛ قال إن المقدم بلغ الحالة التي يعرفها العقد وأعاد الحيازة المحلية.

إذا احتاج المشغل إلى إثبات تأكيد الوصلة، أو الاستلام البعيد، أو معالجة التطبيق، أو الأثر المادي، وجب الحصول على إيصالات من تلك الأدوار. لا تستطيع علامة نجاح واحدة أن تنوب عنها.

أجبرت قيود الجهاز الصغير التصميم على إظهار الزمن والحيازة وعدم اليقين. تستطيع الأنظمة الكبيرة إخفاء الفجوات خلف طبقات وسيطة، لكنها لا تلغيها. النظام الصادق يطابق الطلب بإكماله، ويبقي غير المحسوم ظاهرا، ويحفظ معنى كل دليل داخل حدود مصدره.

المصادر