ورود/ایجاد حساب کاربری
   منوی اصلی
· خانه
· لیست کاربران
· جستجو
· آمار مشاهدات
· آرشیو مقالات


- شرح
· راهنمای نویسندگان
· درباره ما

   همکاری با نشریه
در صورتی که مایل به همکاری با نشریه هستید، می‌توانید در لیست پستی نشریه عضو شده و در جریان امور قرار گیرید. برای اطلاعات بیشتر، اینجا کلیک کنید.

   کاربران
سردبیر
هیچ مدیر کمکی حاضر
همکاران
هیچ مدیر کمکی حاضر
اعضا:
جدیدترین:جدید امروز:0
جدیدترین:جدید دیروز:0
جدیدترین:مجموع:2471
جدیدترین:جدیدترین:
ufumenarayu
اعضا:حاضر
اعضا:اعضا:0
مهمان‌ها:مهمان‌ها:11
مجموع:مجموع:11
کاربران حاضر
هیچ کاربر حاضری وجود ندارد

   ورود کاربران




 


 برای ورود مشکل دارید؟
 ثبت نام کاربران جدید

ماژول نویسی برای هسته لینوکس (قسمت دهم)

(1981 مجموع کلمات موجود در متن)
(7608 بار مطالعه شده است)  نسخه چاپی

ماژول نویسی برای هسته لینوکس ( قسمت یازدهم )

در قسـمت قـــبل بــررسی مدل جدید راه اندازها در هسته لینوکس که به Unified Device Model مــوسوم است را با معرفی چند ساختار داده اصـلی مانند kset , ktype , kobject و subsystem شــروع نمودیم. در این قســـمت به نحوه استفاده از این ساختار های داده در ماژول نویسی هسته لینوکس خواهیم پرداخت. به دلیل حجم بالای مطالب نکات اصلی این توابع مورد بحث وبررسی قرار خواهند گرفت و جزییات بیشتر به خواننده واگذار می شود.


مدیریت kobject ها

با توجه به آنچه در قسمت قبل در مورد kobject ها فرا گرفتیم به بررسی توابعی که مدیریت kobject ها را تسهیل می کنند می پردازیم. ساختار داده kobject معمولا مستقیما به کار نمی رود. بلکه در درون ساختار داده دیگری ( به عنوان مثال cdev که در قسمت قبل آن را بررسی نمودیم ) جاسازی می شود.

اولین قدم در استفاده از kobject هـا تعریف و مقداردهی اولیه آنهاست. این کار با تابع kobject_init انجام می گیرد که در <linux/kobject.h> تعریف شده است.

void kobject_init(struct kobject *kobj);

این تابع kobject ورودی را گرفته و فیلد های آن را مقداردهی می کند. قبل از صدا کردن این تابع بایستی فضای حافظه kobject صفر شود. این کار را می توان با تابع memset انجام داد.

memset(kobj, 0, sizeof (*kobj));

بعد از صفر کردن kobject می توان parent و kset آن را مقدار دهی کرد. به عنوان مثال :

kobj = kmalloc(sizeof (*kobj), GFP_KERNEL);

if (!kobj)

return -ENOMEM;

memset(kobj, 0, sizeof (*kobj));

kobj->kset = kset;

kobj->parent = parent_kobj;

kobject_init(kobj);

بــعداز مــقدار دهی اولیه بایستی نامی برایkobject درنظر گرفته شود.این کار بااستفاده ازتابع ()kobject_set_name انجام می گیرد :

int kobject_set_name(struct kobject * kobj, const char * fmt, ...);

syntax این تابع مانند printk است کــه مـی‌توان آن را بــا fmt بـه صــورت دلخواه نام گذاری کرد. با استفاده از این تابع k_name در ساختار داده kobject مقداردهی می گردد.

بعد از ایجاد یک kobject و مقدار دهی آن شما نیاز دارید که فیــلد‌هــای kset و ktype آن را تنظــیم نمایید. اگر kset نوع kobject را مشخص نکرده باشد تنظیم ktype اجباری می شود در غیر این صورت اختیاری است.



Reference Counts

یکی از امکانات اولیه ای که توسط kobject هــا فراهم شده است مکانیزم یکتایی برای شمارش ارجاعات است. بعد از مقداردهی اولیه مقدار شمارنده ارجاعات kobject به مــقدار ۱ تنظیم می شود. تا زمــانی که این شمارنده صفر نشده است object به حیات خود در حافظه ادامه خواهد داد.

هر کدی که یک ارجاع به object دارد ابتدا یک واحد این شمارنده بالا برده می شود و هنگامی که این کد به پایان رسید یک واحد این شمارنده کاهش می یابد. هنگامی که مقدار این شمارنده به صــفر رســیدobject , از بین رفته و حافظه تخصیص یافته به آن ازاد می شود.

