LINUX.ORG.RU

Где живут аллоцируемые куски памяти и файловые хэндлеры?

 , ,


2

3

Здравствуйте, системные програмисты

Подскажите, вот вызов malloc(size) возвращает указатель на выделенный кусок. При этом free не требует указывать размер.

Так-же open и socket возвращают лишь число

Возникает очевидное подозрение, что есть некие глобальные словари (массивы, списки), в которых ключ - это адрес (для malloc) или число (в случае open), а значение - структура, с настройками этих сущностей.

Почему сделанно именно так? Почему возвращается примитивное значение, а не, как это принято в Си, opaque структура, содержащая состояние?

Имеет ли право на жизнь подобный подход? Существует ли пример несистемных библиотек, которые возвращают число/указатель вместо структуры?

★★★★★

Последнее исправление: makoven (всего исправлений: 5)

Возникает очевидное подозрение, что есть некие глобальные словари (массивы, списоки), в которых ключ - это адрес (для malloc)

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

Harald ★★★★★
()

Возникает очевидное подозрение, что есть некие глобальные словари (массивы, списки), в которых ключ - это адрес (для malloc) или число (в случае open), а значение - структура, с настройками этих сущностей.

Пацаны, кажется нас спалили!

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

А разве в любом(?) ООП языке не то-же самое?
В смысле, это же классическая инкапсуляция.
Т.е. нафига козе баян, или зачем тебе знать как оно там устроено?

anonymous
()

Почему возвращается примитивное значение, а не, как это принято в Си, opaque структура, содержащая состояние?

Что насчёт памяти — то «так сложилось исторически». Некоторые считают, что кроме указателя должен возвращаться размер выделенной памяти. Это на порядок упростило бы жизнь разработчикам менеджеров памяти и повысило производительность этих менеджеров. Особенно в C++.

utf8nowhere ★★★
()

Почему сделанно именно так? Почему возвращается примитивное значение, а не, как это принято в Си, opaque структура, содержащая состояние?

Ты просил память, зачем тебе какая-то структура? А касательно open, структуры связанные с файловым дескриптором хранятся в ядре, и доступа к ним из userland'а нет.

Почему сделанно именно так? Почему возвращается примитивное значение, а не, как это принято в Си, opaque структура, содержащая состояние? Имеет ли право на жизнь подобный подход?

opaque структура не может возвращаться по определению - возвращается указатель на неё. А указатель это или индекс, никакой разницы нет (разве что с индексом работать безопаснее), так что никаких разных подходов которые ты себе придумал также нет. Все всегда возвращают «примитивное значение».

slovazap ★★★★★
()
Последнее исправление: slovazap (всего исправлений: 2)
Ответ на: комментарий от utf8nowhere

Что насчёт памяти — то «так сложилось исторически»

Выходит, на заре написания юникса разработчики были тупые? Что-то не верится. Те же файловые стримы, насколько я понимаю, возвращают структуры

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

Это на порядок упростило бы жизнь разработчикам менеджеров памяти и повысило производительность этих менеджеров. Особенно в C++.

А сейчас в чём проблема? Есть malloc_usable_size(), который работает в glibc и jemalloc. Скорее всего, и в других аллокаторах есть аналог.

i-rinat ★★★★★
()
Ответ на: комментарий от slovazap

А указатель это или индекс, никакой разницы нет

Если это указатель, то он полностью автономен. А если это индекс то где-то есть глобальный словарик «индекс -> структура»

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

Если это указатель, то он полностью автономен. А если это индекс то где0то есть глобальный список «индекс -> структура»

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

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

Про ядро я понял. Структура файлового хэндлера в ядре, поэтому довольствуйся числом. Значит для юзерленда такой подход смысла не имеет, ок

makoven ★★★★★
() автор топика

Почему возвращается примитивное значение, а не, как это принято в Си, opaque структура, содержащая состояние?

Потому что структуры живут в kernel space, это самое простое разделение прав доступа.

mix_mix ★★★★★
()

