محمد لینوکس

همه چیز به غیر از لینوکس!

محمد لینوکس

همه چیز به غیر از لینوکس!

قسمت ۶از سریال آبکی لینوکس بیاموز

با سلام،

با عذر خواهی از کلیه بینندگان سریال آبکی لینوکس بیاموز، به علت پخش فوتبال جام باشگاه‌های آسیا، پخش سریال چند هفته‌ای با مشکل برخورد، که در حال

ادامه اون هستم. برای اطلاعات بیشتر با اپراتور شماره 4 تماس حاصل بفرمایید.

در این قسمت و قسمت بعدی کرنل لینوکس بستونده خواهد شد و ادامه سریال پخش نخواهد شد. به جاش سریال جدیدی شروع میشه به نام سریال ترسناک

لینوکس بیاموز، که در اون به سراغ بخش کاربران خواهیم رفت. طراحی لینوکس، پیاده سازی لینوکس، امن سازی لینوکس، لینوکس و فایلها، مدیریت ساختار‌ها،

لینوکس و POSIX، برنامه سازی لینوکس، گرافیک در لینوکس و ... از قسمتهای سریال ترسناک لینوکس بیاموز هستند.

--------------------------------------------------
در این قسمت شما با وقفه‌ها آشنا خواهید شد و نحوه مدیریت، پیاده سازی و استفاده از اونها رو خواهید دید.

بریم،

اول بگیم وقفه یا interrupt چیه؟

وقفه به هر رخدادی می‌گن که باعث تغییر در روند اجرایی CPU بشه. از اسمش مشخصه. CPU داره کار می‌کنه و تعدادی دستور العمل رو اجرا می‌کنه، ناگهان یه

وقفه که هنوز نمی‌دونیم چیه رخ میده. CPU کار اصلی خودشو قطع کنه و میره به اون وقفه رسیدگی می‌کنه.

وقفه‌های به دو گروه اصلی تقسیم بندی می‌شن. وقفه‌های Synchronous و وقفه‌های ASynchronous.

وقفه‌های Sync اونهایی هستند که توسط CPU تولید می‌شن و زمانی به اجرا می‌رسن که CPU انجام یه دستور العمل رو تموم کرده باشه.
وقفه های Async اونهایی هستند که توسط سخت‌افزار‌های دیگه تولید می‌شن و در هر زمانی میتونن اتفاق بیافتن.

البته بگم intel به وقفه Sync میگه Exception و به وقفه Async میگه Interrupt. ماهم به خاطر احترامی که به Intel قائلیم (به خاطر CPUهای سری GM که تولید

می‌کنه (Googooli Magooli)  با همین نام‌های Intel وقفه‌های رو صدا می‌زنیم. فارسی میشه بهشون گفت خطا و وقفه)

وقفه‌های توسط دستگاه‌های سخت افزاری و تایمر سیستم تولید می‌شن. مثلا فرض کنید شما که روی کیبورد یک دکمه رو می‌زنید، کیبورد به CPU میگه، سلام

علیکم. CPUهم که سرش نمیشه، میاد که کد رو که تو یه آدرس مشخص تعریف شده اجرا می‌کنه. حالا اگه سیستم عامل Windows میخواد کلید‌هارو بگیره باید

بره تو اون آدرس برای خودش کد بنویسه. اگر ننویسه، کیبورد توی سیستم عامل Windows کار نمی‌کنه!

از اون طرف خطاها یا Exceptionها توسط خطاهای برنامه نویسی رخ می‌دن. البته مشکلاتی هم توی کرنل صورت می‌گیره و اونها هم خطا هستند. دسته اول رو

که کرنل لینوکس بهش توجهی نمی‌کنه، فقط بایک Signal به برنامه میگه که فلان Exception رخ داد. مثل موقعی که شما می‌خواهید روی یک آدرس خارج از برنامه

خودتون بنویسید، لینوکس به شما میگه Segmentation Fault و برنامه شما رو می‌بنده.

