Tìm hiểu kiến trúc hệ thống Linux
1.Cấu trúc hệ điều hành Linux
- Kiến trúc hệ điều hành Linux được chia thành 3 phần là: Kernel, Shell và Application
1.1.Kernel (nhân)
- Kernel là một thành phần quan trọng và được coi như là trái tim của hệ điều hành.
- Nó là phần nằm giữa phần cứng máy tính và các chương trình chạy trên máy tính.
-
Phần kernel cung cấp và quản lý các tài nguyên máy tính, cho phép chương trình khác dùng và chạy trên tài nguyên đó.
-
Các loại Kernel:
- Microkernel : Microkernel có đầy đủ các tính năng cần thiết để quản lý bộ vi xử lý , bộ nhớ và IPC . Có rất nhiều thứ khác trong máy tính có thể được nhìn thấy, tiếp xúc và quản lý trong chế độ người dùng . Microkernel có tính linh hoạt khá cao, vì vậy bạn không phải lo lắng khi thay đổi 1 thiết bị nào đó , ví dụ như card màn hình , ổ cứng lưu trữ… hoặc thậm chí là cả hệ điều hành . Microkernel với những thông số liên quan footprint rất nhỏ , tương tự với bộ nhớ và dung lượng lưu trữ , chúng còn có tính bảo mật khá cao vì chỉ định rõ ràng những tiến trình nào hoạt động trong chế độ user mode , mà không được cấp quyền như trong chế độ giám sát - supervisor mode.
- Monolithic Kernel : Với Monolithic thì khác , chúng có chức năng bao quát rộng hơn so với microkernel , không chỉ tham gia quản lý bộ vi xử lý , bộ nhớ , IRC , chúng còn can thiệp vào trình điều khiển driver, tính năng điều phối file hệ thống , các giao tiếp qua lại giữa server… Monolithic tốt hơn khi truy cập tới phần cứng và đa tác vụ , bởi vì nếu 1 chương trình muốn thu thập thông tin từ bộ nhớ và các tiến trình khác , chúng cần có quyền truy cập trực tiếp và không phải chờ đợi các tác vụ khác kết thúc . Nhưng đồng thời , chúng cũng là nguyên nhân gây ra sự bất ổn vì nhiều chương trình chạy trong chế độ supervisor mode hơn , chỉ cần 1 sự cố nhỏ cũng khiến cho cả hệ thống mất ổn định . Linux sử dụng kernel này .
- Hybrid Kernel : Khác với 2 loại kernel trên , Hybrid có khả năng chọn lựa và quyết định những ứng dụng nào được phép chạy trong chế độ user hoặc supervisor . Thông thường, những thứ như driver và file hệ thống I/O sẽ hoạt động trong chế độ user mode trong khi IPC và các gói tín hiệu từ server được giữ lại trong chế độ supervisor . Tính năng này thực sự rất có ích vì chúng đảm bảo tính hiệu quả của hệ thống , phân phối và điều chỉnh công việc phù hợp, dễ quản lý . Windows và Mac OS X sử dụng kernel này .
- Kiểm tra phiên bản kernel hiện tại:
# uname -r 4.15.0-50-generic
1.2.Shell.
- Shell là gì? Nằm trên Kernel đó chính là Shell. Shell có nhiệm vụ nhận và thực thi các lệnh (command) từ người dùng hoặc từ phần mềm khác sau đó chuyển cho kernel xử lý. Shell được coi là lớp trung gian giữa Kernel và Application, có nhiệm vụ “phiên dịch” các lệnh từ Application gửi đến Kernel để thực thi.
- Các loại shell như sau:
- sh (the Bourne Shell): đây là shell nguyên thủy của UNIX được viết bởi Stephen Bourne vào năm 1974. Đến nay shell sh vẫn sử dụng rộng rãi.
- bash(Bourne-again shell): đây là shell mặc định trên linux được viết bởi Brian Fox và Chet Ramey cho dự án GNU ( mục đích của GNU là phát triển 1 hệ điều hành hoàn toàn miễn phí, toàn diện, hiệu năng cao và tương thích với Unix ) . Bash được cải tiến từ sh , nó hỗ trợ nhiều câu lệnh hơn.
- csh (C shell): shell được viết bằng ngôn ngữ lập trình C, được viết bởi Bill Joy vào năm 1978.
- Ngoài ra còn có các loại shell khác như: ash (Almquist shell), tsh (TENEX C shell), zsh (Z shell).
- Nhưng dấu nhắc Shell thay đổi tùy thuộc vào tài khoản user đang làm việc. Ví dụ, khi làm việc với tài khoản user root, dấu nhắc shell có dạng:
[root@localhost root]#
Còn khi làm việc với tài khoản user thường, dấu nhắc shell có dạng:
[linux@localhost ]$
1.3.Applications
Lớp applications, utilities là các ứng dụng, tiện ích, công cụ trên hệ điều hành ví dụ như trình duyệt, game,… các ứng dụng chạy trên shell, dùng shell để giao tiếp với kernel, phần cứng.
2. Command là gì và cách chúng tương tác với hệ thống?
2.1.Command là gì?
- Một command là một yêu cầu từ một người dùng bảo máy tính làm một cái gì đó như một chương trình hay một nhóm các chương trình.
- Các command được ban hành bằng cách gõ chúng vào terminal( or command line là một phần mềm hiển thị văn bản kết nối với shell) và sau đó việc nhấn nút Enter sẽ đưa chúng đến shell.
2.2.Cách các lệnh được thực thi:
- Các bước xử lý một câu lệnh:
- Lấy input từ người dùng
- Kiểm tra regex và alias
- Kiểm tra Builtin
- Kiểm tra PATH
- Nếu file câu lệnh tồn tại: sao chép và chạy chương trình trong một tiến trình con(child process)
- Khi tiến trình con chấm dứt, tiến trình cha in ra lời nhắc đến người dùng báo rằng sẵn sàng cho câu lệnh tiếp theo.
Lấy Input từ người dùng:
Khi bạn nhập vào một lệnh, shell sẽ đọc dữ liệu nhập vào của bạn bằng cách sử dụng getline(). getline đọc dữ liệu từ STDIN- luồng dữ liệu đầu vào, và lưu trữ đầu vào ở một bộ nhớ đệm dưới dạng string.
Bộ đệm sau đó được tách ra thành các token (các đoạn mã nhỏ hơn) và lưu trữ chúng vào một mảng. Ví dụ lệnh ls -l
sẽ được lưu là {“ls”, “-l”, “NULL”}
Kiểm tra regex và alias
Trước khi tìm kiếm lệnh, shell sẽ kiểm tra các ký tự đặc biệt mà cần được làm rõ(.,$,/,…) hay còn gọi là các regex. Shell cũng kiểm tra các alias (alias gần giống với phím tắt trên bàn phím). Ví dụ khi có một alias là alias apple="cat"
thì khi gõ apple, shell sẽ hiểu đó là lệnh cat.
Kiểm tra builtin Nếu câu lệnh không phải là một alias, shell sẽ kiể tra nếu mà lệnh này có phải là một lệnh builtin hay không. Một lệnh builtin là một lệnh được tích hợp và chạy trong chính shell. Ví dụ: cd, echo, alias, help, read, type.
Kiểm tra PATH Nếu lệnh đó không phải là một lệnh builtin, shell sẽ kiểm tra lệnh đó trong biến môi trường, PATH. Đầu tiên, một bản sao của PATH sẽ được chia thành các phần phân cách nhau bằng dấu “:” với mỗi phần là một thư mục. shell sẽ nối thêm gạch chéo (“/”) + đầu vào vào cuối mỗi thư mục trong PATH để kiểm tra xem file có tồn tại hay không. Sau khi tìm qua mỗi phần trong PATH, sẽ có lôi nếu input không có file nào tương ứng.
Sao chép và chạy chương trình trong tiến trình con Sau khi tìm thấy lệnh trong PATH, shell sẽ chạy file đó bằng fork(). fork() là một system call để tạo một bản sao cho tiến trình hiện tại. Tất cả các tiến trình của người dùng trên linux đều là kết quả của fork(). Cả hai tiến trình sẽ chạy theo chỉ dẫn của fork(). Để phân biệt giữa hai tiến trình, fork() sẽ trả về id của tiến trình con về tiến trình cha, và trả về 0 trên tiến trình con, nếu trả về -1 là lỗi.
- Shell(parent process) sẽ gọi fork để tạo bản sao của chính nó (child process). Tiến trình con có pID riêng. Chạy một chương trình trong một tiến trình riêng biệt đảm bảo sẽ bảo vệ quy trình cha nếu chương trình gây ra lỗi khi thực hiện.
- Tiến trình con sau đó được gọi là exec() để chạy câu lệnh của người dùng. exec() sẽ thay thế tiến trình con bằng chương trình mà người dùng yêu cầu.
- Tiến trình cha sẽ đợi tiến trình con hoàn thành quá trình thực thi của nó qua hàm wait().
Sau khi hoàn thành, tiến trình con sẽ chấm dứt và trả quyền điều khiển về tiến trình cha. Bạn sẽ được chào đón với lời nhắc một khi lệnh trước đó đã được thực thi và bạn sẽ có thể nhập một câu lệnh mới. Ví dụ về lời nhắc(prompt):