ליבה (מערכות הפעלה)

במחשבים, ליבה (באנגלית: Kernel) היא הרכיב המרכזי של מרבית מערכות ההפעלה; זהו הגשר שבין תוכניות המחשב לבין עיבוד הנתונים עצמו שמבוצע ברמת החומרה. אחד התפקידים העיקריים של הליבה הוא ניהול משאבי המערכת (התקשורת שבין רכיבי החומרה והתוכנה). בדרך כלל, בתור הרכיב הבסיסי של מערכת הפעלה, הליבה יכולה לספק את שכבת האבסטרקציה ברמה הנמוכה ביותר עבור המשאבים (בייחוד עבור מעבדים והתקני קלט-פלט) שהתוכניות צריכות לשלוט עליהם על מנת לבצע את תפקידן. בדרך כלל הליבה הופכת שירותים כאלה לזמינים עבור תהליכים של תוכניות באמצעות מנגנוני תקשורת בין תהליכים (inter-process communication) וקריאות מערכת.
המשימות של מערכות הפעלה מבוצעות באופן שונה על ידי ליבות שונות, בהתאם לעיצוב ולמימוש שלהן. בעוד שליבות מונוליטיות (Monolithic Kernels) מריצות את כל הקוד של מערכת ההפעלה באותו מרחב כתובות על מנת לשפר את ביצועי המערכת, מיקרו-ליבות (Microkernels) מריצות את מרבית שירותי מערכת ההפעלה במרחב המשתמש כשרתים, במטרה לשפר את האמינות והתחזוקתיות של מערכת ההפעלה. קיים מגוון של אפשרויות בין שתי הדוגמאות הקיצוניות האלה.
ליבת מערכת ההפעלה היא התוכנית היחידה אשר מוכנה לריצה בכל זמן שהוא. בנוסף, הליבה היא התוכנה היחידה שיכולה לבצע אוסף פקודות בצורה אטומית (ללא שום הפרעה או הפסקה מגורם כלשהו). כל מערכת הפעלה חייבת ליבה כדי לפעול, אך הליבה אינה בהכרח ייחודית למערכת ההפעלה - מערכות הפעלה שונות יכולות להשתמש בליבה זהה. לדוגמה, על ליבת לינוקס ניתן להריץ הפצת לינוקס שולחנית אך גם אפשר להריץ את מערכת ההפעלה אנדרואיד למכשירים ניידים.

ניהול תהליכים

המשימה העיקרית של ליבה היא לאפשר הרצה של תוכניות מחשב ולספק להן שירותים כגון אבסטרקציה של החומרה. תהליך מגדיר אילו חלקים מהזיכרון יהיו נגישים לתוכנית, וניהול התהליכים שמתבצע בליבה צריך לקחת בחשבון את החומרה המובנית לצורך הגנה על הזיכרון.
כדי להריץ תוכנית, בדרך כלל הליבה מגדירה עבורה מרחב כתובות, טוענת לזיכרון את הקובץ שמכיל את הקוד של התוכנית, יוצרת מחסנית קריאות, מצביעה למיקום מסוים בתוך התוכנית ובכך מתחילה את הביצוע שלה.
ליבות התומכות בריבוי משימות מסוגלות ליצור אשליה עבור המשתמש, כאילו מספר התהליכים שרצים בו זמנית על גבי המחשב הוא גדול יותר מהמספר המקסימלי של תהליכים שהמחשב פיזית יכול להריץ בו זמנית. בדרך כלל מספר התהליכים שמערכת יכולה להריץ בו זמנית שווה למספר המעבדים שמותקנים במחשב (עם זאת, המצב יכול להיות שונה אם המעבדים תומכים ב- simultaneous multithreading).
במערכת המבוססת על ריבוי משימות מקדים (pre-emptive multitasking), הליבה תיתן לכל תוכנית פרוסת זמן ותבצע מיתוג (switch) מתהליך לתהליך במהירות כזאת עד שהדבר יראה למשתמש כאילו תהליכים אלה מורצים בו זמנית. הליבה משתמשת באלגוריתמי תזמון על מנת לקבוע מה יהיה התהליך הבא שירוץ וכמה זמן יוקצה לו. האלגוריתם הנבחר יכול לאפשר לחלק מהתהליכים להיות בעלי קדימות גבוהה יותר מזו של אחרים. הליבה בדרך כלל גם מספקת לתהליכים אלה אמצעי כלשהו להתקשר; דבר זה ידוע בתור תקשורת בין תהליכים (IPC), והשיטות העיקריות לצורך כך הן זיכרון משותף, העברת מסרים והפעלת פרוצדורות מרחוק (ראו: מחשוב מקבילי).
מערכות אחרות (בייחוד על גבי מחשבים קטנים ופחות עוצמתיים) יכולות להיות מבוססות על ריבוי משימות שיתופי (co-operative multitasking), שבו כל תהליך מורשה לרוץ ללא פסיקות ("ללא הפרעה"), עד שהוא מגיש בקשה שאומרת לליבה שהיא יכולה לבצע מיתוג לתהליך אחר. בקשות כאלה נקראות yielding (ויתור), בדרך כלל הן מתרחשות בתגובה לבקשות לתקשורת בין תהליכים, או כאשר מחכים לאירוע שיתרחש. גרסאות ישנות יותר של Windows ו-Mac OS השתמשו ב-co-operative multitasking, אבל שתיהן עברו לשיטת ה-pre-emptive ככל שגדלה עוצמת המחשבים שעבורם תוכננו.
מערכת ההפעלה עשויה לתמוך גם ב-multiprocessing (בארכיטקטורת Symmetric multiprocessing או Non-Uniform Memory Access); במקרה זה, תוכניות ותהליכונים שונים יכולים לרוץ על מעבדים שונים. הליבה עבור מערכת כזאת צריכה להיות מתוכננת כך שתוכל בו זמנית להריץ בבטחה שני חלקים שונים של הקוד שלה. בדרך כלל המשמעות של כך היא שיש לספק מנגנוני סנכרון (כדוגמת spinlock) על מנת להבטיח שלא יקרה מצב בו שני מעבדים מנסים לשנות את אותם הנתונים באותו זמן.