افزایش این شمارنده توسط تابع ()kobject_get انجام می گیرد. این تابع اشاره گری به kobject و در صورت خطا NULL بر می گرداند.

struct kobject * kobject_get(struct kobject *kobj);


متقابلا کاهش این شمارنده توسط تابع ()kobject_put صورت می پذیرد.

void kobject_put(struct kobject *kobj);

اگر شمارنده به صفر برسد تابع release ای که در ktype به آن اشاره شده است صدا زده خواهد شد.



kref

شمارنده kobject توســـط ساختار داده kref که در <linux/kref.h> تعریف شده است و در lib/kref.c پیاده سازی شده است.

struct kref {

atomic_t refcount;

};

تنها فیلد این ساختار داده متغیر refcount است که به صورت atomic تعریف شده و مـــقدار شمارنده را در خود نگه می دارد. قبل از استفاده از kref بایستی آن را با استفاده از ()kref_init مقدار دهی کنید.

void kref_init(struct kref *kref)

{

atomic_set(&kref->refcount, 1);

}

برای گرفتن یک ارجاع ( بالا بردن شمارنده ) از تابع ()kref_get استفاده می شود.

void kref_get(struct kref *kref)

{

WARN_ON(!atomic_read(&kref->refcount));

atomic_inc(&kref->refcount);

}


برای رها کردن یک ارجاع ( پایین اوردن شمارنده ) از تابع ()kref_put استفاده می شود. هنگامی که مقدار شمارنده به صفر رسید تابعی که توسط اشاره گر به تابع release فراهم شده است صدا زده می شود.


void kref_put(struct kref *kref, void (*release) (struct kref *kref))

{

WARN_ON(release == NULL);

WARN_ON(release == (void (*)(struct kref *))kfree);


if (atomic_dec_and_test(&kref->refcount))

release(kref);

}

فایل سیستم sysfs

فایل سیستم sysfs یک فایل سیستم مجازی در حافظه است که نمایش درختی از kobject ها را برای ما فراهم می کند. این فایل سیستم توپولوژی دستگاه ها را در یک فایل سیستم به ما نمایش می دهد. با استفاده از attribute ها kobject ها می توانند با استفاده از فایل ها این اجازه را بدهند که بتوان بعضی از متغیرهای هسته را خواند و یا در انها نوشت.

اگر چه هــدف ابتدایــی این مدل جدیــد ایجاد یک فرایند کنــتــرل انرژی هوشمند در یک سیستم کامپیوتری بود توسعه دهندگان هسته لینوکس به این نتیجه رسیدند که برای امکانات رفع خطای ساده تر آن را به صورت یک فایل در معرض دیـد بگذارند و sysfs ایجاد شد و به مرور در حال جایگزینی فـــایــل‌های دستگاه‌هـــا در proc/ می‌شــود. امروزه تـــمــام سیستم هایی که از کرنل 2.6 استفاده می کنند فایل سیستم sysfs را به صورت mount شده در سیستم خود دارند.

نمایشی از این فایل سیستم که در mount , /sys شده است را ملاحظه می فرمایید.


شکل ۱- نمایی از فایل سیستم sys/


ریشه این فایل سیستم به طور استاندارد حاوی ۷ دایرکتوری است(در هسته های مختلف ممکن است متفاوت باشد) : block , bus , class , devices , firmware , module , power

دایرکتوری block برای هر دستگاه ( block device ) یـــک دایـــرکتـــوری جـــداگانه دارد. دایرکتوری bus نمایشی از bus سیستم را در خود نگه می دارد. دایرکتوری class نمایشی از دستگاه ها را که توسط توابع سطح بالایی سازمان یافته اند را در بر دارد. دایرکتوری devices نمایشی از توپولوژی دستگاه های موجود در سیستم را در خود نگه می دارد. این دایرکتوری مستقیما به ساختار درختی که از ساختارهای داده ذکر شــــده در هسته تشکیل شده انگاشته می شود. دایرکتوری firmware نیز درختی از اجزای سطح پایین سیستم مانند EFi , EDD , ACPi و ... را نگه می دارد. دایرکتوری های module و power نیز به ترتیب ساختارهایی از ماژول های کرنل و مدیریت انرژی در کرنل را نگه می دارند.

مهمترین دایرکتوری در این فایل سیستم devices است که مدلی از دستگاه های موجود در سیستم را در خود نگه می دارد. تعداد کثیری از فایل های موجود در دایرکتوری های دیگر در حقیقت اشاره گرهایی به فایل های این دایرکتوری هستند. برای اشنایی بیشتر با این فایل سیستم بهتر است ترمینال سیستم گنو/لینوکس خود را باز کرده و چرخی در این فایل سیستم بزنید تا با اجزای آن بیشتر اشنا شوید.