office توی Windows رو دیدید ؟‌ بعضی موقعها که Windows ییهویی Close میده، بعد که Office رو باز می‌کنید میبینید اههههههههههههه نوشته که فایل شما

هست، از نوع Recovery.

این قابلیت به دو صورت پیاده سازی شده، اول اینکه Office در هنگام کار فایل شما رو در مقاطع زمانی مشخص Save می‌کنه روی فایل Recovery و مورد دوم اینکه

Office تمامی سیگنال‌های خطای سیستم عامل رو برای خودش Register کرده و اونها رو دریافت می‌کنه و قبل اینکه Close و End Task بیاد Office متوجه می‌شه

و کارهای لازم رو میکنه.

شما از Exceptionها هیچ راه فراری ندارید. این رو بدونید، اگر توی برنامه خودتون تقسیم بر صفر انجام می‌دید، برنامه شما خارج می‌شه، ولی شما با Register

کردن ورودی Signal از نوع DIVZERO می‌تونید، قبل از بسته شدن برنامه کارهایی رو انجام بدید.

برای مثال برنامه Corel Draw کار جالبی می‌کنه، زمانی که برنامه به هر دلیل خطا یا Exception میگیره، یه Process دیگه از خودش اجرا می‌کنه با فایل Recovery.

برای همین Corel زمانی که Close میده شما میبینید که سریع یه Corel دیگه با همون فایل تحت کار باز میشه. چه جالببببببببببببببببببببببب!!!!

(ببخشید من همش نمونه Windows مثال میزنم، بالاخره هرچی باشه MCSD ها غیرت دارن به Microsoft :P:P:P:P)

خوب

حالا بریم سراغ Interruptها ، زمانی که یک وقفه میاد، CPU باید کار خودش رو قطع کنه و بره به اون وقفه جواب بده. برای همین زمانی که interrupt میادش

سیستم عامل محل جاری اجرای برنامه که شامل دو قسمت CS و IP رو توی Stack ذخیره می‌کنه، تا وقتی کار وقفه تموم شد بتونه برگرده کارای خودشو انجام

بده.

یادتونه توی قسمت‌های قبلی سریال گفتیم، کرنل لینوکس زمانی که می‌خواد یه Process رو عوض کنه باید کلی کار کنه، و از این بحثا. اینجا قضیه یکم فرق داره

اونم اینه‌که، کدهای اجرایی وقفه‌ها مثل Processها نیستند و همگی در Kernel space قرار دارند. پس کرنل نیازی به عوض کردن حافظه و بحث‌های جانبیش نداره،

میشه از این نظر Process و Interrupt رو جدا سازی کرد.

اینجا چند تا مسئله مهم بیان می‌شه، که باید اونها رو شما به عنوان Kernel Proffesional بدونید

* وقفه‌ها هر زمانی میتونند اجرا بشن. یعنی هیچکس از نویسندگان کرنل لینوکس نمی‌دونه که شما کی هوس می‌کنید روی Keyboard فشار بدید یا موس رو تکون

بدید. پس سیستم همیشه باید آماده پاسخگویی به وقفه ها باشه . اینجا سوال پیش میادکه آماده چی باشه ؟‌ فرش قرمز که نمی‌خواد پهن کنه، وقفه میاد جواب

میده میره دیگه، این سوال رو وایسید پایین جواب میدیم بهش، چون خیلی مهم

* چون هر موقعی امکان رسیدن وقفه هست، پس کرنل باید این احتمال رو بده، که وسط اجرای یه وقفه، یکی دیگه از یه نوع دیگه اجرا بشه. باز سوال بالا پیش

میاد و باز شما اندر خماری جواب پایین خواهید ماند

* چون وسط یه Interrupt یکی دیگه ممکنه پیش بیاد، و در کرنل کدهایی هست که به صورت ATOMIC قرار دارند، پس کرنل باید در صورت لازم در زمانهایی

