Trong khi một task đang ở trạng thái DORMANT thì tất cả thông tin thể hiện sự thực thi của nó sẽ không được lưu lại.. Và nếu như task có độ ưu tiên cao nhất không đi vào trạng thái WAIT
Trang 1T-Kernel Operating System (T-Kernel/OS) cung cấp một số hàm chức năng sau:
• Hàm điều khiển task
• Hàm giao tiếp giữa các task
c=VN, email=thanhvt@cse hcmut.edu.vn Reason: I am the author
of this document Date: 2007.06.14 15:10:01 +07'00'
Trang 2T-Kernel Debugger Support (T-Kernel/DS) cung cấp các hàm chức năng được sử dụng cho quá trình debugging:
• Hàm tham khảo các trạng thái bên trong của Kernel
• Trace
1.2 Scalability
T-Kernel là một real-time kernel được sử dụng bởi các hệ thống nhúng , và có phạm vi ứng dụng rộng rãi từ các hệ thống lớn đến các hệ thống nhỏ Mục tiêu nhắm tới của T-Kernel là nâng cao khả năng “khả chuyển” của các phần mềm như device driver và middleware
T-Kernel được thiết kế để có thể áp dụng được trên các hệ thống có qui mô lớn Cách tiếp cận với những hệ thống được chỉ ra trước không còn được áp dụng nữa và việc định ra các hàm cụ thể cho các hệ thống như vậy sẽ gây ra nhiều khó khăn cho tính “khả chuyển” của device driver , middleware và các phần mềm khác.T-Kernel thì không đi theo cách tiếp cận như vậy và về mặt nguyên lý thì các hệ điều hành tương thích với T-Kernel thì phải hiện thực tất cả các đặc tả kĩ thuật của T-Kernel Tuy nhiên, ở một hệ thống nào đó mà nó không cần tất cả các hàm của hệ điều hành thì các hàm đó có thể không cấn phải được hiện thực Điều quan trọng ở đây là người
sử dụng sẽ quyết định hàm nào sẽ không cần được hiện thực chứ không phải nhà cung cấp
- Đối với nhà cung cấp T-Kernel :
• Tất cả những đặc tả kĩ thuật phải được hiện thực nhưng việc hiện thực down” cho một hệ thống đích cụ thể thì được phép “Scale-down” có nghĩa là nó không cung cấp tổng thể các hàm đặc tả của T-Kernel nhưng nó vẫn không có cách cư xử bất thường (return error , …) khi một hàm nào đó không được hiện thực mà được gọi
“Scale-• Cung cấp cho người sử dụng các phương tiện cho phép người sử dụng có thể bỏ qua sự hiện thực các hàm không cần thiết
- Đối với nhà cung cấp Middleware:
• Middleware phải thiết kế để thỏa mãn tất cả các yêu cầu của T-Kernel Nó không thể bị giới hạn bởi sự đặc tả của hệ thống đích nhưng nó phải có khả năng thích hợp với các hệ thống khác biệt nhau
• Cung cấp cho người sử dụng các phương tiện cho phép người sử dụng
có thể bỏ qua sự hiện thực các hàm không cần thiết
Trang 3Chương 2
NHỮNG KHÁI NIỆM CƠ BẢN CỦA T-KERNEL
2.1 Ý nghĩa của một số thuật ngữ cơ bản
2.1.1 Task, invoking task
Đơn vị luận lí cơ bản của một chương trình đang thực thi được gọi là “task” Những chương trình mà gán cho 1 task thì được thực thi một cách tuần tự còn những chương trình mà gán cho nhiều task thì được thực thi một cách song song Khái niệm xử lý đồng thời chỉ tồn tại ở góc nhìn của người dùng , và thực sự thì các task này được thực hiện theo cơ chế time-sharing dưới sự điều khiển của kernel
Một task mà triệu gọi một hàm “system call” thì được gọi là “invoking task”
“dispatcher”
2.1.4 Context
Môi trường mà trong đó một chương trình thực thi được gọi chung là “context” (hay ngữ cảnh) Trong một ngữ cảnh thì phải đồng nhất , ít nhất là chế độ hoạt động của processor và vùng stack phải giống nhau Chú ý rằng , ngữ cảnh là một khái niệm quan trọng từ cách nhìn của ứng dụng , ngay cả khi quá trình xử lý được thực thi độc lập với ngữ cảnh Trong thực tế thì sự hiện thực của cả 2 loại ngữ cảnh trên thì đôi lúc lại xử dụng cùng chế độ hoạt động của processor và cùng stack
2.1.5 Precedence
Mối liên hệ giữa các yêu cầu xử lý khác nhau mà nó xác định thứ tự thực thi thì được gọi là
“precedence” (độ ưu tiên ) Khi một process có độ ưu tiên cao hơn chuyển sang trạng thái ready trong khi task có độ ưu tiên thấp hơn đang thực thi thì như một qui luật chung task có độ ưu tiên cao hơn sẽ chuyển sang trạng thái thực thi còn task đang thực thi phải chuyển sang trạng thái ready
Trang 42.2 Trạng thái của task và các qui luật về định thời
2.2.1 Trạng thái của task
Trạng thái của task được phân làm 5 loại chính được liệt kê bên dưới Trong đó thì trạng thái WAIT được phân làm 3 loại nhỏ hơn
(a) RUN state
Một task đang ở trạng thái RUN state có nghĩa là task đó hiện thời đang được thực thi
Khi mà một task độc lập với ngữ cảnh (Task-independent portion) được thực thi thì task mà thực
thi ngay trước khi bắt đầu sự thực thi của Task-independent portion được nói là đang ở trong trạng thái Run state
(b) READY state
Task mà đã hoàn tất quá trình chuẩn bị cho sự thực thi nhưng chưa chuyển sang trạng thái RUN được vì task có độ ưu tiên cao hơn đang thực thi Trong trường hợp này , thì task sẽ được thực thi bất cứ khi nào nó trở thành task có độ ưu tiên cao nhất giữa các task trong trạng thái READY
(c) WAIT states
Task không thể được thực thi bởi vì những điều kiện cho sự thực thi chưa có sẵn Nói cách khác là task đang chờ đợi những điều kiện cho sự thực thi được thỏa mãn Trong khi một task đang ở trạng thái WAIT thì các giá trị trong các thanh ghi và của program counter cũng như một số thông tin khác của chương trình đang đươc thực thi sẽ được lưu lại Khi task được đánh thức để tiếp tục thực thi từ trạng thái này thì các thông tin được lưu lại sẽ được phục hồi như trước khi task đi vào trạng thái WAIT Trạng thái này được chia làm 3 trạng thái nhỏ hơn
WAIT-đi vào trạng thái SUSPEND
(d) DORMANT state
Task mà chưa được bắt đầu sự thực thi hay đã hoàn thành sự thực thi rồi Trong khi một task đang ở trạng thái DORMANT thì tất cả thông tin thể hiện sự thực thi của nó sẽ không được lưu lại Khi một task bắt đầu sự thực thi của nó từ trạng thái DORMANT thì sự thực thi của nó sẽ bắt đầu tại địa chỉ bắt đầu của task Ngoại trừ những đặc tả khác thì giá trị của thanh ghi sẽ không được lưu lại
(e) NON-EXISTENT state
Đây là một trạng thái ảo trước khi task được tạo ra , hoặc sau khi nó bị deleted hoặc chưa được đăng kí với hệ thống
Phụ thuộc vào sự hiện thực mà ở đây có thể có thêm 1 số trạng thái tạm thời khác mà không thuộc vào bất kì trạng thái nào trong 5 trạng thái được liệt kê ở trên
Trang 5Khi một task chuyển sang trạng thái READY mà có độ ưu tiên cao hơn task đang thực thi hiện tại thì quá trình “dispatching” có thể xảy ra ngay khi task chuyển sang trạng thái READY và sau
đó nó sẽ chuyển sang trạng thái RUN Trong trường hợp này thì task mà đang thực thi cho tới thời điểm “dispatching” xảy ra được nói là nó đã bị tước đoạt quyền thực thi bởi task mới Một task được nói là bắt đầu sự thực thi có nghĩa là nó chuyển từ trạng thái DORMANT sang trạng thái READY Do đó mà khi nói một task đã thực thi có nghĩa là task đang ở trong một trạng thái bất kì nào đó ngoài trạng thái DORMANT hay NON-EXISTENT Và một task được nói là thoát khỏi sự thực thi có nghĩa là task đã đi đến trạng thái DORMANT
Một task được nói là đã được giải phóng khỏi trạng thái “wait” có nghĩa là nếu task đang ở trạng thái WAIT thì sẽ chuyển sang trạng thái READY , còn nếu task đang ở trạng thái WAIT-
SUSPEND thì sẽ chuyển sang trạng thái SUSPEND Sự tiếp tục thực thi của một task ở trạng thái “suspend” có nghĩa là nếu task đang ở trạng thái SUSPEND thì sẽ chuyển sang trạng thái READY, và nếu như task đang ở trạng thái WAIT-SUSPEND thì sẽ chuyển sang trạng thái WAIT
Sự chuyển trạng thái giữa cac task được mô tả như trên hình 2.1
Trang 6Phụ thuộc vào sự hiện thực mà ở đây có thể có thêm một số trạng thái khác ngoài những trạng thái được chỉ ra ở đây Một đặc điểm của T-Kernel đó là nó có sự phân biệt rất rõ ràng giữa sự tác động của các hàm system call lên task đã triệu gọi nó và các task khác (bảng 2.1 ) Lí do cho
sự phân biệt này là nó sẽ làm cho sơ đồ chuyển trạng thái của task trở nên rõ ràng hơn cũng như tạo thuận lợi cho việc hiểu rõ hơn về các hàm system call Sự phân biệt sự tác động của các hàm system call lên các task đã triệu gọi nó và các task khác cũng được xem như là sự phân biệt giữa
sự chuyển trạng thái từ trạng thái RUN và sự chuyển trạng thái từ các trạng thái khác
Bảng 2.1 : Phân biệt sự chuyển trạng thái giữa “invoking task” và các task khác
Trạng thái WAIT và SUSPEND có mối quan hệ trực giao , trong đó bất kì những yêu cầu nào cho sự chuyển tới trạng thái SUSPEND cũng không gây ảnh hưởng tới điều kiện cho sự giải phóng task khỏi trạng thái WAIT Điều đó cũng có nghĩa là những điều kiện để giải phóng task khỏi trạng thái WAIT thì giống nhau khi task đang ở trạng thái WAIT hay WAIT-SUSPEND
Do đó, ngay cả khi một yêu cầu chuyển sang trạng thái SUSPEND được đưa ra đối với 1 task
mà nó đang ở trong trạng thái chờ đợi tài nguyên (semaphore , memory block ,….) thì nó sẽ chuyển sang trạng thái WAIT-SUSPEND và điều kiện để cấp phát tài nguyên cho nó vẫn không
có gì thay đổi so với khi nó bị yêu cầu chuyển sang trạng thái SUSPEND
Lí do để T-Kernel làm sự phân biệt rõ ràng giữa trạng thái WAIT (gây ra bởi sự triệu gọi một hàm system call) và trạng thái SUSPEND ( gây ra bởi 1 task khác) là những trạng thái này đôi khi lại có sự trùng lắp lên nhau Bằng sự phân biệt rõ ràng trạng thái mà chúng trùng lắp lên nhau WAIT-SUSPEND, sơ đồ chuyển trạng thái sẽ rõ ràng hơn và các hàm system call sẽ trở nên dễ hiểu hơn
2.2.2 Các qui luật định thời
T-Kernel định thời dựa trên độ ưu tiên giữa các task và theo cơ chế “preemptive” Nếu có nhiều task mà chúng có thể thực thi được thì chỉ task có độ ưu tiên cao nhất được chuyển sang trạng
Trang 7thái RUN , các task còn lại phải chuyển sang trạng thái READY Những task có cùng độ ưu tiên
sẽ được định thời theo qui tắc FCFS (First Come First Served)
Theo cơ chế định thời của T-Kernel thì task có độ ưu tiên cao nhất sẽ được thực thi , các task còn lại thì đơn giản là sẽ không được thực thi Và nếu như task có độ ưu tiên cao nhất không đi vào trạng thái WAIT , hay vì những lí do nào đó mà nó không được thực thi thì các task khác cũng không được thực thi.Đây chính là sự khác nhau cơ bản so với cách định thời trong hệ thống chia
sẽ thời gian (Time Sharing System - TSS) , trong hệ thống TSS thì các task được đối xử một cách bình đẳng với nhau Tuy nhiên chúng ta cũng có thể dùng các hàm system call để thay đổi thứ tự thực thi giữa các task có cùng độ ưu tiên Do đó một ứng dụng có thể dùng các hàm
system call để định thời theo cơ chế round-robin , đó cũng là một kiểu định thời của TSS
Hình 2.2 : Thứ tự thực thi ở trạng thái khởi tạo
Hình 2.2 và các hình bên dưới sẽ minh họa rõ cho chúng ta thấy cách mà các task được thưc thi khi mà chúng có độ ưu tỉên giống nhau cũng như những task có độ ưu tiên khác biệt nhau Ở hình 2.2 chỉ ra thứ tự thực thi giữa các task sau khi task A có độ ưu tiên là 1, task E có độ ưu tiên là 3 và task B, C , D có cùng độ ưu tiên là 2 được bắt đầu Task với độ ưu tiên cao nhất A sẽ được chuyển sang trạng thái RUN Sau khi task A kết thúc thì task B với độ ưu tiên cao nhất sẽ chuyển sang trạng thái RUN (hình 2.3)
Hình 2.3 : Thứ tự thực thi sau khi task B chuyển sang trạng thái RUN Khi task A lại bắt đầu sự thực thi của mình lần nữa thì task B sẽ bị tước quyền thực thi và sẽ chuyển sang trạng thái READY Nhưng bởi vì task B là task chuyển sang trạng thái RUN sớm hơn task C, D nên nó vẫn còn có quyền thực thi cao nhất giữa các task có cùng độ ưu tiên và thứ
tự thực thi giữa các task vẫn giống hình 2.2
Bây giờ chúng ta hãy xem điều gì sẽ xảy ra nếu như task B chuyển sang trạng thái WAIT khi mà các task đang ở trong trạng thái đụơc miêu tả trong hình 2.3 Vì là thứ tự thực thi giữa các task
Trang 8Hình 2.4 : Thứ tự thực thi sau khi task B chuyển sang trạng thái WAIT
Do đó sau khi mà task B được giải phóng khỏi trạng thái WAIT thì nó sẽ chuyển sang trạng thái RUN sau task C và D Ở đây task B đã nhận quyền thực thi thấp nhất giữa các task có cùng độ
ưu tiên (hình 2.5)
Hình 2.5 : Thứ tự thực thi khi task B được giải phóng khỏi trạng thái WAIT
Tóm lại khi mà một task chuyển từ trạng thái READY sang RUN rồi quay về trạng thái READY thì nó có quyền thực thi cao nhất giữa các task có cùng độ ưu tiên nhưng sau khi task chuyển từ RUN sang WAIT , và khi mà trạng thái WAIT được giải phóng thì nó sẽ có quyền thực thi thấp nhất giữa các task có cùng độ ưu tiên
Chú ý rằng khi một task chuyển từ trạng thái SUSPEND sang trạng thái READY thì nó phải có quyền thực thi thấp nhất giữa các task có cùng độ ưu tiên Trong một hệ thống có sử dụng bộ nhớ
ảo thì khi mà một task phải chờ đợi sự thay trang thì nó bị chuyển sang trạng thái SUSPEND và trong những hệ thống như vậy thì sự thay đổi thứ tự thực thi giữa các task như là một kết quả của quá trình chờ đợi sự thay trang
2.3 Xử lý các interrupt
Interrupt trong T-Engine bao gồm cả interrupt bên ngoài do các thiết bị gây ra hay những
interrupt bên trong do CPU gây ra Một trình xử lý interrupt có thể được định nghĩa cho một số interrupt Mỗi chương trình quản lý interrupt có thể được gán cho một địa chỉ thực thi trực tiếp
mà không cần có sự can thiệp của hệ điều hành hoặc được gán cho một địa chỉ thực thi của một chương trình con được viết bằng ngôn ngữ cấp cao
Trang 92.4 Xử lý các ngoại lệ của task
T-Kernel cho phép định nghĩa hàm xử lý những ngoại lệ của task Cần chú ý là ngoại lệ là những
gì mà không được CPU xem như interrupt
Khi một task đang thực thi mà có một ngoại lệ nào đó xảy ra thì sẽ kích khởi sự thực thi của trình
xử lý những ngoại lệ của task đó và khi đó thì task đang thực thi buộc phải ngưng lại Khi mà trình xử lý ngoại lệ thực thi xong thì task sẽ tiếp tục sự thực thi của mình Một trình xử lý ngoại
lệ của task cho mỗi task có thể được đăng kí cho một ứng dụng nào đó
2.5 Các trạng thái của hệ thống
2.5.1 Các trạng thái của hệ thống khi một Nontask-portion thực thi
Khi mà một task được lập trình để chạy trên T-Engine thì các trạng thái của task có thể được theo dõi bằng cách quan sát lược đồ chuyển trạng thái của task Tuy nhiên , trong trường hợp nó
là các chương trình xử lý interrupt hay các hàm quản lý các dịch vụ mở rộng ( extended SVC handler) thì người sử dụng phải thực hiện quá trình lập trình ở mức độ gần với kernel hơn là với task Và trong trường hợp này thì điều mà chúng ta cần quan tâm đó là trạng thái của hệ thống trong khi Nontask-portion thực thi, đó là lí do mà tại sao mà các trạng thái của hệ thống sẽ được làm rõ ở đây
Hình 2.6 : Phân loại các trạng thái của hệ thống Các trạng thái của hệ thống được phân loại như trên hình 2.6 Trong đó trạng thái “transient state” là trạng thái mà hệ điều hành đang thực thi ( ví dụ như các hàm system call) Điều này rất quan trọng vì từ quan điểm của người dùng thì khi mà các hàm system call được triệu gọi thì quá trình thực thi của chúng sẽ không chia nhỏ và các trạng thái bên trong sẽ không được thấy bời người sử dụng Bời vì lí do này mà khi OS thực thi thì được xem như là “trasient state” và những gì bên trong nó sẽ được xem như là một hộp đen Tuy nhiên , những trường hợp dưói đây thì khi thực thi các “transient state” có thể bị chia nhỏ:
-Khi bộ nhớ được cấp phát hay được giải phóng trong trường hợp các hàm system call thực hiện quá trình “get” hay “release” bộ nhớ ( trong khi một hàm quản lý bộ nhớ của T-
Kernel/SM được gọi)
-Trong các hệ thống sử dụng bộ nhớ ảo, khi mà bộ nhớ không thường trú bị truy xuất
Trang 10dùng để suspend một task tk_sus_tsk có thể gây ra deadlock hay những vấn đề khác do khi ngừng sự thực thi của một task mà không xóa khỏi trạng thái trasient state Do đó , mà như một qui luật các hàm tk_sus_tsk và tk_ter_tsk sẽ không được sử dụng trong những chương trình như vậy Những hàm system call này chỉ được sử dụng trong những hệ thống con như hệ thống có bộ nhớ ảo hay trong chương trình debug mà sự thực thi của nó thì gần với hệ điều hành và đôi lúc được xem như một phần của hệ điều hành
Task-independent portion và quasi-task portion là những trạng thái của hệ thống trong khi một trình xử lý các interrupt hay những ngoại lệ của task thực thi Phần của trình xử lý mà nó thực thi trong ngữ cảnh của task thì được gọi là quasi-task portion , còn phần mà thực thi độc lập với ngữ cảnh của task thì được gọi là Task-independent portion Một trình xử lý các hàm system call
mở rộng của hệ thống do người dùng định nghĩa là một quasi-task portion, ngược lại thì trình xử
lý các interrupt hay các hàm xử lý các sự kiện về thời gian được kích khởi bởi các interrupt bên ngoài là một Task-independent portion Trong quasi-task portion, những task này có sự chuyển trạng thái giống như một task bình thường và các hàm system call có thể được gọi ngay cả khi
nó đang ở trạng thái WAIT Trasient state , Task-independent portion và quasi-task portion được gọi chung là nontask-portion Trong một chương trình đang thực thi thì các task ngoài những trạng thái được liệt kê ở trên thì được gọi là task-portion
2.5.2 Task-independent portion và quasi-task portion
Một đặc điểm của Task-independent portion (interrupt handler, time event handler,…) đó là việc xác định task nào đã thực thi ngay trước khi nó đi vào vùng task-independent là điều vô nghĩa và khái niệm “invoking task” là không tồn tại Do đó mà khi một hàm system call đi vào trạng thái WAIT state hay một hàm system call được thiết kế cho “invoking task” sẽ không được gọi từ Task-independent portion Ngoài ra, vì không thể định ra được task nào đang thực thi trước khi
đi vào Task-independent portion do đó mà sẽ không có quá trình “dispatching” Nếu như quá trình “dispatching” cần thiết phải thực hiện thì nó sẽ bị trì hoãn lại cho đến khi task-independent thực thi xong Quá trình này được gọi là “delay dispatching”
Nếu như quá trình “dispatching” xảy ra trong lúc trình xử lý interrupt đang thực thi (
Task-independent portion) thì phần còn lại của trình xử lý phải bị hoãn lại cho đến khi một task nào đó được bắt đầu bởi quá trình “dispatching” này ,điều này sẽ gây ra sự lồng nhau giữa các interrupt
và được minh họa trên hình 2.7.Trong ví dụ bên dưới thì interrupt X xảy ra khi mà task A đang thực thi và trong khi trình xử lý interrupt của nó đang thực thi thì có một interrupt Y có độ ưu tiên cao hơn đến Trong trường hợp này thì nếu như interrupt Y kích khởi sự hoạt động của task
B và task B sẽ bắt đầu sự thực thi của mình khi mà trình xử lý interrupt Y kết thúc và như vậy thì phần còn lại của quá trình xử lý interrupt X từ (2) đến (3) chỉ có thể được tiếp tục thực thi khi task A chuyển sang trạng thái RUN Điều nguy hiểm ở đây là trình xử lý interrupt của A bị tước quyền thực thi không chỉ bởi trình xử lý interrupt của Y mà còn cả task B nữa Điều này làm cho trình xử lý interrupt không còn độ ưu tiên cao nhất so với các task thông thường đó là lí do vì sao phải giới thiệu về quá trình trì hoãn dispatching
Trang 11Hình 2.7: Interrupt lồng nhau và trì hoãn quá trình dispatching Khác với Task-independent portion thì quasi-task portion có thể định ra task nào đã thực thi ngay trước khi trạng thái của hệ thống đi vào quasi-task portion và do đó nó sẽ định ra được trạng thái của task ngay trước khi đi vào trạng thái này Ngoài ra thì một task nằm trong quasi-task-portion thì có thể đi vào trạng thái WAIT Do đó mà quá trình dispatching xảy ra bên trong quasi-task portion cũng giống như quá trình dispatching đối với các task bình thường khác Và kết quả là mặc dù những phần mở rộng của hệ điều hành cũng như các quasi-task portion là các nontask portion nhưng sự thực thi của nó thì không cần có độ ưu tiên cao hơn tất cả các task thông
thường Điều này thì trái ngược với các trình xử lý interrupt, nó luôn có độ ưu tiên cao hơn so với tất cả các task thông thường khác Hai ví dụ sau sẽ làm rõ sự khác biệt giữa Task-
independent portion và quasi-task portion
-Trong khi task A đang thực thi ( có độ ưu tiên là 8) thì có một intẹrrupt xảy ra , do đó sẽ kích hoạt trình xử lý interrupt của nó (Task-independent portion) thực thi Và bên trong hàm xử
lý interrupt lại gọi hàm tk_wup_tsk để đánh thức sự thực thi của task B (có độ ưu tiên là 2 cao hơn task A) Theo nguyên lý của việc trì hoãn quá trình dispatching thì quá trình dispatching sẽ không xảy ra ở thời điểm này mà thay vì vậy sau khi hàm tk_wup_tsk thực thi xong thì phần còn lại của trình xử lý interrupt sẽ được thực thi kế tiếp Chỉ khi tk_ret_int được thực thi xong tại phần cuối của trình xử lý interrupt thì quá trình dispatching xảy ra làm cho task B chuyển sang trạng thái thực thi
-Một hàm mở rộng của system call được triệu gọi trong khi task A đang thực thi (có độ
ưu tiên là 8 ) và trong trình xử lý của nó (quasi-task portion) có kích khởi sự thực thi của task B (
có đô ưu tiên là 2) bằng hàm tk_wup_tsk Trong trường hợp này thì nguyên lý trì hoãn quá trình dispatching không được áp dụng và ngay sau khi tk_wup_tsk thực thi xong thì quá trình
dispatching sẽ được xảy ra và task B sẽ chuyển sang trạng thái RUN còn task A phải chuyển sang trạng thái READY Do đó mà phần còn lại của trình xử lý của hàm mở rộng của system call chỉ có thể được thực thi sau khi task A chuyển sang trạng thái RUN một lần nữa
Trang 12Trong giá trị thuộc tính của một đối tượng hay của một trình xử lý thì các bit thấp chỉ ra các thuộc tính của hệ thống còn các bit cao chỉ ra các thuộc tính mà nó phụ thuộc vào cách hiện thực (implementation-dependent) Tuy nhiên, T-Kernel không chỉ rõ vị trí của bit nào được cho là cao hay thấp, mà như là một nguyên tắc thì các thuộc tính của hệ thống sẽ được bố trí từ bit ít có ý nghĩa nhất (least significant bit) đến bit có nhiều ý nghĩa nhất (most significant bit) còn các thuộc tính phụ thuộc vào cách hiện thực sẽ được bố trí theo chiều ngược lại Những bit nào không được định nghĩa thuộc tính cho nó thì được xoá về 0
Trong một số trường hợp thì đối tượng có thể chứa thêm những thông tin mở rộng Phần thông tin mở rộng này sẽ được thiết kế khi đối tượng được đăng kí Những thông tin mà truyền cho đối tượng như những thông số khi đối tượng bắt đầu sự thực thi sẽ không ảnh hưởng tới các hoạt động của T-Kernel Những phần thông tin mở rộng có thể được đọc bằng cách gọi hàm system call để tham khảo đến trạng thái của đối tượng đó
2.7 Memory
2.7.1 Không gian địa chỉ
Không gian bộ nhớ khả định địa chỉ được phân làm 2 loại đó là không gian bộ nhớ hệ thống và không gian bộ nhớ của các task Không gian bộ nhớ của hệ thống có thể được truy xuất như nhau giữa tất cả các task, còn không gian địa chỉ của task thì chỉ được truy xuất bởi những task mà nó thuộc không gian bộ nhớ này Trong một số trường hợp thì các task khác nhau có thể cùng thuộc
về một không gian địa chỉ
Hình 2.8 : Không gian địa chỉ Không gian địa chỉ luận lý của task và của hệ thống phụ thuộc vào những giới hạn của CPU (hay MMU) do đó nó phụ thuộc vào sự hiện thực nhưng về nguyên tắc thì không gian của task nên
Trang 13được gán cho không gian địa chỉ thấp còn không gian địa chỉ của hệ thống là không gian địa chỉ cao
Vì các trình xử lý interrupt và những phần mềm Task-independent portion không là các task nên chúng cũng sẽ không có không gian địa chỉ của task Thay vì vậy, Task-independent portion sẽ
có không gian địa chỉ task chính là không gian địa chỉ của task mà trước khi nó đi vào independent portion Điều này có thể được thực hiện bởi kết quả trả về của hàm system call tk_get_tid Nếu như không có task nào đang ở trạng thái RUN thì không gian địa chỉ của task sẽ không được xác định T-Kernel sẽ không tạo và cũng không quản lý không gian địa chỉ mà thông thường thì T-Kernel sẽ được sử dụng cùng với một hệ thống con nào đó để quản lý các không gian địa chỉ Trong một hệ thống mà không có MMU hay không sử dụng MMU thì không gian địa chỉ của các task về bản chất là không tồn tại
Task-2.7.2 Bộ nhớ không thường trú
Bộ nhớ thì có thể là thường trú hay không thường trú
Khi mà bộ nhớ không thường trú được truy xuất thì T-Kernel sẽ chép dữ liệu từ đĩa cũng như các thiết bị lưu trữ vào trong bộ nhớ chính của nó Do đó mà nó yêu cầu một quá trình xử lý phức tạp giống như quá trình truy xuất đĩa bằng một đevice driver Do đó mà khi truy xuất bộ nhớ không thường trú thì device driver, cũng như những thiết bị có liên quan phải ở trạng thái sẵn sàng hoạt động
Quá trình truy xuất sẽ không thể được thực hiện trong những trạng thái mà ở đó khộng cho phép quá trình “dispatch” hay “interrupt” hoặc trong Task-independent portion
Cũng tương tự như vậy thì bên trong quá trình xử lý của OS , điều cần thiết là phải nên né tránh việc truy xuất vào các vùng nhớ không thường trú khi mà quá trình xử lý đang nằm trong vùng tranh chấp (critical section) Một trường hợp cụ thể cho vấn đề này là khi truyền thông số cho các hàm system call mà thông số này lại trỏ đến một vùng nhớ không thường trú Việc cho phép hay không cho phép truyền các thông số kiểu như vậy thì còn phụ thuộc vào cách hiện thực cụ thể
Dữ liệu được chuyển từ đĩa hay các thiết bị khác tương tự như vậy và gây ra quá trình truy xuất các bộ nhớ không thường trú thì không được thực hiện bời T-Kernel Mà thông thường T-Kernel được xử dụng cùng với một số hệ thống con mà các hệ thống này sẽ quản lý các vùng bộ nhớ ảo cũng như các quá trình xử lỳ khác Trong một hệ thống mà không sử dụng bộ nhớ ảo thì thông số của các hàm system call cũng như các hàm khác tương tự như vậy mà trỏ đến các vùng nhớ không thường trú thì sẽ được bỏ qua, hoặc hệ thống đó sẽ xem tất cả các vùng nhớ đều là ở dạng thường trú
2.7.3 Các mức độ bảo vệ
T-Kernel cung cấp 4 mức độ bảo vệ bộ nhớ từ 0 đến 3:
• Mức 0 có đặc quyền cao nhất còn mức 3 có đặc quyền thấp nhất
• Việc truy xuất vùng nhớ chỉ có thể được thực hiện ở vùng nhớ mà có mức độ bảo
vệ hiện tại bằng hoặc tháp hơn
• Vịêc thay đổi mức độ bảo vệ sang một mức độ bảo vệ khác có thể được thực hiện bằng cách gọi hàm system call hoậc các hàm dịch vụ mở rộng (được định nghĩa thêm bởi người
Trang 14Hình 2.9 : Các mức độ bảo vệ bộ nhớ
Một Nontask portion ( Task-independent portion ,quasi-task portion , ) thì được thực thi ở mức
độ bảo vệ là 0 Chỉ duy nhất một task có thể chạy ở mức độ bảo vệ là từ 1 đến 3 Một task của người sử dụng cũng có thể được chạy ở mức độ bảo vệ là 0 Có một số MMU chỉ hỗ trợ có 2 mức bảo vệ là mức đặc quyền và mức độ người sử dụng Và trong trường hợp này thì mức độ từ
0 đến 2 được gán cho chế độ đặc quyền còn mức độ 3 được gán cho chế độ người sử dụng Còn trong những hệ thống mà không có MMU thì tất cả các mức độ bảo vệ từ 0 đến 3 đều được đối
xử như nhau
Trang 15Chương 3
NHỮNG ĐẶC TẢ CHUNG CỦA T-KERNEL
3.1 Kiểu dữ liệu
3.1.1 Các kiểu dữ liệu chung
typedef char B ; /* số nguyên 8-bit có dấu */
typedef short H ; /* số nguyên 16-bit có dấu */
typedef int W ; /* số nguyên 32-bit có dấu */
typedef unsigned char UB ; /* số nguyên 8-bit không dấu */
typedef unsigned short UH ; /* số nguyên 16-bit không dấu */
typedef unsigned int UW ; /* số nguyên 32-bit không dấu */
typedef char VB ; /* 8-bit dữ liệu mà không có kiểu cố định */
typedef char VH ; /*16-bit dữ liệu mà không có kiểu cố định */
typedef char VW ; /*16-bit dữ liệu mà không có kiểu cố định */
typedef char *VP ; /*con trỏ dữ liệu mà không có kiểu cố định */
typedef volatile B _B ; /* đặc tả kiểu không ổn định*/
typedef volatile H _H ;
typedef volatile W _W ;
typedef volatile UB _UB ;
typedef volatile UH _UH ;
typedef volatile UW _UW ;
typedef int INT;
typedef unsigned int UINT;
typedef int ID;/* ID tổng quát */
typedef int MSEC;/*thời gian tổng quát (milisecond) */
typedef void (*FP) ();/*địa chỉ hàm tổng quát */
typedef void (*FUNCP) ();/*địa chỉ hàm tổng quát */
#define LOCAL static /* đánh dấu sự định nghĩa cục bộ */
#define EXPORT /* đánh dấu sự định nghĩa toàn cục */
#define IMPORT extern /* đánh dấu sự tham khảo toàn cục */
Trang 16* Theo định nghĩa thì TRUE =1 nhưng bất kì giá trị nào khác 0 cũng được xem là TRUE Do đó mà nên né tránh những câu lệnh như bool == TRUE mà thay vào đó ta sẽ dùng câu lệnh bool != FALSE
typedef INT BOOL;
#define TRUE 1 /* True */
#define FALSE 0 /* False */
/*
* Mã kí tự TRON
*/
typedef UH TC; /* mã kí tự TRON */
typedef TNULL ((TC)0); /* kí tự kết thúc chuỗi kí tự trong TRON*/
• VB, VH và VW cho ta biết được độ rộng của bit dùng để biểu diễn nhưng không cho ta biết được kiểu dữ liệu còn B,H,W thì chỉ rõ cho ta biết đó là kiểu số nguyên
• Vì bộ xủ lý là 32 bit hoặc hơn nên kiểu INT và UINT cũng có độ rộng bit ít nhất
là 32 bit
Các thông số như stksz, wupcnt, và chiều dài của 1 message thì rõ ràng là các giá trị không âm
nhưng về nguyên tắc thì nó được gán cho kiểu dữ liệu là kiểu số nguyên có dấu Điều này cũng thể hiện như một qui tắc chung của TRON đó là các số nguyên nên được xem như là các số nguyên có dấu để có thể mở rộng khi cần thiết Ví dụ như thông số thời gian timeout (TMO tmout ) thì được gán cho giá trị nguyên có dấu để có thể sử dụng TMO_FEVR ( = -1 ) để thể hiện 1 ý nghĩa đặc biệt của nó Các thông số mà có kiểu dữ liệu là kiểu số nguyên không dấu thì được xem như các mẫu bit ( như các đối tượng, các thuộc tính , các cờ sự kiện, v.v )
3.1.2 Các kiểu dữ liệu được định nghĩa khác
Các tên được liệt kê bên dưới thì được sử dụng cho các kiểu dữ liệu khác mà nó xuất hiện thường xuyên hoặc có một ý nghĩa đặc biệt hoặc để làm rõ ý nghĩa của các thông số
typedef INT FN; /* Function code */
typedef INT RNO; /* Rendezvous number */
typedef INT ATR; /* Thuộc tính của đối tượng hoặc của các trình xử lý */
typedef INT ER; /* Mã lỗi */
typedef INT PRI; /* Độ ưu tiên */
typedef INT TMO; /*Thời gian timeout */
typedef UINT RELTIM; /* Thời gian tương đối */
typedef struct systim { /* Thời gian của hệ thống */
W hi; /* 32 bit cao */
UW lo; /* 32 bit thấp */
} SYSTIM;
/* Các hằng chung */
Trang 17#define NULL 0 /* Con trỏ NULL */
#define TA_NULL 0 /* Cho biết không có thuộc tính đặc biệt */
#define TMO_POL 0 /* Polling */
#define TMO_FEVR (-1) /* Chờ đợi mãi mãi */
Kiểu dữ liệu có được bởi sự kết hợp của 2 hay nhiều kiểu dữ liệu khác thì được thể hiện bằng kiểu dữ liệu chính Ví dụ như giá trị trả về của hàm tk_cre_tsk có thể là task ID hoặc mã lỗi nhưng vì giá trị chính của nó là task ID nên kiểu dữ liệu là task ID
3.2 Các hàm system call
3.2.1 Định dạng của các hàm system call
T-Kernel lấy C làm ngôn ngữ chuẩn cấp cao và T-Kernel cũng thực hiện chuẩn hóa sự giao tiếp với các hàm system call được viết bằng ngôn ngữ C Cách thức thực hiện việc giao tiếp với các hàm system call ở mức độ ngôn ngữ Assembly là phụ thuộc vào sự hiện thực và không chuẩn hóa.Việc gọi các hàm system call thông qua cách thức của C thì được khuyến khích ngay cả với một chương trình được viết bằng Assembly Bằng cách này thì sẽ bảo đảm được tính khả
chuyển của các chương trình được viết bằng Assembly ngay cả khi hệ điểu hành thay đổi , miễn
là CPU giống nhau
Những qui luật chung sau đây đươc thiết lập cho tất cả các hàm system call :
• Tất cả các hàm system call được định nghĩa như những hàm của C
• Mã giá trị trả về của một hàm là 0 hay một số dương chỉ ra sự kết thúc bình thường , trong khi đó thì số âm được sử dụng cho các mã lỗi của hàm
Tất cả giao tiếp của các hàm system call được cung cấp như những hàm thư viện Các macro được viết bằng C , inline functions, và inline assembly code thì không được phép sử dụng Lí do của việc này đó là vì C macro và inline function chỉ có thể được sử dụng từ các chương trình C Ngoài ra thì inline function và inline assembly không là đặc tính chuẩn của C, những chức năng này là phụ thuộc vào sự hiện thực của trình biên dịch và do đó sẽ hạn chế tính khả chuyển của các hàm system call
3.2.2 Các hàm system call có thể được gọi từ Task-independent portion
Các hàm system call liệt kê bên dưới thì được phép gọi từ một Task-independent portion hoặc từ một trạng thái không cho phép quá trình dispatch Các hàm system call còn lại có được phép gọi
từ Task-independent portion hay từ các trạng thái mà không cho phép quá trình dispatch hay không là phụ thuộc vào sự hiện thực
tk_sta_tsk Start task
tk_wup_tsk Wakeup task
tk_rel_wai Release wait
tk_sus_tsk Suspend task
tk_sig_sem Signal semaphore
tk_set_flg Set event flag
Trang 18tk_sta_cyc Start cyclic handler tk_stp_cyc Stop cyclic handler
tk_sta_alm Start alarm handler
tk_stp_alm Stop alarm handler tk_ref_tsk Reference task status tk_ref_cyc Reference cyclic handler status
tk_ref_alm Reference alarm hanlder status tk_ref_sys Reference system status tk_ret_int Return from interrupt handler
3.2.3 Giới hạn việc triệu gọi các hàm system call
Mức độ bảo vệ mà tại đó hàm system call được triệu gọi có thể bị giới hạn Trong trường hợp này nếu như một hàm system call được triệu gọi từ một task (task portion ) có mức độ bảo vệ thấp hơn mức độ bảo vệ được thiết kế cho hàm system call đó thì mã lỗi E_OACV sẽ được trả
về
Các hàm dịch vụ mở rộng thì không có bất kì một giới hạn nào
Một hàm system call được triệu gọi ở mức độ bảo vệ thấp hơn 1 thì bị cấm do đó các task đang thực thi ở mức độ bảo vệ là 2 và 3 sẽ không được phép gọi các hàm system call Các task này chỉ
có thể triệu gọi các hàm dịch vụ mở rộng và được lập trình để sử dụng các hàm của hệ thống con Việc giới hạn này được sử dụng khi T-Kernel được kết hợp với các hệ điều hành cao hơn, nhằm ngăn chặn việc gọi trực tiếp các hàm system call từ các task thuộc hệ điều hành cao hơn đó Điều này cho phép T-Kernel được sử dụng như 1 microkernel
Việc giới hạn mức độ bảo vệ cho các hàm system call thì được thiết lập bằng cách sử dụng các hàm quản lý các thông tin cấu hình của hệ thống
3.2.4 Chỉnh sửa một gói thông số
Một số loại tham số khi truyền cho các hàm system call thì sử dụng định dạng kiểu gói Những thông số mà có định dạng kiểu gói thì có 2 loại , hoặc là những thông tin đầu vào được truyền cho các hàm system call ( T_CTSK, …) hoặc là những giá trị trả về của các hàm system call (T_RTSK,…)
Những thông tin phụ có thể được thêm vào gói thông số nhưng đó là tùy thuộc vào cách hiện thực Tuy nhiên, những thông tin phụ này sẽ không được phép thay đổi kiểu dữ liệu hoặc thứ tự những thông số mà đã được đặc tả theo 1 dạng chuẩn trước đó hoặc xóa bất kì thông tin nào đã
có Khi một thông tin phụ nào đó được thêm vào gói thông số thì nó phải ở vị trí sau những thông số đã được chuẩn hóa trước đó
Khi những hàm system call được gọi mà các thông tin được thêm vào gói thông số đầu vào của các hàm này chưa được khởi tạo giá trị cho nó ( nội dung ô nhớ của các thông tin này không được xác định ) thì các hàm system call này vẫn còn hoạt động bình thường giống như lúc chưa
có những thông tin thêm vào này
Thông thường thì giá trị thuộc tính của cờ mà nó cho ta biết giá trị của các thông tin được thêm vào đã được thiết lập hay chưa thì phụ thuộc vào cách hiện thực Khi mà giá trị của cờ được thiết lập (1) thì các thông tin được thêm vào được sử dụng , còn ngược lại thì các thông tin được thêm vào chưa được khởi tạo và những giá trị mặc định sẽ được sử dụng Lí do của việc đăc tả này là
Trang 19để bảo đảm khi một chương trình được phát triển trong sự đăc tả chuẩn thì sẽ có thể thực thi trên một hệ điều hành với một số hàm mở rộng bằng cách dịch lại chương trình đó mà thôi
C như những hàm không có giá trị trả về như hàm có kiểu void
Một mã lỗi thì bao gồm mã lỗi chính và mã lỗi phụ 16 bit thấp của mã lỗi là giá trị của mã lỗi phụ và phần còn lại là giá trị của mã lỗi chính Mã lỗi chính thì được phân thành các lớp lỗi khác nhau dựa trên sự cần thiết của việc phát hiện lỗi cũng như hoàn cảnh mà lỗi xảy ra hay những yếu tố khác Vì T-Kernel không sử dụng mã lỗi phụ nên những bit này sẽ được thiết lập giá trị là
0
#define MERCD(er) ( (ER)(er) >> 16) /* Mã lỗi chính */
#define SERCD(er) ( (H)(er) ) /* Mã lỗi phụ */
#defing ERCD(mer, ser) ( (ER)(mer ) << 16 | (ER) (UH) (ser) )
3.2.7 Timeout
Một hàm system call mà có thể đi vào trạng thái WAIT thì có nó một hàm timeout Nếu quá trình
xử lý chưa hoàn tất trong thời gian được thiết kế cho hàm timeout thì quá trình xử lý sẽ bị huỷ
và hàm system call sẽ trả về mã lỗi là E_TMOUT
Theo nguyên lý trên thì một hàm system call sẽ không nên gây ra bất kì hiệu ứng lề nào nếu như hàm system call trả về một mã lỗi, và việc gọi hàm system call mà gây ra timeout thì về mặt nguyên tắc thì không nên thay đổi trạng thái của hệ thống Một ngoại lệ xảy ra ở đây là khi một hàm system call giống như trên sẽ không thể trở về trạng thái ban đầu của nó nếu như quá trình thực thi bị huỷ Điều này sẽ được chỉ rõ trong phần mô tả các hàm system call
Nếu khoảng thời gian timeout được thiết lập là 0 thì hàm system call sẽ không thể đi vào trạng thái WAIT ngay cả khi đó về mặt nguyên tắc thì nó phải đi vào trạng thái WAIT Việc triệu gọi một hàm system call mà có thời gian timeout được thiết lập là 0 thì được gọi là polling và như vậy thì nếu một hàm system call thực hiện quá trình polling thì sẽ không bao giờ đi vào trạng thái WAIT
Trang 20hàm system call được nói là có thể đi vào trạng thái WAIT , nhưng nếu thời gian timeout được thiết lập và thời gian thực thi vượt qua thời gian timeout thì trạng thái WAIT sẽ được giải phóng
và hàm system call sẽ trả về mã lỗi là E_TMOUT Trong trường hợp polling thì hàm system call
sẽ trả về giá trị E_TMOUT mà không đi vào trạng thái WAIT
Giá trị timeout ( có kiểu là TMO ) được thiết lập là một số dương hoặc TMO_POL (= 0) cho polling hoặc TMO_FEVER (= -1 ) cho vịêc chờ đợi mãi mãi Nếu thời gian timeout được thiết lập thì quá trình xử lý timeout phải được bảo đảm thực hiện ngay sau khi hàm sysstem call được gọi
Vì một hàm system call thực hiện quá trình polling thì không thể đi vào trạng thái WAIT do đó
mà không có bất kì sự thay đồi nào về độ ưu tiên đối với task gọi nó
Trong cách hiện thực tổng quát thì nếu thời gian timeout được thiết lập là 1 thì quá trình xử lý sẽ diễn ra trong thời gian 1giây kể từ khi hàm system call được gọi Do thời gian timeout là 0 thì không được thiết kế (vì 0 được gán cho TMO_POL ) , vì vậy mà theo cách thiết lập thời gian timeout này thì timeout không thể xảy ra ngay lúc khởi tạo thời gian sau khi hàm system call được gọi
3.2.8 Thời gian tương đối và thời gian hệ thống
Khi thời gian xảy ra của một sự kiện được thiết lập liên quan tới thời gian của một sự kiện khác giống như thời gian timeout khi mà một hàm system call được gọi thì thời gian tương đối (có kiểu là RELTIM) được sử dụng đến Nếu thời gian tương đối được sử dụng để chỉ ra thời gian xảy ra sự thực thi của một sự kiện thì nó phải đảm bảo là quá trình xử lý sự kiện đó phải được diễn ra sau khi khoảng thời gian được thiết kế trôi qua kể từ một mốc thời gian nào đó Thời gian tương đối cũng được sử dụng trong trường hợp một sự kiện lặp lại quá trình xử lý sau 1 khoảng thời gian hay có những thiết kế khác cùng với thời gian xảy ra sự thực thi của sự kiện đó Và trong mỗi trường hợp trên thì sẽ có một cách xác định thời gian tương đối riêng
Khi thời gian được thiết kế như thời gian tuyệt đối thì thời gian của hệ thống ( có kiểu là
SYSTIM ) sẽ được sử dụng T-Kernel có cung cấp một hàm dùng để thiết lập thời gian của hệ thống, nhưng ngay cả khi thời gian của hệ thống được thay đổi bằng chính hàm này thì không có bất kì sự thay đổi nào đối với thời gian của thế giới thực mà tại đó thời gian để xảy ra một sự kiện mà nó được thiết kế để sử dụng thời gian tương đối
• SYSTIM : thời gian của hệ thống
Thời gian dựa trên 1 mili giây, có kiểu là số nguyên có dấu 64 bit
typedef struct systim {
W hi; /*32 bit cao */
UW lo; /*32 bit thấp */
}SYSTIM ;
• RELTIM: thời gian tương đối
Thời gian dựa trên 1 mili giây, có kiểu là số nguyên không dấu 32 bit hoặc nhiều hơn typedef UINT RELTIM;
• TMO : thời gian timeout
Thời gian dựa trên 1 mili giây, có kiểu là số nguyên có dấu 32 bit hoặc nhiều hơn
Trang 21typedef INT TMO;
Quá trình chờ mãi mãi có thể được thiết kế với TMO_FEVR (= -1 )
3.3 Thường trình hỗ trợ ngôn ngữ cấp cao
T-Kernel cũng cung cấp các thường trình hỗ trợ ngôn ngữ cấp cao nhằm tách rời quá trình xử lý gắn với hạt nhân và quá trình xử lý gắn với môi trường của ngôn ngữ trong quá trình xử lý một task hay một trình xử lý được viết bằng ngôn ngữ cấp cao
Có hay không việc sử dụng chương trình con hỗ trợ ngôn ngữ cấp cao được thực hiện bằng cách thiết lập biến thuộc tính TA_HLNG của các đối tượng hoặc của các trình xử lý Khi mà
TA_HLNG không được thiết lập thì task hay trình xử lý sẽ bắt đầu sự thực thi trực tiếp của nó tại
địa chỉ mà nó truyền cho hàm tk_cre_tsk hoặc tk_def_??? và ngược lại nếu như TA_HLNG đã
được thiết lập thì thường trình hỗ trợ ngôn ngữ cấp cao sẽ được thực thi trước tiên , và sau đó từ chương trình con này nó sẽ thực hiện nhảy giáng tiếp tới địa chỉ đã được truyền cho hàm
tk_cre_tsk hoặc tk_def_??? Từ quan điểm của hệ điều hành thì địa chỉ bắt đầu sự thực thi của
task hay của trình xử lý chính là các thông số trỏ tới thường trình hỗ trợ ngôn ngữ cấp cao này Việc tách rời giữa quá trình xử lý gắn liền với hạt nhân và quá trình xử lý gắn với môi trường của ngôn ngữ làm cho T-Kernel có khả năng hỗ trợ nhiều ngôn ngữ khác nhau Một lợi ích nữa của việc xử dụng thường trình hỗ trợ ngôn ngữ cấp cao đó là khi ta viết các task hay các trình xử lý bằng ngôn ngữ C thì hàm system call để thoát khỏi task hoặc trở về từ trình xử lý sẽ được thực
thi một cách tự động bằng câu lệnh return hoặc ‘}’ trong C
Cách thức làm việc của thường trình hỗ trợ ngôn ngữ cấp cao sẽ được minh họa cụ thể
trong hình 3.1
Hình 3.1 : Cách thức hoạt động của thường trình hỗ trợ ngôn ngữ cấp cao
Trang 22Chương 4
T-KERNEL / OS FUNTIONS
Chương này mô tả chi tiết các hàm system call do T-kernel Operating System cung cấp kernel/OS)
Trang 23(T-4.1 Quản lý Task
Đây là các hàm system call cho phép ta thao tác hay tham khảo trực tiếp các trạng thái của Task Những hàm được cung cấp để tạo và xoá một Task, khởi động và thoát, huỷ bỏ một yêu cầu khởi động Task, thay đổi độ ưu tiên, và tham khảo trạng thái của một Task Mỗi Task được định danh
bởi một số ID gọi là Task ID
Mỗi Task có một độ ưu tiên cơ bản và độ ưu tiên hiện tại để system kiểm soát thứ tự thực thi của các Task Thông thường khi ta chỉ nói đến độ ưu tiên của Task mà không đề cập loại ưu tiên nào thì ta ngầm hiểu là độ ưu tiên hiện tại Độ ưu tiên cơ bản của một Task được khởi tạo là độ ưu tiên khởi động khi khởi động một Task Khi ta không sử dụng mutex thì độ ưu tiên hiện tại cũng chính là độ ưu tiên cơ bản, do vậy độ ưu tiên hiện tại được khởi tạo trực tiếp là độ ưu tiên khởi động của Task
Kernel không thực hiện công việc giải phóng các tài nguyên do Task yêu cầu (semaphore
resources, memory blocks…) khi thoát Task, công việc này là nhiệm vụ của ứng dụng
Trang 24tk_cre_tsk
Create Task [C Language Interface]
ID tskid = tk_cre_tsk ( T_CTSK * pk_ctsk ) ;
[Parameters]
T_CTSK * pk_ctsk Thông tin về Task được tạo
Chi tiết của pk_ctsk :
VP exinf Thông tin phụ được thêm vào
ATR tskatr Các thuộc tính của Task
FP Task Địa chỉ của Task
PRI itskpri Độ ưu tiên khởi động của Task
INT stksz Kích thước của stack (bytes)
INT sstksz Kích thước của stack hệ thống (bytes)
VP stkptr Pointer chỉ tới stack của người dùng
VP uatb Bảng không gian trang của Task
INT lsid ID không gian luận lý
ID resid ID tài nguyên
E_LIMIT Số lượng Task vượt quá giới hạn của hệ thống
E_RSATR Lỗi thuộc tính
E_NOSPT Chức năng không được cung cấp(khi TA_USERSTACK hay
TA_TASKSPACE không được hỗ trợ) E_PAR Lỗi tham số
E_ID ID tài nguyên (resid) không hợp lệ
E_NOCOP Coprocessor được chỉ định không sử dụng được
[Description]
- Khởi tạo một Task và gán một số ID cho nó Hàm này định vị một TCB (Task Control
Block) để khởi tạo Task dựa theo các tham số itskpri, task, stksz …Trạng thái của Task sau
khi khởi tạo là DORMANT
Trang 25- itskpri chỉ định độ ưu tiên khởi tạo tại thời điểm tạo Task Itskpri có giá trị từ 1 đến 140,
theo thứ tự độ ưu tiên giảm dần
- exinf có thể được sử dụng tự do bởi người dùng để chèn thêm thông tin về Task, và được
tham khảo bằng hàm tk_ref_tsk Nếu thông tin của Task là một vùng lớn, ứng dụng phải
xin cấp phát vùng nhớ riêng biệc và đặt địa chỉ vào exinf
- tskatr cho biết các thuộc tính hệ thống trong các bit thấp của nó và thông tin hiện thực
trong các bit cao
tskatr := (TA_ASM || TA_HLNG)
| [TA_SSTKSZ] | [TA_USERSTACK] | [TA_TASKSPACE] | [TA_RESID]
| (TA_RNG0 || TA_RNG1 || TA_RNG2 || TA_RNG3)
| [TA_COP0] | [TA_COP1] | [TA_COP2] | [TA_COP3] | [TA_FPU]
TA_ASM Cho biết chương trình được viết bằng hợp ngữ
TA_HLNG Cho biết chương trình được viết bằng ngôn ngữ cấp cao
TA_SSTKSZ Cho biết thuộc tính sstksz được sử dụng, nếu TA_SSTKSZ không
được chỉ định thì sstksz sẽ bị bỏ qua và kích thước mặc dịnh sẽ được thiết đặt
TA_USERSTACK Khi thuộc tính này được chỉ định thì sstkptr sẽ hợp lệ Trong
trường hợp này OS không cung cấp stack người dùng nhưng người dùng phải xin cấp phát, và sstksz phải được thiết lập là 0 Nếu
TA_USERSTACK không được chỉ định, sstkptr sẽ bị bỏ qua Nếu
TA_RNG0 được thiết lập thì TA_USERSTACK không thể được chỉ định
TA_TASKSPACE Khi thuộc tính này được chỉ định thì uatb và lisd sẽ hợp lệ và được
thiết lập như là không gian của Task.Nếu TA_TASKSPACE
không được chỉ định, uatb và lisd sẽ bị bỏ qua, không gian của Task sẽ không được định nghĩa Trong suốt thời gian này, ta chỉ truy cập được không gian hệ thống Cho dù TA_TASKSPACE được hay không được chỉ định, không gian Task vẫn có thể được thay đổi sau khi tạo Task
TA_RESID Khi thuộc tính này được chỉ định thì resid sẽ hợp lệ, và chỉ ra
nhóm resources nào mà Task sẽ phụ thuộc
TA_RNGn Cho biết Task chạy ở cấp bảo vệ cấp n
TA_COPn Cho biết có sử dụng Coprocessor thứ n(bao gồm floating point
Coprocessor hay DSP)
TA_FPU Cho biết có sử dụng FPU
#define TA_ASM 0x00000000 /* Assembly program */
#define TA_HLNG 0x00000001 /* High-level language program */
#define TA_SSTKSZ 0x00000002 /* System stack size */
#define TA_USERSTACK 0x00000004 /* User stack pointer */
#define TA_TASKSPACE 0x00000008 /* Task space pointer */
#define TA_RESID 0x00000010 /* Task resource group */
#define TA_RNG0 0x00000000 /* Run at protection level 0 */
#define TA_RNG1 0x00000100 /* Run at protection level 1 */
Trang 26#define TA_COP1 0x00002000 /* Use ID=1 Coprocessor */
#define TA_COP2 0x00004000 /* Use ID=2 Coprocessor */
#define TA_COP3 0x00008000 /* Use ID=3 Coprocessor */
- Khi TA_HLNG được chỉ định, khi Task bắt đầu nó sẽ nhảy đến địa chỉ của Task không trực tiếp mà thông qua sự hỗ trợ của môi trường ngôn ngữ cấp cao Hàm xử lý Task có dạng như sau :
void Task( INT stacd, VP exinf ) {
Những thông số khởi động bao gồm cả mã khởi động Task stacd trong hàm tk_sta_tsk,
và thông tin thêm về Task exinf
Một Task không thể kết thúc bởi một sự trả về đơn giản mà ta phải gọi các hàm khác tùy thưộc vào hiện thực
Định dạng của Task khi TA_ASM được chỉ định phụ thuộc vào sự hiện thực và các thông
số cũng phải dược truyền như là thông số khởi động
- Mỗi Task chạy ở một cấp bảo vệ được chỉ định trong thuộc tính TA_RNGn Khi một hàm
system call hay hàm dịch vụ mở rộng được gọi thì cấp bảo vệ sẽ về 0, và trở lại như cũ khi các hàm được thực hiện xong
- Mỗi Task có hai vùng stack : stack hệ thống và stack người dùng, Stack người dùng được
sử dụng ở cấp bảo vệ được chỉ định trong TA_RNGn, trong khi stack hệ thống được sử dụng ở cấp bảo vệ 0 Khi TA_RNG0 được chỉ định thì cả hai stack sẽ được nhập lại làm
một stack
Trang 27tk_del_tsk
Delete Task [C Language Interface]
ER ercd = tk_del_tsk ( ID tskid ) ;
E_ID tskid không hợp lệ hay không được sử dụng
E_NOEXS Task được chỉ định trong tskid không tồn tại
E_OBJ Trạng thái của Task không phải là DORMANT
[Description]
- Xóa bỏ Task có ID là tskid
- Hàm system call này thay đổi trạng thái của Task từ DORMANT thành NON-EXSTENT (không còn tồn tại trong hệ thống ), giải phóng TCB và vùng stack Task ID cũng được giải phóng Khi trạng thái Task không là DORMANT mà gọi hàm này thì mã lỗi E_OBJ sẽ được trả về
- Hàm này không thể xóa bỏ Task gọi nó, bởi vì Task gọi nó không nằm trong trạng thái
DORMANT Ta sẽ dùng hàm tk_exd_tsk để xóa bỏ chính nó
Trang 28tk_sta_tsk
Start Task [C Language Interface]
ER ercd = tk_sta_tsk ( ID tskid, INT stacd ) ;
E_ID tskid không hợp lệ hay không được sử dụng
E_NOEXS Task được chỉ định trong tskid không tồn tại
E_OBJ Trạng thái của Task không phải là DORMANT
[Description]
- Khởi động Task có ID là tskid
- Hàm system call này thay đổi trạng thái của Task từ DORMANT thành READY Những
thông số được truyền cho Task khi khởi động được thiết lập trong stacd Những thông số
này có thể được tham khảo từ Task được khởi động , có thể sử dụng đặc điểm này cho việc truyền nhận thông điệp đơn giản
- Độ ưu tiên của Task được chỉ định trong thuộc tính itskpri khi khởi tao Task đó
- Các yêu cầu khởi động Task được gọi bởi hàm này không được xếp hàng Nếu Task đích không nằm trong trạng thái DORMANT thì mã lỗi E_OBJ sẽ được trả về cho Task goi hàm này
Trang 29tk_ext_tsk
Exit Task [C Language Interface]
- Khi một Task kết thúc bởi hàm tk_exd_tsk ( ) , những tài nguyên do Task đang nắm giữ sẽ
không tự động được giải phóng, mà người dùng phải tự giải phóng chúng
Trang 30tk_ter_tsk
Terminate Task [C Language Interface]
ER ercd = tk_ter_tsk ( ID tskid ) ;
E_ID tskid không hợp lệ hay không được sử dụng
E_NOEXS Task được chỉ định trong tskid không tồn tại
E_OBJ Trạng thái của Task không phải là DORMANT
[Description]
- Kết thúc sự thực thi của Task có ID là tskid
- Hàm system call này thay đổi trạng thái của Task có ID là tskid thành DORMANT.
- Ngay cả khi Task đích đang ở trạng thái đợi (bao gồm cả trạng thái SUSPEND) hay nằm trong các hàng đợi (semaphore, message …), thì nó được giải phóng khỏi trạng thái đợi và
Trạng thái của Task đích Mã lỗi trả về của tk_ter_tsk Kết quả thực thi của hàm
RUN hoặc READY
(ngoại trừ Task gọi hàm)
E_OK Kết thúc thực thi Task đích
RUN
WAIT E_OK Kết thúc thực thi Task đích
Bảng 4.1: Trạng thái của Task đích và kết quả thực thi (tk_ter_tsk)
- Khi một Task kết thúc bởi hàm tk_ext_tsk ( ) , những tài nguyên do Task đang nắm giữ sẽ
không tự động được giải phóng, mà người dùng phải tự giải phóng chúng
- Khi trạng thái của Task chuyển xuống DORMANT thì độ ưu tiên và những thông tin khác trong TCB sẽ được tái khởi tạo
Trang 31E_ID tskid không hợp lệ hay không được sử dụng
E_NOEXS Task được chỉ định trong tskid không tồn tại
E_PAR Lỗi tham số (tskpri không hợp lệ hay không được dùng)
E_ILUSE tskpri vượt quá giới hạn của hệ thống
[Description]
- Thay đổi độ ưu tiên cơ bản có Task ID la tskid đến giá trị được chỉ định trong tskpri, đồng
thời độ ưu tiên hiện tại của Task cũng thay đổi theo
- Khi TSK_SELF (= 0) được gán cho tskid thì Task đích cũng chính là Task gọi hàm Tuy nhiên , khi tskid = TSK_SELF được chỉ định trong hàm system call được gọi từ một Task-
independent portion, thì mã lỗi E_ID sẽ được trả về
- Khi TPRI_INI (= 0) được gán cho tskpri, thì độ ưu tiên cơ bản của Task đích bị thay dổi
về giá trị khởi tạo khi Task được bắt đầu thực thi ( itskpri )
- Độ ưu tiên bị thay đổi bởi hàm này vẫn có giá trị cho tới khi Task bị kết thúc (terminated) Khi một Task trở lại trạng thái DORMANT, độ ưu tiên của Task trước khi thoát bị loại bỏ
và khi đó nó sẽ được thiết lập lại giá trị khởi tạo khi Task dó được bắt đầu thực thi ( itskpri
) Tuy nhiên sự thay đổi độ ưu tiên trong khi Task đang ở trong trạng thái DORMANT sẽ
có hợp lệ khi nó được khởi động vào lần kế tiếp
Trang 32E_ID tskid không hợp lệ hay không được sử dụng
E_NOEXS Task được chỉ định trong tskid không tồn tại
E_PAR Lỗi tham số (slicetime không hợp lệ hay không được dùng)
[Description]
- Thay đổi khe thời gian của một Task có Task ID la tskid bằng giá trị được chỉ định trong
slicetime, chức năng khe thời gian được sử dụng trong việc định thời các Task theo Round
Robin Khi một Task thực thi liên tục trong một khoảng thời gian là slicetime hay dài hơn ,
độ ưu tiên (thứ tự thực thi trước sau) của nó chuyển về thấp nhất giữa các Task có cùng độ
ưu tiên (Priority), và tự động nhường sự thực thi cho Task kế tiếp
- Thiết lập slicetime = 0 cho biết thời gian không giới hạn, và Task sẽ không tự động nhường
sự thực thi của nó cho Task khác
- Khi một Task được khởi tạo thì slicetime của nó được thiết lập mặc định là 0
- Khi TSK_SELF (= 0) được gán cho tskid thì Task đích cũng chính là Task gọi hàm Tuy nhiên , khi tskid = TSK_SELF được chỉ định trong hàm system call được gọi từ một Task-
independent portion, thì mã lỗi E_ID sẽ được trả về
- Khe thời gian bị thay đổi bởi hàm này vẫn có giá trị cho tới khi Task bị kết thúc
(terminated) Khi một Task trở lại trạng thái DORMANT, khe thời gian của Task trước khi thoát bị loại bỏ và khi đó nó sẽ được thiết lập lại giá trị khởi tạo khi Task đó được bắt đầu
thực thi ( slicetime = 0 ) Tuy nhiên sự thay đổi độ ưu tiên trong khi Task đang ở trong
trạng thái DORMANT sẽ có hợp lệ khi nó được khởi động vào lần kế tiếp
- Một Task bị tước đoạt sự thực thi bởi một Task có độ ưu tiên cao hơn thì thời gian thực thi của nó sẽ bị bỏ qua và chỉ được đếm lại từ đầu trong lần thực thi kế tiếp
- Nếu Task đích là Task duy nhất đang thực thi tại độ ưu tiên của nó thì khe thời gian sẽ không có ý nghĩa, và Task đó được thực thi liên tục
- Nếu trong nhiều Task có cùng độ ưu tiên có một Task mà slicetime = 0, thì Task đó sẽ
được thực thi ngay khi có thể và định thời theo Round Robin cũng kết thúc
Trang 33ER ercd Mã lỗi (Error Codes)
T TSKSPC tskspc Thông tin về không gian của Task
E_ID tskid không hợp lệ hay không được sử dụng
E_NOEXS Task được chỉ định trong tskid không tồn tại
E_PAR Lỗi tham số (địa chỉ trả về không dùng được)
[Description]
- Thu thập thông tin hiện tại của một Task có Task ID la tskid
- Khi TSK_SELF (= 0) được gán cho tskid thì Task đích cũng chính là Task gọi hàm Tuy nhiên , khi tskid = TSK_SELF được chỉ định trong hàm system call được gọi từ một Task-
independent portion, thì mã lỗi E_ID sẽ được trả về
Trang 34E_ID tskid không hợp lệ hay không được sử dụng
E_NOEXS Task được chỉ định trong tskid không tồn tại
E_PAR Lỗi tham số (địa chỉ trả về không dùng được)
[Description]
- Thiết lập thông tin hiện tại của một Task có Task ID la tskid
- Khi TSK_SELF (= 0) được gán cho tskid thì Task đích cũng chính là Task gọi hàm Tuy nhiên , khi tskid = TSK_SELF được chỉ định trong hàm system call được gọi từ một Task-
independent portion, thì mã lỗi E_ID sẽ được trả về
- OS không quan tâm đến hậu quả của những thay đổi không gian Task Ví dụ, không gian của một Task bị thay đổi trong khi Task đó đang sử dụng nó để thực thi thì Task đó có thể
bị treo hay đụng độ những vấn đề khác Chương trình phải có trách nhiệm tránh những vấn
đề trên
Trang 35ID resid ID của nhóm tài nguyên
hoặc Mã lỗi (Error Code)
[Error Codes]
E_OK Kết thúc bình thường
E_ID tskid không hợp lệ hay không được sử dụng
E_NOEXS Task được chỉ định trong tskid không tồn tại
E_OBJ Task không phụ thuộc một nhóm tài nguyên nào
[Description]
- Trả về ID của nhóm tài nguyên của một Task có Task ID là tskid thuộc về
- Khi TSK_SELF (= 0) được gán cho tskid thì Task đích cũng chính là Task gọi hàm Tuy nhiên , khi tskid = TSK_SELF được chỉ định trong hàm system call được gọi từ một Task-
independent portion, thì mã lỗi E_ID sẽ được trả về
- Nếu nhóm tài nguyên đó đã bị xóa bỏ , thì hàm system call này có thể trả về ID của nhóm tài nguyên đã bị xóa Mã lỗi E_OBJ được trả về hay không là phụ thuộc vào sự hiện thực
(Xem tk_cre_res, tk_del_res )
Trang 36ID oldid ID của nhóm tài nguyên cũ
hoặc Mã lỗi (Error Code)
[Error Codes]
E_OK Kết thúc bình thường
E_ID tskid không hợp lệ hay không được sử dụng
E_NOEXS Task được chỉ định trong tskid hay resid không tồn tại
[Description]
- Thay đổi nhóm tài nguyên hiện tại của một Task có Task ID là tskid bằng một nhóm tài
nguyên mới có ID là resid, đồng thời trả về giá trị ID của nhóm tài nguyên cũ
- Khi TSK_SELF (= 0) được gán cho tskid thì Task đích cũng chính là Task gọi hàm Tuy
nhiên , khi tskid = TSK_SELF được chỉ định trong hàm system call được gọi từ một
Task-independent portion, thì mã lỗi E_ID sẽ được trả về
- Trong một số trường hợp lỗi không được trả về cho dù resid đã bi xóa Mã lỗi E_NOEXS
được trả về hay không là phụ thuộc vào sự hiện thực Theo nguyên tắc thì chương trình gọi
không được chỉ định nhóm tài nguyên mới là nhóm đã bị xóa bỏ
Trang 37T_REGS pk_regs Thanh ghi công dụng chung
T_EIT pk_eit Lưu các thanh ghi khi EIT xảy ra
T_CREGS pk_cregs Thanh ghi điều khiển
ER ercd Mã lỗi
Nội dung của T_REGS, T_EIT, và T_ CREGS được định nghĩa cho mỗi CPU và sự hiện thực
[Error Codes]
E_OK Kết thúc bình thường
E_ID tskid không hợp lệ hay không được sử dụng
E_NOEXS Task được chỉ định trong tskid không tồn tại
E_OBJ Trạng thái của đối tượng không hợp lệ ( gọi cho Task gọi hàm)
E_CTX Lỗi ngữ cảnh ( gọi từ Task-independent portion)
[Description]
- Thu thập nội dung các thanh ghi của một Task có Task ID là tskid
Trang 38T_REGS pk_regs Thanh ghi công dụng chung
T_EIT pk_eit Lưu các thanh ghi khi EIT xảy ra
T_CREGS pk_cregs Thanh ghi điều khiển
E_ID tskid không hợp lệ hay không được sử dụng
E_NOEXS Task được chỉ định trong tskid không tồn tại
E_OBJ Trạng thái của đối tượng không hợp lệ ( gọi cho Task gọi hàm)
E_CTX Lỗi ngữ cảnh ( gọi từ Task-independent portion)
E_PAR Giá trị các thanh ghi không hợp lệ ( phụ thuộc vào sự hiện thực)
[Description]
- Thiết lập nội dung các thanh ghi của một Task có Task ID là tskid
Trang 39Nội dung của T_COPnREG được định nghĩa cho mỗi CPU và sự hiện thực
[Error Codes]
E_OK Kết thúc bình thường
E_ID tskid không hợp lệ hay không được sử dụng
E_NOEXS Task được chỉ định trong tskid không tồn tại
E_OBJ Trạng thái của đối tượng không hợp lệ ( gọi cho Task gọi hàm)
E_CTX Lỗi ngữ cảnh ( gọi từ Task-independent portion)
E_PAR Lỗi tham số
[Description]
- Thu thập nội dung các thanh ghi được chỉ định trong copno của một Task có Task ID là
tskid
Trang 40INT copno Số Coprocessor (0 to 3)
T_COPREGS pk_copregs Thanh ghi Coprocessor
[Return Parameters]
ER ercd Mã lỗi
[Error Codes]
E_OK Kết thúc bình thường
E_ID tskid không hợp lệ hay không được sử dụng
E_NOEXS Task được chỉ định trong tskid không tồn tại
E_OBJ Trạng thái của đối tượng không hợp lệ ( gọi cho Task gọi hàm)
E_CTX Lỗi ngữ cảnh ( gọi từ Task-independent portion)
E_PAR Lỗi tham số
[Description]
- Thiết lập nội dung các thanh ghi được chỉ định trong copno của một Task có Task ID là
tskid