Làm thế nào để nhân Linux tìm ra quá trình nào để thức dậy trong quá trình xử lý ngắt?


7

Tôi đã đọc cuốn sách Phát triển hạt nhân Linux về Lập kế hoạch chương trình . Trên trang 61, phần Thức dậy , đoạn đầu tiên ghi:

Việc đánh thức được xử lý thông qua Wake_up (), đánh thức tất cả các nhiệm vụ đang chờ trên hàng đợi chờ đã cho. ( Q1 : này những gì hiện ittham khảo ?) Gọi try_to_wake_up (), thiết lập của nhiệm vụ ( Q2 : ? Mà nhiệm vụ tất cả các nhiệm vụ đánh thức ) nhà nước để TASK_RUNNING, gọi điện enqueue_task () để thêm các nhiệm vụ để cây đỏ-đen, và đặt Need_resched nếu mức ưu tiên của tác vụ được đánh thức cao hơn mức ưu tiên của tác vụ hiện tại. Mã gây ra sự kiện thường xảy ra thường gọi chính thức Wake_up (). Ví dụ, khi dữ liệu đến từ đĩa cứng, VFS gọi Wake_up () trên hàng đợi chờ giữ các quá trình chờ dữ liệu.

Tôi khá bối rối về những điều trên. Hãy để tôi chỉ sử dụng ví dụ trong đoạn văn trên, tức là đĩa bị gián đoạn sau khi đọc dữ liệu, nhưng với một hình ảnh đầy đủ hơn. Vui lòng sửa cho tôi nếu bất kỳ điều nào sau đây là sai hoặc không đầy đủ:

  1. Một số quy trình người dùng đã ban hành một hoạt động đọc chặn, kích hoạt một cuộc gọi sys và quá trình này nằm trong địa hạt nhân.

  2. Kernel thiết lập bộ điều khiển đĩa yêu cầu dữ liệu cần thiết và đưa quá trình này vào chế độ ngủ (quá trình này được đưa vào hàng đợi). Kernel lên lịch một quá trình khác để chạy.

  3. Ngắt đĩa xảy ra. CPU tạm dừng quá trình thực thi hiện tại và nhảy vào xử lý ngắt đĩa.

  4. Bộ điều khiển đĩa đôi khi sẽ khởi động trong quá trình xử lý ngắt để chuyển dữ liệu đọc từ đĩa sang bộ nhớ chính (theo hướng của CPU hoặc bởi DMA)

  5. (Không chắc chắn, vui lòng sửa lại) Như đoạn văn đã nói, VFS gọi Wake_up () trên hàng đợi chờ chứa các quá trình chờ dữ liệu.

Câu hỏi cụ thể của tôi là như sau:

Q1 (tham khảo đoạn trích dẫn): Tôi giả sử It trong câu thứ hai đề cập đến chức năng wake_up(). Tại sao chức năng wake_upđánh thức tất cả các tác vụ thay vì chỉ chờ dữ liệu đĩa này?

Câu 2 (tham khảo đoạn trích dẫn): try_to_wake_up()Bằng cách nào đó có biết nhiệm vụ cụ thể mà trạng thái cần được đặt thành TASK_RUNNING không? Hoặc try_to_wake_up()đặt trạng thái của tất cả các nhiệm vụ được đánh thức thành TASK_RUNNING?

Câu 3 : Có bao nhiêu hàng đợi để nhân quản lý? Nếu có nhiều hơn 2 hàng đợi như vậy, làm thế nào để kernel biết hàng đợi nào được chọn, sao cho quá trình chờ dữ liệu đĩa nằm trên hàng đợi đó?

Q4 : Bây giờ hãy nói rằng chúng tôi biết hàng đợi nơi quá trình chờ đợi được bật. Làm thế nào để kernel biết quá trình nào đang chờ dữ liệu từ đĩa. Tôi chỉ có thể hình ảnh rằng một số thông tin cụ thể cho quá trình yêu cầu dữ liệu đĩa được chuyển đến bộ điều khiển đĩa, như PID, địa chỉ bộ nhớ hoặc một cái gì đó. Sau đó, khi hoàn thành việc xử lý ngắt, bộ điều khiển đĩa (hoặc kernel?) Sử dụng thông tin này để xác định chính xác quy trình trên hàng đợi.

Xin hãy giúp tôi hoàn thành bức tranh về quá trình Wake_up này! Cảm ơn!

Câu trả lời:


7

Q1: “Nó” là wake_up. Nó đánh thức tất cả các tác vụ đang chờ dữ liệu đĩa . Nếu họ không đợi dữ liệu đó, họ sẽ không đợi trên hàng đợi đó.

