رایانهها را میتوان یکی از مهمترین اختراعات و ابداعات بشری دانست. آنان در سطوح گستردهای در زندگی روزانه ما نفوذ یافتهاند و تمامی امور روزانه و حیاتی بشر را در چنته دارند. رایانههای امروزی دیگر مانند سابق مختص به رایانههای شخصی قدیمی و بزرگ که بر روی میز قرار میگرفتند و کاربردهای خاصی داشتند، نبوده و در گستره گستردهای از کاربردهای مختلف در حال ارائه خدمات هستند. به عنوان مثال زمانی که از گوشیهوشمند خود استفاده میکنید؛ نیز از یک رایانه استفاده میکنید که از معماری آرم بهره میبرد.
رایانهها در هر شکل و ساختاری از دو بخش تشکیل شدهاند؛ سختافزار و نرمافزار، که کموبیش با این موضوع آشنا هستید. بااینحال بخش نرمافزاری نیز خود به چند قسمت دیگر قابل تقسیم است که در زیر به آنان اشاره شده است.
به طور کلی نرمافزارهای رایانه را میتوان به دو دسته عمده تقسیم کرد
-
نرمافزارهای کاربردی که کارهای مورد نیاز کاربران را انجام میدهند؛
-
نرمافزارهای سیستمی که وظیفه کنترل و مدیریت خود رایانه را بر عهده دارند؛
سیستمعامل «Operating System»، اساسیترین برنامه سیستمی است که مدیریت کلیه منابع سیستم را به عهده گرفته و زمینهای فراهم میسازد که برنامههای کاربردی بتوانند بر روی آن نوشته شوند.
دراین نوشتار قصد دارم به بررسی اجمالی معماری یکپارچه لینوکس و سپس ریزهسته و مینیکس بهعلاوه نحوه کار آن و سپس توضیحات مفصل در اینباره بپردازم که در برخی موارد در انتهای مقاله ممکن است کاملا تخصصی باشد. بنابراین مخاطب اصلی مقالات فوق را افرادی تشکیل خواند داد که حداقل دو واحد درس سیستمعامل را پاس کرده باشند.
ساختار و معماری سیستمعاملها
ساختارهای مختلفی در این بخش وجود دارد که ما به بررسی مختصر ساختار مربوط به لینوکس که هسته سیستمعامل گنو/لینوکس است و سیستمعامل مینیکس که نمونهای خوب برای ساختار ریزهسته است؛ خواهیم پرداخت. ساختارهای عمده موجود عبارتند از :
-
ساختار یکپارچه
-
ساختار پیوندی*
-
ساختار مشتری خدمتگزار «ریزهسته»
سیستمهای یکپارچه
میتوان این روش متداول در گذشته را «درهمریختگی بزرگ» نامید. ساختار آن در بیساختاری نهفته است. سیستمعامل به صورت مجموعهای از روندها نوشته شده که هر یک از آنها میتواند به فراخور نیاز، دیگری را صدا بزند وقتی از این تکنیک استفاده شود هر فرآیند در سیستم، یک واسط دارد که شامل مولفهها و نتایج خروجی است که به شکلی ساده تعریف شده است. هر یک از آنان قادر است تا دیگری را فراخوانی کند تا محاسبات لازم را برایش انجام دهد.
وقتی از این تکنیک استفاده شود برای ساخت برنامه شیء «آبجکت» واقعی سیستمعامل، ابتدا باید روندهای جداگانه و یا فایلهای شامل روندها را ترجمه نماییم و سپس یا استفاده از پیونددهنده «Linker» سیستم، همه آنها را به هم پیوندزده و در یک فایل آبجکت یکتا قرار دهیم. برای مخفی کردن اطلاعات، امکانات خاصی وجود ندارد و هر رویه برای دیگر رویهها کاملا قابل مشاهده است.
به هر حال حتی در سیستمهای یکپارچه، امکان داشتن حداقل یک ساختار کوچک وجود دارد. برای تقاضای سرویسهای «فراخوان سیستمی» فراهم شده توسط سیستمعامل، مولفههای مرتبط را در مکانهای دقیقا تعریف شده مانند ثباتها یا پشته قرار میدهیم و سپس یک ساختار تله «trap instruction» مخصوص را اجرا میکنیم. که «Supervisor call» و «Kernel call» نام دارند. این دستورالعمل، ماشین را از مد کاربر به مد هسته تغییر حالت داده و کنترل را در اختیار سیستمعامل قرار میدهد.
ساختار پیوندی:
ساختار پیوندی «Hybrid» ساختاری برای هسته سیستمعامل است که هم ویژگیهای ریزهسته و هم ویژگیهای هستههای یکپارچه را داراست. مدلهای سنتی مورد استفاده در هسته سیستمعاملها، مدلهای ریزهسته و هسته یکپارچه یا همان یکپارچه هستند.برخی افراد است ساختار را همان ساختار یکپارچه میدانند؛ ایده اصلی پشت این ساختار این است که هسته از مزایای ریزهسته برخوردار باشد، اما به دلیل مشکلات اجرایی ریزهستهها در عمل به صورت هستهای یکپارچه پیادهسازی شود. برخلاف ریزهستهها، در یک هسته پیوندی، همه (یا تقریباً همه) سرویسهای سیستمعامل در بخش فضای هسته قرار دارند (مشابه هسته یکپارچه). برخلاف هستههای یکپارچه، نمیتوان در زمان اجرا بودن سیستم، ماژولهایی را به هستههای پیوندی حذف یا اضافه کرد.
ارائه توضیحات بیشتر در مورد ساختار پیوندی از موضوع این بحث خارج است و چون ساختار هسته لینوکس از ساختار یکپارچه بهره میبرد، مجبور به ارایه توضیحاتی بیشتر در مورد ساختار یکپارچه شدم. برای خواندن توضیحات بیشتر درباره ساختار پیوندی به کتاب سیستمهای عامل نوشته تننباوم «Andrew Tanenbaum» مراجعه کنید.
ساختار ریزهسته «میکروکرنل»
مینیکس ویرایش سوم، سیستمعاملی متنباز است که بسیار منعطف، قابل اطمینان و امن میباشد. این سیستمعامل از نظر پایه «Base» چیزی شبیه به نسخههای قبلی خود اما در بسیاری از جهات کاملا متفاوت است. مینیکس ویرایش اول و دوم بیشتر برای ابزار آموزشی در نظر گرفته شده بودند , اما هدف مینیکس ویرایش سوم به سمت یک سیستمعامل معمولی بودن نشانه رفته شده است.
سیستمعامل جدید بینهایت کوچک است. قسمتهایی که در مد کاربر اجرا میشوند به ماژولهای کوچکتر تقسیم و به خوبی از هم جدا شدهاند، برای مثال راهانداز هر وسیله در مد«حالت»-کاربرِ مجزا پردازش میشود، بنابراین وجود مشکلات در یک راهانداز کل سیستمعامل را تحتالشعاع قرار نمیدهد. در حقیقت در اکثر مواقع زمانی که یک راهانداز با مشکل مواجه میشود به صورت خودکار بدون نیاز به مداخله کاربر و یا راهاندازی مجدد سیستم، جایگزین میشود. حتی این روند تأثیری بر روی برنامههای در حال اجرا هم نخواهد گذاشت. این ویژگیها در هستهای با این حجم کوچک کد منبع، یک سیستم قابل اعتماد را برای ما ایجاد خواهد کرد.
اکنون میتوانیم به منظور تکمیل مطالعات خود در زمینه مدیریت فرآیند، ارتباط بین فرآیندها و زمانبندی، به بررسی چگونگی استفاده از آنها در مینیکس ویرایش سوم بپردازیم. بر خلاف یونیکس که هسته آن یکپارچه است و به ماژولهای مختلف تجزیه نشده، مینیکس ۳ مجموعهای از فرآیندهاست که با یکدیگر و با فرآیندهای کاربر، از طریق یکی از روشهای اولیه ارتباط به نام تبادل پیغام، ارتباط برقرار میکنند. این طراحی یک ساختار پیمانهای «ماژولار» با قابلیت انعطاف بیشتر را به وجود میآورد که آن را سادهتر میسازد. به عنوان مثال میتوان کل سیستمفایل را بدون نیاز به ترجمه «کامپایل» مجدد هسته با یک سیستم کاملاً جدید دوباره نویسی و جایگزین کرد؛ به عبارت دیگر اگر قسمتی از سیستمعامل مانند سیستمفایل بهروز شود، میتوان از امکانات و بهبودهای جدید آن بدون نیاز به دستکاری هسته استفاده کرد.
همچنین افزودن خدمتگزارهای جدید مستلزم ترجمه مجدد کل سیستم نیست. میتوان سیستم مدیر فرآیند و سیستمفایل را با خدمتگزار شبکه و سایر خدمتگزارها تکمیل نمود و این امر به وسیله اضافه نمودن خدمتگزارهای اضافی مورد نیاز صورت میگیرد. اگرچه معمولاً گردانندههای دستگاه در هنگام بارگزاری سیستم، راهاندازی میشوند اما میتوانند بعداً نیز به سیستم افزوده شوند. هم گردانندههای دستگاه و هم خدمتگزارها ترجمه میشوند و به عنوان فایلهای اجرایی معمولی بر روی دیسک ذخیره میشوند، اما وقتی که به طور مناسب نصب میشوند از دسترسیهای ممتاز مخصوص خود برخوردار خواهند بود. یک برنامه کاربر به نام «سرویس»، واسط مربوط خدمتگزار تناسخ، که مدیریت این امور محوله را فراهم میکند. اگر چه گردانندهها و خدمتگزارها فرآیندهای مستقلی هستند اما معمولاً با فرآیندهای کاربر، این تفاوت را دارند که تقریبا در تمام مواقع در زمان فعال بودن سیستم، خاتمه نمییابند.
ما اغلب به گردانندهها و خدمتگزارهای درون لایههای ۲ و ۳، تحت عنوان فرآیندهای سیستم اشاره میکنیم. فرآیندهای سیستم بخشی از سیستمعامل به شمار میروند. آنها به هیچ کاربری تعلق ندارند و بسیاری از آنها «البته نه تمامی آنها» قبل از برقراری ارتباط از سوی اولین کاربر، فعال میشوند. تفاوت دیگر فرآیندهای سیستم و فرآیندهای کاربر این است که فرآیندهای سیستم از اولویت اجرایی بالاتری نسبت به فرآیندهای کاربر برخوردار هستند. در حقیقت، معمولاً گردانندهها، اولویت اجرایی بالاتری نسبت به خدمتگزارها دارند، اما این امر به صورت خودکار تحقق نمییابد. اولویت اجرایی در مینیکس ۳ به صورت موردی تعیین میشود؛ ممکن است یک گرداننده که خدمات یک دستگاه کُند را بر عهده دارد، اولویتی پایینتر نسبت به خدمتگزاری که باید به سرعت پاسخ دهد داشته باشد.
این مزیت در هورد «HURD» نیز وجود دارد، اما هسته لینوکس از ساختار مشابه یونیکس و بیاسدی یعنی ساختار یکپارچه استفاده میکند.
ساختار داخلی مینیکس سه
اجازه دهید برای مطالعه مینیکس سه از بالا به آن نگاه کنیم. مینیکس سه از چهار لایه تشکیل شده است که هر لایه وظیفه کاملاً تعریف شدهای دارد. هسته در لایه پایین وظیفه کنترل زمانبندی فرآیندها، مدیریت جابجایی بین حالات آماده، در حال اجرا و بلوکه را بر عهده دارد. همچنین هسته پیغامهای بین فرآیندها را مدیریت میکند؛ مدیریت پیغامها مستلزم بررسی گیرنده میباشد. بخشی از هسته دسترسی به درگاههای ورودی/خروجی و وقفهها را پشتیبانی میکند که در پردازندههای پیشرفته مستلزم استفاده از دستورالعملهای ممتاز مد هسته است و برای فرآیندهای معمولی خارج از دسترس میباشد.
علاوه بر خود هسته، این لایه شامل دو ماژول دیگر است که عملکردی مشابه با گردانندههای دستگاه دارند. وظیفه ساعت یک گرداننده ابزار ورودی /خروجی است به این معنی که با سختافزاری که سیگنالهای زمان را تولید میکند، در تعامل است، اما گردانندههای دیسک یا خطوط ارتباطی، در دسترس کاربر نیست و تنها با هسته در ارتباط است.
یکی از وظایف اصلی لایه اول، فراهم نمودن مجموعهای از فراخوانهای ممتاز هسته برای گردانندهها و خدمتگزارهای قرار گرفته در بالای آن میباشد.این مجموعه شامل خواندن و نوشتن بر روی درگاه ورودی / خروجی، کپی اطلاعات بین فضاهای آدرس و نظیر اینها است. پیادهسازی این فراخوانها به وسیله وظیفه سیستم انجام میشود. اگر چه وظیفه سیستم و وظیفه ساعت در فضای آدرس هسته ترجمه میشوند، اما آنها به عنوان فرآیندهای جداگانه زمانبندی شده و پشتههای فراخوانی خودشان را دارند.
بیشتر هسته و کل وظایف ساعت و سیستم به زبان سی نوشته میشوند. البته بخش کوچکی از هسته به زبان اسمبلی نوشته شده است. این بخشهای زبان اسمبلی به اداره وقفهها، سازوکارهای سطح پایین مدیریت تعویض متن بین فرآیندها «ذخیره و بازیابی ثباتها و امثال آن» و بخشهای سطح پایین کار با ثباتهای سختافزاری MMU میپردازند. کد اسمبلی، اداره بخشهایی از هسته را بر عهده دارد که مستقیماً مرتبط با سختافزار و در سطح بسیار پائین هستند و قادر نیستند به زبان سی بیان شوند.
سه لایه روی هسته میتوانند به صورت یک لایه منفرد در نظر گرفته شوند زیرا هسته اساساً به یک صورت با آنها رفتار میکند. هر سه لایه به دستورالعمل مد کاربر محدود میشوند و همگی توسط هسته زمانبندی میشوند. هیچ یک از آنها به طور مستقیم به درگاه ورودی / خروجی دسترسی ندارند. همچنین، هیچ کدام از آنها نمیتوانند به فضای حافظه خارج از قطعه تخصیص یافته به خود، دسترسی پیدا کنند.
با این حال، فرآیندها به صورت بالقوه امتیازات خاصی دارند «مانند قابلیت اجرای فراخوانهای هسته». این تفاوت واقعی بین فرآیندهای لایه، دوم، سوم و چهارم است. فرآیندهای لایه دوم، از حداکثر امتیاز برخوردارند. در لایه ۳، امتیازات کمتری وجود دارد و در لایه ۴ هیچ امتیاز ویژه ای وجود ندارد. به عنوان مثال فرآیندهای لایه ۲ که گردانندههای دستگاه نام دارند، اجازه دارند که از وظیفه سیستم درخواست خواندن و نوشتن دادهها بر روی درگاه ورودی / خروجی مربوط به خود کنند. برای هر نوع دستگاه از قبیل دیسکها، چاپگرها، ترمینالها و واسطهای شبکه، یک گرداننده مخصوص لازم است. بدیهی است اگر دستگاه دیگری اضافه شود به گرداننده خاص خود نیاز دارد. همچنین گردانندههای دستگاه میتوانند سایر فراخوانهای هسته مانند درخواست کپی دادههای وارد شده جدید به فضای آدرس فرآیند متفاوت را اجرا کنند.
لایه سوم شامل خدمتگزارها میشود. خدمتگزارها فرآیندهایی هستند که ارایه خدمات مفید به فرآیندهای کاربر را بر عهده دارند. دو مورد از خدمتگزارها نقش اساسی دارند؛ یکی از آنها مدیر فرآیند «Process Manager» است که در بر گیرنده آن دسته از فراخوانهای سیستمی مینیکس۳ است که آغاز یا توقف اجرای فرآیندها را برعهدهدار دارند، مانند انشعاب «fork»، اجرا «exec» و خروج «exit». همچنین پیادهسازی فراخوانهای سیستمی مرتبط با سیگنالها را شامل میشود، نظیر هشدار «alarm» و کشتن یک فرآیند «kill» که قادر هستند وضعیت اجرایی یک فرآیند را تغییر دهند. همچنین مدیر فرآیند در اموری از مدیریت حافظه مانند فراخوان سیستمی «BRK» مسئولیت دارد. دومین خدمتگزار، سیستمفایل «File System» است که کلیه فراخوانهای مدیریت حافظه مانند خواندن «read», اتصال «mount» و تغییر شاخه «chdir» را انجام میدهد.
درک تفاوت بین فراخوانهای هسته و فراخوانهای سیستمی پاسیکس «POSIX» از اهمیت زیادی برخوردار است. فراخوانهای هسته عملیات سطح پایینی هستند که به وسیله وظیفه سیستم فراهم شدهاند تا به گردانندهها و خدمتگزارها اجازه انجام کار خود را بدهند. خواندن یک درگاه ورودی / خروجی سختافزاری، یک فراخوان هسته نوعی به شمار میرود. در مقابل، فراخوانهای سیستمی پاسیکس «POSIX» مانند خواندن «read», انشعاب «fork» و پیوندزدایی «unlink» فراخوانهای سطح بالایی هستند که در استاندارد پاسیکس تعریف شدهاند و برای برنامههای کاربر در لایه چهارم، قابل دسترسی میباشند.
برنامههای کاربر شامل تعداد زیادی از فراخوانهای پاسیکس است، اما فراخوانهای هسته ندارد. گاهی در اثر اشتباه لفظی ممکن است فراخوان هسته را فراخوانی سیستمی بنامیم. مکانیسمهای استفاده شده در ایجاد این فراخوانها مشابهاند و فراخوانهای هسته میتوانند زیر مجموعه خاصی از فراخوانهای سیستمی تلقی شوند.
همانگونه که اطلاع دارید سیستمهای عامل دو وظیفه اساسی دارند : مدیریت منابع و فراهم نمودن یک ماشین توسعه یافته به وسیله پیادهسازی فراخوانهای سیستمی. در مینیکس سه مدیریت منابع تا حد زیادی توسط گرداننده های لایه دوم به کمک لایه هسته صورت میپذیرد؛ هنگامی که دسترسی ممتاز به درگاههای ورودی / خروجی یا سیستم وقفه در خواست میشود. تفسیر فراخوان سیستمی به وسیله خدمتگزارهای مدیر فرآیند و سیستمفایل در لایه سوم، انجام میگیرد. سیستمفایل دقیقا به صورت یک فایل «خدمتگزار» طراحی شده است بطوریکه میتواند با تغییرات ناچیزی به یک ماشین راه دور منتقل شود.
در نهایت لایه چهارم متشکل از کلیه فرآیندهای کاربر از قبیل پوستهها، ویرایشگرها، کامپایلرها، و برنامه ساده «Program.O» ایجاد شده توسط کاربر میباشد. بسیاری از فرآیندهای کاربر، با ورود کاربر به سیستم و یا انجام کار و خروج از سیستم، میآیند و میروند. در مقابل، معمولا در یک سیستم در حال اجرا تعدادی فرآیند کاربر وجود دارند که در زمان راهاندازی سیستم آغاز به کار میکنند و همیشه در حال اجرا هستند.
یکی از آنها اینیت «init» است؛ init کوتاهشدهٔ «Initialization»، نام برنامه یا پروسهای در سیستمعاملهای رایانهای شبهیونیکس است که تمام فرآیندهای دیگر را ایجاد میکند و بالا میآورد. این برنامه به صورت یک خدمت و معمولاً با PID 1 اجرا میشود. راهانداز بوت، هسته را شروع میکند و هسته نیز اینیت را شروع میکند. اگر اینیت را بدون جایگزین کردنش حذف کنید، سیستم در راهاندازی مجدد بعدی با «هشدار هسته» مواجه میشود. این اینیت است که تعیین میکند کامپیوتر چگونه کار میکند و آن را هدایت میکند،
معمولا چند برنامه به صورت سرویس (دیمن) نیز اجرا میشوند. دیمن یا خدمت یک فرآیند پسزمینه است که یا به طور متناوب اجرا میشود یا همواره در انتظار رویدادی مانند ورود یک بسته از شبکه به سر میبرد. به عبارتی می توان گفت که این خدمت، خدمتگزاری است که به طور مستقل راهاندازی میشود و به عنوان یک فرآیند کاربر اجرا میگردد. خدمت «دیمن» خدمتگزارهای واقعی که در هنگام راهاندازی سیستم نصب شدهاند. این امکان وجود دارد که یک دیمن نیز به گونه ای پیکربندی شود که از اولویت بالاتری نسبت به فراخوانهای معمولی کاربر برخوردار باشد.
نکتهپایانی:
در اینجا نکتهای پیرامون عبارت «وظیفه» و گرداننده دستگاه ضروری به نظر میرسد. در نسخههای قدیمی مینیکس کلیه گردانندههای دستگاه همراه با هسته ترجمه میشدند و امکان دسترسی آنها به ساختارهای داده متعلق به هسته و دیگر وظایف وجود داشت. همچنین آنها میتوانستند به طور مستقیم به درگاههای ورودی/خروجی دسترسی داشته باشند، بنابراین، به آنها تحت عنوان «وظیفه» اشاره میشود تا از فرآیندهای مستقلی که به طور محض در فضای کاربر قرار دارند متمایز شوند. در مینیکس سه، گردانندههای دستگاه به طور کامل در فضای کاربر اجرا میشوند. تنها استثناء، «وظیفه» ساعت است که از نظر منطقی مانند سایر گردانندههای دستگاه نیست که بتواند از طریق فایلهای دستگاه به وسیله فرآیندهای کاربر مورد دسترسی قرار بگیرند. ما در درون متن، اصطلاح «وظیفه» را تنها برای «وظیفه» ساعت یا «وظیفه» سیستم به کار بردیم که هر دو برای انجام وظیفه در درون هسته ترجمه شدهاند. از آنجا که نام توابع، نام متغیرها و توضیحات درون کد برنامه بادقت بهروزرسانی نشده است، شما در طی مطالعه کد برنامه مینیکس سه ممکن است به کلمه «وظیفه» برخورد کنید که در آنجا واژه «وظیفه» به معنی گرداننده دستگاه باشد.
منابع مورد استفاده در این نوشتار:
ترجمهای آزاد از بخشهای کتاب زیر با تصرف و تلخیص:
-
Operating System Design & Implementation, 3rd ed., 2006 | Tanenbaum, Andrew S., 1944
-
ویکیپدیا پارسی، برای بیان برخی مفاهیم