سی‌گروپس کیست؟ توضیح بده.
cgroups (مخفف control groups به معنی گروه‌های کنترلی) یک قابلیت هستهٔ لینوکس است که منابع مجموعه‌ای از فرایندها را مدیریت و مجزاسازی می‌کند.cgroup v2.تاریخچه.نسخه‌ی دوم سی‌گروپس در سال ۲۰۱۶ به همراه کرنل نسخه ۴.۵ منتشر شد. Tejun Heo مسئول طراحی و بازنویسی مجدد سی‌گروپس بوده است.ساختار.cgroup مکانیسمی برای سازمان‌دهی سلسله‌مراتبی پردازه‌ها و اختصاص منابع سیستم در طول این سلسله‌مراتب است. این ویژگی از دو قسمت اصلی تشکیل شده است: هسته و کنترل‌کننده‌ها . وظیفه‌ی اصلی هسته سازمان‌دهی پردازه‌ها در یک ساختار سلسله‌مراتبی است. کنترل‌کننده‌ها نیز وظیفه‌ی توزیع یک منبع خاص سیستم در طول این سلسله‌مراتب را دارند.این سلسله‌مراتب تشکیل یک درخت را می‌دهد. یعنی یک cgroup می‌تواند فرزند یک cgroup دیگر باشد. هر پردازه درون دقیقا یک cgroup قرار می‌گیرد. هنگام ساخت پردازه‌ی جدید این پردازه درون cgroup پدر خود قرار می‌گیرد ولی می‌تواند به cgroup های دیگر مهاجرت کند. کنترل‌کننده‌ها نیز می‌توانند روی یک cgroup فعال یا غیرفعال شوند. در صورت فعال شدن یک کنترل‌کننده روی یک گروه، تمامی فرزندان این گروه که می‌تواند شامل cgroup های دیگر باشد تحت تاثیر قرار می‌گیرند.پرونده‌های رابط.هر cgroup یک پوشه مربوط به خود دارد که در آن فایل‌هایی که اطلاعات گروه را نگه می‌دارند ذخیره می‌شود. در زیر تعدادی از این فایل‌ها به اختصار ذکر شده است:کنترل‌کننده‌ها.از بین کنترل‌کننده‌هایی که برای cgroup ها وجود دارند می‌توان به کنترل‌کننده‌های CPU ،Memory ،IO ، Writeback و PID اشاره کرد. با فعال‌کردن هر کدام از کنترل‌کننده‌ها فایل‌هایی با پیشوند کنترل‌کننده به پوشه‌ی فرزندان cgroup اضافه می‌شوند و در آن‌ها می‌توان تنظیمات مربوط به منابع را انجام داد.برای توزیع منابع بین گروه‌ها چهار روش وجود دارد که به دوتا از آن‌ها اشاره می‌کنیم: یکی از آن‌ها با استفاده از وزن است؛ یعنی به هر گروه فرزند یک عدد نسبت داده می‌شود و منبع بر اساس نسبت این اعداد به مجموع توزیع می‌شود. این روش در توزیع CPU کاربرد دارد. روش دیگر محدود کردن منبع است؛ یعنی برای هر گروه یک مقدار بیشینه تعیین شود که مقدار استفاده‌ی آن از منبع از آن مقدار بیشتر نشود. به طور مثال برای توزیع IO می‌توان از این نوع تخصیص استفاده کرد.قابلیت فریزر cgroup v2.با استفاده از این ویژگی می‌توان تمام تسک‌های موجود در یک سی‌گروپس را به طور موقت متوقف کرد. این ویژگی برای cgroup v2 در هسته‌ی لینوکس نسخه 5.2 اضافه شده است.کاربردها.قابلیت فریزر cgroup در که در آن‌ها مدیر یک سیستم می‌خواهد مجموعه‌ای از کارها رو هم‌زمان شروع یا متوقف کند کاربرد دارد. این گونه برنامه‌ها به خصوص در خوشه‌های استفاده می‌شوند که در آن‌ها تعداد زیادی گره مختلف به صورت توزیع شده وجود دارند.از سیگنال‌های کنترلی SIGSTOP و SIGCONT نیز می‌توان برای توقف یا ادامه دادن یک پردازه استفاده کرد. اما مشکل این سیگنال‌ها این است که می‌توانند توسط پردازه‌ی پدر مشاهده شوند و برنامه‌هایی مثل یا در صورت استفاده از این سیگنال‌ها برای متوقف کردن و ادامه دادن برنامه دچار مشکل می‌شوند.این قابلیت هم‌چنین می‌تواند برای حالت‌برداری از برنامه‌ها استفاده شود. با فریز کردن یک cgroup می‌توان پردازه‌های آن را به یک حالت غیرفعال برد و از آن‌ها یک تصویر ذخیره کرد و/یا با استفاده از رابط‌های کرنل اطلاعات مورد نظر درباره‌ی آن‌ها را ذخیره کرد و پس از آن با درآوردن cgroup از حالت فریز شده آن‌ها را دوباره فعال کرد.پیاده‌سازی در کرنل.برای پیاده‌سازی این قابلیت داده ساختار زیر به cgroups-defs.h اضافه شده است:struct cgroup_freezer_state { /* Should the cgroup and its descendants be frozen. */ bool freeze; /* Should the cgroup actually be frozen? */ int e_freeze; /* Fields below are protected by css_set_lock */ /* Number of frozen descendant cgroups */ int nr_frozen_descendants; * Number of tasks, which are counted as frozen: * frozen, SIGSTOPped, and PTRACEd. int nr_frozen_tasks;این داده ساختار به داده ساختار cgroup با عنوان freezer اضافه شده است. هم چنین در پرچم‌های cgroup دو بیت به codice_1 و codice_2 اختصاص داده شده است که به ترتیب نشان‌دهنده‌ی این هستند که cgroup باید فریز شود یا خیر و آیا cgroup فریز شده است یا خیر. به داده ساختار codice_3 نیز یک پرچم frozen اضافه شده که مشخص می‌کند تسک فریز شده است یا خیر.فرایند فریز شدن یک تسک.در JOBCTL یک تله برای فریز کردن یک تسک در نظر گرفته شده است. تابع codice_4 مسئول رسیدگی به این تله است. در این تابع پس از اطمینان از این که سیگنال یا تله‌ی پراهمیت دیگری که به آن‌ها رسیدگی نشده باشد وجود نداشته باشد تابع codice_5 را صدا می‌زند که در ادامه توضیح داده خواهد شد. پس از آن نیز تابع codice_6 صدا زده می‌شود که پرچمی را در تسک ست می‌کند که در زمان‌بندی شرکت داده نشود و سپس تسک بعدی را زمان‌بندی می‌کند. تابع codice_6 پیش از پیاده‌سازی فریزر cgroup نیز وجود داشته است و به طور مثال برای خوابیدن برای مدت زمان خاص در تابع codice_8 یا خوابیدن در صف در تابع codice_9 استفاده شده است. در نتیجه برای این که تسک‌های فریز شده در زمان‌بند زمان‌بندی نشوند نیازی به تغییرات در زمان‌بند وجود ندارد.در تابع codice_5 پرچم frozen تسک در صورتی که یک نباشد یک می‌شود و بعد از زیاد کردن تعداد تسک‌های فریز شده‌ی cgroup تسک، تابع codice_11 برای cgroup صدا زده می‌شود: * Revisit the cgroup frozen state. * Checks if the cgroup is really frozen and perform all state transitions.void cgroup_update_frozen(struct cgroup *cgrp) bool frozen; lockdep_assert_held(&amp;css_set_lock); * If the cgroup has to be frozen (CGRP_FREEZE bit set), * and all tasks are frozen and/or stopped, let's consider * the cgroup frozen. Otherwise it's not frozen. frozen = test_bit(CGRP_FREEZE, &amp;cgrp-&gt;flags) &amp;&amp; cgrp-&gt;freezer.nr_frozen_tasks == __cgroup_task_count(cgrp); if (frozen) { /* Already there? */ if (test_bit(CGRP_FROZEN, &amp;cgrp-&gt;flags)) return; set_bit(CGRP_FROZEN, &amp;cgrp-&gt;flags); } else { /* Already there? */ if (!test_bit(CGRP_FROZEN, &amp;cgrp-&gt;flags)) return; clear_bit(CGRP_FROZEN, &amp;cgrp-&gt;flags); cgroup_file_notify(&amp;cgrp-&gt;events_file); /* Update the state of ancestor cgroups. */ cgroup_propagate_frozen(cgrp, frozen);در این تابع بررسی می‌شود که آیا یک cgroup باید به حالت frozen دربیاید یا خیر. یک cgroup باید فریز شود اگر پرچم codice_1 آن یک باشد و تعداد تسک‌های فریز شده‌ی آن با تعداد کل تسک‌های زیردرختش برابر باشد. در صورتی که وضعیت یک cgroup از فریز شده به نشده یا بلعکس تغییر کرده باشد این تغییر در فایل مربوط به رخدادهای آن نوشته می‌شود و هم چنین یک تابع به نام codice_13 صدا زده می‌شود که وظیفه‌ی آن انتشار وضعیت cgroup به اجداد آن است تا تعداد تسک‌های فریز شده‌ی آن‌ها نیز تغییر کند و در صورت لزوم وضعیت فریز بودن یا نبودن آن‌ها در فایل رخدادهایشان به‌روزرسانی شود.فرایند فریز شدن یک cgroup.هنگامی که تغییری در فایل cgroup.freeze که در قسمت اول ذکر شد صورت بگیرد تابع codice_14 اجرا می‌شود. این تابع در صورتی که مقدار نوشته شده در فایل معتبر، یعنی صفر یا یک باشد تابع cgroup_freeze(cgrp, freeze)را صدا می‌زند. در این تابع به ازای هر کدام از گروه‌ها در زیردرخت cgrp مقدار codice_15 که در واقع تعداد فریزهای انجام شده روی یک گروه است بسته به یک یا صفر بودن freeze یکی زیاد یا کم می‌شود. در صورتی که این مقدار قبلا بزرگ‌تر از صفر بوده باشد و اکنون نیز بزرگ‌تر از بماند یعنی cgroup پیش از این نیز در حالت فریز قرار داشته است و لازم نیست کاری انجام شود. در غیر این صورت تابعcgroup_do_freeze(cgrp, freeze)صدا زده می‌شود که در این تابع پرچم codice_1 مقداردهی می‌شود و پس از آن به ازای هر تسک داخل cgroup تابع codice_17 اجرا می‌شود. لازم به ذکر است که پردازه‌های کرنل (kthreads) قابلیت فریز شدن ندارند و هر جایی که بخواهد تغییری در وضعیت تسک صورت بگیرد این نکته چک می‌شود و این پردازه‌ها کنار گذاشته می‌شود.در تابع codice_17 در صورتی که که تسک در حال فریز شدن باشد پرچم codice_19 مربوط به jobctl را یک می‌کند و با استفاده از codice_20 به پردازه اعلام می‌کند که یک سیگنال برای رسیدگی دارد. هنگامی که پردازه شروع به اجرا کند به سیگنال گفته شده با استفاده از تابع codice_4 که در بالا توضیح داده شد رسیدگی می‌کند و به حالت خواب می‌رود. در صورتی که تسک در حال بیرون آمدن از حالت فریز شدن باشد پرچم ذکر شده صفر می‌شود و با استفاده از تابع codice_22 تسک بیدار می‌شود.هنگامی که یک تسک بیدار می‌شود اگر پرچم frozen آن یک بوده باشد یعنی به تازگی از حالت فریز بیرون آمده است که در این صورت تابع codice_23 صدا زده می‌شود. در این تابع پس از کاهش تعداد بچه‌های فریزشده‌ی cgroup تابع codice_11 صدا زده می‌شود که پیش‌تر توضیح داده شد و هم چنین پرچم frozen تسک را نیز صفر می‌کند.مهاجرت یک تسک به cgroup دیگر.نکته‌ی آخر فرایند مهاجرت یک تسک از یک cgroup به دیگری است. هنگامی که یک تسک به cgroup ای برود که فریز شده است متوقف می‌شود. هم چنین اگر یک تسک از یک cgroup فریز شده به گروه غیر فریز برود از حالت فریز بیرون می‌آید. برای پیاده‌سازی این قسمت در تابع codice_25 که برای مهاجرت تسک‌ها استفاده می‌شود تابع codice_26 صدا زده می‌شود. در این تابع پس از کاهش و افزایش تعداد تسک‌های فریز شده‌ی cgroup مبدا و مقصد، تابع codice_11 برای هر دوی مبدا و مقصد صدا زده می‌شود. در نهایت نیزcgroup_freeze_task(task, test_bit(CGRP_FREEZE, &amp;dst-&gt;flags));صدا زده می‌شود که باعث می‌شود تسک با توجه به وضعیت cgroup مقصد (dst) به حالت مناسب برود.