Q2: Tôi không chắc là tôi hiểu câu hỏi. Mỗi mục hàng đợi đánh thức chứa một con trỏ đến nhiệm vụ. try_to_wake_upnhận được một con trỏ đến nhiệm vụ mà nó phải thức dậy. Nó được gọi một lần cho mỗi chức năng.

Câu 3: Có rất nhiều hàng đợi. Có một cho mọi sự kiện có thể xảy ra. Trình điều khiển đĩa thiết lập một hàng đợi cho mỗi yêu cầu vào đĩa. Ví dụ, khi trình điều khiển hệ thống tệp muốn nội dung của một khối đĩa nhất định, nó sẽ yêu cầu trình điều khiển đĩa cho khối đó và sau đó yêu cầu bắt đầu với tác vụ thực hiện yêu cầu hệ thống tệp. Các mục khác có thể được thêm vào hàng đợi nếu yêu cầu khác cho cùng một khối xuất hiện trong khi yêu cầu này vẫn còn tồn tại.

Khi xảy ra gián đoạn, trình điều khiển đĩa xác định đĩa nào có dữ liệu có sẵn từ thông tin được truyền bởi phần cứng và tra cứu cấu trúc dữ liệu chứa dữ liệu kernel cho đĩa này để tìm yêu cầu nào cần điền. Trong cấu trúc dữ liệu này, trong số những người khác, là vị trí ghi dữ liệu và hàng đợi đánh thức tương ứng cho biết phải làm gì tiếp theo.

Q4: Quá trình thực hiện cuộc gọi hệ thống, giả sử đọc tệp. Điều này kích hoạt một số mã trong trình điều khiển hệ thống tập tin xác định rằng dữ liệu cần phải được tải từ đĩa. Mã đó tạo một yêu cầu cho trình điều khiển đĩa và thêm quy trình gọi vào hàng đợi chờ của yêu cầu. (Thực tế có nhiều lớp hơn thế, nhưng bạn có ý tưởng.) Khi đọc xong đĩa, sự kiện hàng đợi chờ kích hoạt và do đó quá trình được xóa khỏi hàng đợi chờ của đĩa. Mã được kích hoạt bởi sự kiện hàng đợi là một chức năng được cung cấp bởi trình điều khiển hệ thống tập tin, sao chép dữ liệu vào bộ nhớ của quy trình và khiến readcuộc gọi hệ thống trở lại.


Tôi giả sử có thể có nhiều quá trình trên hàng đợi của đĩa. Khi đọc xong đĩa, quá trình nào được loại bỏ khỏi hàng đợi chờ của đĩa? Mặt trước của hàng đợi?
Giàu

@Rich Tất cả bọn họ. Vâng, tất cả những người đã đọc xong. Tôi không biết các trình điều khiển đĩa được tổ chức chính xác như thế nào: liệu có một hàng đợi chờ cho đĩa (với tất cả các quy trình đang chờ đĩa) hay một cho mỗi yêu cầu (mỗi quy trình đang chờ cho khu vực cụ thể đó).
Gilles 'SO- ngừng trở thành ác quỷ'

OH? Nhưng điều gì sẽ xảy ra nếu dữ liệu đọc từ đĩa chỉ dành riêng cho một trong quá trình trên hàng đợi?
Giàu

Vì vậy, công việc của trình điều khiển đĩa là tìm ra yêu cầu của quy trình nào được thực hiện? Có thể xảy ra rằng chỉ một số quy trình đang chờ trong hàng đợi có thể được đánh thức, do các yêu cầu của các quy trình khác không được thực hiện hoàn toàn? Tôi đoán sự nhầm lẫn chung của tôi là wake_upđánh thức tất cả các quy trình nhưng cuối cùng có thể chỉ một tập hợp con của các quy trình là thực sự có thể chạy được.
Giàu

@Rich Có nhiều điều kiện có thể làm cho một quá trình không thể chạy được, ví dụ nếu nó bị treo. Tôi không biết rõ về nhân Linux đủ để biết liệu chúng có bị xóa khỏi hàng đợi chờ của đĩa hay không trong trường hợp đó; Tôi nghĩ rằng chúng thường như vậy, bởi vì nếu không thì hàng đợi và tất cả các hàng đợi tương tự sẽ có xu hướng lấp đầy các quy trình không thể đánh thức và điều đó sẽ làm giảm hiệu suất. Nói chung, là một nhà thiết kế hệ điều hành, bạn không muốn các quá trình bị đánh thức một cách không cần thiết; chúng tôi cố gắng để điều đó chỉ xảy ra trong điều kiện cuộc đua (khi lý do thức dậy vừa mới biến mất).
Gilles 'SO- ngừng trở thành ác quỷ'

2

Để xây dựng dựa trên câu trả lời của Gilles,