Interrupt هارو قطع کنه، ولی نباید این زمانها زیاد باشه چون باعث معطل موندن سخت افزار‌ها میشه.

و اما جواب سوال. ببینید، سیستم در حال اجرای کار‌های خودشه، مثلا یه برنامه داره چک میکنه که آیا میتونم توی فایل فلان، بخش فلان بنویسم یا خیر؟ می بینه

که میتونه و میاد شروع کنه که بنویسه، ییهویی که وقفه رخ میده، وقفه‌هه در حال اجراست که یهو یه وقفه دیگه رخ میده از نوع Timer. وفقه Timer میبینه به به،

این Process کلی اجرا شده پس نوبت بعدیه، CPU رو میده به بعدی. Process دوم میبینه اون فایل، اون قسمتش خالیه، شروع میکنه به نوشتن و فلاگ پرشدن رو

برای اون بخش فایل در نظر می‌گیره. دوباره Timer میزنه و وقفه تایمر میگه بسه دیگه، CPUرو میده به Process اول. حالا اینجا مشکل پیش میاد. این Process از

خدا بی خبر،‌ فکر می‌کنه فایل خالیه و میاد روی داده‌های Process دوم می‌نویسه و این داده‌ها پاک می‌شن.
چیکار باید کرد ؟‌ Process اول باید توی همچین مسئله مهمی، وقفه‌ها رو از کار بندازه و بعد از انجام کارش دوباره اونها رو فعال کنه. خوب آیا برنامه نویس‌ها این کار رو

می‌کنن؟ خیررررررررررررررررررررررررررررررررررررررررررررررررررررر،‌کی حالشو داره. پس نتیجتا وظیفه کرنل لینوکس که این چکها رو انجام بده . البته در برنامه نویسی

Modular این کار درسته که توسط Kernel از چک‌ها صورت بگیره. حالا این یه مسئلس، شاید شما فکر کنید که این مشکل در Interruptها سالی یک بار اتفاق بیافته

ولی جالبه بدونید که اگر سیستم عامل این چک هارو انجام نده، اصلا لینوکس بالا نمیاد. این مشکل زمانی حادتر میشه که شما دوتا CPU داشته باشید، که اون

موقع اصلا قضیه فرق می‌کنه و توضیح خواهیم داد.
پس جواب سوال اینجوری میشه، بله کرنل باید خودش رو آماده Interrupt کنه، آمادگی برای Interrupt یعنی استفاده از Mutexها و Spin-lockها، Kernel

Preemptionها و Semaphoreها که خودش یه سریال بسیار پیچیده به نام Kernel Synchronization که چون خارج از حوصله جمع، ماهم طبق روال سریال آبکی

ماست مالیش میکنیم بره. فقط اینو بدونید، ATOMIC Operation یعنی فعالیتی که یا باید اجرا نشه، یا کامل اجرا بشه. یه موقع شما می‌خواهید پول از حسابتون

بریزید حساب مش غلام که براتون تراکتور بفرسته. پس شما پول رو حساب می‌کنید، از حساب خودتون کم می‌کنید و به حساب مش غلام واریز می‌کنید. اگر بعد از

کم کردن پول از حساب شما ،‌ عمل واریز کردن به حساب مش غلام صورت نگیره اصطلاحا سیستم به وضعیت آبگوشتی میره (خدارو شکر برنامه‌های ATM مارو

شرکت NCR آمریکا نوشته. صلوات) . عمل واریز کردن پول به حسال مش غلام یه عمل Atomic حساب میشه. کرنل لینوکس از اعمال Atomic (البته مربوط به

خودش، مثال ذکر شده مربوط به Atomicity در DBMSها بود که ایشالا در کلوب Database سریال آبکی راه خواهیم انداخت ) به طور کامل پشتیبانی می‌کنه و

زمانی که بخشی کد Atomic داره اجرا می‌کنه، هیچ وقفه‌ای یا CPU دیگه‌ای نمی‌تونه اون بخش کد رو اجرا کنه.

