Глава 19 Переносимость

Глава 19

Переносимость

Linux — переносимая операционная система, которая поддерживает большое количество различных компьютерных аппаратных платформ. Переносимость— это свойство, которое указывает, насколько легко можно перенести код, который выполнялся на одной аппаратной платформе, для выполнения на другой аппаратной платформе (если вообще это возможно). Известно, что ОС Linux является переносимой операционной системой, поскольку ее уже перенесли (портировали) на большое количество различных аппаратных платформ. Тем не менее переносимость не возникает сама по себе, для выполнения она требует большого количества проектных решений. Сегодня процесс перенесения ОС Linux на другую аппаратную платформу достаточно прост (в относительном смысле, конечно). В этой главе рассказывается о том, как писать переносимый код, — вопрос, о котором всегда необходимо помнить при написании нового кода ядра или драйверов устройств.

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

С противоположной стороны можно поставить операционные системы, в которых оптимизация кода выполняется в ущерб переносимости. Код, по возможности, пишется на языке ассемблера или специфические свойства аппаратных платформ используются каким-либо другим образом. Свойства ядра разрабатываются на основании свойств аппаратной платформы. В этом случае перенос операционной системы на другую аппаратную платформу сводится к написанию ядра с нуля. Оптимальность выполняется в ущерб переносимости. Примером таких систем могут быть DOS и Windows 9x. Сегодня таким системам нет необходимости иметь более оптимальный код, чем переносимым операционным системам, однако они предоставляют возможность в максимальной степени использовать ручную оптимизацию кода.

Операционная система Linux в плане переносимости занимает промежуточное положение. Насколько это целесообразно из практических соображений, интерфейсы и код сохраняются независимыми от аппаратной платформы и пишутся на языке С. Однако функции ядра, которые критичны к производительности, выполняются зависимыми от аппаратной платформы. Например, низкоуровневый код и код, который должен выполняться очень быстро, разрабатывается зависимым от аппаратной платформы и обычно на языке ассемблера. Такой подход позволяет сохранить переносимость ОС Linux и при этом воспользоваться оптимизациями.

В случаях, когда переносимость становится помехой производительности, производительность обычно всегда побеждает. В остальных случая сохраняется переносимость кода.

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

Хороший пример — планировщик. Большая часть планировщика написана независимым от аппаратной платформы образом на языке С. Реализация находится в файле kernel/sched.c. Некоторые из функций планировщика, такие как переключение состояния процессора или переключение адресного пространства, очень сильно зависят от аппаратной платформы. Следовательно, функция context_switch(), которая переключает выполнение от одного процесса к другому и написана на языке С, вызывает функции switch_to() и switch_mm() для переключения состояния процессора и переключения адресного пространства соответственно.

Код функций switch_to() и switch_mm() выполнен отдельно для каждой аппаратной платформы, которую поддерживает операционная система Linux. Когда операционная система Linux портируется на новую аппаратную платформу, то для новой аппаратной платформы просто необходимо реализовать эти функции.

Файлы, которые относятся к определенной аппаратной платформе, находятся в каталоге arch/<аппаратная платформа>/ и include/asm-<аппаратная платформа>/, где <аппаратная платформа> — это короткое имя, которое представляет аппаратную платформу, поддерживаемую ядром Linux. Например, аппаратной платформе Intel x86 присвоено имя i386. Для этого типа машин файлы находятся в каталогах arch/i386 и include/asm-i386. Ядра серии 2.6 поддерживают следующие аппаратные платформы: alpha, arm, cris, h8300, i38, ia64, m68k, m68knommu, mips, mips64, parisc, ppc, ppc64, s390, sh, spare, sparc64, um, v850 и x86-64. Более полное описание приведено в табл. 19.1.