এই পর্বে যা শিখবেন
- OS কী কী সেবা দেয়, আর মানুষ ও প্রোগ্রাম কোন তিন দরজা দিয়ে সেগুলো চায় — CLI, GUI আর API
- “কী করা হবে” (policy) আর “কীভাবে করা হবে” (mechanism) আলাদা রাখার নকশা-নীতি
- ছয় রকম গঠন — simple, monolithic, layered, microkernel, modular, hybrid — আর exokernel ও unikernel-এর পরিচয়
- একটি
read()কল দুই রকম kernel-এ কোন পথে যায়, আর driver-এর বাগ কেন monolithic kernel-কে ফেলে দেয় - নিজের হাতে চালানো kernel-এর তথ্য, module লোড হওয়ার ধাপ, আর AI-এর দেওয়া kernel-তথ্য যাচাইয়ের উপায়
১ · OS কী সেবা দেয় — আর কোন দরজা দিয়ে
পর্ব ০১-এ দেখেছেন, OS হলো কম্পিউটারের ব্যবস্থাপক। পর্ব ০৫-এ দেখেছেন, প্রোগ্রাম OS-এর কাছে কিছু চাইলে system call করে, আর CPU তখন user mode থেকে kernel mode-এ যায়। এই পর্বের প্রশ্নটি তার এক ধাপ ওপরে: OS নামের এই বিশাল সফটওয়্যারটি — বিশেষ করে তার কেন্দ্রীয় অংশ kernel — ভেতরে কীভাবে সাজানো? কোন অংশ কোথায় থাকে, কে কাকে ডাকে, আর একটি অংশ ভেঙে পড়লে বাকিদের কী হয়?
গঠন বোঝার আগে দেখে নিই OS আসলে কী কী কাজ দেয়। প্রায় সব OS-এর পাঠ্যবইয়ে একই তালিকা পাবেন। প্রথম দলটি ব্যবহারকারী ও প্রোগ্রামের সরাসরি সুবিধার জন্য:
প্রোগ্রাম চালানো
প্রোগ্রাম মেমরিতে আনা, চালানো, শেষ হলে ফল জানানো — স্বাভাবিকভাবে বা ত্রুটিসহ।
fork, exec, CreateProcessI/O আর ফাইল
ডিস্ক, কীবোর্ড, নেটওয়ার্ক কার্ড সরাসরি ছুঁতে না দিয়ে নিরাপদ, একই রকম একটি পথ দেওয়া; ফাইল খোলা, পড়া, লেখা, খোঁজা।
open, read, writeযোগাযোগ
একই কম্পিউটারের প্রসেসগুলোর মধ্যে, বা নেটওয়ার্কে দূরের কম্পিউটারের সাথে তথ্য আদান-প্রদান।
pipe, socketত্রুটি ধরা
মেমরির ভুল ঠিকানা, ডিস্কের খারাপ সেক্টর, শূন্য দিয়ে ভাগ — ধরা এবং যতটা সম্ভব সামলানো।
signal, exceptionদ্বিতীয় দলটি সিস্টেমকে দক্ষ ও নিরাপদ রাখার জন্য: resource বণ্টন (কে কতক্ষণ CPU, কত মেমরি পাবে), হিসাব রাখা (কে কতটা ব্যবহার করল, log), আর সুরক্ষা ও নিরাপত্তা (একজনের ফাইল আরেকজন যেন না পড়ে, বাইরের আক্রমণ যেন না ঢোকে)।
তিনটি দরজা: CLI, GUI আর API
এই সেবাগুলো পাওয়ার জন্য OS তিন রকম দরজা খোলা রাখে। মানুষের জন্য দুটি, প্রোগ্রামের জন্য একটি।
| দরজা | কে ব্যবহার করে | উদাহরণ | ভেতরে আসলে কী হয় |
|---|---|---|---|
| CLI — command-line interface | মানুষ, স্ক্রিপ্ট | bash, zsh (Linux, macOS), PowerShell, cmd (Windows) | shell একটি সাধারণ প্রোগ্রাম; কমান্ড পড়ে অন্য প্রোগ্রাম চালায় (পর্ব ১১) |
| GUI — graphical user interface | মানুষ | Windows Explorer, macOS Finder, GNOME, Android-এর টাচস্ক্রিন | মাউস-ক্লিক বা টাচ শেষ পর্যন্ত সেই একই system call-এ রূপ নেয় |
| API — application programming interface | প্রোগ্রাম | POSIX (Linux, macOS, BSD), Win32 (Windows), Android-এর Java/Kotlin API | library-র ফাংশন (যেমন C-র fopen) ভেতরে system call করে |
একটি মজার ও কাজের পার্থক্য খেয়াল করুন। Linux তার system call-এর নম্বরগুলো স্থির রাখে — কয়েক দশক পুরোনো প্রোগ্রামও নতুন kernel-এ চলে, কারণ Linus Torvalds-এর বিখ্যাত নিয়ম “user space ভাঙা চলবে না”. Windows উল্টো পথে হাঁটে: ভেতরের system call নম্বর Windows-এর এক build থেকে আরেক build-এ বদলাতে পারে, তাই প্রোগ্রামকে সবসময় Win32 API-র (ভেতরে ntdll.dll) মাধ্যমেই যেতে হয়। macOS-এও Apple শুধু library-র মাধ্যমে যাওয়াকেই সমর্থিত পথ বলে। অর্থাৎ “স্থির চুক্তি” কোথায় — kernel-এর দরজায়, নাকি library-র দরজায় — সেটি OS-ভেদে ভিন্ন।
Policy বনাম mechanism — নকশার প্রথম নীতি
ঢাকার একটি ব্যস্ত ট্রাফিক মোড়ের কথা ভাবুন। খুঁটিতে লাগানো লাল-সবুজ বাতি, তার ভেতরের টাইমার আর তার — এগুলো হলো mechanism: কীভাবে গাড়ি থামানো বা ছাড়া হবে। আর সকাল ৯টায় মিরপুর রোডের দিকে ৯০ সেকেন্ড সবুজ, রাতে ৩০ সেকেন্ড — এটি policy: কী করা হবে, কাকে কতটা অগ্রাধিকার। ভালো নকশায় policy বদলাতে বাতির খুঁটি ভাঙতে হয় না, শুধু নিয়মটি বদলালেই চলে।
Policy আর mechanism আলাদা রাখা: OS-এ timer interrupt দিয়ে একটি প্রসেসকে থামিয়ে আরেকটিকে CPU দেওয়ার ক্ষমতা হলো mechanism; কোন প্রসেস পরের পালা পাবে আর কতক্ষণ — সেটি scheduling policy (মডিউল ৩)। Mechanism হয় সাধারণ ও স্থির; policy হয় বদলযোগ্য। এই নীতিটি OS-এর গঠনের প্রতিটি বিতর্কের ভেতরে লুকিয়ে আছে — microkernel-এর পুরো দর্শনই হলো “kernel-এ শুধু mechanism, policy বাইরে”.
নীতিটির শিকড় ১৯৬০–৭০-এর দশকে। ডেনমার্কে Per Brinch Hansen তাঁর RC 4000 কম্পিউটারের জন্য (১৯৬৯) একটি ছোট “nucleus” বানান, যার ওপর আলাদা আলাদা OS-অংশ বসানো যেত — অনেকে একে microkernel-চিন্তার পূর্বসূরি বলেন। ১৯৭০-এর দশকের মাঝামাঝি Carnegie Mellon বিশ্ববিদ্যালয়ের Hydra প্রকল্পে William Wulf ও সহকর্মীরা “policy/mechanism separation” কথাটিকে স্পষ্ট নকশা-নীতি হিসেবে লেখেন।
২ · সরল গঠন আর monolithic kernel — MS-DOS, Unix, Linux
প্রথমে সবচেয়ে সরল উত্তরটি দেখি: “আলাদা করার দরকার কী? সব এক জায়গায় রাখি।”
সরল গঠন: MS-DOS
১৯৮১ সালে IBM PC-র সাথে আসা MS-DOS-এ কোনো স্পষ্ট স্তর বা সীমানা ছিল না। প্রোগ্রাম চাইলে OS-এর ফাংশন ডাকত, আবার চাইলে সরাসরি স্ক্রিনের মেমরিতে লিখত বা ডিস্ক কন্ট্রোলারের পোর্টে নির্দেশ পাঠাত। কারণটি হার্ডওয়্যারেও: Intel 8088 CPU-তে user mode আর kernel mode-এর পার্থক্যই ছিল না (পর্ব ০৪)। ফল — একটি প্রোগ্রামের ভুলে পুরো কম্পিউটার আটকে যেত, আর “রিস্টার্ট করুন” ছিল নিত্যদিনের সমাধান। ছোট, সস্তা মেশিনের জন্য এটি তখন যুক্তিসংগত ছিল; কিন্তু একসাথে অনেক প্রোগ্রাম আর অনেক ব্যবহারকারীর যুগে চলে না।
Monolithic kernel: সব এক ছাদের নিচে, কিন্তু user-এর থেকে আলাদা
Monolithic kernel-এ একটি বড় সীমানা আছে: নিচে kernel, ওপরে user program. কিন্তু kernel-এর ভেতরে process ব্যবস্থাপনা, মেমরি, file system, নেটওয়ার্ক stack, device driver — সব একটি প্রোগ্রাম, একটি address space, একই kernel mode-এর পূর্ণ ক্ষমতা নিয়ে চলে। এক অংশ আরেক অংশকে ডাকে সাধারণ C ফাংশন কলের মতো — কোনো মধ্যস্থতা নেই।
একটি বড় রেস্তোরাঁর রান্নাঘর ভাবুন — একটি ঘর, একটি বড় চুলার সারি, সব বাবুর্চি পাশাপাশি। ভাত-রাঁধুনি তরকারির বাবুর্চিকে মুখে বললেই লবণ এগিয়ে দেন — কোনো কাগজ লেখালেখি নেই, তাই কাজ খুব দ্রুত। কিন্তু একজনের কড়াইয়ে আগুন লাগলে পুরো রান্নাঘরই ঝুঁকিতে, আর একজনের ভুলে পুরো রান্না নষ্ট হতে পারে। Monolithic kernel ঠিক এমন: দ্রুত, কারণ সবাই এক ঘরে; ঝুঁকিপূর্ণ, একই কারণে। আর ঘরের দরজায় দারোয়ান আছেন — বাইরের অতিথি (user program) সরাসরি চুলায় হাত দিতে পারেন না, কাউন্টারে অর্ডার (system call) দিতে হয়।
১৯৭০-এর দশকে Bell Labs-এর মূল Unix এই ধাঁচের — একটি kernel, তার ওপরে shell আর ছোট ছোট system program. ১৯৯১ সালে ফিনল্যান্ডের ছাত্র Linus Torvalds Linux লেখা শুরু করেন একই monolithic ধাঁচে। আজকের Linux kernel কয়েক কোটি লাইনের — তার বড় অংশ, সাধারণত অর্ধেকেরও বেশি, শুধু device driver. Android ফোন, বেশিরভাগ ওয়েব সার্ভার, ক্লাউড, সুপারকম্পিউটার — সবখানে এই monolithic kernel চলছে। অর্থাৎ “পুরোনো ধাঁচ” মানেই বাতিল নয়; এর গতির সুবিধা খুব বাস্তব।
আপনি যে কম্পিউটারে কোড চালাচ্ছেন, তার kernel নিজের পরিচয় কী দেয়? নিচের স্ক্রিপ্টটি চালিয়ে দেখুন। এটি একটি container-এর ভেতরে চলে, তাই কিছু ফাইল লুকানো বা খালি থাকতে পারে — সেজন্য প্রতিটি পড়া 2>/dev/null || echo … দিয়ে সাবধানে করা:
echo "== uname -a =="
uname -a
echo "== /proc/version =="
cat /proc/version 2>/dev/null || echo "/proc/version not readable here"
echo "== /proc/sys/kernel (first 10 entries) =="
ls /proc/sys/kernel 2>/dev/null | head || echo "/proc/sys/kernel not available"
echo "== ostype and osrelease =="
cat /proc/sys/kernel/ostype /proc/sys/kernel/osrelease 2>/dev/null || echo "not available"
echo "== loaded modules =="
if [ -r /proc/modules ] && [ -s /proc/modules ]; then
echo "visible modules: $(wc -l < /proc/modules)"
else
echo "/proc/modules is empty or hidden here (container)"
fi
echo "== /sys/module =="
if [ -d /sys/module ]; then
echo "entries: $(ls /sys/module | wc -l)"
ls /sys/module | head -5
else
echo "/sys/module not mounted here"
fi
echo "tainted = $(cat /proc/sys/kernel/tainted 2>/dev/null || echo unknown)"একটি আসল চালানোয় এসেছিল (আপনার চালানোয় সংখ্যা ও তারিখ ভিন্ন হতে পারে):
Linux 7d2d0558be46 6.8.0-137-generic #137-Ubuntu SMP PREEMPT_DYNAMIC Fri Jul 17 20:28:23 UTC 2026 x86_64 x86_64 x86_64 GNU/Linux
Linux version 6.8.0-137-generic (buildd@lcy02-amd64-064) (x86_64-linux-gnu-gcc-13 (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0, GNU ld (GNU Binutils for Ubuntu) 2.42) ...
acct
acpi_video_flags
apparmor_display_secid_mode
...
Linux
6.8.0-137-generic
/proc/modules is empty or hidden here (container)
entries: 247
8021q
8250
...
tainted = 0
uname -a: kernel-এর নাম (Linux), release (6.8.0-137-generic— Ubuntu-র বানানো 6.8 kernel),SMP(একাধিক CPU সামলাতে পারে),PREEMPT_DYNAMIC(kernel-এর ভেতরেও কাজ থামিয়ে অন্য কাজ ধরা যায় — বুটের সময় ধরন বাছা যায়), আর CPU-র ধরনx86_64. শুরুর7d2d0558be46হলো hostname — container-এর একটি এলোমেলো নাম।/proc/version: kernel-টি কোন compiler দিয়ে বানানো —gcc-13আর GNUld. মনে করিয়ে দেয়, kernel-ও শেষ পর্যন্ত C-তে লেখা একটি বড় প্রোগ্রাম, যা toolchain দিয়ে তৈরি।/proc/sys/kernel: চলন্ত kernel-এর বদলযোগ্য সেটিং (sysctl) — প্রতিটি নাম একটি “knob”. এখানে policy-র অনেক নিয়ন্ত্রণ থাকে, যেমন সর্বোচ্চ PID সংখ্যা।apparmor_…নামগুলো Ubuntu-র নিরাপত্তা-ব্যবস্থার (পর্ব ৪৯)।- module-এর অংশ: container-এ
/proc/modulesখালি দেখাল — container নিজের kernel পায় না, host-এর kernel ভাগ করে, আর সেটির ভেতরের তালিকা তাকে দেখানো হয়নি। অথচ/sys/module-এ ২৪৭টি নাম দেখা গেল — এখানে লোড-করা module-এর পাশাপাশি kernel-এ স্থায়ীভাবে বসানো (built-in) অংশও থাকে, যাদের কোনো সেটিং আছে।tainted = 0মানে kernel-এ কোনো অস্বাভাবিক বা বাইরের module ঢোকেনি (অংশ ৬)।
সবচেয়ে বড় শিক্ষা: container-এর ভেতরে uname যে kernel দেখায়, সেটি আসলে host কম্পিউটারের kernel. Container কোনো আলাদা OS নয় — একই kernel-এর ওপর আলাদা করে রাখা প্রসেসের দল (পর্ব ৫১)।
৩ · Layered — Dijkstra-র THE সিস্টেম
সব এক জায়গায় রাখলে বড় সমস্যা হলো বোঝা আর প্রমাণ করা কঠিন — যেকোনো অংশ যেকোনো অংশকে ডাকতে পারে। ১৯৬৮ সালে নেদারল্যান্ডসের আইন্দহোফেন প্রযুক্তি বিশ্ববিদ্যালয়ে (Technische Hogeschool Eindhoven) Edsger W. Dijkstra ও তাঁর দল একটি ভিন্ন পথ দেখান। তাঁদের “THE multiprogramming system”-এর বিবরণ সে বছর Communications of the ACM-এ প্রকাশিত হয়। নিয়মটি সহজ: OS-কে কয়েকটি স্তরে (layer) ভাগ করুন। প্রতিটি স্তর শুধু নিজের নিচের স্তরগুলোর সেবা ব্যবহার করতে পারবে, কখনো ওপরের নয়।
একটি বহুতল অফিসের কথা ভাবুন, যেখানে ফাইল শুধু নিচের তলায় পাঠানো যায়। ছয় তলার কর্মকর্তা চার তলায় ফাইল পাঠাতে পারেন, কিন্তু চার তলা কখনো ছয় তলাকে কাজ দিতে পারে না। সুবিধা: নিচের তলা ঠিকঠাক কাজ করে প্রমাণিত হলে ওপরের তলা পরীক্ষা করার সময় নিচের কথা আর ভাবতে হয় না। Dijkstra ঠিক এভাবেই নিচ থেকে ওপরে একেকটি স্তর পরীক্ষা করে দাবি করেছিলেন, সিস্টেমটি প্রায় ত্রুটিমুক্ত।
THE-তে ছয়টি স্তর ছিল। সবচেয়ে নিচের স্তর ০ CPU বণ্টন আর প্রসেসের মধ্যে সমন্বয় করত — এখানেই Dijkstra-র semaphore (P আর V অপারেশন) প্রথম বাস্তবে কাজে লাগে, যা আপনি পর্ব ২৪-এ বিস্তারিত পড়বেন। স্তর ১ মেমরি সামলাত: মূল মেমরি (core) আর ধীরগতির ঘূর্ণায়মান drum-এর মধ্যে তথ্য আনা-নেওয়া। একটি user program একটি লাইন ছাপতে চাইলে কী হয়, ধাপে ধাপে দেখুন:
| এখন যে স্তর | |
| কল-স্তূপের গভীরতা | |
| প্রসেসের অবস্থা |
- স্তর ৪ — user program. একটি প্রোগ্রাম বলল, “এই লাইনটি ছাপা হোক।” সে জানে না প্রিন্টার কোথায়, মেমরি কীভাবে সাজানো — জানার দরকারও নেই। সে শুধু নিচের স্তরের দেওয়া সেবাটি ডাকল।
- স্তর ৩ — I/O ব্যবস্থাপনা. এই স্তর ধীরগতির যন্ত্রগুলোর জন্য buffer রাখে: লাইনটি আগে একটি buffer-এ জমা হবে, পরে প্রিন্টারে যাবে। কিন্তু buffer-টি মেমরির একটি segment-এ থাকে — সেটি এখন মূল মেমরিতে আছে তো?
- স্তর ১ — মেমরি. দেখা গেল segment-টি এখন drum-এ, মূল মেমরিতে নেই। স্তর ১ সেটি আনার নির্দেশ দিল। লক্ষ করুন, স্তর ৩ সরাসরি স্তর ১-কে ডেকেছে, স্তর ২ (অপারেটরের কনসোলের বার্তা) লাগেনি — নিয়ম শুধু “নিচের দিকে”, ঠিক পাশের নিচের স্তরই হতে হবে এমন নয়।
- স্তর ০ — CPU বণ্টন. Drum থেকে আনতে সময় লাগে, এতক্ষণ CPU বসিয়ে রাখার মানে নেই। স্তর ১ একটি semaphore-এ
Pকরল — প্রসেসটি অপেক্ষায় চলে গেল, আর স্তর ০ CPU অন্য প্রসেসকে দিল। কল-স্তূপ এখন সবচেয়ে গভীরে: ৪ → ৩ → ১ → ০. - Interrupt এলো. Drum কাজ শেষ করে interrupt দিল; স্তর ০ semaphore-এ
Vকরল, প্রসেসটি আবার ready হলো এবং পালা এলে চলল। স্তর ১-এর কাজ শেষ, নিয়ন্ত্রণ ফিরল স্তর ৩-এ — buffer-এ লাইনটি জমা হলো। - ওপরে ফেরা. স্তর ৩ লাইনটি প্রিন্টারে পাঠানোর ব্যবস্থা করল, আর স্তর ৪-এর প্রোগ্রাম পরের লাইনে চলে গেল। পুরো যাত্রায় প্রতিটি স্তর কেবল নিচের স্তরকে ডেকেছে — এই শৃঙ্খলাই layered নকশার শক্তি; আর প্রতিটি স্তর পেরোনোর বাড়তি খরচই তার দুর্বলতা।
তাহলে আজকের OS-গুলো পুরোপুরি layered নয় কেন? দুটি কারণ। এক, গতি: প্রতিটি অনুরোধকে অনেকগুলো স্তর পার হতে হয়, প্রতিটি পারাপারে কিছু খরচ। দুই, কোন অংশ কোন স্তরে — এই সিদ্ধান্তই কঠিন। ধরুন মেমরি-ব্যবস্থাপকের ডিস্ক থেকে পাতা আনতে হয় (তাই ডিস্ক driver তার নিচে থাকা উচিত), আবার ডিস্ক driver-এর buffer-এর জন্য মেমরি লাগে (তাই মেমরি-ব্যবস্থাপক তার নিচে থাকা উচিত)। দুটোই একসাথে সত্য হতে পারে না। বাস্তবের kernel তাই কঠোর স্তর মানে না; কিন্তু layered চিন্তা সর্বত্র রয়ে গেছে — নেটওয়ার্ক stack (TCP/IP-এর স্তর), Windows-এর HAL (হার্ডওয়্যার-ভেদ লুকানোর স্তর), আর Linux-এর VFS → file system → block layer → driver ক্রম।
৪ · Microkernel — kernel ছোট, বাকিরা user space-এ
এবার একেবারে উল্টো প্রশ্ন: kernel mode-এ সর্বনিম্ন কতটুকু না রাখলেই নয়? Microkernel-এর উত্তর: শুধু তিনটি mechanism — (১) address space তৈরি ও আলাদা রাখা (মেমরি সুরক্ষা), (২) থ্রেড চালানো ও CPU বদলানো (scheduling), আর (৩) প্রসেসগুলোর মধ্যে বার্তা পাঠানো (IPC). File system, device driver, নেটওয়ার্ক stack — সবাই আলাদা আলাদা user-mode প্রসেস, যাদের বলে server. একটি প্রোগ্রাম ফাইল পড়তে চাইলে kernel-কে বলে না “ফাইলটি পড়ে দিন”, বলে “এই বার্তাটি file server-এর কাছে পৌঁছে দিন।” এই ধাঁচকে বলে message passing.
সরকারি অফিসে ফাইল চালাচালির কথা ভাবুন। হিসাব শাখা, রেকর্ড রুম, সই-স্বাক্ষরের টেবিল — প্রত্যেকে আলাদা ঘরে। মাঝে একজন পিয়ন শুধু ফাইল এক টেবিল থেকে আরেক টেবিলে নেন; তিনি ফাইলের ভেতরের কাজ জানেন না, জানার দরকারও নেই। রেকর্ড রুমে আগুন লাগলেও হিসাব শাখা চলতে থাকে, আর রেকর্ড রুম নতুন করে সাজানো যায়। কিন্তু প্রতিটি কাজে ফাইল কয়েকবার হাতবদল হয় — তাই সময় বেশি লাগে। Microkernel হলো সেই পিয়ন; server-গুলো আলাদা ঘর।
একটি সাধারণ read() দুই রকম kernel-এ কোন পথে যায়, পাশাপাশি দেখুন। নিচের হিসাব-টেবিলে কতবার kernel-এ ঢুকতে হলো (trap), কতবার এক প্রসেস থেকে আরেক প্রসেসে CPU বদলাল (context switch), আর কতবার ডেটা কপি হলো — খেয়াল রাখুন:
| monolithic: trap | |
| monolithic: context switch | |
| monolithic: কপি | |
| microkernel: বার্তা (= trap) | |
| microkernel: context switch | |
| microkernel: কপি |
- দুই জায়গাতেই শুরু একই. Program ডাকল
read(fd, buf, 14). দুই সিস্টেমেই এটি আসলে C library-র একটি ছোট ফাংশন। Monolithic-এ library একটি system call নির্দেশ চালাবে; microkernel-এ library একটি অনুরোধ-বার্তা সাজাবে। এখনো কোনো খরচ হয়নি — সব শূন্য। - Kernel-এ প্রবেশ. Monolithic: একটি trap — CPU kernel mode-এ গেল, সরাসরি VFS (virtual file system, পর্ব ৪২) ফাংশনে। Microkernel: kernel-এও trap হলো, কিন্তু kernel শুধু বার্তাটি (msg#1) file server-এর কাছে কপি করে CPU তাকে দিল — ১টি বার্তা, ১টি context switch, ১টি কপি।
- File system-এর কাজ. Monolithic: VFS সাধারণ ফাংশন কলে ext4-কে ডাকল; ext4 হিসাব করল ফাইলের ঐ অংশ কোন block-এ (ধরি 812) — বাড়তি খরচ নেই। Microkernel: file server-ও একই হিসাব করল, কিন্তু ডিস্ক পড়তে হলে তাকে আবার বার্তা (msg#2) পাঠাতে হবে disk driver server-কে — আবার trap, switch, কপি। এখন ২টি বার্তা।
- ডিস্ক থেকে ডেটা. দুই জায়গাতেই driver ডিস্ককে নির্দেশ দেয়, আর ডিস্ক DMA-র মাধ্যমে ডেটা মেমরিতে রাখে — monolithic-এ kernel-এর buffer-এ, microkernel-এ driver server-এর buffer-এ। দুই দিকে ১টি করে কপি গুনলাম। (আসল microkernel-এ ডিস্কের interrupt-ও driver-এর কাছে একটি বার্তা হয়ে আসে — সরল রাখতে সেটি গুনছি না।)
- উত্তর ফিরছে. Monolithic: kernel
copy_to_userদিয়ে ডেটা প্রোগ্রামেরbuf-এ কপি করে ফিরে এলো — কাজ শেষ: ১টি trap, ০টি switch, ২টি কপি। Microkernel: driver উত্তর-বার্তা (msg#3) পাঠাল file server-কে — ৩টি বার্তা। - Microkernel-এও শেষ. File server শেষ বার্তা (msg#4) পাঠাল প্রোগ্রামকে, ডেটাসহ। চূড়ান্ত হিসাব: ৪টি বার্তা, ৪টি context switch, ৫টি কপি — monolithic-এর ১টি trap আর ২টি কপির বিপরীতে। এই তফাতই microkernel-এর “IPC-এর দাম”. নিচের C প্রোগ্রামটি ঠিক এই হিসাবই গুনে দেখায়।
শুধু ছবি নয় — একটি খেলনা সিমুলেশন চালিয়ে দেখুন। এখানে monolithic অংশে file system আর driver সাধারণ C ফাংশন; microkernel অংশে তারা “server”, আর ipc() ফাংশনটি kernel-এর ভূমিকায় বার্তা কপি করে, প্রতিবার trap, context switch আর বার্তার হিসাব বাড়ায়:
#include <stdio.h>
#include <string.h>
typedef struct { int traps, switches, msgs, copies; } Cost;
typedef struct { int op, len; char data[16]; } Msg;
static const char disk[16] = "Hello, Dhaka!";
/* Monolithic: FS and driver are plain functions inside one kernel */
static void driver_read(char *b, int n, Cost *c) { memcpy(b, disk, n); c->copies++; }
static void fs_read(char *b, int n, Cost *c) { driver_read(b, n, c); }
static void mono_read(char *ubuf, int n, Cost *c) {
char kbuf[16]; c->traps++; /* one trap into the kernel */
fs_read(kbuf, n, c); /* direct function calls */
memcpy(ubuf, kbuf, n); c->copies++; /* kernel buffer -> user */
}
/* Microkernel: FS and driver are user-space servers; kernel only passes messages */
static void ipc(Msg *to, const Msg *from, Cost *c) {
c->traps++; c->switches++; c->msgs++;
*to = *from; c->copies++; /* kernel copies the message */
}
static void micro_read(char *ubuf, int n, Cost *c) {
Msg req = {1, n, ""}, at_fs, at_drv, reply_fs, reply_app;
ipc(&at_fs, &req, c); /* app -> FS server */
ipc(&at_drv, &at_fs, c); /* FS -> disk driver */
memcpy(at_drv.data, disk, n); c->copies++; /* driver reads disk */
ipc(&reply_fs, &at_drv, c); /* driver -> FS */
ipc(&reply_app, &reply_fs, c); /* FS -> app */
memcpy(ubuf, reply_app.data, n); /* reply sits in app memory */
}
int main(void) {
char a[16] = "", b[16] = ""; Cost m = {0}, k = {0};
mono_read(a, 14, &m); micro_read(b, 14, &k);
printf("%-12s %-14s traps switches msgs copies\n", "design", "data");
printf("%-12s %-14s %5d %8d %4d %6d\n", "monolithic", a, m.traps, m.switches, m.msgs, m.copies);
printf("%-12s %-14s %5d %8d %4d %6d\n", "microkernel", b, k.traps, k.switches, k.msgs, k.copies);
}আসল আউটপুট:
design data traps switches msgs copies
monolithic Hello, Dhaka! 1 0 0 2
microkernel Hello, Dhaka! 4 4 4 5
দুই পথেই প্রোগ্রাম একই ডেটা পেল — Hello, Dhaka! (১৩টি অক্ষর আর শেষের '\0', মোট 14 byte). ফল এক, খরচ ভিন্ন। Monolithic-এ ১টি trap আর ২টি কপি (ডিস্ক → kernel buffer → প্রোগ্রাম)। Microkernel-এ ৪টি বার্তা — প্রতিটির জন্য একটি trap, একটি context switch আর একটি কপি — আর ডিস্ক থেকে পড়ার কপিসহ মোট ৫টি কপি। Context switch সস্তা নয়: CPU-র register বদলানো, address space বদলানো আর তার ফলে cache ও TLB-এর অনেক তথ্য অকেজো হওয়া (পর্ব ০৯ আর ৩৩)। এটি একটি সরল মডেল — আসল microkernel ছোট বার্তা register-এ পাঠায়, বড় ডেটা কপি না করে মেমরি-পাতা ভাগ করে দেয়, কিন্তু বার্তার সংখ্যা-র মৌলিক তফাতটি থেকে যায়।
চারটি বিখ্যাত microkernel
Mach (১৯৮৫ থেকে)
Carnegie Mellon বিশ্ববিদ্যালয়ে Richard Rashid-এর দলের কাজ। Microkernel ধারণাকে বিখ্যাত করে, কিন্তু প্রথম দিকের সংস্করণে IPC ছিল বেশ ধীর — “microkernel মানেই ধীর” ধারণাটি এখান থেকেই। এর বংশধর আজ macOS-এর ভেতরে (অংশ ৭)।
গবেষণা → macOS, iOSQNX (১৯৮২ থেকে)
বাণিজ্যিক real-time microkernel OS — গাড়ির ইনফোটেইনমেন্ট ও নিয়ন্ত্রণ, শিল্প-যন্ত্র, চিকিৎসা-যন্ত্রে বহুল ব্যবহৃত। ২০১০ সাল থেকে BlackBerry-র মালিকানায়। প্রমাণ করে microkernel বাস্তবে দ্রুত ও নির্ভরযোগ্য হতে পারে (পর্ব ৫৪)।
real-time, embeddedL4 আর seL4 (১৯৯৩ থেকে)
জার্মান বিজ্ঞানী Jochen Liedtke দেখান, Mach-এর ধীরতা microkernel-এর দোষ নয়, নকশার দোষ — IPC-কে কেন্দ্র করে নতুন করে বানিয়ে তিনি অনেকগুণ দ্রুত বার্তা পাঠানো দেখান। L4 পরিবার থেকে এসেছে seL4, যার সঠিকতা গাণিতিকভাবে প্রমাণিত (অংশ ৮)।
দ্রুত IPC, প্রমাণিত নিরাপত্তাMINIX 3 (২০০৫ থেকে)
Andrew S. Tanenbaum-এর শিক্ষণ-OS MINIX (১৯৮৭)-এর নতুন রূপ, লক্ষ্য: “নিজে নিজে সেরে ওঠা” নির্ভরযোগ্যতা। একটি driver মরে গেলে reincarnation server তাকে আবার চালু করে (অংশ ৫)।
নির্ভরযোগ্যতা, শিক্ষাMicrokernel-এর লাভগুলো তাহলে কী? নির্ভরযোগ্যতা — একটি server ভেঙে পড়লে শুধু সেটিই পড়ে। নিরাপত্তা — kernel mode-এ চলা কোড অনেক কম, তাই যে কোডকে অন্ধভাবে বিশ্বাস করতে হয় (trusted computing base) তা ছোট; seL4-এর মতো kernel কয়েক হাজার লাইনের, আর Linux-এর কয়েক কোটি। বদলানো ও বাড়ানো সহজ — নতুন file system মানে একটি নতুন user-mode প্রোগ্রাম, kernel ছোঁয়ার দরকার নেই। দামটি তো দেখলেনই: প্রতিটি সেবায় বাড়তি বার্তা ও context switch.
৫ · Driver কোথায় থাকে — একটি বাগ কেন পুরো কম্পিউটার ফেলে দেয়
Device driver হলো সেই কোড, যা একটি নির্দিষ্ট যন্ত্রের — Wi-Fi কার্ড, প্রিন্টার, গ্রাফিক্স কার্ড — ভাষা জানে (পর্ব ৩৯)। প্রতিটি নতুন যন্ত্রের জন্য নতুন driver লাগে, আর এগুলো প্রায়ই লেখে যন্ত্রের নির্মাতা কোম্পানি, OS-এর মূল দল নয়। ফলে OS-এর কোডের মধ্যে driver-ই সবচেয়ে বেশি, সবচেয়ে বৈচিত্র্যময়, আর গড়ে সবচেয়ে কম পরীক্ষিত।
গবেষণাও তাই বলে। ২০০১ সালে Stanford-এর Andy Chou ও সহকর্মীরা Linux-এর কোড স্বয়ংক্রিয়ভাবে বিশ্লেষণ করে দেখান, driver-এর কোডে বাগের হার kernel-এর বাকি অংশের চেয়ে কয়েকগুণ বেশি। ২০০৩ সালে Michael Swift ও সহকর্মীরা তাঁদের “Nooks” গবেষণাপত্রে উল্লেখ করেন, Microsoft-এর তথ্য অনুযায়ী Windows XP-র সাম্প্রতিক crash-গুলোর প্রায় ৮৫ শতাংশের কারণ ছিল driver.
Monolithic kernel-এ driver চলে kernel mode-এ, kernel-এর বাকি সব কোডের সাথে একই address space-এ। অর্থাৎ বাগওয়ালা একটি Wi-Fi driver চাইলে file system-এর ডেটা, প্রসেসের তালিকা, এমনকি অন্য প্রোগ্রামের মেমরিও ভুল করে লিখে ফেলতে পারে — কোনো দেয়াল নেই। বাড়ির দারোয়ানের কথা ভাবুন: বাইরের একজন মিস্ত্রিকে পুরো ভবনের মাস্টার-চাবি দিয়ে দেওয়া হলো। তিনি সৎ, কিন্তু অসাবধান হলে যেকোনো ফ্ল্যাটের দরজা খোলা রেখে যেতে পারেন।
একই বাগ — একটি NULL pointer (কোথাও নির্দেশ করে না এমন pointer) থেকে মান পড়া — দুই রকম kernel-এ কী ঘটায়, দেখুন:
| monolithic: editor | |
| microkernel: editor | |
| microkernel: Wi-Fi |
- সব স্বাভাবিক. আপনি একটি editor-এ লিখছেন, ফাইলটি এখনো সেভ করা হয়নি। Wi-Fi driver নেটওয়ার্ক থেকে আসা packet সামলাচ্ছে। ওপরের সিস্টেমে driver kernel-এর ভেতরে; নিচের সিস্টেমে driver একটি আলাদা user-mode প্রসেস, আর পাশে আছে reincarnation server (RS) — MINIX 3-এর পাহারাদার প্রসেস।
- বাগ. একটি বিরল অবস্থায় driver-এর কোড
p->lenপড়তে গেল, অথচpহলো NULL. দুই সিস্টেমে কোড হুবহু এক, বাগও এক। পার্থক্য হবে শুধু বাগটি কোথায় চলছে তাতে। - CPU-র page fault. ঠিকানা 0-তে কোনো মেমরি-পাতা নেই, তাই MMU fault দিল। Monolithic: fault হয়েছে kernel mode-এ, kernel-এর নিজের কোডে — kernel ধরে নেয় তার ভেতরের অবস্থা আর বিশ্বাসযোগ্য নয়: Linux-এ “oops” বা kernel panic, Windows-এ নীল পর্দা (BSOD). Microkernel: fault হয়েছে একটি সাধারণ প্রসেসে — kernel শুধু সেই driver প্রসেসটি বন্ধ করে দেয়, ঠিক যেমন ভুল করা যেকোনো সাধারণ প্রোগ্রামকে করে।
- তারপর. Monolithic: পুরো মেশিন রিবুট, editor-এর অসংরক্ষিত লেখা হারাল। Microkernel: RS টের পেল driver মারা গেছে, একটি নতুন, পরিষ্কার driver প্রসেস চালু করল। Wi-Fi এক মুহূর্ত বন্ধ থেকে ফিরে এলো; editor কিছু টেরই পায়নি।
- সূক্ষ্ম দিক — দুই দিকেই. Linux-এ সব oops-এ পুরো মেশিন থামে না (সেটিং
panic_on_oops-এর ওপর নির্ভর করে), কিন্তু এরপর kernel-কে আর বিশ্বাস করা যায় না — “tainted” চিহ্ন বসে, রিবুটই নিরাপদ। Microkernel-এর restart-ও বিনামূল্যে নয়: driver-এর হাতে থাকা packet হারায় (TCP নিজেই আবার পাঠায়), আর যে server-এর অনেক অবস্থা (state) থাকে — যেমন file server — সেটি মরলে অবস্থা ফিরিয়ে আনা অনেক কঠিন।
এর একটি বড় বাস্তব উদাহরণ ২০২৪ সালের ১৯ জুলাই। সাইবার-নিরাপত্তা কোম্পানি CrowdStrike-এর Falcon সফটওয়্যারের kernel-mode অংশের জন্য পাঠানো একটি ত্রুটিপূর্ণ কনফিগারেশন আপডেটে Windows কম্পিউটার চালু হতেই crash করতে থাকে। Microsoft-এর হিসাবে প্রায় ৮৫ লাখ Windows যন্ত্র আক্রান্ত হয়; বিশ্বজুড়ে বিমান, ব্যাংক, হাসপাতাল ও সম্প্রচারের কাজ ব্যাহত হয়। কোডটি kernel mode-এ চলছিল বলেই একটি ভুল পুরো OS ফেলে দিয়েছিল।
তাই আজকের প্রবণতা: যতটা সম্ভব driver-কে kernel-এর বাইরে আনা, বা kernel-এর ভেতরেও দেয়াল তোলা। Windows-এ আছে User-Mode Driver Framework (UMDF), আর আধুনিক গ্রাফিক্স driver-এর বড় অংশ user mode-এ চলে। Apple ২০১৯ সালে macOS Catalina থেকে DriverKit চালু করে user space-এ driver লেখার জন্য, আর পুরোনো kernel extension-কে ধীরে ধীরে নিরুৎসাহিত করছে। Linux-এ আছে নিরাপদভাবে kernel-এ ছোট প্রোগ্রাম চালানোর eBPF (যার কোড আগে একটি verifier যাচাই করে, পর্ব ৫৫), আর ২০২২ সালের Linux 6.1 থেকে driver লেখার জন্য Rust ভাষার প্রাথমিক সমর্থন — যাতে NULL pointer-এর মতো ভুল compile-এর সময়েই ধরা পড়ে।
৬ · Loadable module — চলন্ত kernel-এ নতুন অংশ জোড়া
Monolithic kernel-এর একটি ব্যবহারিক সমস্যা ছিল: নতুন একটি USB যন্ত্রের driver লাগলে পুরো kernel আবার compile করে রিবুট করতে হতো। আবার সম্ভাব্য সব যন্ত্রের driver আগে থেকে kernel-এ রাখলে kernel বিশাল হয়ে যায়, অথচ একটি কম্পিউটারে তার সামান্য অংশই লাগে। সমাধান: loadable kernel module (LKM) — kernel-এর একটি অংশ আলাদা ফাইলে রাখা, যা চলন্ত kernel-এ দরকারমতো জোড়া বা খোলা যায়, রিবুট ছাড়াই।
ঈদের আগে রেস্তোরাঁয় পিঠা-সেমাইয়ের জন্য একজন বিশেষ বাবুর্চিকে কয়েক সপ্তাহের জন্য আনা হলো। তিনি একই রান্নাঘরে, একই চুলায় কাজ করেন, কাজ শেষে চলে যান — পুরো রান্নাঘর নতুন করে বানাতে হয়নি। কিন্তু খেয়াল করুন, তিনি একই রান্নাঘরে কাজ করছেন: তাঁর হাতে আগুন লাগলে ঝুঁকি আগের মতোই। Module ঠিক তেমন — নমনীয়তা দেয়, কিন্তু microkernel-এর মতো দেয়াল দেয় না।
Linux-এ module-এর ফাইলের নাম .ko (kernel object). ১৯৯০-এর দশকের মাঝামাঝি Linux-এ এই সুবিধা যোগ হয়, আর আজ বেশিরভাগ distribution-এ driver আর file system-এর বড় অংশ module হিসেবেই আসে। Sun-এর Solaris-ও একই নকশা নেয় — একটি ছোট মূল kernel, আর তার চারপাশে scheduling class, file system, device driver, executable-এর ধরন ইত্যাদির loadable module. একটি সবচেয়ে ছোট module দেখতে এমন:
#include <linux/module.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Smallest possible example module");
static int __init hello_init(void)
{
pr_info("hello: loaded\n");
return 0; /* 0 = success; a negative errno aborts loading */
}
static void __exit hello_exit(void)
{
pr_info("hello: unloaded\n");
}
module_init(hello_init);
module_exit(hello_exit);এখানে main() নেই, printf নেই — kernel-এ C library থাকে না, তাই লেখা ছাপার জন্য kernel-এর নিজের pr_info, যা লেখে kernel-এর log-এ (dmesg দিয়ে দেখা যায়)। module_init বলে দেয় লোড হওয়ার সময় কোন ফাংশন চলবে, module_exit বলে খোলার সময় কোনটি। এবার দেখুন insmod চালালে ভেতরে কী হয়:
| kernel-এর চোখে hello | |
| কোন mode-এ কাজ |
- insmod. Administrator
sudo insmod hello.koচালালেন।insmodনিজে একটি সাধারণ user-mode প্রোগ্রাম (kmod প্যাকেজের); সে শুধু ফাইলটি খোলে। Kernel এখনো hello-র কথা জানে না। - System call আর যাচাই.
insmodডাকলfinit_module()system call, ফাইলের descriptor দিয়ে। Kernel আগে যাচাই করে: ডাকছেন যিনি, তাঁরCAP_SYS_MODULEক্ষমতা আছে কি (সাধারণত root)? Signature-যাচাই চালু থাকলে module-টি বিশ্বস্ত চাবিতে সই করা কি? আর module-টি এই kernel version-এর জন্যই বানানো কি (vermagic)? যেকোনো একটিতে ব্যর্থ হলে লোড হবে না। - জায়গা আর জোড়া. Kernel module-এর কোড ও ডেটার জন্য মেমরি নিল, কপি করল, আর ঠিকানাগুলো বসাল (relocation). Module-এর ভেতরে
pr_infoশেষ পর্যন্ত kernel-এর_printkফাংশন ডাকে — kernel তার “রপ্তানি-করা” symbol-এর টেবিল (EXPORT_SYMBOL) থেকে আসল ঠিকানা বসিয়ে দিল। এ যেন linker-এর কাজ, কিন্তু চলন্ত kernel-এর ভেতরে। অবস্থা: UNFORMED থেকে COMING. - init চলল. Kernel ডাকল
hello_init()— এবং এই মুহূর্তে module-এর কোড চলছে kernel mode-এ, পূর্ণ ক্ষমতা নিয়ে। সে log-এ লিখল “hello: loaded” আর 0 ফেরত দিল। আসল driver এখানে নিজেকে নিবন্ধন করে — “আমি এই USB যন্ত্রগুলো সামলাব”, বা “আমি এই file system চিনি”। - LIVE. Module এখন kernel-এর পূর্ণ অংশ।
lsmod-এ দেখা যায় (নাম, আকার, কয়জন ব্যবহার করছে),/sys/module/helloফোল্ডার তৈরি হয়েছে। Kernel-এর বাকি অংশের সাথে তার কোনো দেয়াল নেই — এটি ঠিক monolithic kernel-এর মতোই। - rmmod. খোলার জন্য
rmmod hello→delete_module()system call. Kernel দেখে কেউ module-টি ব্যবহার করছে কি না (reference count 0 কি না); তারপর অবস্থা GOING,hello_exit()চলে, মেমরি ফেরত যায়। ব্যবহার চলতে থাকলে খোলা যায় না — ব্যস্ত USB ড্রাইভের driver হঠাৎ সরিয়ে নেওয়া বিপজ্জনক।
আসল কম্পিউটারে (container-এ নয়) module দেখার কমান্ডগুলো এমন — নিচে একটি উদাহরণ আউটপুট:
$ lsmod | head -6
Module Size Used by
iwlmvm 802816 0
iwlwifi 598016 1 iwlmvm
cfg80211 1323008 2 iwlmvm,iwlwifi
btusb 77824 0
bluetooth 1032192 7 btusb
$ modinfo iwlwifi | head -6
filename: /lib/modules/6.8.0-45-generic/kernel/drivers/net/wireless/intel/iwlwifi/iwlwifi.ko.zst
license: GPL
description: Intel(R) Wireless WiFi driver for Linux
firmware: iwlwifi-ty-a0-gf-a0-89.ucode
depends: cfg80211
vermagic: 6.8.0-45-generic SMP preempt mod_unload modversions
$ sudo modprobe -r iwlmvm iwlwifi # Wi-Fi driver খুলে ফেলা (Wi-Fi বন্ধ হবে)
$ sudo modprobe iwlwifi # আবার লোড; modprobe নির্ভরতাও (cfg80211) নিজে আনে“Used by” কলামে দেখুন — iwlwifi-কে iwlmvm ব্যবহার করছে, তাই আগে iwlmvm না খুলে iwlwifi খোলা যাবে না। insmod শুধু একটি ফাইল লোড করে; modprobe নির্ভরতার তালিকা (modules.dep) দেখে দরকারি সব module ক্রম মেনে আনে — দৈনন্দিন কাজে সেটিই ব্যবহার হয়। আর অন্য OS-এ?
lsmod (আসলে /proc/modules পড়ে), modinfo নাম, modprobe. কোনটি module নয় বরং kernel-এ স্থায়ীভাবে বসানো, তার তালিকা /lib/modules/$(uname -r)/modules.builtin ফাইলে।
Driver-গুলো .sys ফাইল, kernel mode-এ চলে। তালিকা দেখতে Command Prompt বা PowerShell-এ driverquery; বিস্তারিত দেখতে Device Manager. Windows ৬৪-বিট সংস্করণে kernel-mode driver-এর digital signature বাধ্যতামূলক।
driverquery /v | Select-Object -First 5পুরোনো ধাঁচের kernel extension (.kext) দেখতে নতুন macOS-এ kmutil showloaded (আগে ছিল kextstat). Apple নতুন driver-এর জন্য user-space-এর DriverKit উৎসাহিত করে, আর তৃতীয় পক্ষের kext চালাতে এখন ব্যবহারকারীর আলাদা অনুমতি লাগে।
লক্ষ করুন, modular kernel গঠনে সুশৃঙ্খল — প্রতিটি module-এর একটি নির্দিষ্ট interface থাকে, layered নকশার মতো কঠোর স্তরের বাধ্যবাধকতা নেই, যেকোনো module যেকোনো রপ্তানি-করা ফাংশন ডাকতে পারে। কিন্তু সুরক্ষায় এটি monolithic-এর মতোই: একটি খারাপ module পুরো kernel ফেলতে পারে। তাই বাইরের বা লাইসেন্স-বহির্ভূত module লোড হলে Linux “tainted” চিহ্ন দেয় — bug report দেখে যেন kernel ডেভেলপাররা বোঝেন, সমস্যা হয়তো বাইরের কোডে।
৭ · Hybrid — Windows NT আর macOS XNU; সাথে exokernel ও unikernel
বাস্তবের বড় OS-গুলো কোনো একটি খাঁটি নকশা মানে না। Hybrid kernel কথাটি সাধারণত বোঝায়: নকশায় microkernel-এর মতো আলাদা আলাদা অংশ ও বার্তা-ভিত্তিক চিন্তা, কিন্তু গতির জন্য সেই অংশগুলো একই kernel address space-এ kernel mode-এ চলে। কেউ কেউ বলেন “hybrid” আসলে বিপণনের শব্দ — শেষ বিচারে এগুলো monolithic-ই। দুই পক্ষের যুক্তিই বুঝে রাখা ভালো।
Windows NT (১৯৯৩)
Dave Cutler-এর নেতৃত্বে Microsoft-এর দল NT নকশা করে microkernel-এর প্রভাবে: নিচে HAL (হার্ডওয়্যার-ভেদ লুকায়), তার ওপর ছোট একটি “kernel” (scheduling, interrupt, সমন্বয়), তার ওপর Executive (মেমরি, I/O, object, security ব্যবস্থাপক)। শুরুতে Win32, OS/2 আর POSIX-এর জন্য আলাদা user-mode “subsystem” ছিল — এক kernel-এর ওপর একাধিক OS-এর চেহারা। কিন্তু ১৯৯৬ সালে NT 4.0-তে গতির জন্য window manager আর গ্রাফিক্সের বড় অংশ user mode থেকে kernel mode-এ (win32k.sys) আনা হয়। Driver-ও kernel mode-এ। ফলে আজকের Windows-এর kernel-ভাগে HAL, kernel, Executive, driver আর গ্রাফিক্সের একাংশ — সবাই একই address space-এ। বিস্তারিত পর্ব ৫৬-এ।
macOS ও iOS-এর XNU
XNU নামটি নিজেই একটি রসিকতা — “X is Not Unix”. এটি এসেছে Steve Jobs-এর NeXT কোম্পানির NeXTSTEP থেকে, যা ১৯৯৭ সালে Apple কিনে নেয়। XNU-তে তিনটি অংশ: Mach (task, thread, virtual memory, IPC), BSD স্তর (FreeBSD থেকে নেওয়া — process, POSIX system call, file system, নেটওয়ার্ক), আর C++-এর একটি সীমিত রূপে লেখা driver-কাঠামো I/O Kit. মূল কথা: Mach থাকলেও BSD আর driver আলাদা server নয় — তিনটিই একই kernel address space-এ, তাই BSD-অংশ Mach-কে বার্তা না পাঠিয়ে সরাসরি ফাংশন ডাকতে পারে। Mach-এর নকশা, monolithic-এর গতি।
কোন অংশ কোথায় চলে
Where the file system and drivers run in each design
| নকশা | Kernel mode-এ | User mode-এ |
|---|---|---|
| Linux (monolithic + module) | scheduler, মেমরি, VFS, file system, নেটওয়ার্ক, প্রায় সব driver | shell, প্রোগ্রাম, কিছু সহায়ক daemon |
| Windows (hybrid) | HAL, kernel, Executive, driver, win32k.sys | subsystem প্রসেস, সেবা (service), প্রোগ্রাম, UMDF driver |
| macOS XNU (hybrid) | Mach + BSD + I/O Kit (একসাথে) | প্রোগ্রাম, launchd, DriverKit driver |
| QNX / seL4 / MINIX 3 (microkernel) | শুধু IPC, scheduling, address space | file system, driver, নেটওয়ার্ক — সব server |
আরও দুই দিক: exokernel আর unikernel
Exokernel (১৯৯৫, MIT-তে Dawson Engler ও Frans Kaashoek-এর গবেষণা) microkernel-এর চেয়েও এক ধাপ এগোয়: kernel কোনো সুন্দর বিমূর্ত ধারণাই (ফাইল, সাধারণ virtual memory) দেবে না, শুধু হার্ডওয়্যারের টুকরো — ডিস্কের block, মেমরির পাতা, CPU-র সময় — নিরাপদে ভাগ করে দেবে। ফাইল কীভাবে সাজানো হবে, সেটি প্রোগ্রামের সাথে জোড়া একটি “library OS” ঠিক করবে। ফলে একটি ডেটাবেস নিজের কাজের মতো করে ডিস্ক সাজাতে পারে। এটি মূলত গবেষণার ধারণা, কিন্তু এর চিন্তা পরে অনেক জায়গায় প্রভাব ফেলেছে।
Unikernel ক্লাউড যুগের ধারণা: একটি প্রোগ্রাম আর তার যতটুকু OS-অংশ লাগে, সব মিলিয়ে একটিমাত্র ছোট image বানানো হয়, যা সরাসরি hypervisor-এর (পর্ব ৫০) ওপর চলে। কোনো shell নেই, একাধিক ব্যবহারকারী নেই, user/kernel ভাগও প্রায়ই নেই — এক address space-এ এক প্রোগ্রাম। Cambridge-এর MirageOS (OCaml ভাষায়, ২০১৩) আর পরের Unikraft এর পরিচিত উদাহরণ। সুবিধা: খুব দ্রুত চালু হয়, আক্রমণের জায়গা কম; অসুবিধা: debug করা কঠিন, প্রচলিত টুল চলে না। VM, container আর এদের তুলনা পর্ব ৫২-এ।
৮ · Tanenbaum–Torvalds বিতর্ক আর পাশাপাশি তুলনা
১৯৯২ সালের ২৯ জানুয়ারি আমস্টারডামের Vrije Universiteit-এর অধ্যাপক Andrew S. Tanenbaum, MINIX-এর স্রষ্টা, Usenet-এর comp.os.minix আলোচনা-গ্রুপে একটি পোস্ট দেন, শিরোনাম “LINUX is obsolete”. তাঁর মূল যুক্তি দুটি: এক, ১৯৯১ সালে monolithic kernel বানানো পেছনের দিকে হাঁটা — ভবিষ্যৎ microkernel-এর; দুই, Linux শুধু Intel 386 CPU-র সাথে বাঁধা, অথচ ভবিষ্যতের OS-কে নানা CPU-তে চলতে হবে। তখন ২২ বছরের ছাত্র Linus Torvalds কড়া ভাষায় উত্তর দেন: MINIX-এর নিজের সীমাবদ্ধতা আছে, Linux-এর নকশা বাস্তবে কাজ করে ও দ্রুত, আর “তত্ত্বে সুন্দর” হওয়াই সব নয়। আলোচনায় আরও অনেকে যোগ দেন, যার মধ্যে Unix-এর সহ-স্রষ্টা Ken Thompson-ও ছিলেন। পরে দুজনেই স্বীকার করেন কিছু কথা অতিরিক্ত কড়া হয়েছিল।
পরের তিন দশকে কী হলো? Portability-র প্রশ্নে Torvalds-এর kernel জিতেছে নিজের মতো করে — Linux আজ x86, ARM, RISC-V সহ বহু রকম CPU-তে চলে। বাজারের প্রশ্নে monolithic Linux সার্ভার, ক্লাউড আর Android-এ রাজত্ব করছে। কিন্তু Tanenbaum-এর যুক্তিও হারিয়ে যায়নি: যেখানে ভুলের দাম জীবন বা বিপুল অর্থ — গাড়ি, বিমান, চিকিৎসা, প্রতিরক্ষা — সেখানে QNX, seL4-এর মতো microkernel বা তাদের ধারণা ব্যবহৃত হয়। ২০১৭ সালে নিরাপত্তা-গবেষকেরা জানান, Intel-এর বহু প্রসেসরের ভেতরের Management Engine নামের আলাদা ছোট কম্পিউটারটি MINIX 3-এর একটি রূপ চালায় — হয়তো পৃথিবীর সবচেয়ে বেশি চলা OS-গুলোর একটি, যদিও কেউ চোখে দেখে না। আর driver-কে user space-এ আনা, eBPF, Rust — monolithic জগৎও ধীরে ধীরে microkernel-এর শিক্ষা গ্রহণ করছে।
পাশাপাশি তুলনা
| গঠন | গতি | নির্ভরযোগ্যতা (ভুল আটকানো) | নিরাপত্তা (TCB-র আকার) | বাড়ানো/বদলানো | উদাহরণ |
|---|---|---|---|---|---|
| Simple | দ্রুত | খুব দুর্বল — কোনো সীমানা নেই | দুর্বল — সবাই সব পারে | সহজ কিন্তু বিশৃঙ্খল | MS-DOS |
| Monolithic | সবচেয়ে দ্রুত — সরাসরি ফাংশন কল | দুর্বল — একটি driver পুরো kernel ফেলতে পারে | TCB বিশাল (কোটি লাইন) | নতুন অংশে প্রায়ই kernel আবার build | মূল Unix, পুরোনো BSD |
| Layered | মাঝারি — প্রতি স্তরে খরচ | মাঝারি — স্তরভিত্তিক পরীক্ষা সহজ | নির্ভর করে স্তর কোথায় mode বদলায় | কঠিন — স্তর ভাগ করাই সমস্যা | THE, Multics-এর ring-চিন্তা |
| Microkernel | ধীরতর — প্রতিটি সেবায় IPC | ভালো — server আলাদা, restart করা যায় | TCB ছোট (হাজার লাইন) | খুব সহজ — নতুন server | QNX, seL4, MINIX 3 |
| Modular (LKM) | monolithic-এর মতো দ্রুত | monolithic-এর মতো দুর্বল | বড়; module যাচাই/সই দরকার | সহজ — রিবুট ছাড়া module | Linux, Solaris, FreeBSD |
| Hybrid | প্রায় monolithic-এর মতো | মাঝারি — কিছু অংশ user mode-এ | বড় | মাঝারি থেকে সহজ | Windows NT, macOS XNU |
আরও গভীরে: seL4-এর দল (অস্ট্রেলিয়ার NICTA, এখন CSIRO-র Data61) ২০০৯ সালে দেখান, প্রায় ৯ হাজার লাইনের C কোডে লেখা kernel-টি তার গাণিতিক specification-কে হুবহু মেনে চলে — Isabelle/HOL নামের প্রমাণ-সহায়ক সফটওয়্যারে যাচাই-করা কয়েক লক্ষ লাইনের প্রমাণ দিয়ে। এই formal verification-এর ফলে প্রমাণিত হয় যে NULL pointer, buffer overflow বা অসীম লুপের মতো ভুল এতে নেই, আর পরে প্রমাণ বাড়িয়ে compile-হওয়া binary পর্যন্ত এবং তথ্য ফাঁস না হওয়ার মতো নিরাপত্তা-বৈশিষ্ট্য পর্যন্ত নেওয়া হয়। তবু প্রমাণের কিছু পূর্বধারণা থাকে — হার্ডওয়্যার ঠিকঠাক, বুটের কোড ও কিছু assembly ঠিক আছে — আর specification নিজে ভুল হলে প্রমাণও ভুল জিনিসকেই “সঠিক” বলবে।
পরীক্ষা ও ইন্টারভিউতে এই বিষয়ে প্রায়ই যা জিজ্ঞেস করা হয়:
- Monolithic আর microkernel-এর পার্থক্য কী? — Monolithic-এ সব OS-সেবা একই kernel address space-এ kernel mode-এ, অংশগুলো সরাসরি ফাংশন কলে কথা বলে; microkernel-এ kernel-এ শুধু IPC, scheduling ও address space, বাকি সেবা user-mode server, কথা হয় বার্তা দিয়ে।
- Microkernel কেন ধীর হতে পারে? — প্রতিটি সেবার জন্য একাধিক বার্তা, প্রতিটিতে mode বদল, context switch ও কপি; ফলে cache/TLB-র কার্যকারিতাও কমে।
- Loadable kernel module কী, এর সুবিধা-অসুবিধা? — চলন্ত kernel-এ রিবুট ছাড়া কোড জোড়া/খোলা; নমনীয় ও ছোট kernel image, কিন্তু module kernel mode-এ চলে বলে একটি বাগ পুরো kernel ফেলতে পারে।
- Policy আর mechanism-এর উদাহরণ দিন। — Timer interrupt দিয়ে প্রসেস বদলানোর ক্ষমতা mechanism; time slice কত আর কে আগে পাবে, সেটি policy.
- Windows আর macOS কোন ধরনের kernel? — দুটিই সাধারণত hybrid বলা হয়: NT-তে HAL, kernel, Executive, driver; XNU-তে Mach, BSD ও I/O Kit — সবই একই kernel address space-এ।
৯ · AI-এর যুগে OS-এর গঠন
“Linux-এ একটি driver লোড করার কমান্ড কী?” বা “microkernel কি monolithic-এর চেয়ে ধীর?” — এমন প্রশ্নে AI কয়েক সেকেন্ডে আত্মবিশ্বাসী উত্তর দেয়। কিন্তু kernel-জগতের তথ্য দ্রুত বদলায়, আর OS-ভেদে খুব আলাদা। AI-এর সাধারণ ভুলগুলো চিনে রাখুন:
| AI যা বলতে পারে | আসল সমস্যা | কীভাবে যাচাই করবেন |
|---|---|---|
“macOS-এ kextload দিয়ে driver লোড করুন” | পুরোনো তথ্য; নতুন macOS-এ kmutil, আর অনেক ক্ষেত্রে DriverKit | আপনার OS version লিখে Apple-এর নিজের নথি দেখুন |
“Module লোড না হলে --force দিয়ে চালান” বা “signature-যাচাই বন্ধ করে দিন” | vermagic না মেলা বা সই না থাকা একটি সুরক্ষা; জোর করলে crash বা নিরাপত্তা-ঝুঁকি | এই kernel version-এর জন্য module নতুন করে build করুন; dmesg-এ আসল কারণ পড়ুন |
| “Windows হলো microkernel” | NT নকশায় microkernel-প্রভাবিত, কিন্তু driver ও গ্রাফিক্স kernel mode-এ — সাধারণত hybrid বলা হয় | পাঠ্যবই বা Microsoft-এর Windows Internals ধরনের নির্ভরযোগ্য উৎস |
| “Microkernel IPC-তে ১০০ গুণ ধীর” | নির্দিষ্ট সংখ্যা প্রায়ই বানানো বা পুরোনো Mach-যুগের; L4-পরিবারে অনেক কম | সংখ্যার উৎস (গবেষণাপত্র, বছর, হার্ডওয়্যার) চান; না দিলে ধরে নিন অনুমান |
Container-এর ভেতরে lsmod খালি দেখে “module নেই” | Container host-এর kernel ভাগ করে; তালিকা লুকানো থাকতে পারে | Host-এ চালিয়ে দেখুন; uname -r দুই জায়গায় মিলিয়ে নিন |
Kernel ছুঁয়ে দেখার ধাপে sudo chmod 777 /dev/… | সবাইকে যন্ত্রের পূর্ণ অধিকার — বড় নিরাপত্তা-ছিদ্র | নির্দিষ্ট group বা udev নিয়মে ন্যূনতম অনুমতি (পর্ব ৪৭) |
AI-কে গঠন বা kernel-সংক্রান্ত প্রশ্ন করার সময় নিজের পরিবেশ আর যাচাইয়ের দাবি স্পষ্ট করে দিন:
AI-এর উত্তর হাতে পেলে — যাচাইয়ের চেকলিস্ট
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন।
প্র ০১১৯৯২ সালে Tanenbaum বলেছিলেন monolithic Linux “obsolete”. তিন দশক পরে কে ঠিক প্রমাণিত হলেন?
সৎ উত্তর হলো: দুজনেই আংশিক ঠিক, কারণ তাঁরা আসলে দুটি ভিন্ন প্রশ্নের উত্তর দিচ্ছিলেন। Tanenbaum প্রশ্ন করছিলেন “কোন নকশা নীতিগতভাবে ভালো?” আর Torvalds প্রশ্ন করছিলেন “আজকের হার্ডওয়্যারে কোনটি দিয়ে দ্রুত একটি কাজের OS বানানো যায়?”
- Torvalds-এর পক্ষে: Linux শুধু টিকেই থাকেনি, পৃথিবীর বেশিরভাগ সার্ভার, ক্লাউড, সুপারকম্পিউটার আর Android ফোনের kernel. Portability নিয়ে Tanenbaum-এর আশঙ্কাও মেলেনি — Linux আজ বহু রকম CPU-তে চলে। আর ১৯৯০-এর দশকের বহুল আলোচিত microkernel-ভিত্তিক প্রকল্প GNU Hurd বহু বছরেও বড় পরিসরে ব্যবহারযোগ্য হয়নি।
- Tanenbaum-এর পক্ষে: Linux-এর সবচেয়ে বড় দুর্বলতা আজও ঠিক সেটি, যা তিনি বলেছিলেন — কোটি লাইনের kernel-এ যেকোনো driver-এর ভুল পুরো সিস্টেমকে বিপদে ফেলে, আর নিরাপত্তা-ত্রুটির বড় উৎস kernel-এর বিশাল আকার। নিরাপত্তা-সংবেদনশীল ক্ষেত্রে microkernel জিতেছে: গাড়িতে QNX, প্রতিরক্ষা ও বিমান-গবেষণায় seL4, আর Intel-এর Management Engine-এ MINIX 3.
- মাঝখানের পথ: বাস্তবে সবাই একে অপরের কাছ থেকে নিয়েছে। Windows ও macOS hybrid, Linux-এ এসেছে user-space-এ driver (FUSE দিয়ে user-space file system, VFIO দিয়ে user-space-এ যন্ত্র নিয়ন্ত্রণ), eBPF আর Rust. আবার microkernel-গুলোও গতির জন্য বার্তা-পাঠানো অনেক অপ্টিমাইজ করেছে।
আরেকটি শিক্ষা আছে বিতর্কের ধরনে: প্রযুক্তিতে “সেরা নকশা” প্রায়ই বাজারে জেতে না — জেতে যেটি সময়মতো আসে, যেটিতে অনেকে অবদান রাখতে পারে, আর যার লাইসেন্স সুবিধাজনক। Linux-এর GPL লাইসেন্স আর খোলা উন্নয়ন-পদ্ধতি তার সাফল্যে নকশার মতোই বড় ভূমিকা রেখেছে।
মূল উপলব্ধি: নকশা-বিতর্কে “কে ঠিক” না জিজ্ঞেস করে জিজ্ঞেস করুন “কোন কাজে, কোন শর্তে কে ঠিক”. নির্ভরযোগ্যতা যেখানে সবচেয়ে দামি, সেখানে microkernel; গতি, হার্ডওয়্যার-সমর্থন আর বিশাল সম্প্রদায় যেখানে দামি, সেখানে monolithic.
প্র ০২Windows NT শুরুতে microkernel-ধাঁচে গ্রাফিক্স user mode-এ রেখেছিল, NT 4.0-তে kernel-এ আনল। লাভ কী হলো, দাম কী দিতে হলো?
NT 3.x-এ window manager আর গ্রাফিক্সের কাজ চলত একটি user-mode server প্রসেসে (Win32 subsystem). প্রতিটি জানালা আঁকা, প্রতিটি বোতাম চাপার উত্তর — প্রোগ্রাম থেকে সেই server-এ বার্তা যেত, আবার ফিরত। ১৯৯০-এর দশকের মাঝামাঝির কম্পিউটারে এই অতিরিক্ত context switch আর কপির দাম ছিল চোখে পড়ার মতো, বিশেষ করে গ্রাফিক্স-ভারী কাজে।
লাভ: ১৯৯৬ সালের NT 4.0-তে এই কাজের বড় অংশ win32k.sys নামে kernel mode-এ আনা হয়। এখন জানালা আঁকার অনুরোধ একটি সাধারণ system call, কোনো বাড়তি প্রসেস-বদল নেই — গ্রাফিক্স লক্ষণীয়ভাবে দ্রুত হয়, আর ডেস্কটপে Windows 95-এর সাথে প্রতিযোগিতা সহজ হয়।
দাম — নির্ভরযোগ্যতা: গ্রাফিক্স driver আর window manager-এর বাগ এখন kernel-এর বাগ, যা নীল পর্দা দেখাতে পারে। দাম — নিরাপত্তা: win32k.sys হয়ে ওঠে বহু বছর ধরে Windows-এর সবচেয়ে বেশি নিরাপত্তা-ত্রুটির উৎসগুলোর একটি, কারণ সাধারণ প্রোগ্রাম অসংখ্য গ্রাফিক্স-system call করতে পারে আর প্রতিটি kernel-এর একটি দরজা। পরে Microsoft নানা প্রতিরক্ষা যোগ করে — যেমন কিছু প্রসেসের (ব্রাউজারের sandbox-করা অংশ) জন্য এই system call-গুলো বন্ধ করে দেওয়ার নীতি, আর win32k-কে কয়েকটি ভাগে ভাগ করা।
মজার ব্যাপার, পরে গ্রাফিক্স আংশিক উল্টো পথে হেঁটেছে: Windows Vista-র নতুন display driver model-এ (WDDM) গ্রাফিক্স driver-এর বড় অংশ user mode-এ চলে, আর driver crash করলে অনেক সময় শুধু পর্দা এক মুহূর্ত কালো হয়ে আবার ফিরে আসে — পুরো সিস্টেম পড়ে না। অর্থাৎ হার্ডওয়্যার দ্রুত হওয়ায় নির্ভরযোগ্যতার জন্য সামান্য গতি ছাড়তে রাজি হওয়া সহজ হয়েছে।
মূল উপলব্ধি: একটি গঠন-সিদ্ধান্ত চিরস্থায়ী নয়। হার্ডওয়্যারের দাম ও গতি বদলালে একই trade-off-এর উত্তরও বদলায় — কোনো অংশ কোথায় চলবে, সে প্রশ্ন প্রতি দশকে নতুন করে করা যায়।
প্র ০৩Microkernel যদি বেশি নির্ভরযোগ্য হয়, তাহলে গাড়ি আর চিকিৎসা-যন্ত্রে microkernel, অথচ ফোন আর সার্ভারে Linux কেন?
কারণ দুই জগতের “সবচেয়ে দামি জিনিস” আলাদা।
- গাড়ি, বিমান, চিকিৎসা-যন্ত্র: এখানে একটি crash-এর দাম মানুষের জীবন। এসব ক্ষেত্রে সফটওয়্যারকে কঠোর মান-সনদ (যেমন গাড়ির জন্য ISO 26262) পেতে হয়, যেখানে প্রমাণ করতে হয় যে কোড কীভাবে আচরণ করবে। ছোট kernel যাচাই করা অনেক সহজ — কয়েক হাজার লাইন বিশ্লেষণ করা যায়, কয়েক কোটি নয়। আবার একই চিপে বিনোদন-ব্যবস্থা আর জরুরি নিয়ন্ত্রণ চললে microkernel-এর কঠোর আলাদাকরণ নিশ্চিত করে, গান বাজানোর সফটওয়্যারের ভুল যেন ব্রেকের সফটওয়্যারকে স্পর্শ না করে। এজন্যই এই জগতে QNX, বিভিন্ন RTOS আর seL4-এর মতো kernel জনপ্রিয় (পর্ব ৫৪)।
- ফোন আর সার্ভার: এখানে সবচেয়ে দামি হলো হার্ডওয়্যার-সমর্থন, গতি আর সফটওয়্যারের বিশাল জগৎ। প্রতি বছর নতুন চিপ, ক্যামেরা, মডেম আসে, আর তাদের নির্মাতারা প্রথমে Linux-এর জন্য driver লেখে। লাখো প্রোগ্রাম আর টুল Linux-এ চলে। Crash হলে ফোন রিবুট হয় বা সার্ভার-গুচ্ছে অন্য সার্ভার কাজ নেয় — বিরক্তিকর, কিন্তু প্রাণঘাতী নয়।
তবে দেয়ালটি ভাঙছে। Google তাদের নতুন OS Fuchsia-র জন্য Zircon নামের একটি microkernel বানিয়েছে, যা ২০২১ সালে প্রথম প্রজন্মের Nest Hub স্মার্ট-ডিসপ্লেতে চালু হয়। Android-এও Google driver-কে মূল kernel থেকে আলাদা রাখার চেষ্টা করছে (GKI — একটি সাধারণ kernel, যন্ত্র-নির্মাতাদের কোড আলাদা module-এ)। আর অনেক ফোনে মূল OS-এর পাশে নিরাপত্তার কাজের জন্য আলাদা ছোট kernel চলে — যেমন চাবি আর আঙুলের ছাপ রাখার জন্য।
মূল উপলব্ধি: প্রযুক্তি বেছে নেওয়া মানে আগে ঠিক করা — এই সিস্টেমে ভুলের দাম কত, আর কে সেই দাম দেবে। সেই উত্তরই বলে দেয় গতি না নির্ভরযোগ্যতা, কোনটিকে প্রাধান্য দিতে হবে।
প্র ০৪বেশিরভাগ crash যদি driver থেকে আসে, তাহলে driver-এর সমস্যা সমাধানের বাস্তব উপায়গুলো কী কী, আর প্রতিটির সীমা কোথায়?
২০০৩ সালের Nooks গবেষণায় উল্লেখ ছিল, Windows XP-র crash-এর বড় অংশ driver থেকে; ২০২৪ সালের CrowdStrike-ঘটনা দেখাল, kernel mode-এ চলা নিরাপত্তা-সফটওয়্যারও একই ঝুঁকি বহন করে। সমাধানের পথ কয়েকটি, কোনোটিই নিখুঁত নয়:
- Driver-কে user mode-এ আনা (UMDF, macOS DriverKit, Linux-এ FUSE ও VFIO): crash হলে শুধু সেই প্রসেস পড়ে। সীমা: প্রতিটি I/O-তে বাড়তি mode-বদল; খুব দ্রুত যন্ত্রে (উচ্চগতির নেটওয়ার্ক, গ্রাফিক্স) গতি কমে, তাই সব driver সরানো যায় না।
- Kernel-এর ভেতরেই দেয়াল (Nooks-এর মতো গবেষণা): driver-কে kernel-এ রেখেই হার্ডওয়্যারের মেমরি-সুরক্ষা দিয়ে আলাদা করা। সীমা: জটিল, আর বাস্তব kernel-এ ব্যাপকভাবে চালু হয়নি।
- যাচাই-করা ছোট কোড (eBPF): kernel-এ কোড ঢোকার আগে একটি verifier প্রমাণ করে কোডটি সীমার বাইরে মেমরি পড়বে না, অসীম লুপে আটকাবে না। সীমা: শুধু সীমিত ধরনের প্রোগ্রাম লেখা যায়; পূর্ণ driver এভাবে লেখা যায় না, আর verifier নিজেও বাগমুক্ত নয়।
- নিরাপদ ভাষা (Linux-এ Rust): অনেক ধরনের মেমরি-ভুল compile-এর সময়েই আটকে যায়। সীমা: যুক্তির ভুল (ভুল কনফিগারেশন, ভুল হিসাব) Rust ধরে না, আর বিদ্যমান কোটি লাইনের C রাতারাতি বদলানো যায় না।
- প্রক্রিয়া: driver-এর সই বাধ্যতামূলক করা, স্বয়ংক্রিয় পরীক্ষা, আপডেট ধাপে ধাপে অল্প কিছু যন্ত্রে আগে ছাড়া (staged rollout). CrowdStrike-এর ক্ষেত্রে পরে আলোচনার বড় অংশ ছিল এই শেষ বিষয়টি নিয়ে।
মূল উপলব্ধি: নির্ভরযোগ্যতা শুধু kernel-এর গঠন দিয়ে আসে না; গঠন, ভাষা, যাচাই-যন্ত্র আর প্রকাশের প্রক্রিয়া — চারটিকে একসাথে লাগে। যে কোড kernel mode-এ চলে, তার প্রতিটি লাইনকে পুরো সিস্টেমের দায় বহন করতে হয়।
প্র ০৫seL4 গাণিতিকভাবে “প্রমাণিত সঠিক” — তাহলে সবাই seL4 ব্যবহার করে না কেন? “প্রমাণিত” কথাটির মানে আসলে কী?
২০০৯ সালে Gerwin Klein-এর নেতৃত্বে NICTA-র দল SOSP সম্মেলনে seL4-এর প্রমাণ প্রকাশ করেন। “প্রমাণিত” এখানে একটি নির্দিষ্ট গাণিতিক দাবি: kernel-এর C কোড একটি বিমূর্ত specification-কে হুবহু মেনে চলে — অর্থাৎ যেকোনো ইনপুটে কোডটি ঠিক তা-ই করবে যা specification বলে, এর বেশি বা কম নয়। এতে আপনাআপনি প্রমাণিত হয় যে NULL pointer, buffer overflow, মেমরি-ফাঁস বা kernel-এর ভেতরে অসীম লুপের মতো ভুল নেই। কাজটি ছিল বিশাল: প্রায় ৯ হাজার লাইন C-এর জন্য কয়েক লক্ষ লাইনের যন্ত্র-যাচাই-করা প্রমাণ, আর বহু মানুষ-বছরের শ্রম।
“প্রমাণিত” যা বলে না:
- প্রমাণ কিছু পূর্বধারণার ওপর দাঁড়িয়ে — হার্ডওয়্যার নির্দেশিকা অনুযায়ী কাজ করে, বুটের কোড ও কিছু assembly ঠিক। CPU-র নিজের ত্রুটি (যেমন ২০১৮ সালের Spectre-ধরনের সমস্যা) এই কাঠামোর বাইরে ছিল; পরে timing-এর মাধ্যমে তথ্য ফাঁস ঠেকানো নিয়ে আলাদা গবেষণা চলছে।
- Specification নিজে যদি ভুল জিনিস চায়, প্রমাণ সেই ভুলকেই “সঠিক” বলবে।
- প্রমাণ শুধু kernel-এর। তার ওপর চলা file server, driver, প্রোগ্রাম — এগুলোর ভুল আলাদা। তবে microkernel-এর আলাদাকরণ নিশ্চিত করে, একটির ভুল আরেকটিতে ছড়াবে না।
সবাই ব্যবহার করে না কেন? seL4 শুধু একটি kernel, পূর্ণ OS নয় — ডেস্কটপ, ব্রাউজার, হাজারো driver কিছুই এর সাথে আসে না, সব আলাদা করে বানাতে হয়। প্রমাণ ধরে রাখতে kernel-এর প্রতিটি পরিবর্তনে প্রমাণও হালনাগাদ করতে হয়, তাই নতুন বৈশিষ্ট্য যোগ হয় ধীরে। তাই এটি জনপ্রিয় সেইসব ক্ষেত্রে যেখানে ছোট, নির্দিষ্ট কাজের সিস্টেম আর সর্বোচ্চ নিরাপত্তা লাগে — যেমন যুক্তরাষ্ট্রের DARPA-র HACMS প্রকল্পে চালকবিহীন হেলিকপ্টার ও ড্রোনের নিয়ন্ত্রণ-সফটওয়্যারে এটি পরীক্ষিত হয়েছে।
মূল উপলব্ধি: “প্রমাণিত” একটি শক্ত কিন্তু সীমিত দাবি — সবসময় জিজ্ঞেস করুন, কী প্রমাণ করা হয়েছে, কোন পূর্বধারণায়, আর কী বাদ রয়ে গেছে। একই প্রশ্ন AI-এর “এই কোড নিরাপদ” দাবিতেও প্রযোজ্য।
অনুশীলন
একটি হিসাব, একটি আউটপুট-অনুমান, একটি শ্রেণিবিন্যাস আর একটি কমান্ড লেখা — প্রতিটির উত্তর লুকানো আছে।
-
খরচের হিসাব (হাতে করুন): একটি কাল্পনিক মেশিনে ধরে নিন, একটি trap (user → kernel → user) = 0.1 µs, একটি context switch = 1.0 µs, একটি কপি = 0.2 µs. উপরের C প্রোগ্রামের হিসাব অনুযায়ী (monolithic: ১ trap, ০ switch, ২ কপি; microkernel: ৪ trap, ৪ switch, ৫ কপি) প্রতিটি
read()-এর OS-খরচ কত? সেকেন্ডে ১,০০,০০০টিread()হলে প্রতিটি নকশায় CPU-র কত অংশ এতে যায়? আর ডিস্ক যদি প্রতি read-এ 100 µs নেয়, তাহলে microkernel-এর বাড়তি খরচ মোট সময়ের তুলনায় কতটুকু?Monolithic: 1 × 0.1 + 0 × 1.0 + 2 × 0.2 = 0.1 + 0.4 = 0.5 µs.
Microkernel: 4 × 0.1 + 4 × 1.0 + 5 × 0.2 = 0.4 + 4.0 + 1.0 = 5.4 µs — প্রায় ১০.৮ গুণ।
সেকেন্ডে ১,০০,০০০ read: monolithic-এ 100000 × 0.5 µs = 50,000 µs = 0.05 সেকেন্ড, অর্থাৎ একটি CPU-র ৫%; microkernel-এ 100000 × 5.4 µs = 0.54 সেকেন্ড, অর্থাৎ ৫৪%. ছোট ও ঘন ঘন অনুরোধে তফাত বিশাল।
ডিস্কসহ: monolithic-এ মোট 100.5 µs, microkernel-এ 105.4 µs; বাড়তি 4.9 µs, যা 100.5-এর প্রায় ৪.৯%. ধীর যন্ত্রের সামনে IPC-এর খরচ প্রায় ঢাকা পড়ে যায়। শিক্ষা: microkernel-এর দাম নির্ভর করে কাজটি কতটা ছোট ও ঘন ঘন — আর সংখ্যাগুলো এখানে কাল্পনিক, বাস্তবে মেপে নিতে হয়।
-
আউটপুট অনুমান করুন: C প্রোগ্রামে ধরুন file server-এর নিজের একটি cache আছে, আর চাওয়া ডেটা আগে থেকেই সেখানে আছে। তাই
micro_read()-এ শুধু দুটিipc()থাকবে — app → FS, আর FS → app; driver-কে ডাকা আর ডিস্ক পড়ার লাইনটি বাদ। microkernel সারিতে traps, switches আর msgs কত দেখাবে (মডেলের নিয়মে প্রতিটিipc()এই তিনটি একবার করে বাড়ায়)? Monolithic-এ একই রকম cache (Linux-এর page cache) থাকলে কী বদলাত?প্রতিটি
ipc()একবার করে traps, switches, msgs আর copies বাড়ায়, তাই microkernel সারিতে traps, switches আর msgs তিনটিই হবে 2, আর copies-ও 2 (শুধু দুটি বার্তা-কপি; cache থেকে উত্তর-বার্তায় ডেটা তোলাকে মডেলে আলাদা কপি না গুনলে)। Monolithic-এ page cache-এ ডেটা পেলে driver-এ যেতেই হয় না: ১টি trap, ০টি switch, আর শুধু ১টি কপি (cache → প্রোগ্রাম)। দুই নকশাতেই cache অনেক খরচ বাঁচায়, কিন্তু microkernel-এ তবুও ২টি context switch থেকে যায় — সাধারণ নিয়ম: microkernel-এ প্রতিটি “server পর্যন্ত যাওয়া-আসা” = কমপক্ষে ২টি বার্তা। -
শ্রেণিবিন্যাস: প্রতিটির গঠন বলুন — MS-DOS, Linux, THE, MINIX 3, Windows 11, macOS, QNX, seL4, MirageOS.
MS-DOS — simple (সীমানাহীন); Linux — monolithic, loadable module-সহ (modular); THE — layered; MINIX 3 — microkernel; Windows 11 — hybrid (NT); macOS — hybrid (XNU: Mach + BSD + I/O Kit); QNX — microkernel (real-time); seL4 — microkernel (L4 পরিবার, formally verified); MirageOS — unikernel.
-
কমান্ড লিখুন: আপনার নিজের Linux কম্পিউটারে (container নয়) জানতে চান ext4 file system-এর কোড একটি loadable module, নাকি kernel-এ স্থায়ীভাবে বসানো (built-in). কোন কমান্ড/ফাইল দেখবেন?
lsmod | grep -w ext4 # লোড-করা module হিসেবে আছে? grep -w ext4 /lib/modules/$(uname -r)/modules.builtin # built-in তালিকায় আছে? modinfo ext4 | head -3 # module বা built-in, দুটির তথ্যই দেখায়lsmod-এ এলে সেটি module হিসেবে লোড আছে। না এলেmodules.builtinদেখুন — সেখানেkernel/fs/ext4/ext4.koথাকলে কোডটি kernel image-এর ভেতরেই। অনেক distribution-এ root file system-এর কোড built-in রাখা হয়, যাতে বুটের সময় ডিস্ক পড়তে module খুঁজতে না হয় (পর্ব ০৭)।modinfobuilt-in অংশের জন্যওfilename: (builtin)দেখাতে পারে।
নিজেকে যাচাই করুন
ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।
ক্রমMonolithic Linux-এ একটি read()-এর পথ সঠিক ক্রমে সাজান (▲▼ চেপে সরান)
- প্রোগ্রাম C library-র
read()ডাকে - System call নির্দেশে trap — CPU kernel mode-এ যায়
- VFS ঠিক করে ফাইলটি কোন file system-এর
- ext4 block খুঁজে block layer ও disk driver-কে ডাকে
- ডেটা প্রোগ্রামের buffer-এ কপি হয়ে user mode-এ ফেরা
কোন গঠনে file system আর device driver আলাদা user-mode প্রসেস (server) হিসেবে চলে, আর kernel শুধু তাদের মধ্যে বার্তা পৌঁছে দেয়?
- Monolithic kernel
- Microkernel
- Loadable kernel module
- Simple (MS-DOS ধাঁচ)
Monolithic kernel-এ একটি Wi-Fi driver-এর NULL pointer বাগ কেন পুরো সিস্টেম ফেলে দিতে পারে?
- কারণ Wi-Fi কার্ড পুড়ে যায়
- কারণ driver C ভাষায় লেখা
- কারণ driver kernel mode-এ, kernel-এর সাথে একই address space-এ চলে
- কারণ scheduler driver-কে অগ্রাধিকার দেয়
macOS ও iOS-এর kernel XNU মূলত কোন অংশগুলো মিলিয়ে তৈরি?
- Mach, BSD স্তর আর I/O Kit
- Linux kernel আর GNU টুল
- Windows NT kernel আর HAL
- MINIX 3 আর seL4
Policy আর mechanism আলাদা রাখার নীতিতে নিচের কোনটি policy?
- Timer interrupt দিয়ে চলমান প্রসেস থামানোর ক্ষমতা
- Context switch-এ register সংরক্ষণ ও ফিরিয়ে আনা
- Page table দিয়ে প্রসেসের মেমরি আলাদা রাখা
- কোন প্রসেস পরের পালা পাবে আর কত মিলিসেকেন্ড চলবে, তা ঠিক করা
একটি সিস্টেমে ধরুন একটি IPC বার্তার মোট খরচ 2 µs আর একটি সাধারণ system call (trap) 0.5 µs. একটি read-এ microkernel-এ ৪টি বার্তা লাগে, monolithic-এ ১টি system call. প্রতি read-এ microkernel-এর বাড়তি খরচ কত?
- 1.5 µs
- 7.5 µs
- 8 µs
- 16 µs
Linux-এ loadable kernel module (যেমন insmod hello.ko) সম্পর্কে কোন কথাটি সঠিক?
- Module-এর কোড user mode-এ চলে, তাই এর বাগে kernel পড়ে না
- Module লোড করতে কম্পিউটার রিবুট করতে হয়
- রিবুট ছাড়া জোড়া যায়, কিন্তু kernel mode-এ চলে বলে বাগ পুরো kernel-কে বিপদে ফেলতে পারে
- যেকোনো সাধারণ ব্যবহারকারী module লোড করতে পারেন
শব্দকোষ
লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:
মনে রাখুন
- OS-এর গঠন মানে সিদ্ধান্ত: কোন কোড kernel mode-এ, একই address space-এ চলবে আর কোনটি user mode-এ; আর নকশার নীতি — mechanism স্থির, policy বদলযোগ্য.
- Monolithic (Unix, Linux) সবচেয়ে দ্রুত, কিন্তু driver-এর একটি বাগ পুরো kernel ফেলতে পারে; layered (THE, ১৯৬৮) সুশৃঙ্খল কিন্তু ধীর ও ভাগ করা কঠিন।
- Microkernel (Mach, QNX, L4/seL4, MINIX 3): kernel-এ শুধু IPC, scheduling, address space; নির্ভরযোগ্য ও নিরাপদ, কিন্তু প্রতিটি সেবায় বাড়তি বার্তা ও context switch.
- Module (Linux, Solaris) রিবুট ছাড়া kernel বাড়ায়, কিন্তু kernel mode-এ চলে; hybrid (Windows NT, macOS XNU) microkernel-ধাঁচের নকশা, monolithic-এর মতো এক address space.
- Tanenbaum–Torvalds (১৯৯২) বিতর্কের শিক্ষা: “সেরা” নকশা নেই, আছে কাজ অনুযায়ী trade-off; আর AI-এর kernel-তথ্য সবসময় version, OS ও উৎস মিলিয়ে যাচাই।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পর্ব ০৭ · বুট প্রক্রিয়া — BIOS/UEFI, bootloader, kernel আর initপরবর্তী পর্বপাওয়ার বোতাম থেকে প্রথম প্রসেস পর্যন্ত।
- অপারেটিং সিস্টেম · কোর্স হোম৬৪টি পর্বপুরো কোর্সের রোডম্যাপ — ১০টি মডিউল।
- C প্রোগ্রামিং · প্রসেস আর IPCপাশের ট্র্যাকfork, pipe আর বার্তা-আদান-প্রদান C কোডে।
- C প্রোগ্রামিং · function pointer আর callbackগভীরে যানkernel-এর module আর driver interface-এর ভিত্তি এই কৌশল।
- Computer Architectureপাশের ট্র্যাকprivilege mode, MMU আর interrupt হার্ডওয়্যারে কীভাবে কাজ করে।