Hệ Điều Hành Phân Tán Chorus (Phần 3)

Phần 3: Quản lý tiến trình trong Chorus

3.1. Tiến trình (Processes)

Một tiến trình trong Chorus là tập hợp các yếu tố chủ động và thụ động làm việc với nhau để thực hiện một số tính toán. Các yếu tố hoạt động là các luồng (thread). Các yếu tố thụ động là một không gian địa chỉ (address space) như một số khu vực (region) và một tập các cổng (cho việc gửi và nhận thông điệp). Một tiến trình với một luồng như một tiến trình UNIX truyền thống. Một tiến trình không có luồng không thể làm bất cứ điều gì hữu ích, và thường chỉ tồn tại trong một khoảng rất ngắn trong khi một tiến trình đang được tạo ra.

Ba loại tiến trình tồn tại, khác nhau ở số lượng đặc quyền và sự tin cậy, như được liệt kê trong hình. 3-1. Đặc quyền (Privilege) là khả năng để thực hiện I / O và các hướng dẫn khác, Tin cậy (Trust) có nghĩa là tiến trình được phép gọi trực tiếp hạt nhân.

Type Trust Privilege Mode Space
User Untrusted Unprivileged User User
System Trusted Unprivileged User User
Kernel Trusted Privileged Kernel Kernel

Hình 3-1. 3 loại tiến trình trong Chorus.

Chorus có cấu trúc nhiều lớp, như minh họa trong hình. 3-2. Ở phía dưới là microkernel hay gọi là hạt nhân (nucleus). Nó cung cấp quản lý tối thiểu tên, tiến trình, luồng, bộ nhớ và truyền thông. Những dịch vụ này được truy cập bởi các cuộc gọi đến microkernel này. Hơn 100 cuộc gọi tồn tại. Các tiến trình trong các lớp cao hơn cung cấp cho phần còn lại của hệ điều hành. Mỗi máy trong hệ thống phân tán dựa trên Chorus chạy một bản sao giống hệt của Chorus microkernel.

Hình 3.2. Chorus có cấu trúc nhiều lớp, với một microkernel, các hệ thống con, và các quy trình người sử dụng

Phía trên  microkernel, là các tiến trình hạt nhân (kernel processes). Những tiến trình này có thể được tự động nạp và loại bỏ trong quá trình thực hiện hệ thống và cung cấp một cách để mở rộng chức năng của microkernel mà không cần tăng kích thước và độ phức tạp của nó. Từ đó các tiến trình này chia sẻ không gian hạt nhân với microkernel và với các tiến trình khác, sau đó phải di dời sau khi được nạp. Các tiến trình có thể gọi microkernel để có được dịch vụ, và có thể gọi nhau.

Ví dụ, xử lý ngắt được viết như các tiến trình hạt nhân. Trên một máy với một ổ đĩa, vào thời gian khởi động hệ thống, các tiến trình xử lý ngắt đĩa sẽ được nạp. Khi ngắt đĩa xảy ra, chúng sẽ được xử lý bởi tiến trình này. Trên các máy trạm không đĩa, các bộ xử lý đĩa gián đoạn là không cần thiết và sẽ không được nạp. Khả năng tự động tải và dỡ bỏ các quy trình hạt nhân làm cho nó có thể cấu hình hệ thống phần mềm để phù hợp với phần cứng, mà không cần phải biên dịch lại các microkernel

Các lớp tiếp theo bao gồm các tiến trình hệ thống (system processes). Những tiến trình này chạy trong chế độ người dùng, nhưng có thể gửi các thông điệp đến tiến trình hạt nhân (các tiến trình khác) và có thể thực hiện cuộc gọi đến các microkernel, thể hiện bởi các mũi tên trên hình 3.2. Một tập các tiến trình hạt nhân và hệ thống có thể làm việc cùng nhau để tạo thành một hệ thống con. Trong hình 3.2, các tiến trình S2, S1, và K1 hình thành một hệ thống con và tiến trình K2, S3 hình thành một hệ thống con thứ hai. Hệ thống con A trình bày một giao diện rõ ràng cho người sử dụng của nó, chẳng hạn như hệ thống UNIX gọi là giao diện. Một tiến trình trong mỗi hệ thống con là người quản lý và kiểm soát hoạt động của hệ thống con.

Trên các hệ thống con là tiến trình người dùng (user processes). Ví dụ, hệ thống các cuộc gọi được thực hiện bởi một tiến trình người dùng U1 có thể bị chặn bởi K1 và truyền lại cho S1 hoặc S2 để xử lý. Những tiến trình này, lần lượt, có thể sử dụng dịch vụ microkernel, khi thích hợp. Các hệ thống con làm cho nó có thể xây dựng hệ điều hành mới (hoặc cũ) trên microkernel như một mô-đun, và cho phép nhiều giao diện điều hành hệ thống để tồn tại trên một máy cùng lúc.