Где живут аллоцируемые куски памяти

Куча !

файловые хэндлеры?

Структура в ядре.

sysctl fs.file-max

И вообще, ты где взял 4(!) звезды, с такими вопросами ?

как это принято в Си

В оригинальном C вообще много чего не принято было.

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

На заре написания юникса не то, что malloc(), языка C не было.

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

Значит для юзерленда такой подход смысла не имеет, ок

Не ok, имеет не меньше и не больше чем указатели, потому что он то же самое. Ты путаешь интерфейс с реализацией, а именно то что возвращается наружу библиотеки (может возвращаться и указатель на таблицу, если что) и внутреннее устройство (наличие самой таблицы). А уже для чего может понадобиться таблица, вопрос дизайна библиотеки. Например, когда не нужно отдавать наружу ownership, или для gc.

slovazap ★★★★★
()
Последнее исправление: slovazap (всего исправлений: 1)
Ответ на: комментарий от i-rinat

А сейчас в чём проблема?

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

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

Если это указатель, то он полностью автономен.

И это неудобно. Чуть выше уже написали, что если ресурсы находятся в другом адресном пространстве, то адрес не имеет смысла.

И даже если в одном, использование идентификаторов вместо адресов позволяет сделать API крепче. Легче защититься от двойного освобождения ресурса или от использования после освобождения. Вспомни, что такое бывает с памятью, но не бывает с файлами.

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

Тоже верно

Спасибо всем за пищу для размышлений )

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

И вообще, ты где взял 4(!) звезды, с такими вопросами ?

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

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

Тупость тут не причем, ведь (чорт побери) можно сорцы почитать, или книжку тани, про операционные системы ....

robot12 ★★★★★
()

Про память написали.
Про файлы — к процессу привязывается что-то вроде таблицы файловых дескрипторов. Её условно можно представить как пару полей: номер дескриптора и имя файла.
Чем это удобней некой структуры?
По-умолчанию, как известно, есть три дескриптора, привязанных к std{in,out,err}. Соответственно, мы можем довольно просто сделать вот так: cat f1 2>&1 1>/dev/null, устроив перенаправление простой последовательной заменой записей при запуске программы.
А с «файловыми структурами» для тех же стандартных потоков будет не совсем понятно, когда они должны создаваться, хотя бы уже это проблема.

evilface ★★
()
Ответ на: комментарий от i-rinat

если ресурсы находятся в другом адресном пространстве, то адрес не имеет смысла

fd там тоже не имеет смысла.

Легче защититься от двойного освобождения ресурса или от использования после освобождения

И с указателями легко делается: добавляешь в дескриптор флаг good - получается то же самое. Разве только памяти может побольше уйти, но зато нет больше ENFILE.

anonymous
()

Почему возвращается примитивное значение, а не, как это принято в Си, opaque структура, содержащая состояние?

Щто? Чего это я тут читаю? С чего возвращение примитивных типов нетипично?

С аллокатором легко отстрелить себе все ложноножки, поэтому оставление всего под капотом не только оправданно, но и приветствуется.

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

fd там тоже не имеет смысла

Не надо зацикливаться на fd. Есть Pixmap'ы в X сервере, которые для клиента — просто число.

И с указателями легко делается: добавляешь в дескриптор флаг good - получается то же самое.

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

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

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

И тут стоит всопмнить что такое close-on-exec, почему для закрытия сокета недостаточно сделать close(), сколько плясок нужно сделать при fork() с fd и что обычно ядро берёт наименьшее возможное значение fd для нового объекта. Итого, имеешь ещё больше проблем по сравнению с указателеями, разве что нет явных сегфолтов и порчи памяти.

mashina ★★★★★
()

Почему сделанно именно так? Почему возвращается примитивное значение, а не, как это принято в Си, opaque структура, содержащая состояние?