ניהול זיכרון

לליבה יש גישה מלאה לזיכרון המערכת ותפקידה לאפשר לתהליכים לגשת לזיכרון זה בצורה בטוחה בהתאם לדרישותיהם. בדרך כלל השלב הראשון לצורך כך הוא מיעון וירטואלי (virtual addressing), המושג בדרך כלל באמצעות דפדוף או סגמנטציה. מיעון וירטואלי מאפשר לליבה לגרום לכתובת פיזית בזיכרון להופיע בתור כתובת שונה, הכתובת הווירטואלית. מרחבי כתובות וירטואליים עשויים להיות שונים עבור תהליכים שונים; הזיכרון אליו ניגש תהליך אחד בכתובת (וירטואלית) מסוימת עשוי להיות זיכרון שונה מהזיכרון שאליו ניגש תהליך אחר באותה הכתובת. זה מאפשר לכל תוכנית להתנהג כאילו היא התוכנית היחידה (חוץ מהליבה) שרצה, ובכך מונעת מתוכניות להפיל אחת את השנייה.
במערכות רבות, הכתובת הווירטואלית של תוכנית עשויה להצביע לנתונים שלא נמצאים כרגע בזיכרון. שכבה נוספת זו של פעילות עקיפה המסופקת על ידי מיעון וירטואלי מאפשרת למערכת ההפעלה להשתמש באמצעי אחסון אחרים, כגון דיסק קשיח, על מנת לאחסן נתונים שאחרת היו חייבים להישאר בזיכרון הראשי (RAM). כתוצאה מכך, מערכות הפעלה יכולות לאפשר לתוכניות להשתמש ביותר זיכרון מהזיכרון הפיזי הפנוי במערכת. כאשר תוכנית זקוקה לנתונים שלא מאוחסנים כרגע בזיכרון ה-RAM, המעבד מאותת לליבה על כך שהדבר התרחש, והליבה מגיבה על ידי כתיבה לדיסק של התוכן של בלוק בזיכרון שלא נמצא כרגע בשימוש (אם הדבר נדרש) ואז מחליפה תוכן זה בנתונים שהתבקשו על ידי התוכנית. לאחר מכן התוכנית יכולה להמשיך לרוץ מהנקודה שבה היא נעצרה. שיטה זו ידועה כ-demand paging.
מיעון וירטואלי מאפשר גם יצירה של מחיצות זיכרון וירטואליות בשני אזורים שונים, כאשר אחת שמורה עבור הליבה (מרחב הליבה) והשנייה עבור התוכניות (מרחב משתמש). המעבד אינו מאפשר לתוכניות להשתמש בזיכרון הליבה, ובכך מונע מתוכניות לפגוע בליבה הרצה. חלוקה עקרונית זו של מרחב הזיכרון תרמה רבות לעיצובן של הליבות המודרניות שמיועדות לשימוש כללי, והיא אוניברסלית כמעט לכל המערכות מסוג זה, אם כי קיימות כמה ליבות מחקר (למשל Singularity) אשר נוקטות בגישות אחרות.

