فراخوانی سیستمی

امروزه قابلیت‌های بسیار متنوعی از سمت سیستم‌های عامل در اختیار برنامه‌های سیستمی است و برنامه‌های بزرگ که کاربران زیادی از آن‌ها استفاده می‌کنند برای پیشرفت و افزایش کارایی خود باید این قابلیت‌ها را در نظر بگیرند. به عنوان مثال ۲ برنامه را تصور کنید: یک برنامه وظیفه‌اش خواندن یک پرونده از جنس فیلم و نمایش آن است و برنامه دیگر وظیفه‌اش آن است که پخش زنده‌ای که داده‌هایش از یک دوربین دریافت می‌شود را در اینترنت بارگزاری کند و نمایش دهد.

در سیستم عامل لینوکس یک فراخوانی سیستمی تحت عنوان `madvise(2)` وجود دارد که به سیستم عامل رهنمودهایی دربارهٔ الگوی ارجاع برنامه به بخش‌های مختلف حافظه می‌دهد. در برنامهٔ اول برنامه‌نویس می‌تواند با این فراخوانی سیستمی اعلام کند که ارجاع به حافظه به صورت پشت سر هم و به ترتیب است، بنابراین سیستم عامل می‌تواند بخش‌های مختلف پروندهٔ فرد را قبل از دسترسی به آن در حافظه آورده تا در آیندهٔ نزدیک برنامه به آن دسترسی پیدا کند که به این عمل جلوخوانی می‌گویند. برخلاف برنامهٔ اول، در برنامهٔ دوم عملاً نمی‌دانیم که دسترسی به حافظه چگونه است، زیرا به صورت زنده داده‌ها دریافت می‌شود و جلوخوانی در دسترسی به حافظه کمکی به برنامه نمی‌کند. حال فرض کنید که بخواهیم در سیستم عامل این امکان را فراهم کنیم که یک پردازه بتواند این سیاست‌ها را برای پردازه‌ای دیگر مشخص کند.

در نسخهٔ ۵٫۱۰ لینوکس یک فراخوانی سیستمی با عنوان `process_madvise(2)` به مجموعه فراخوانی‌های سیستمی اضافه شده‌است که این نیاز را برای کاربر برطرف می‌کند.

## ساختار
این فراخوانی سیستمی ساختاری به صورت زیر دارد
```c
#include <sys/uio.h>

ssize_t process_madvise(int pidfd, const struct iovec *iovec,
    size_t vlen, int advice,
    unsigned int flags);
```
برای آن که متوجه شویم این فراخوانی سیستمی چه کاری انجام می‌دهد ابتدا باید کمی با مفهوم توصیف کنندهٔ فایل شناسه پردازه (process id file descriptor) یا [./https://en.wikipedia.org/wiki/Pidfd pidfd] آشنا شویم.

می‌دانیم که در سیستم‌های عامل از جمله لینوکس، پردازه‌ها با یک شناسهٔ عددی مشخص می‌شوند. همچنین این شناسه‌ها بازهٔ محدودی دارند؛ مثلاً در هستهٔ لینوکس مقدار پیشفرض برای تعداد پردازه‌ها ۳۲۷۶۸ است.

این موضوع باعث می‌شود که سیستم عامل هنگامی که یک پردازه با شناسه پردازه‌ای خاص به اتمام رسید، شناسهٔ آن را برای پردازه‌های بعدی استفاده کند.

این یعنی ممکن است پردازه `A`، پردازه ای دیگر مانند `B` را با شناسه اش که `id_b` است در نظر بگیرد و پردازهٔ `B` به اتمام برسد و بعد از مدتی پردازه‌ای جدید مانند `C` با همان شناسه پردازه یعنی `id_b` ایجاد شود. در این حالت پردازه `A` فقط `id_b` را دارد و فکر می‌کند که این شناسه متناظر با `B` است، حال آن که `id_b` اکنون `C` را مشخص می‌کند؛ بنابراین اگر `A` هدفش ارتباط با `B` بوده ممکن است به اشتباه با `C` ارتباط برقرار کند. این موضوع ممکن است باعث بروز خطاهایی شود و گاهی امنیت را به خطر بیندازد.

مفهوم pidfd برای حل این مشکل ایجاد شده و هر پردازه به‌طور یکتا با pidfd متناظر خود شناخته می‌شود.بنابراین ورودی اصلی `process_madvise` یک pidfd است که پردازهٔ هدف را به‌طور یکتا مشخص می‌کند.

## فایده
فرض کنید که در سیستم عامل تعدادی برنامه وجود دارد که خودشان اطلاعی از الگوهای استفاده‌شان از حافظه ندارند، ولی پردازهٔ دیگری وجود دارد که در نقش مدیر می‌تواند این الگوها را به دست بیاورد (چنین عملکردی به‌طور خاص در سیستم عامل اندروید وجود دارد). در چنین شرایطی می‌توان با استفاده از این فراخوانی سیستمی عملکرد پردازه‌های مختلف و همچنین کل سامانه را بهبود داد تا با بهترین سیاست از حافظه استفاده کنند.

## عملکرد
در حال حاضر این فراخوانی سیستمی تنها ۲ پرچم به عنوان راهنمای پردازهٔ هدف (`advise`) دارد:
* `MADV_COLD`: این پرچم احتمال بازپس‌گیری بازه حافظه‌ای که با `iovec` مشخص شده را افزایش می‌دهد.
* `MADV-PAGEOUT`: این پرچم سعی می‌کند که بخش‌هایی از حافظه که با `iovec` مشخص شده را از حافظه خارج کند، مثلاً اگر بخشی مربوط به داده‌های یک پرونده بود آن را به دیسک منتقل می‌کند و اگر امکان خارج کردن آن بخش از حافظه نبود، سیاست اعلامی را برای آن بخش نادیده می‌گیرد.

## منابع

رده:برنامه‌نویسی
رده:مقاله‌های ایجادشده توسط ایجادگر
رده:نرم‌افزار
رده:ویکی‌سازی رباتیک