Как стать автором
Обновить

Пакет 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.

Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.