ניהול התקנים

כדי לעשות פעילות מועילה כלשהי, לתהליכים צריכה להיות גישה לציוד ההיקפי (peripherals) שמחובר למחשב. ציוד היקפי זה נשלט על ידי הליבה באמצעות מנהלי התקנים (device drivers). מנהל התקנים (דרייבר) הוא תוכנת מחשב המאפשרת למערכת ההפעלה ליצור אינטראקציה עם התקן חומרה כלשהו. מנהל ההתקנים מספק למערכת ההפעלה מידע כיצד לשלוט על יחידת חומרה מסוימת ואיך לתקשר איתה. לדרייבר חשיבות מכרעת עבור תוכנית יישומים. המטרה בתכנון מנהל התקנים היא ליצור אבסטרקציה על ידי תרגום קריאות של פונקציות (function/programming calls) היוצאות ממערכת ההפעלה, לקריאות הספציפיות עבור התקן מסוים. עקרונית, התקן אמור לעבוד באופן תקין עם מנהל ההתקנים המתאים עבורו. בדרך כלל מהנדסים כותבים את הקוד עבור מנהלי התקנים. הם פועלים על: כרטיסי מסך, כרטיסי קול, מדפסות, סורקים, מודמים, כרטיסי רשת, ועוד.
לדוגמה, כדי להציג למשתמש משהו על גבי המסך, תוכנית תגיש בקשה לליבה, שבתורה תעביר את הבקשה למנהל ההתקנים של המסך, אשר באחריותו לבצע את ההצגה עצמה של התו/פיקסל.
על הליבה להחזיק ברשימה של כל ההתקנים הזמינים. רשימה זו יכולה להיות ידועה מראש (למשל במערכת משובצת מחשב שבה הליבה תיכתב מחדש אם החומרה תשתנה); יכולה להיות מוגדרת על ידי המשתמש (טיפוסי למחשבים אישיים ישנים ובמערכות שלא מיועדות לשימוש אישי); או שהיא מזוהה על ידי מערכת ההפעלה בזמן ריצה (plug and play). במערכת plug and play, מנהל ההתקנים תחילה מבצע סריקה על אפיקי חומרה שונים, כגון PCI ו-USB על מנת לזהות התקנים מותקנים, ואז מחפש אחר הדרייברים המתאימים.
מכיוון שניהול התקנים הוא ייחודי ותלוי מערכת הפעלה, כל אחד מסוגי התכנון של ליבות מטפל במנהלי התקנים אלה באופן שונה. אך בכל מקרה, הליבה צריכה לספק את האמצעים לביצוע קלט/פלט על מנת לאפשר לדרייברים גישה פיזית אל ההתקנים שלהם דרך פורט מסוים או מקום כלשהו בזיכרון. יש לקבל החלטות חשובות מאוד בזמן התכנון של מערכת לניהול התקנים, מכיוון שבחלק מהעיצובים, הגישה להתקנים יכולה להיות כרוכה בהחלפות הקשר, מה שהופך את הפעולה לכזאת שדורשת פעילות אינטנסיבית של המעבד, ובכך יכולה לגרום לירידה משמעותית בביצועי המערכת.

קריאות מערכת

קריאת מערכת (system call) היא מנגנון המשמש תוכניות לצורך בקשת שירות ממערכת ההפעלה. הן משתמשות בהוראות בשפת מכונה אשר גורמות למעבד לשנות מצב. דוגמה לכך יכולה להיות מעבר בין המצבים supervisor mode ל-protected mode. כאן מערכת ההפעלה מבצעת פעולות כמו גישה להתקני חומרה או ליחידת ניהול הזיכרון (MMU). בדרך כלל מערכת ההפעלה מספקת ספרייה שיושבת בינה לבין התוכניות הרגילות. בדרך כלל זוהי ספרייה בשפת C כמו glibc או Windows API. הספרייה מטפלת בפרטים ברמה הנמוכה (low level) של העברת מידע אל הליבה ומעבר למצב משגוח (supervisor mode). קריאות מערכת נפוצות הן: close, open, read, write.
כדי לעשות פעילות מועילה כלשהי, על התהליך להיות מסוגל לגשת לשירותים שמספקת הליבה. דבר זה ממומש באופן שונה על ידי כל ליבה, אבל רובן מספקות ספרייה - C standard library, או ממשק תכנות יישומים (API), שבתורם קוראים לפונקציות של הליבה.