برای اینکه سیستم های کامپیوتری ما X86 هستند، لینوکس در x86 Arch خودش، قوانین Intel رو رعایت می‌کنه. توی مستندات Intel اگه حال داشته باشید برید

بخونید خواهید دید که تقسیم بندی ها به صورت زیر اومده:

Interrupt:

Maskable:وقفه‌های Maskable اونهایی هستند که سیستم عامل میتونه از CPUدرخواست کنه که بهشون توجهی نشه. یعنی این وقفه‌ها قابل قطع شدن

هستند.
Nonmaskable: تعداد بسیار کمی از وقفه‌ها هستند که غیر قابل قطع شدن هستند. اینها همیشه و در همه صورت توسط CPU رسیدگی می‌شن.

Exceptions:

Processor: زمانی رخ می‌دن که CPU، یه مشکلی رو توی اجرای یه دستور العمل پیدا کنه.
Faults: این نوع خطا‌ها باعث بسته شدن برنامه نمیشن، بلکه بعد از رسیدگی بهشون،‌برنامه میتونه ادامه بده خودش رو فقط به شرطی که اون مشکل رو حل

کنه.
Traps: بیشتر به منظور Debugging استفاده می‌شه و توسط خود برنامه نویسان قرار داده می‌شه. این نوع خطا‌ها هم قابل ادامه دادن برنامه هستند.
Aborts: خطاهای اصلی که هویت برنامه رو دچار مشکل می‌کنن مثل خوندن یه آدرس غیر مجاز، که ادامه برنامه بی معنیه چون اون برنامه احتمالا به اون داده نیاز

داشته. در صورت رخ دادن این خطا برنامه بسته خواهد شد (البته بعد از اطلاع دادن به برنامه)
Programmers Exception: این خطاها بازهم توسط برنامه‌ها اجرا میشه و CPU با اونها همانند Trapها برخورد می‌کنه.

دوتا نکته بسیار مهم مهم مهم مهم مهم مهم مهم
اول اینکه، خطاها همیشه بد نیستند، اینکه شما الان داری با RAM پایین صدتا برنامه اجرا میکنی مزیت این خطاهاست. کرنل ویندوز و لینوکس از این خطاها به این

صورت استفاده می‌کنند. بخشی از برنامه شمارو داخل حافظه میارن، هم سرعت Load میره بالا و هم حافظه کم می‌خواد. برنامه میاد ییهویی میپره یه جای دور،

CPU خنگ به سیستم عامل خطاااااااااااا میده، میگه ببین این Process میخواد اینجای حافظه رو اجرا کنه ولی چیزی نیست، سیستم عامل میاد اون قسمت از

برنامه رو میاره داخل حافظه و بعد به CPU میگه، بابا این که هست، چشات اشتباه دیدن و CPU خنگ از خدا بی خبرهم برنامه رو اجرا می‌کنه بدون هیچ

مشکلی.
یا از این خطا استفاده امنیتی می‌کنن، یعنی زمانی که یک Process میخوادبه حافظه‌ای از برنامه دیگه دسترسی داشته باشه، CPU به سیستم عامل میگه فلان

Process داره شیطونی می‌کنه، سیستم عامل هم Signal میده که Access Denied.
مورد دوم در مورد Programmers Exceptionها. برنامه‌ها برای اینکه به کرنل لینوکس یه چیزی بگن، میان یه خطا ایجاد می‌کنن. خطایی برای CPU که CPU میاد به

کرنل میگه کاربر این خطا رو ایجاد کرد. کرنل هم میگه، کاریت نباشه این خودیه. این خطا در اصل وقفه شماره 128 یا همون Systam Call توی لینوکس که Process

ها از این طریق میتونن یه راهی به داخل کرنل پیدا کنن و دستورات کرنلی رو اجرا کنن.

