LINUX.ORG.RU

Системные вызовы ядра и библиотека glibc

 ,


0

1

Изучаю программирование под linux, что бы процесс изучения не был скучным решил написать игру - морской бой. Игра будет работать в консоли - буквы цифры, начиная 80x25 и с большим разрешением. Графика символами псевдографики. Хочу написать данную игру используя только системные вызовы ядра, повторяю ТОЛЬКО СИСТЕМНЫЕ ВЫЗОВЫ ЯДРА!!!! Сразу предвижу шквал предложений использовать библиотеку glibc, ncurses. Но ведь библиотека ncurses сама работает через системные вызовы ядра linux. Я прав? Вот я и хочу разобраться как можно написать эту игру используя только системные вызовы ядра linux!!!! Приступая к делу обнаружил пробелы в ряде вопросов. Итак: Немного отступлю от темы, просто хотелось бы выяснить некоторые вопросы. Первый момент общий по поводу библиотеки Си - glibc. Я понимаю так, что библиотека glibc виртуальная, в ней нет ассемблерного кода, а значит она вызывает системные вызовы ядра и работает только через них и никак иначе, что логично. Правильно ли я понимаю? Если это так, то из этого следует второй момент. Если я не ошибаюсь то файл текущего терминала /dev/tty, не важно какой это терминал: виртуальный и открыт в графическом эмуляторе терминала, не виртуальный соединённый через com порт, буквенно цифровой 80x25 и т.д. файл текущего открытого терминала в котором работают всё равно будет /dev/tty правильно я понимаю, это так? Далее если это так, то используя только системные вызовы ядра, повторяю только системные вызовы ядра, в терминал я могу при неканоническом вводе, вводить символы и выводить их, следующими системными вызовами ядра write и read при этом в начале не забыв для файла терминала /dev/tty назначить дескриптор - функцией open, а в конце работы закрыть этот файл системным вызовом close. Правильно ли я понимаю? Если всё выше изложенное правильно то тогда идём дальше. Как мне при помощи системных вызовов ядра, опять же повторяю только системных вызовов ядра, не использую функции библиотеки glibc, получить информацию о терминале. Например геометрию терминала, сколько в открытом терминале символов по горизонтали и строк и т. д. Конкретно какая мне ещё будет нужна другая информация кроме числа символов и строк я ещё не знаю. Но число символов и число строк нужно что бы правильно «разрисовать» интерфейс программы в терминале. Он будет состоять из символов псевдо-графики, для морского боя хватит. Да вот ещё нужно узнать какая локализация, koi8-r, utf8 или ещё какая и наверное перевести локализацию в utf8. В библиотеке glibc очень много функций для работы с терминалом: isatty, tcsetattr, tcgetattr и т.д. очень много всяких структур данных. Конечно при помощи этих функций и структур данных можно работать с терминалом. Но я хотел бы узнать как можно полноценно работать с терминалом не используя библиотеку glibc, а пользуясь только системными вызовами ядра. Ну например как я уже писал выше, ввести данные и вывести я уже знаю как write, read, open, close, а вот как получить какое в используемом терминале /dev/tty количество символов и строк при помощи системных вызовов ядра?

В моём посте я всё время повторяю - системные вызовы ядра, потому, что хотел узнать как можно это реализовать не используя библиотеки glibc или ncurses!!!!

Предвижу ещё вопросы, а сможешь ли ты вообще написать саму логику игры и т. д. С разработкой самого алгоритма игры у меня проблем нет. Разные алгоритмы я разрабатываю без проблем. У меня проблемы, а вернее отсутствие знаний по самому ядру linux. Вот как бы его и изучаю, возникли вопросы, поэтому и спрашиваю на этом форуме.

За помощь буду заранее благодарен!

★★

а вот как получить какое в используемом терминале /dev/tty количество символов и строк при помощи системных вызовов ядра?

Нужно использовать системный вызов ioctl. Повторяю, не функцию ioctl из glibc, а системный вызов ioctl.

Но ведь библиотека ncurses сама работает через системные вызовы ядра linux.

Сильно сомневаюсь. Для всех необходимых функций уже есть обёртки в glibc. Зачем им париться с системными вызовами?

i-rinat ★★★★★ ()
Последнее исправление: i-rinat (всего исправлений: 2)

В чем смысл хотения написать игру через системные вызовы? Ты считаешь что от этого станешь понимать ядро Linux сильно больше? Вот спроси у i-rinat.