Потому что в случае с файлом этим занимается ядро. Поэтому все изменения идут через системные вызовы и handler, в роли которого выступает число. Если бы это была сложная структура, возможно, лишние данные попали бы юзерспейс. Легко бы было подредактировать хендлер и получить права на запись, скажем, если бы юзерспейс рулил открытием файлов. Но в библиотеке C есть тип FILE*, там хранятся какие-нибудь буфферы или вроде того.

В случае malloc, он возвращает указатель на память. Зачем тогда возвращать что-то ещё, помимо указателя на память?

anonymous
()

Мда, все ответы не по теме, кроме моего, царского

anonymous
()

вы не думали, что есть более простые решения, чем «глобальные словари в которых в которых ключ это адрес»? :-) в значительной части аллокаторов (ога, это impl beh) служебные данные hip лежат строго __перед__ указателем.

и кстати зачем юзеру знать по какой дисциплине выделен ему кусочек памяти ? может ему выдали из пула мелочей..а может система «легла костьми» чтобы таки выдать 100500..

MKuznetsov ★★★★★
()
Ответ на: комментарий от i-rinat

Тогда придётся держать память под эту структуру вечно, даже если ресурс освобождён.

Нет, конечно. fd переиспользуются, и структура также будет.

Этот подход хуже сработает, если в начале открыли 1000 файлов, потом все закрыли - дескрипторы «повиснут». Но он сработает лучше в типичном случае: когда файлов немного. В UNIX здоровая таблица дескрипторов при этом будет висеть мертвым грузом.

Плюс, при открытии нового файла добавляется задача найти первый свободный слот.

Итого, так и не видно никаких аргументов за эти интовые дескрипторы.

anonymous
()
Ответ на: комментарий от deadskif

Имеет в случае userspace <-> kernelspace и после fork()/exec()

Только exec меняет адресное пространство, но ок, хотя нужно это, наверно, только для перенаправления потоков в шелле.

anonymous
()
Ответ на: комментарий от mashina

а можно поинтересоваться что еще надо сделать с сокетом кроме close() и какие пляски надо совершить для fd во время fork()?

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

в значительной части аллокаторов (ога, это impl beh) служебные данные hip лежат строго __перед__ указателем

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

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

и кстати зачем юзеру знать по какой дисциплине выделен ему кусочек памяти

Как минимум удобно было бы знать размер выделенной памяти по указателю. А тут как выяснилось такая функция есть, но она нестандартная, gnu-extension

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

так и не видно никаких аргументов за эти интовые дескрипторы.

Чего я не понимаю, так это почему для для защиты варианта с указателями ты выбрал самый неудобный для себя пример, файловые дескрипторы. Ты указатель из ядра как возвращать собрался? И что ты там вообще собрался хранить? Как собираешься данные валидировать при системных вызовах? Или разрешаем любому процессу уронить ядро, by design?

Плюс, при открытии нового файла добавляется задача найти первый свободный слот.

Пф-ф. Массив структур, одно из полей — ссылка на следующий элемент (int). Освобождённые слоты подцепляются в список свободных. Если нужен новый дескриптор, просто берём из списка свободных.

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

почему для для защиты варианта с указателями ты выбрал самый неудобный для себя пример, файловые дескрипторы

Его выбрал ТС. А я не защищаю, а тоже пытаюсь понять зачем так сделали, если всю жизнь АТД делались на указателях.

Ты указатель из ядра как возвращать собрался?

Как есть, бит в бит.

Пф-ф

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

Как собираешься данные валидировать при системных вызовах?

Ok, причина прояснилась: дескрипторы - это ограниченный набор разрешенных входов в адресное пространство ядра, а указатели так не ограничишь (ЕМНИП, что-то такое активно используется в микроядрах). Странно, что все вы не сформулировали это сразу, а водили окольными путями.

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

Адреса в юзер- и кернелспейсе в общем обычно разные вещи.

После fork() имеются два одинаковых адресных пространства, но запись в одном не влияет на другое. При этом файловые дискрипторы шарятся.

Это же используется в серверах, где сокет после accept(2) передается дочернему процессу.

Перенаправление так не только в шелле работает (pipe(2)/popen(3)).

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