توابع کار با فایل سیستم sysfs


در این قسمت به دلیل تعداد زیاد توابع , توابع اصلی به صورت تیتروار مورد بررسی قرار می گیرند. برای جزییات بیشتر به کتاب ها یا مقالات اشنایی با هسته لینوکس ( مانند منابع انتهای مقاله ) مراجعه کنید.

kobject هایی که مقدار اولیه داده شده اند به طور اتوماتیک به این فایل سیستم اضافه نمی شوند. برای این کار از تابع kobject_add استفاده می شود. مکان این فایل در این فایل سیستم از موقعیت kobject در ساختار درختی خود تعیین می شود. با استفاده از تابع ()kobject_register می توان دو عمل kobject_init و kobject_add را به یکباره انجام داد. برای حذف نمایشkobject درsysfs ازتابعkobject_dell استفاده می شود. تابع kobject_unregister ترکیبی از دو تابع kobject_dell و kobject_put می باشد.

kobject ها به دایرکتوری ها در sysfs نگاشته می شوند. برای نگاشتن فایل ها به sysfs از فیلد attribute موجود در kobject ها و ktype ها استفاده می شود. ساختار داده attribute در <linux/sysfs.h> تعریف شده و به صورت زیر می باشد:

struct attribute {

char *name; /* attribute's name */

struct module *owner; /* owning module, if any */

mode_t mode; /* permissions */

};

فیلدهای owner , name و mode به ترتیب بیانگر نام , صاحب و سصح دسترسی فایل موجود در sysfs می باشد.

همان طور که در قسمت قبل در بخش ktype گفتیم رفتار پیش فرض دسته ای از kobject ها در ساختار ktype در فیلد default_attrs قرار می گیرد. ولی با استفاده از فیلد sysfs_ops در همین ساختار داده می توان رفتار های kobject را مشخص کرد.

struct sysfs_ops {

/* method invoked on read of a sysfs file */

ssize_t (*show) (struct kobject *kobj,

struct attribute *attr,

char *buffer);


/* method invoked on write of a sysfs file */

ssize_t (*store) (struct kobject *kobj,

struct attribute *attr,

const char *buffer,

size_t size);

};

به طور خلاصه متد ()show برای خواندن به کار می رود. این تابع مقدار attr را در بافری به نام buffer کپی می کند. متد ()store نیز برای نوشتن به کار می رود. این تابع به اندازه size از buffer می خواند و در attr می نویسد. روش ذکر شده برای دسته ای از kobject ها کارایی دارد. برای تنظیم attribute برای یک kobject از توابع زیر استفاده می شود:


int sysfs_create_file(struct kobject *kobj, const struct attribute *attr);
int sysfs_create_link(struct kobject *kobj, struct kobject *target, char *name);
void sysfs_remove_file(struct kobject *kobj, const struct attribute *attr);
void sysfs_remove_link(struct kobject *kobj, char *name);

نتیجه گیری: در این دو قسمت اخیر با مدل جدیدی از دستگاه ها موسوم به sysfs and kobjects اشنا شدیم. ساختار های داده ای مانند kref , ktype , attribute , subsystem , kset و ... را مورد بررسی قرار دادیم و با روش های متفاوتی نحوه استفاده و مدیریت kobject ها و نحوه نمایش انها در sysfs را بررسی کردیم. مطالبی که در این دو قسمت بررسی شدند از جدیدترین موضوعاتی هستند که در هسته لینوکس مورد پیاده سازی قرار گرفته اندو به نظر می رسد که اشنایی هر توسعه دهنده هسته با این مبانی کاملا ضروری می نماید. مطالب این مدل جدید را در همین جا به پایان می بریم و یادگیری جزییات بیشتر را به خواننده واگذار می کنیم. در قسمت اینده به ادامه بحثمان در ماژول نویسی هسته لینوکس خواهیم پرداخت و مطالبی چون کار با توابع سیستمی را مورد بررسی قرار می دهیم.



نویسنده: سعید تقوی s.taghavi@ece.ut.ac.ir

منابع :

1-R. Love, “Linux Kernel Development”, 2nd ed, Sams Publishing, 2005

2-Linux Source Code/Documentation/filesystems/sysfs.txt

3-Linux Source Code/Documentation/kobject.txt

4->http://lwn.net/Articles/54651

5->http://www.win.tue.nl/~aeb/linux/lk/lk-12.html

PDF Version

تمامی مطالب و مقالات این سایت تحت مجوز GNU FDL قرار دارند. بنابراین کپی و ایجاد تغییر در آنها مطابق شرایط این مجوز آزاد می‌باشد.