I-Love-Microsoft ★★★★★ ()
Последнее исправление: I-Love-Microsoft (всего исправлений: 1)

Я предлагаю самый простой вариант: написать с использованием libc и какого-нибудь termbox, а дальше взять их исходники, man и плавно вычленять вызовы функций.

open('/dev/tty'...) делать не обязательно, можно просто писать в fd = 1. Переменные окружения есть в extern char** environ. По хорошему надо понимать переменную окружения COLUMNS, помимо ioctl'ей.

P.S. В любом случае это очень плохая идея. libc - часть стандарта C, переписывать ее нет никакого смысла.

rymis ★★ ()

на голом с не написать вьізов сискола. повторяю, сискола. нужньі асм вставки. повторяю - асмвставки.

anonymous ()

А в чем, собственно, разница то по существу? Определения системных вызовов glibc соответствуют один в один определениям системных вызовов в ядре.

int open(const char *pathname, int flags, mode_t mode);
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)

Никакого «уровня ниже» ты не узнаешь ― только потратишь время на мишуру из макросов.

Deleted ()

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

Лол, конечно в glibc есть куча ассемблерного кода, потому что на чистом C сделать системный вызов ядра не получится.
Открываешь исходники и смотришь как это работает
* glibc
https://github.com/lattera/glibc/blob/master/sysdeps/unix/sysv/linux/x86_64/s...
* musl
https://git.musl-libc.org/cgit/musl/tree/arch/x86_64/syscall_arch.h
Реализация из musl выглядит немного проще чем то что в glibc наворотили, но я соглашусь с rymis, не нужно переизобретать велосипед, лучше всеравно не сделаешь.

pftBest ★★★★ ()

По диагонали просмотрел, вроде рассуждаешь верно.

Но если у тебя совсем нет навыков по системному программированию, то может быть сложно - сразу начинать с приложения, содержащего какую-то продвинутую логику.

Deleted ()
Ответ на: комментарий от EXL

Сделай игрушку в виде ядерного модуля

Удваиваю, мысель хорошая, и ядро изучит хорошо :)

P.S. Повторюшки, дяди хрюшки )

I-Love-Microsoft ★★★★★ ()
Последнее исправление: I-Love-Microsoft (всего исправлений: 1)
Ответ на: комментарий от rymis

Переменные окружения есть в extern char** environ.

Эту переменную заполняет glibc. Повторяю, glibc, она не получается из системного вызова ядра, повторяю, системного вызова ядра.

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

vzzo ★★★ ()

Ты понимаешь, зачем нужна glibc? Там кеши есть и, например, чтение/запись буферизируются. Буферизация это хорошо, если что. Работает быстрее, к железу обращается реже. Тыкать сисколы на каждый чих, конечно, можно, но пользы от этого ноль. Даже наоборот. Если кто-то узнает, что ты так пишешь, тебя потом на работу не возьмут. Потому что будут за дурака считать.

unt1tled ★★★★ ()
Ответ на: комментарий от unt1tled

Ты понимаешь, зачем нужна glibc? Там кеши есть и, например, чтение/запись буферизируются.

В случае с обертками над read/write ничего не буферизируется. Не вводи в заблуждение.

Буферизация это хорошо, если что. Работает быстрее

Для небольших объемов данных (записывать с помощью fwrite по строкам, например) ― да. Для больших ― совсем нет.

Deleted ()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от Deleted

В случае с обертками над read/write ничего не буферизируется. Не вводи в заблуждение.

fwrite/write?

Для небольших объемов данных (записывать с помощью fwrite по строкам, например) ― да.

У ТС же объемы данных как у гугла и фейсбука, ты че.

Для больших ― совсем нет.

Не пойму, толи бред толи просто спорное утверждение.

unt1tled ★★★★ ()
Ответ на: комментарий от unt1tled

fwrite/write?

Да. Внутри fwrite есть буферизация, а write это просто обертка.

У ТС же объемы данных как у гугла и фейсбука, ты че.

ТСу оно, конечно, не нужно. Но всё-таки стоит отметить этот момент.

Не пойму, толи бред толи просто спорное утверждение.

Да вроде очевидно, что в некоторых случаях накладные расходы на буферизацию выходят боком. Для записи буфера в 128MB с помощью одного write/fwrite в файл разница стабильно получается ~3% в пользу write. Если записывать этот же буфер по одному байту, то разница уже на порядок в пользу fwrite. Такие дела.

p.s. Стоит отметить, что с другим ядром и с другой libc ситуация может быть другой ― очень много факторов.

Deleted ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.