مسئله بعدی که یکم سخت افزاریه، در رابطه با ارتباط سخت افزار‌هاست. مطمئن زمانی که شما کیبورد می‌خرید،‌ و میاید منزل، یکی از سیم‌هاشو با چسب آهن

یا هویه به CPU وصل نمی‌کنید. پس باید مدار واسطی باشه این وسط که ارتباط سخت افزار‌ها با ‍CPU رو انجام بده. در کنار این، مگه CPU بیکاره که هی از سخت افزارها بپرسه حال شما چطوره؟ اونام بگن هیچییییییییییییی!!

توی کامپیوتر‌های قدیمی سخت افزاری بود به نام PIC، یعنی Programmable Interrupr Controller. کارش این بود:
یه طرفش کلی PIN داشت که وصل بود به سخت افزارها. طرف دیگش یه خط میومد به CPU.

پشت سر هم از سخت افزارها سوال میکرد آقا چه خبر ؟ اگه دوتاشون می‌گفتن، خبر خبر، اونوقت محل اونی میذاشت که شماره PIN کمتری داشت. یعنی وقفه‌ها با PIN شماره کمتر اولویت بیشتر داشتن. TIMER و RESET اون بالا بودن.

بعدش سیگنال رسیده روی چند PIN مختلف رو دیجیتال میکرد، یعنی یه کد می‌کرد. اونو میذاشت روی یکی از PORTهای Data bus بعد چنان سیخی به CPU میزد که در آن واحد CPU اون Port رو می‌خوند. بعدش انقد سیخ رو نگه میداشت تا CPU روی یه Port دیگه بنویسه، خوندم. اونوقت سیخ رو در می‌آورد. این میشد که شما ویندوزت هنگه، ماوس ولی تکون می‌خوره، چه تکونیم میده بدنو (حیف که محرمه بیشتر نمیشه توضیح داد)

بعد دوباره میرفت گوش میداد. این سخت افزار مال کامپیوتر های قدیمیه. یادتونه،‌ Windows 98 فلاپی که کار می‌کرد، ماوس و کیبوردو خلاصه همه چی از کار میافتاد. آخه شماره اون بیشتر بود و وقتی داشت میخوند یه بند PIC رو سیخ میزد و PIC هم اصلا گوشش شنوای Interruptهای دیگه پایین تر نبود.

خوب حالا که شما میگی سخت افزار‌های قدیمی، خالی بند، ما همون موقع XP داشتیم ماوس کار می‌کرد عین هلو. بله درسته، قدیم منظورم 1970 بود، الان روی بردهای x86 هم PICهست و هم APIC. اون زمانی که شما می‌گی XP داشتم ولی فلاپی و ماوس باهم کار می‌کنند، به خاطر اینه که APIC یا Advanced PIC روی بردها اومده. ولی Intel به دلیل اینکه میدونه هنوز هم عده‌ای از OS های قدیمی استفاده می کنن PIC رو حذف نکرده.

و اما APIC

این سخت افزار خیلی بهتر شده. اولا اینکه PIC برای سیستم‌های تک CPU ساخته شده. اگر اشتباه نکنم، Intel توی PIII اومد APIC رو معرفی کرد. به اضافه اینکه، CPUهای جدید X86 همشون یه APIC داخلی هم دارند.که در موردش زیاد توضیح نمی‌دیم.

پیشرفت‌های APIC رو توی Intel APIC Architecture بخونید ولی کلیتش اینه که،‌دیگه اولویت‌ها بر حسب شماره PIN نیست و توسط نرم افزار کنترل میشه، سیستم تک CPU تبدیل به ICC BUS شده که CPUها میتونن با هم از طریقش توسط APICهای محلی خودشون صحبت کنن که این CPU به اون یکی میگه، یکی مال من، یکی مال تو،‌یکی مال من،‌... یا مثلا میگن،‌من دارم فلان کار ATOMIC رو میکنم فعلا تو یه دوری بزن یا همون SPIN-Lock و دیگه اینکه APICمیتونه برنامه ریزی بشه که بعضی Interruptهارو بده یکی بقیه بده یکی دیگه، خلاصه اگه APIC نبود هیچ سیستم چند CPU یا SMP که در قسمت‌های قبلی سریال گفتیم نبود. دیگم بحث نکنید.

