Современные операционные системы являются сложными программными комплексами, которые обеспечивают взаимодействие между пользовательскими приложениями и аппаратным обеспечением. Центральную роль в этом процессе играют системные вызовы — интерфейс, через который приложения обращаются к возможностям ядра ОС, например, для работы с файлами, управления процессами или сетевых операций. Традиционно считается, что системные вызовы возвращают одно значение, как правило, числовое, которое либо обозначает успешность операции, либо код ошибки. Однако на практике ядра операционных систем могут возвращать сразу несколько значений за один вызов, что исторически было доступно еще в Unix и других системах, и при этом современные ограничения часто связаны не с самим ядром, а с особенностями языков программирования, в частности, языка C. Исторически Unix для передачи параметров системных вызовов и их результатов опирался на регистры процессора, поскольку доступ к ним был значительно быстрее, чем работа с памятью пользователя.
Различные архитектуры процессоров предоставляют множество регистров, в которые можно поместить не только аргументы вызова, но и возвращаемые значения. Например, на платформе PDP-11 использовались два регистра — r0 и r1 — для возврата двух значений сразу. В знаменитой версии Unix V7 системные вызовы pipe(), getuid(), getgid(), getpid() и wait() возвращали второй результат именно через регистр r1. Это позволяло эффективно передавать в процесс возвращаемые данные, сокращая необходимость дополнительного копирования и упрощая обработку информации. Такой подход демонстрирует, что ядра операционных систем не имели жестких технических барьеров для возврата множества значений за один вызов, и ограничение скорее носило принципиальный характер, связанный с дизайном прикладного интерфейса и языков программирования.
Язык C, который заложил основу для разработки Unix и множества других систем, не имел встроенной поддержки множественных возвращаемых значений из функций. Это привело к тому, что системные вызовы Unix, как и многие другие, возвращали только одно значение, обычно указывающее на успех или код ошибки, а остальные данные передавались через указатели, ссылающиеся на область в памяти пользователя. Такой подход, несмотря на свою распространенность, обладает недостатками, такими как более высокая сложность обработки ошибок и необходимость постоянного чтения или записи дополнительных данных в пользовательскую память, что сказывается на производительности. Вместо этого, если бы системные вызовы могли возвращать несколько значений напрямую через регистры процессора, было бы возможным повысить эффективность взаимодействия между ядром и пользовательским пространством, а также более элегантно конструировать интерфейсы системных вызовов. В последние годы, с развитием новых языков программирования, которые поддерживают множественные возвращаемые значения напрямую — например, Go, Rust, Swift или современные версии Python — появляется концептуальная возможность пересмотреть интерфейсы системных вызовов, чтобы они могли нативно возвращать несколько значений.
Обновленные системные вызовы могли бы предоставлять первое значение как код успешности или ошибку, а за ним следовать дополнительные данные, варьирующиеся в зависимости от специфики вызова. Такой подход мог бы устранить ограничения, присущие errno в Unix — механизме передачи ошибок, используемом во множестве операционных систем. В системе errno ошибка передается отдельно от основного возвращаемого значения, что не всегда эффективно и порождает неоднозначности, особенно при сложных системных взаимодействиях. В современном мире возросшего спроса на производительность и надежность систем, внедрение многоуровневых или множественных значений из системных вызовов выглядит как логичная эволюция. Несмотря на это, сегодня практически ни одна широко используемая операционная система не использует такой механизм на системном уровне.
Причина кроется в преобладании устоявшихся стандартов, обратной совместимости и ограничениях ABI — интерфейса двоичного приложения. Любые изменения в системных вызовах требуют тщательного планирования, чтобы избежать масштабных сбоев и несовместимостей. Тем не менее, экспериментальные или специализированные системы, а также проекты исследовательских операционных систем могут внедрять подобные идеи, что в будущем, возможно, позволит увидеть переход к более гибким и мощным интерфейсам. Различные архитектуры процессоров предоставляют средства для параллельной передачи данных через регистры — от x86 с его множеством регистров общего назначения до ARM с расширенными многочисленными регистрами. Современные модели процессоров допускают использование нескольких регистров для передачи данных без значительных потерь производительности.
Соответственно, системные вызовы могут быть разработаны так, чтобы использовать эти аппаратные возможности максимально эффективно. Не менее важна сторона безопасности и управления памятью, где системные вызовы играют роль стража, контролирующего взаимодействие приложения с ядром. Возможность возвращать несколько значений также потенциально влияет на архитектуру механизмов контроля доступа и обработки ошибок, обеспечивая более детализированную и надежную информацию. В итоге, возвращение множественных значений из системных вызовов — это не столько техническое ограничение, сколько вопрос парадигмы и стандартов, сложившихся в истории развития операционных систем и языков программирования. Со временем, когда возрастут требования к эффективности и удобству разработки, а языки станут более продвинутыми в плане обработки множественных возвращаемых значений, возможно постепенное переосмысление системных интерфейсов.
Разработчики и исследователи ПО уже сегодня могут использовать опыт и идеи прошлого, подкрепленные современными возможностями аппаратного и программного обеспечения, чтобы создать новые, более гибкие и мощные операционные системы. В такой системе системные вызовы станут не просто механизмом передачи ошибки или одного результата, а комплексным инструментом получения множества данных и состояний за минимальное количество обращений, что повысит быстродействие, удобство и качество работы приложений. Таким образом, концепция множественных возвращаемых значений из системных вызовов открывает перспективы для революционных изменений в архитектуре операционных систем, делая их более адаптивными к современным вызовам и потребностям, а также максимально используя потенциал аппаратуры.