ماژول نویسی برای هسته لینوکس (قسمت هشتم)
در قسمت های قبل با اصول و مبانی ماژول نویسی برای هسته لینوکس آشنا شدیم و ابتدایی
ترین مفاهیم نوعی از دستگاهها موسوم به دستگاه های کاراکتری را بررسی نمودیم. در این قسمت و دو قسمت آینده مطالبمان را با بررسی فایل سیستم proc/ و کاربرد آن در ماژول نویسی برای هسته لینوکس ادامه خواهیم داد.
در لینوکس مکانیزم ویژهای بـرای هسته و ماژولهای هسته بــرای ارسال و دریافت اطلاعـات از پروسسها وجـود دارد که در قالب فایل سیستم مجازی proc/ پیاده سازی شده است. این فایل سیستم بـرای ســهولت دستـرسی به اطلاعاتی در زمینه پروسسها طراحی شده است. به عنوان مثــالproc/modules/ لیستی از مــاژولهای وارد شــده در هـسته و proc/meminfo/ اماری از میزان مصرف حافظه را نشان میدهند. روشی که برای استفاده از فایل سیستم proc/ به کار میرود بسیـار شبـیـه روشـی است که در مورد راه اندازها به کار میرود، یک نمونه یا instance از struct ای که تمامی این اطلاعات را به همراه اشاره گــرهــایی بـه توابع مورد نظر ایجاد میگردد. سپس در تابع شروع ماژول که همان init_module است ایــن سـاخـتـار داده در هسـتـه ثبت شده و در هنگام اتمام ماژول که cleanup_module صدا زده میشود این ساختار داده از هسته خارج میگردد.
بحثمان را با یک مثال شروع میکنیم. با مثال اول ( فایل procfs1.c ) شــروع میکنـیـم. ایــن مثال از ۳ قسمت تشکیل شده است: در تابع init_moduleفایلproc/helloworld/ ایجــاد میشـود، هنگامیکه از این فایل خوانده میشود تابع procfs_read صدا زده میشود که یک مقدار ( و یک بافر ) بر میگرداند. در نهایت در تابع cleanup_module این فایل حذف میگردد.
فایل proc/helloworld/ هنگامیکه ماژول در هسته وارد میشود توســط تابع create_proc_entry ایجاد میگردد. مقدار بازگشتی ایـن تابع یک '* struct proc_dir_entry' اسـت کــه بــرای پـیـکـربندی فایل proc/helloworld/ (به عنوان مثال تعیین صاحب فایل) به کار میرود. مقدار بازگشتی NULL نشان میدهد که اجرای این تابع ناموفق بوده است.
هر هنگام کــه از فایل proc/helloworld/ خوانده میشود تــابع procfs_read صدا زده میشود. دو پارامتر ورودی این تابع بسیار مهم هستند. buffer ( اولین پارامتر ) و offset ( سومین پارامتر ). محتــوای بافر به برنامهای کــه تقاضای خواندن داده است باز میگردد (به عنوان مثال دستور cat). پارامتر offset نیز مکان فعلی در فــایــل را نـشـان میدهد. اگر مقدار بازگشتی این تابع NULL نباشد، این تابع دوباره صدا زده خواهد شد. بنــابـراین مراقب این تابع باشید اگر مقدار بازگشتی این تابع هیجگاه صفر نشود صدا زدن این تابع به صورت بی پایان ادامه خواهد داشت.
مثالprocfs1.c را کامپایل کرده و ماژول تولیدی را در هسته وارد نمــایـیــد. بـا استفاده از دستور زیر از proc/helloworld/ بخوانید :
#cat /proc/helloworld
خواندن از و نوشتن در یک فایل proc/
مثال قبل که مثال ساده ای از خواندن از یک فایل proc/ بود را دیدیم. نکتهای کــه میخواهیم در ایــن قســمت بـررسـی کنیم، نوشتن در یک فایل proc/ است. هنگام نوشتن در فایل proc/ مانند حالت خواندن یک تابع مانند procfs_write صدا زده میشود. اما تفاوتهایی بیــن خــواندن و نوشتن وجــود دارد کــه مـهم ترین آن انتقال یافتن اطلاعات از فضای کاربر به فضای هسته در حال نوشتن است که این کار توسط توابعی مانند copy_from_user یا get_user انجام میشود.
دلیل وجود توابعی مانند دو تابع بالا این است که حافظه در لینــوکس (در معماری پردازنده اینتل، ممکن است در پردازنده های دیگر متفاوت باشد) بــه segment هایی تقسیم شده است. ایــن بدان معنا است که یک اشاره گر به تنهایی به ادرس یکتایی در حافظه اشاره نمیکند , بلکه به موقعیتی در segment اشاره میکند و شما نیاز داید که segment حافظه را بدانید تا بتوانید از ان استفاده کنید.
فقط یک segment برای هسته وجود دارد و برای هر پروسس نیز یک segment اختصاص مییابد. تنها segment ای که یک پروسس میتواند به ان دسترسی داشته باشد segment خود پروسس است. بنابراین هنگامیکه شما برنامهای توسعه میدهید یا اجرا میکنید، واقعا لازم نیست که نگران مدیریت segmentهای حافظه باشید. امــا هنـگـامی که یک ماژول هسته مینویسید، معمــولا میخواهید کــه بــه فضــای حـافـظه segment هسته کــه توسط سیستم راه اندازی میشود دسترسی داشته باشید. با این حال هنگامیکه نیــاز است محتـوای یک بافر حافظه بین یک پروسس و هسته رد و بدل شود هسته یــک اشاره گر به بافر حافظه segment پروسس دریافت میدارد. ماکروهای put_user و get_user اجازه دسترسی به این حافظه را میدهند. این توابع فقط یک کاراکتر تحویل میدهـند. شما میتوانید با استفاده از توابع copy_to_user و copy_from_user کاراکترهای متعددی را دریافت دارید و یا به هسته تحویل دهید.
چون که بافر (در توابع خواندن و نوشتن) در فضای هسته است، برای نوشتن شما نیاز دارید کــه اطــلاعاتـتـان را import کنید اما در تابع خواندن اطلاعات هم اکنون در فضای هسته است.
در قسمت آینده نحوه مدیریت فایل سیستم مجازی proc/ را بررسی خواهیم کرد.
در قسمت های قبل با اصول و مبانی ماژول نویسی برای هسته لینوکس آشنا شدیم و ابتدایی
ترین مفاهیم نوعی از دستگاهها موسوم به دستگاه های کاراکتری را بررسی نمودیم. در این قسمت و دو قسمت آینده مطالبمان را با بررسی فایل سیستم proc/ و کاربرد آن در ماژول نویسی برای هسته لینوکس ادامه خواهیم داد.
در لینوکس مکانیزم ویژهای بـرای هسته و ماژولهای هسته بــرای ارسال و دریافت اطلاعـات از پروسسها وجـود دارد که در قالب فایل سیستم مجازی proc/ پیاده سازی شده است. این فایل سیستم بـرای ســهولت دستـرسی به اطلاعاتی در زمینه پروسسها طراحی شده است. به عنوان مثــالproc/modules/ لیستی از مــاژولهای وارد شــده در هـسته و proc/meminfo/ اماری از میزان مصرف حافظه را نشان میدهند. روشی که برای استفاده از فایل سیستم proc/ به کار میرود بسیـار شبـیـه روشـی است که در مورد راه اندازها به کار میرود، یک نمونه یا instance از struct ای که تمامی این اطلاعات را به همراه اشاره گــرهــایی بـه توابع مورد نظر ایجاد میگردد. سپس در تابع شروع ماژول که همان init_module است ایــن سـاخـتـار داده در هسـتـه ثبت شده و در هنگام اتمام ماژول که cleanup_module صدا زده میشود این ساختار داده از هسته خارج میگردد.
بحثمان را با یک مثال شروع میکنیم. با مثال اول ( فایل procfs1.c ) شــروع میکنـیـم. ایــن مثال از ۳ قسمت تشکیل شده است: در تابع init_moduleفایلproc/helloworld/ ایجــاد میشـود، هنگامیکه از این فایل خوانده میشود تابع procfs_read صدا زده میشود که یک مقدار ( و یک بافر ) بر میگرداند. در نهایت در تابع cleanup_module این فایل حذف میگردد.
فایل proc/helloworld/ هنگامیکه ماژول در هسته وارد میشود توســط تابع create_proc_entry ایجاد میگردد. مقدار بازگشتی ایـن تابع یک '* struct proc_dir_entry' اسـت کــه بــرای پـیـکـربندی فایل proc/helloworld/ (به عنوان مثال تعیین صاحب فایل) به کار میرود. مقدار بازگشتی NULL نشان میدهد که اجرای این تابع ناموفق بوده است.
هر هنگام کــه از فایل proc/helloworld/ خوانده میشود تــابع procfs_read صدا زده میشود. دو پارامتر ورودی این تابع بسیار مهم هستند. buffer ( اولین پارامتر ) و offset ( سومین پارامتر ). محتــوای بافر به برنامهای کــه تقاضای خواندن داده است باز میگردد (به عنوان مثال دستور cat). پارامتر offset نیز مکان فعلی در فــایــل را نـشـان میدهد. اگر مقدار بازگشتی این تابع NULL نباشد، این تابع دوباره صدا زده خواهد شد. بنــابـراین مراقب این تابع باشید اگر مقدار بازگشتی این تابع هیجگاه صفر نشود صدا زدن این تابع به صورت بی پایان ادامه خواهد داشت.
مثالprocfs1.c را کامپایل کرده و ماژول تولیدی را در هسته وارد نمــایـیــد. بـا استفاده از دستور زیر از proc/helloworld/ بخوانید :
#cat /proc/helloworld
خواندن از و نوشتن در یک فایل proc/
مثال قبل که مثال ساده ای از خواندن از یک فایل proc/ بود را دیدیم. نکتهای کــه میخواهیم در ایــن قســمت بـررسـی کنیم، نوشتن در یک فایل proc/ است. هنگام نوشتن در فایل proc/ مانند حالت خواندن یک تابع مانند procfs_write صدا زده میشود. اما تفاوتهایی بیــن خــواندن و نوشتن وجــود دارد کــه مـهم ترین آن انتقال یافتن اطلاعات از فضای کاربر به فضای هسته در حال نوشتن است که این کار توسط توابعی مانند copy_from_user یا get_user انجام میشود.
دلیل وجود توابعی مانند دو تابع بالا این است که حافظه در لینــوکس (در معماری پردازنده اینتل، ممکن است در پردازنده های دیگر متفاوت باشد) بــه segment هایی تقسیم شده است. ایــن بدان معنا است که یک اشاره گر به تنهایی به ادرس یکتایی در حافظه اشاره نمیکند , بلکه به موقعیتی در segment اشاره میکند و شما نیاز داید که segment حافظه را بدانید تا بتوانید از ان استفاده کنید.
فقط یک segment برای هسته وجود دارد و برای هر پروسس نیز یک segment اختصاص مییابد. تنها segment ای که یک پروسس میتواند به ان دسترسی داشته باشد segment خود پروسس است. بنابراین هنگامیکه شما برنامهای توسعه میدهید یا اجرا میکنید، واقعا لازم نیست که نگران مدیریت segmentهای حافظه باشید. امــا هنـگـامی که یک ماژول هسته مینویسید، معمــولا میخواهید کــه بــه فضــای حـافـظه segment هسته کــه توسط سیستم راه اندازی میشود دسترسی داشته باشید. با این حال هنگامیکه نیــاز است محتـوای یک بافر حافظه بین یک پروسس و هسته رد و بدل شود هسته یــک اشاره گر به بافر حافظه segment پروسس دریافت میدارد. ماکروهای put_user و get_user اجازه دسترسی به این حافظه را میدهند. این توابع فقط یک کاراکتر تحویل میدهـند. شما میتوانید با استفاده از توابع copy_to_user و copy_from_user کاراکترهای متعددی را دریافت دارید و یا به هسته تحویل دهید.
چون که بافر (در توابع خواندن و نوشتن) در فضای هسته است، برای نوشتن شما نیاز دارید کــه اطــلاعاتـتـان را import کنید اما در تابع خواندن اطلاعات هم اکنون در فضای هسته است.
در قسمت آینده نحوه مدیریت فایل سیستم مجازی proc/ را بررسی خواهیم کرد.
+ نوشته شده توسط امیرحسین عربی زاده در جمعه یازدهم خرداد 1386 و ساعت
15:44 |