مدیریت Interruptها توسط لینوکس:

خوب حالا که فهمیدیم چی هستن، ببینیم لینوکس چیکار می‌کنه؟ زمانی که لینوکس Boot میشه، تمامی Slotهای interruptهای مختلف و Exceptionها با Codeهای مشخصی پر میشن، این عملیات توسط خود Kernel صورت میگیره.

رسیدگی به بعضی Interruptها خیلی زمان گیره، یعنی اگه لینوکس بخواد به اونها رسیدگی کنه،‌باعث کندی شدید سیستم میشه، شما اونوقت هی ماوس رو تکون میدید اونوقت نصب نرم‌افزار کند میشه، ضایع نیست؟

برای همین منظور لینوکس میاد از تکنیکی به نام BH یا Bottom Halves استفاده می‌کنه، که معنیش میشه نیمه‌های پایینی. میاد Interruptهای سنگین رو 2 تیکه می‌کنه و تیکه اول رو به عنوان Code Interrupt قرار میده و تیکه اول تیکه دوم یا همون نیمه پایین رو به صورت یه Task معمولی در لیست کارهای Kernel قرار میده. Kernelهم تضمین داده در اولین فرصت مثل همه Processها تیکه پایینی رو اجرا کنه.

مسئله ای می‌مونه به نام Nested Execution یا اجرای تو در تو. همون مسئله که گفتیم، وسط اجرای یه Int یکی دیگه بیاد. کرنل باید همیشه اطلاعات لازم رو نگه داره، تا زمانی که یه Interrupt وسط یکی دیگه رخ داد بعد از اتمامش،‌ اطلاعات int اول از بین نرفته باشه و بتونه اونها رو برگردونه. کار سختیه ولی نشدنی نیست

کرنل و درایورها:
شما اصطلاحی شنیدید به نام IRQ. در اصل IRQ همون خط‌های سخت افزارین که به سمت APIC میان. زمانی که شما Keyboard وصل میکنید درایور مربوط به Keyboard فعال میشه. این درایور نیاز داره که به یکی از Interrupt ها گوش بده. اگه بخواد کد بنویسه برای Interrupt دستگاه Keyboard اونوقت 2 تا مشکل پیش میاد. یکی اینکه مسعلوم نیست چه قاراچ میشی میشه، دوما فقط خودش میتونه از این Interrupt استفاده کنه. ما بعضی دستگاه‌ها داریم که به خاطر کمبود پینهای APIC و کم بودن تعداد سیخ زدناشون باهم IRQ Sharing راه میندازن پس 2 تا درایور همزمان یه IRQ رو میخوان. پس بهتره خودشون رو توی یه لیست درایور‌ها Register کنن و کدی که در Interrupt نوشته میشه، فقط این زنجیره رو صدا بزنه. آره اینجوری بهتره

مسائلی که میمونه مربوط به پیاده سازی Interruptها، Taskletها، BHها و IRQ Handlersهاست که مربوط به کد نویسا میشه و از ذکرشون در اینجا خود داری میشود.

با تشکر از همراهی شما در این برنامه
تا برنامه بعدی همه شما رو  به خداوند یکتا می سپارم
حالا همه جیغ صوت کف هوراییییییییییییی بلند

خدافظظظظظظظظ خدافظظظظظظظظظظظظظظ ;)) ;)) ;))

بی ساکزز

از طرفEmadCT

نظرات 0 + ارسال نظر
برای نمایش آواتار خود در این وبلاگ در سایت Gravatar.com ثبت نام کنید. (راهنما)
ایمیل شما بعد از ثبت نمایش داده نخواهد شد