Найти тему
Hub of my knowlege

Как пользоваться системными вызовами в языке Golang?

Оглавление
Разбор части пакета syscall в языке Golang
Разбор части пакета syscall в языке Golang

Как все начиналось

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

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

Быстро про системные вызовы

Системный вызов - это обращение к ядру операционной системы. С помощью них наши программы могут планировать процессы, создавать каналы взаимодействия друг с другом и много чего ещё интересного.

В данной статье я рассмотрю следующие системные вызовы:

  • fork() - создание нового процесса с тем же исполняемым кодом, что и родительском процессе. Причем продолжение обоих процессов продолжится с того места, где был вызван syscall
  • exec() - меняет исполняемый код процесса на другой

Обёртки над системными вызовами

В пакете syscall есть разные реализации приведенных выше системных вызовов.

ForkExec() объединила в себе fork и exec, что немного упростило написание кода. Посмотрим на сигнатуру этого метода:

ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error)
  • argv0 - файл с программой, которую мы хотим запустить в новом процессе.
  • argv - остальные аргументы командной строки, включая argv0.
  • attr - специальная структура ProcAttr, в которой описаны параметры для запуска нового процесса.Возвращает функция pid нового процесса или 0, если не получилось его создать, и ошибку, если таковая имеется.

Давайте рассмотрим ProcAttrподробнее:

type ProcAttr struct {
Dir string // Current working directory.
Env []string // Environment.
Files []uintptr // File descriptors.
Sys *SysProcAttr
}
  • dir - путь до рабочей директории.
  • env - переменные окружающей среды.
  • files - файловые дескрипторы. Можно удобно их задать для текущего процесса без использования дополнительных системных вызовов.
  • sys - остальные параметры процесса типа SysProcAttr.

Я не использовал всех полей, пример кода выглядит так

args := &syscall.ProcAttr{
Files: []uintptr{os.Stdin.Fd(), os.Stdout.Fd(), os.Stderr.Fd()},
}

Если вам нужно перенаправить stdin, stdout или stderr в другие файлы, то файловые дескрипторы следует поменять.

Классическое представление

Если у вас возникла потребность вызвать эти системные вызовы отдельно, то можно использовать следующие функции:

syscall.Syscall(syscall.SYS_FORK, 0)

Первым аргументом идёт системный вызов, далее аргументы. Возвращается pid дочернего процесса в родительском, а в дочернем 0.

Exec(argv0 string, argv []string, envv []string) (err error)
  • argv0 - файл с программным кодом, который будет исполняться в новом процессе.
  • argv - аргументы командной строки
  • envv - переменные окружения

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

Вывод

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