Câu 2 : Tôi không chắc, nhưng tôi sẽ diễn giải đoạn văn trong cuốn sách có nghĩa là trình xử lý ngắt gọi wake_up() một lần (chuyển định danh hàng đợi làm đối số) và wake_up() gọi try_to_wake_up()cho mỗi quy trình trên hàng đợi đó. (Điều này nhắc lại câu trả lời của Gilles cho Q1 : nó không đánh thức tất cả các nhiệm vụ, chỉ là những nhiệm vụ nằm trong hàng chờ liên quan đến sự kiện được gọi wake_up().)

Câu 3 : Mỗi hàng đợi được sở hữu bởi một số mã hạt nhân - chủ yếu là trình điều khiển thiết bị, một số khác. Thói quen sở hữu một hàng đợi gán cho nó một định danh duy nhất, dựa trên một số đặc điểm duy nhất của sự kiện mà hàng đợi dành cho. Khi nó (trình điều khiển / mô-đun khác) đặt một quá trình để ngủ, nó chỉ định (bằng ID) hàng đợi để đặt nó vào. Thói quen gọi wake_up()(thường là một trình xử lý ngắt) phải là một phần của cùng một mô-đun đưa tiến trình vào trạng thái ngủ, để nó biết định danh cho hàng đợi tương ứng với sự kiện đã xảy ra.

Lần trước tôi đã xem mã nguồn hạt nhân Unix (cách đây nhiều năm), các trình điều khiển đĩa có ID sự kiện khác nhau cho mỗi yêu cầu I / O. Như Gilles nói, nhiều quá trình có thể chờ đợi cùng một sự kiện nếu chúng đang đọc cùng một tệp cùng một lúc. (Tất nhiên, điều này cũng liên quan đến Q1 .)

Q4 : Khi tôi nghe cụm từ Bộ điều khiển đĩa trên đĩa cứng, tôi nghĩ về phần cứng. Nhưng, ngoài điều đó, bạn đúng; trình điều khiển đĩa (một mô-đun phần mềm trong kernel) (ít nhất có khả năng) truy cập vào tất cả thông tin về bất kỳ quy trình nào gọi nó (nghĩa là bằng cách thực hiện I / O trên đĩa). Vì vậy, khi trình điều khiển đĩa đặt một tiến trình vào chế độ ngủ vì nó đã khởi tạo một I / O vật lý cần có thời gian để hoàn thành, nó (trình điều khiển) sẽ đặt ra cho bộ xử lý PID, địa chỉ bộ nhớ hoặc một thứ gì đó vào hàng đợi. Dù đây là gì, nó cũng đủ try_to_wake_up()để đánh thức quá trình.


Câu cuối cùng của đoạn văn mà bạn đã trích dẫn nói, Vạn ngữ VFS gọi Wake_up () trong hàng đợi chờ đợi Hồi. Tôi đặt câu hỏi liệu điều này có đúng theo nghĩa đen không. Mã hệ thống tập tin là một lớp trên trình điều khiển đĩa. Tôi hy vọng ngắt (tín hiệu từ phần cứng đĩa tới CPU) sẽ được xử lý bởi trình xử lý ngắt đĩa (một phần của trình điều khiển đĩa) sẽ đánh thức (các) quá trình đang chờ (bằng cách gọi wake_up()). Trình điều khiển sau đó sẽ đánh thức mã hệ thống tập tin. (Thuật ngữ này cũng có thể không chính xác. Tốt hơn là nên nói rằng trình điều khiển làm gì đó để cho phép mã hệ thống tập tin tiếp tục xử lý.) Mã hệ thống tập tin có thể quay lại quy trình người dùng hoặc có thể gọi lại trình điều khiển đĩa, dẫn đến quá trình được đưa vào giấc ngủ một lần nữa.

Tôi ngụy biện với bước 4 của bạn. Nếu một thiết bị đang sử dụng DMA, thiết bị sẽ không bị gián đoạn cho đến khi quá trình truyền dữ liệu hoàn tất.


1

Vấn đề bạn nêu ra, đánh thức tất cả các quy trình đang chờ đợi là vấn đề được gọi là vấn đề "sấm sét" (nhiều quy trình được đánh thức khi có tài nguyên, họ chiến đấu để ai đó có quyền truy cập độc quyền vào tài nguyên, những người khác quay lại ngủ ). Điều này trở thành một vấn đề khi có nhiều bộ xử lý, và do đó có nhiều bộ xử lý chiến đấu ở đây. Các phiên bản mới hơn của Linux giải quyết điều này bằng cách đánh thức một trong các quy trình đang chờ.

Hầu hết thời gian sẽ có một (hoặc chỉ một vài) quá trình chờ đợi một sự kiện cụ thể (không có số lượng sự kiện cố định, nhỏ hơn nhiều, trong đó một quá trình có thể chờ).

Câu trả lời của Gilles đi qua từng điểm của bạn, không có gì nhiều để thêm vào đó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.