Как работает sched_setaffinity()?

Я пытаюсь понять, как работает linux syscall sched_setaffinity(). Это продолжение моего вопроса здесь.

У меня это руководство, в котором объясняется, как использовать syscall и имеет довольно аккуратный (рабочий!) пример.

Итак, я загрузил Linux 2.6.27.19 источники ядра.

Я сделал "grep" для строк, содержащих этот syscall, и получил 91 результат. Не обещаю.

В конечном счете, я пытаюсь понять, как ядро ​​может установить указатель инструкции для определенного ядра (или процессора.)

Я знаю, как работают одноядерные однопоточные программы. Можно было бы выпустить инструкцию jmp foo, и это в основном устанавливает IP-адрес в адрес памяти метки "foo". Но когда у вас есть несколько ядер, нужно сказать: "Принесите следующую команду в адрес памяти foo и установите указатель инструкции для ядра номер 2, чтобы начать там выполнение".

Где в коде сборки мы указываем, какое ядро ​​выполняет эту операцию?

Вернуться к коду ядра: что здесь важно? Файл 'kernel/sched.c' имеет функцию sched_setaffinity(), но возвращает тип long, который не соответствует его странице руководства. Итак, что здесь важно? На каком из этих модулей отображаются инструкции по сборке? Какой модуль читает "task_struct", глядя на член "cpus_allowed", а затем переводим его в инструкцию? (Я также просмотрел источник glibc, но я думаю, что он просто делает вызов кода ядра для выполнения этой задачи.)

Ответ 1

sched_setaffinity() просто сообщает планировщику, что процессоры - это процесс/поток, разрешенный для запуска, а затем вызывает перерасчет.

Планировщик фактически работает на каждом из процессоров, поэтому у него появляется возможность решить, какую задачу выполнить дальше на этом конкретном процессоре.

Если вам интересно, как вы можете называть какой-то код на других процессорах, я предлагаю вам взглянуть на smp_call_function_single(). Если мы хотим вызвать что-то на другом CPU, это вызывает generic_exec_single(). Последний просто добавляет функцию в целевую очередь целевого процессора и заставляет перепланировать через некоторый IPI (если очередь была пуста).

Нижняя строка: нет реального варианта SMP команды _jmp_. Вместо этого код, работающий на других ЦП, взаимодействует для выполнения задачи.

Ответ 2

Я думаю, что вы не понимаете, что ядро ​​работает на всех ядрах процессора. При каждом прерывании таймера (~ 1000 в секунду) планировщик запускается на каждом CPU и выбирает процесс для запуска. Нет ни одного процессора, который каким-то образом подсказывает другим начать процесс. sched_setaffinity() работает, просто устанавливая флаги в процессе. Планировщик читает эти флаги и не будет запускать этот процесс на своем CPU, если он установлен не.

Ответ 3

Где в коде сборки мы указываем, какое ядро ​​выполняет эту операцию?

Здесь нет сборки. Каждая задача (поток) назначается одному процессору (или ядру в ваших терминах) за раз. Чтобы перестать работать на заданном CPU и возобновить работу на другом, задача должна " migrate" (также this). Когда задача переносится с одного процессора на другой, планировщик выбирает процессор, который более неактивен среди процессоров, разрешенных sched_setaffinity().

Нет никаких инструкций по сборке магии. Ядро имеет более низкоуровневое представление о оборудовании, каждый процессор представляет собой отдельный объект, очень отличающийся от того, как он выглядит для процессов пользовательского пространства (в пользовательском пространстве процессоры почти невидимы).