Tiến trình người sử dụng là không tin cậy và không có đặc quyền. Các tiến trình này không thể thực hiện I /O trực tiếp, và không thể gọi cho hạt nhân, trừ các cuộc gọi mà hệ thống con đã làm. Mỗi tiến trình người dùng có hai phần: phần người sử dụng thường xuyên và một phần hệ thống được gọi sau khi gặp sự cố. Sự sắp xếp này cũng tương tự như cách UNIX làm.

Mỗi tiếntrình (và cổng) có một định danh bảo vệ (protection identifier) liên kết với nó. Nếu tiến trình nhánh, các cá thể của nó được thừa hưởng cùng một bảo vệ nhận dạng. Định danh này chỉ là một chuỗi bit, và không có bất kỳ ngữ nghĩa liên kết nào cho biết rằng hạt nhân biết về nó. Bảo vệ định danh cung cấp một cơ chế có thể được sử dụng để xác thực. Ví dụ, các hệ thống con UNIX có thể chỉ định một UID (người sử dụng nhận dạng) với mỗi quá trình và sử dụng các bảo vệ định danh để thực hiện các UID.

3.2 Luồng (Threads)

Mỗi tiến trình hoạt động trong Chorus có một hoặc nhiều luồng (thread) để thực thi các mã. Mỗi thread có bối cảnh riêng của nó (như stack, chương trình truy cập, và đăng ký), và sẽ được lưu khi các khối thread đang chờ đợi sự kiện nào đó và được phục hồi khi thread này được kết nối lại. Thread gắn liền với tiến trình mà nó được tạo ra, và không thể chuyển tới tiến trình khác.

Thread trong Chorus được quản lí bởi hạt nhân và dự kiến ​​bởi hạt nhân, do đó, để tạo ra và phá hủy chúng cần thực hiện liên lạc với hạt nhân. Một lợi thế là khi một khối thread chờ đợi đối với một số sự kiện (ví dụ, khi một thông điệp đến), hạt nhân có thể sắp xếp cho một thread khác. Một lợi thế khác là khả năng chạy các thread khác nhau trên các CPU khác nhau khi bộ đa xử lý đang hoạt động. Những bất lợi của thread hạt nhân là cần thêm chi phí cần thiết để quản lý chúng. Tất nhiên, người dùng vẫn còn miễn phí để thực hiện một gói các thread cấp người dùng bên trong một thread hạt nhân duy nhất.

Thread liên lạc với nhau bằng cách gửi và nhận thông điệp. Nó không quan trọng nếu người gửi và người nhận đang trong tiến trình tương tự hoặc là trên các máy khác nhau. Nếu có từ hai thread cùng trong tiến trình, chúng có thể giao tiếp bằng cách sử dụng bộ nhớ chia sẻ, nhưng sau đó hệ thống có thể không cấu hình lại được để chạy với các thread trong các tiến trình khác.

Các trạng thái dưới đây được phân biệt, nhưng không loại trừ lẫn nhau:
1. KÍCH HOẠT (ACTIVE) – Thread có thể chạy.
2. TREO (SUSPENDED)- Thread này đã bị hoãn.
3. DỪNG (STOPPED) – Tiến trình của thread này đã bị hoãn.
4. CHỜ (WAITING) – Các thread đang chờ một số sự kiện xảy ra.

Một thread trong trạng thái ACTIVE hoặc là đang chạy hoặc chờ đến lượt của mình cho một CPU rảnh. Trong cả hai trường hợp, nó đều có thể chạy. Một thread ở trạng SUSPENDED đã bị treo bằng một thread khác (hoặc tự bản thân nó) mà một hạt nhân ban hành. Tương tự, khi hạt nhân ngăn chặn một tiến trình, tất cả các thread trong trạng thái ACTIVE được đặt ở trạng thái dừng lại (STOPPED) cho đến khi tiến trình này được tiếp tục. Cuối cùng, khi một thread thực hiện một hoạt động ngăn chặn mà không thể được kết thúc ngay lập tức, thread được đặt trong tình trạng WAITING cho đến khi sự kiện xảy ra.

Một thread có thể được ở nhiều hơn một trạng thái cùng lúc. Ví dụ, một thread trong tình trạng bị treo sau đó cũng có thể nhập trạng thái dừng lại và nếu tiến trình của nó bị treo. Khái niệm, mỗi thread có ba bit độc lập liên kết với nó, mỗi bit cho trạng thái TREO, DỪNG, và CHỜ. Chỉ khi cả ba bit bằng 0 thì  có thể chạy thread.

Các thread chạy trong chế độ và không gian địa chỉ tương ứng với tiến trình của chúng. Nói cách khác, các thread của một tiến trình hạt nhân chạy ở chế độ hạt nhân, và các chủ đề của tiến trình người sử dụng chạy trong chế độ người dùng.

(Hết phẩn 3)

Leave a Reply