مقدمه
MINIX 3 سیستمعاملی منبعباز است که بسیار منعطف، قابل اطمینان و امن میباشد. این سیستمعامل از نظر بیس چیزی شبیه به نسخههای قبلی خود اما در بسیاری از جهات کاملا متفاوت است. MINIX 1 و ۲ بیشتر برای ابزار آموزشی در نظر گرفته شده بودند , اما هدف MINIX 3 به سمت یک سیستم معمول بودن نشانه رفته شده.
سیستمعامل جدید بینهایت کوچک است. قسمتهایی که در مد کاربر اجرا میشوند به ماژولهای کوچکتر تقسیم و به خوبی از هم جدا شدهاند، برای مثال راهانداز هر دیوایس در مد-کاربرِ مجزایی پردازش میشود، بنابراین وجود مشکلات در یک راهانداز کل سیستمعامل را تحت الشعاع قرار نمیدهد. در حقیقت در اکثر مواقع زمانی که یک راهانداز با مشکل مواجه میشود به صورت خودکار بدون نیاز به مداخله کاربر و یا راهاندازی مجدد سیستم، جایگزین میشود. حتی این روند تأثیری بر روی برنامههای در حال اجرا هم نخواهد گذاشت. این ویژگیها در هستهای با این حجم کوچکِ کد، یک سیستم قابل اعتماد را برای ما به ارمغان میآورد.
اکنون میتوانیم به منظور تکمیل مطالعات خود در زمینه مدیریت فرآیند، ارتباط بین فرآیندها و زمانبندی، به بررسی چگونگی استفاده از آنها در MINIX 3 بپردازیم. بر خلاف UNIX که هستهی آن یکپارچه است و به ماژولهای مختلف تجزیه نشده ، MINIX 3 مجموعهای از فرآیندهاست که با یکدیگر و با فرآیندهای کاربر، از طریق یکی از روشهای اولیهی ارتباط به نام تبادل پیغام، ارتباط برقرار میکنند. این طراحی یک ساختار پیمانهای (ماژولار) با قابلیت انعطاف بیشتر را به وجود میآورد که آن را سادهتر میسازد. به عنوان مثال میتوان کل سیستمفایل را بدون نیاز به کامپایل مجدد هسته با یک سیستم کاملاً جدید دوباره نویسی و جایگزین کرد. به عبارت دیگر اگر قسمتی از سیستمعامل مانند سیستمفایل بهروز شود، میتوان از امکانات و بهبودهای جدید آن بدون نیاز به دستکاری هسته استفاده کرد. همچنین افزودن خدمتگزارهای جدید مستلزم کامپایل مجدد کل سیستم نیست. میتوان سیستم مدیر فرآیند و سیستمفایل را با خدمتگزار شبکه و سایر خدمتگزارها تکمیل نمود و این امر به وسیله اضافه نمودن خدمتگزارهای اضافی مورد نیاز صورت میگیرد. اگرچه معمولاً گردانندههای دستگاه در هنگام بارگزاری سیستم، راهاندازی میشوند اما میتوانند بعداً نیز به سیستم افزوده شوند. هم گردانندههای دستگاه و هم خدمتگزارها کامپایل میشوند و به عنوان فایلهای اجرایی معمولی بر روی دیسک ذخیره میگردند، اما وقتی که به طور مناسب نصب میشوند از دسترسیهای ممتاز مخصوص خود برخوردار خواهند بود. یک برنامه کاربر به نام «سرویس»، واسط مربوط خدمتگزار تناسخ، که مدیریت این امور را برعهده دارد را فراهم مینماید. اگر چه گردانندهها و خدمتگزارها فرآیندهای مستقلی هستند اما معمولاً با فرآیندهای کاربر، این تفاوت را دارند که تقریبا در تمام مواقع در زمان فعال بودن سیستم، خاتمه نمییابند.
ما اغلب به گردانندهها و خدمتگزارهای درون لایههای ۲ و ۳، تحت عنوان فرآیندهای سیستم اشاره میکنیم. فرآیندهای سیستم بخشی از سیستمعامل به شمار میروند. آنها به هیچ کاربری تعلق ندارند و بسیاری از آنها (البته نه تمامی آنها) قبل از برقراری ارتباط از سوی اولین کاربر، فعال میشوند. تفاوت دیگر فرآیندهای سیستم و فرآیندهای کاربر این است که فرآیندهای سیستم از اولویت اجرایی بالاتری نسبت به فرآیندهای کاربر برخوردار هستند. در حقیقت، معمولاً گردانندهها، اولویت اجرایی بالاتری نسبت به خدمتگزارها دارند، اما این امر به صورت خودکار تحقق نمییابد. اولویت اجرایی در MINIX 3 به صورت موردی تعیین می شود؛ ممکن است یک گرداننده که خدمات یک دستگاه کُند را بر عهده دارد، اولویت پایینتری نسبت به خدمتگزاری که باید به سرعت پاسخ دهد داشته باشد.
این مزیت در Hurd نیز وجود دارد، اما هستهی لینوکس از ساختار مشابه یونیکس و بیاسدی یعنی ساختار یکپارچه استفاده میکند.
ساختار داخلی MINIX 3
اجازه دهید برای مطالعهی MINIX 3 از بالا به آن نگاه کنیم. MINIX 3 از چهار لایه تشکیل شده است که هر لایه وظیفه کاملاً تعریف شدهای دارد. هسته در لایه پایین وظیفهی کنترل زمانبندی فرآیندها، مدیریت جابجایی بین وضعیتهای آماده، در حال اجرا و بلوکه را بر عهده دارد. همچنین هسته پیغامهای بین فرآیندها را مدیریت مینماید. مدیریت پیغامها مستلزم بررسی گیرنده میباشد. بخشی از هسته دسترسی به پورتهای I/O و وقفهها را پشتیبانی میکند که در پردازندههای پیشرفته مستلزم استفاده از دستورالعملهای ممتاز مد هسته است و برای فرآیندهای معمولی خارج از دسترس میباشد.
علاوه بر خود هسته، این لایه شامل دو ماژول دیگر است که عملکردی مشابه با گردانندههای دستگاه دارند. task ساعت یک گرداننده دستگاه I/O است به این معنی که با سختافزاری که سیگنالهای زمان را تولید میکند، در تعامل است، اما گردانندههای دیسک یا خطوط ارتباطی، در دسترس کاربر نیست و تنها با هسته در ارتباط است.
یکی از وظایف اصلی لایه ۱، فراهم نمودن مجموعهای از فراخوانهای ممتاز هسته برای گردانندهها و خدمتگزارهای قرار گرفته در بالای آن میباشد.این مجموعه شامل خواندن و نوشتن بر روی پورتهای I/O، کپی اطلاعات بین فضاهای آدرس و نظیر اینهاست. پیاده سازی این فراخوانها به وسیله task سیستم انجام میشود. اگر چه task سیستم و task ساعت در فضای آدرس هسته کامپایل میشوند، اما آنها به عنوان فرآیندهای جداگانه زمانبندی شده و پشتههای فراخوانی خودشان را دارند.
بیشتر هسته و کل taskهای ساعت و سیستم به زبان C نوشته میشوند. البته بخش کوچکی از هسته به زبان اسمبلی نوشته شده است. این بخشهای زبان اسمبلی به اداره وقفهها، مکانیسمهای سطح پایین مدیریت تعویض متن بین فرآیندها (ذخیره و بازیابی رجیسترها و امثال آن) و بخشهای سطح پایین کار با رجیسترهای سختافزار MMU میپردازند. کد اسمبلی، اداره بخشهایی از هسته را بر عهده دارد که مستقیماً مرتبط با سختافزار و در سطح بسیار پائین هستند و نمیتوانند به زبان C بیان شوند.
(کدام سه لایه؟)سه لایه روی هسته میتوانند به صورت یک لایه منفرد در نظر گرفته شوند زیرا هسته اساساُ به یک صورت با آنها رفتار میکند. هر سه لایه به دستورالعمل مد کاربر محدود میشوند و همگی توسط هسته زمانبندی میشوند. هیچ یک از آنها به طور مستقیم به پورتهای I/O دسترسی ندارند. همچنین، هیچ کدام از آنها نمیتوانند به فضای حافظه خارج از قطعه تخصیص یافته به خود، دسترسی پیدا کنند.
با این حال، فرآیندهها به صورت بالقوه امتیازات خاصی دارند (مانند قابلیت اجرای فراخوانهای هسته). این تفاوتِ واقعی بین فرآیندهای لایه، ۲، ۳ و ۴ است. فرآیندهای لایه ۲، از حداکثر امتیاز برخوردارند. در لایه ۳، امتیازات کمتری وجود دارد و در لایه ۴ هیچ امتیاز ویژه ای وجود ندارد. به عنوان مثال فرآیندهای لایه ۲ که گردانندههای دستگاه نام دارند، اجازه دارند که از task سیستم درخواست خواندن و نوشتن دادهها بر روی پورتهای I/O مربوط به خود بنمایند. برای هر نوع دستگاه از قبیل دیسکها ، چاپگرها، ترمینالها و واسطهای شبکه، یک گرداننده مخصوص لازم است. بدیهی است اگر دستگاه دیگری اضافه شود به گرداننده خاص خود نیاز دارد. همچنین گردانندههای دستگاه میتوانند سایر فراخوانهای هسته مانند درخواست کپی دادههای خوانده شدهی جدید به فضای آدرس فرآیند متفاوت را اجرا کنند.
لایهی سوم شامل خدمتگزارها میشود. خدمتگزارها فرآیندهایی هستند که ارایه خدمات مفید به فرآیندهای کاربر را بر عهده دارند. دو مورد از خدمتگزارها نقش اساسی دارند؛ یکی از آنها مدیر فرآیند (Process Manager) است که در بر گیرنده آن دسته از فراخوانهای سیستمی MINIX3 است که آغاز یا توقف اجرای فرآیندها را برعهده دارند، مانند fork, exec و exit. همچنین پیاده سازی فراخوانهای سیستمی مرتبط با سیگنالها را شامل میشود، نظیر alarm و kill که قادر هستند وضعیت اجرایی یک فرآیند را تغییر دهند. همچنین مدیر فرآیند در اموری از مدیریت حافظه مانند فراخوان سیستمی brk مسئولیت دارد. دومین خدمتگزار، سیستم فایل (File System) است که کلیه فراخوانهای مدیریت حافظه مانند read, mount و chdir را انجام میدهد.
درک تفاوت بین فراخوانهای هسته و فراخوانهای سیستمی POSIX از اهمیت زیادی برخوردار است. فراخوانهای هسته عملیات سطح پایینی هستند که به وسیله task سیستم فراهم شدهاند تا به گردانندهها و خدمتگذارها اجازه انجام کار خود را بدهند. خواندن یک پورت I/O سختافزاری، یک فراخوان هستهی نوعی به شمار میرود. در مقابل، فراخوانهای سیستمی POSIX مانند read, fork و unlink فراخوانهای سطح بالایی هستند که در استاندارد POSIX تعریف شدهاند و برای برنامههای کاربر در لایه ۴، قابل دسترسی میباشند. برنامههای کاربر شامل تعداد زیادی از قراخوانهای POSIX است، اما فراخوانهای هسته ندارد. گاهی در اثر اشتباه لفظی ممکن است فراخوان هسته را فراخوانی سیستمی بنامیم. مکانیسمهای استفاده شده در ایجاد این فراخوانها مشابهاند و فراخوانهای هسته میتوانند زیر مجموعه خاصی از فراخوانهای سیستمی تلقی گردند.
همانگونه که اطلاع دارید سیستمهای عامل دو وظیفه اساسی دارند : مدیریت منابع و فراهم نمودن یک ماشین توسعه یافته به وسیله پیاده سازی فراخوانهای سیستمی. در MINIX3 مدیریت منابع تاحد زیادی توسط گرداننده های لایه ۲ به کمک لایه هسته صورت میپذیرد؛ هنگامی که دسنرسی ممتاز به پورتهای I/O یا سیسم وقفه در خواست میشود. تفسیر فراخوان سیستمی به وسیلهی خدمتگزارهای مدیر فرآیند و سیستمفایل در لایه ۳، انجام میگیرد. سیستمفایل دقیقا به صورت یک فایل «خدمتگزار» طراحی شده است به طوریکه میتواند با تغییرات ناچیزی به یک ماشین راه دور منتقل شود.
در نهایت لایه ۴ متشکل از کلیه فرآیندهای کاربر از قبیل پوستهها، ویرایشگرها، کامپایلرها، و برنامههای a.out ایجاد شده توسط کاربر میباشد. بسیاری از فرآیندهای کاربر، با ورود کاربر به سیستم و یا انجام کار و خروج از سیستم، میآیند و میروند. در مقابل، معمولا در یک سیستم در حال اجرا تعدادی فرآیند کاربر وجود دارند که در زمان راه اندازی سیستم آغاز به کار مینمایند و همیشه در حال اجرا هستند.
یکی از آنها init است که در مقالههای بعدی بیشتر به آن میپردازیم. معمولا چند برنامه شبح نیز اجرا می شوند. شبح یک فرآیند پسزمینه است که یا به طور متناوب اجرا می شود یا همواره در انتظار رویدادی مانند ورود یک بسته از شبکه به سر میبرد. به عبارتی می توان گفت که شبح، خدمتگزاری است که به طور مستقل راهاندازی میشود و به عنوان یک فرآیند کاربر اجرا میگردد. شبیه خدمتگزارهای واقعی که در هنگام راهاندازی سیستم نصب شدهاند. این امکان وجود دارد که یک شبح نیز به گونه ای پیکربندی شود که از اولویت بالاتری نسبت به فراخوانهای معمولی کاربر برخوردار باشد.
در اینجا یک نکته پیرامون عبارت task و گرداننده دستگاه ضروری به نظر میرسد. در نسخههای قدیمی MINIX کلیه گردانندههای دستگاه همراه با هسته کامپایل میشدند و امکان دسترسی آنها به ساختارهای داده متعلق به هسته و دیگر taskها وجود داشت. همچنین آنها میتوانستند به طور مستقیم به پورتهای I/O دسترسی داشته باشند، بنابراین، به آنها تحت عنوان «task» اشاره میشود تا از فرآیندهای مستقلی که به طور محض در فضای کاربر قرار دارند متمایز شوند. در MNIX 3، گردانندههای دستگاه به طور کامل در فضای کاربر اجرا میشوند. تنها استثناء، task ساعت است که از نظر منطقی مانند سایر گردانندههای دستگاه نیست که بتواند از طریق فایلهای دستگاه به وسیله فرآیندهای کاربر مورد دسترسی قرار بگیرند. ما در درون متن، اصطلاح task را تنها برای task ساعت یا task سیستم به کار بردیم که هر دو برای انجام وظیفه در درون هسته کامپایل شدهاند. از آنجا که نام توابع، نام متغیرها و توضیحات درون کد برنامه بهدقت بهروزرسانی نشده است، شما در طی مطالعه کد برنامه MINIX 3 ممکن است به کلمه task برخورد کنید که در آنجا واژه task به معنی گرداننده دستگاه باشد.
منبع:
Operating System Design and Implementation, 3rd ed., 2006 | Tanenbaum, Andrew S., 1944