Billy Bones
-
Постов
8 -
Зарегистрирован
-
Посещение
-
Победитель дней
2
Сообщения, опубликованные Billy Bones
-
-
В 27.03.2021 в 21:34, Billy Bones сказал:
Альтернативный способ состоит в том, чтобы напрямую (без библиотеки libc ) выполнить системный вызов stat, обратившись непосредственно к ядру ОС.
Коли хвастался, значит нужно показать как это делается:
Пишем такое консольное приложение:
Program ownof; {$APPTYPE CONSOLE} {$R *.res} Type kernel_ulong_t = UInt64; kernel_long_t = Int64; TStat = packed record st_dev : kernel_ulong_t; st_ino : kernel_ulong_t; st_nlink : kernel_ulong_t; st_mode : UInt32; st_uid : UInt32; st_gid : UInt32; __pad0 : UInt32; st_rdev : kernel_ulong_t; st_size : kernel_long_t; st_blksize : kernel_long_t; st_blocks : kernel_long_t; st_atime : kernel_ulong_t; st_atime_nsec : kernel_ulong_t; st_mtime : kernel_ulong_t; st_mtime_nsec : kernel_ulong_t; st_ctime : kernel_ulong_t; st_ctime_nsec : kernel_ulong_t; __unused : array[0..2] of kernel_long_t; end; (* Функция mystat реализована на ассемблере. Откомпилирована в Linux и объектный файл перенесен в проект. *) function mystat(path_to_file : PAnsiChar; var S : TStat) : NativeUInt; external 'mystat.o' var S : TStat; Begin // Файл a.txt создан руками в том-же каталоге, куда помещается исполняемый // модуль данной программы. mystat('a.txt', S); Writeln('Owner is ', S.st_uid); End.
Исходный код для mystat.asm:
.text # function mystat(path_to_file : PAnsiChar; var S : TStat) : NativeUInt; # # Параметры: # rdi - path_to_file # rsi - @S # # Параметры функции помещаются, в те-же регистры, что и требует интерфейс системных # вызовов - не делаем ничего лишнего ! # # После выхода из режима ядра в регистре rax будет содержаться рузультат работы # системного вызова. Наша функция тоже возвращает рузультат в rax - не делаем # ничего лишнего ! .global mystat .align 16 mystat: movq $4, %rax # поместим номер системного вызова в регистр rax syscall # переходим в режим ядра ret
Все данные для написания этой программы получены из исходных кодов ядра Linux 5.11.10.
Данная реализация привязана к нескольким вещам:
- К архитектуре процессора (т.к. mystat написана на x86_64 ассемблере )
- К ядру Linux (т.е. программа не будет работать на других Unix подобных ОС)
- К структуре с которой работает системный вызов sys_newstat (так называется, та процедура в ядре, что выполнает нужные нам действия).
- Способу выполнения системных вызовов (сам способ привязан к архитектуре процессора и к ядру ОС)
Пока ничего из этого не поменяется всё будет ОК. И никаких Вам libc.
PS:
- Номер системного вызова и его имя взято из файла arch/x86/entry/syscalls/syscall_64.tbl .
- Как делать системный вызов написано тут: arch/x86/entry/entry_64.S .
- Описание структуры взято из файла arch/x86/include/uapi/asm/stat.h
-
6 минут назад, Олег Киреев сказал:
Файл Posix.SysStat.dcu у меня лежит в C:\Program Files (x86)\Embarcadero\Studio\20.0\lib\iossimulator\debug
Этот не подходит, т.к должен быть файл, конкретно, для платформы Linux: lib\linux64\release\Posix.SysStat.dcu.
В своем прошлом посте, Я, описал процедуру, как самому собрать модуль Posix.SysStat.dcu:
- Создать проект консольного приложения.
- Скопировать в каталог с проектом файлы (см. список файлов и их расположение в прошлом посте - я его менял добавляя информацию).
- Включить в проект файл Posix.SysStat.pas - он сам добавится в uses.
- Добавить платформу Linux64 и сделать её активной.
- Выбрать кофигурацию Release
- Собрать консольное приложение - автоматически будет собран Posix.SysStat.dcu - он лежит в подкаталоге проекта linux64\Release.
- Выложить Posix.SysStat.dcu в lib\linux64\release.
Всё.
-
2 минуты назад, krapotkin сказал:
нет. готовых компонентов, которые позволяют не держать в памяти полную модель данных, вы, скорее всего не найдете.
Это уже понятно .
2 минуты назад, krapotkin сказал:Кроме того для десктопа пара тысяч элементов в ListView особых проблем обычно не вызывает
Тормозить, при изменении размеров окна (и вместе с ним ListView), начинает уже от 1000, а виртуалный ListBox в VCL и при 65535 не тормозит !
Очень не хотелось свои компоненты писать !
-
В 29.03.2021 в 08:38, Олег Киреев сказал:
Почему у меня при прописывании Uses Posix.SysStat RAD Studio 10.3 "ругается" что cannot resolve unit filename Posix.SysStat at line...???? Хотя в библиотеке путь source\rtl\posix прописан.
Компилировать самому модуль Posix.SysStat.pas не нужно, т.к. он уже откомпилирован и лежит в:
lib\linux64\debug - отладочная версия
lib\linux64\release - релизная версия
Компилятор его найдет, если путь к модулю указан в Tools | Options | Language | Delphi | Libraries | Library Path.
А он, по умолчанию, там указан: $(BDSLIB)\$(Platform)\release
Проверьте есть ли там откомпилированный модуль и прописан ли путь.
Если модуля нет, то его можно откомпилировать самому - в каталоге source\rtl лежит файл buildrtl.bat - он собирает все библиотеки rtl. Процедура его использования не очень прозрачная. Где -то, в документации Embarcadero, написано как его правильно запустить.
Суть, состоит в том, что перед его запуском, должны быть, правильно, установлены, некоторые переменные, среды окружения.
Помню, что правил bin\rsvars.bat, и поменял там, все пути в стиле C:\Program Files (x86)\Embarcadero\Studio\21.0\XXXX на C:\RADStudio\XXX. Где RADStudio получен с помощью mklink /J RADStudio "С:\Program Files (x86)\Embarcadero\Studio\21.0" . Это нужно, т.к. многие утилиты командной строки, например make, не понимают пути с пробелами. Без этого rtl библиотеки не соберутся ! (по крайней мере не собираются c++ rtl, где всё на make построено)
После того, как соберете rtl библиотеки, просто найдите Posix.SysStat.dcu (релизную версию, конечно ), и положите его в lib\linux64\release.
Если, вдруг, модуль Posix.SysStat.dcu не соберется, то нужно будет искать, куда его нужно прописать, чтобы он собирался.
Ха, Ха, Ха - а rll для Linux не собирается с помощью buildrtl.bat - только для Win32, Win64, OSX32.
Значит нужно самому собрать. Создать свой проект, воткнуть туда исходники, прописать пути, если нужно, и откомпилировать. Изучите исходный код Posix.SysStat.pas - туда куча файлов включается includ'ом.
На самом деле, к себе в проект (например консольного приложения), нужно скопиповать эти файлы (сохраняя структуру каталогов):
source\rtl\posix в проекте как posix
Posix.SysStat.pas
Posix.SysStatAPI.inc
Posix.Base.pas
Posix.SysTypes.pas
source\rtl\posix\linux в проекте как posix\linux
BaseTypes.inc
SysStatTypes.inc
SysTypesTypes.inc
Потом включить Posix.SysStat.pas, Posix.Base.pas, Posix.SysTypes.pas так:
Uses Posix.SysStat in 'posix\Posix.SysStat.pas', Posix.Base in 'posix\Posix.Base.pas', Posix.SysTypes in 'posix\Posix.SysTypes.pas';
Добавляем платформу Linux64 и компилируем - Дело в шляпе.
Выкладываем скомпилированный модуль в lib\linux64\release и дальше не паримся.
В RAD Studio 10.4.2 по умолчанию всё на месте. Uses Posix.SysStat прекрасно работает.
-
Получить UID (идентификатор пользователя - владельца) можно с помошью функции stat (Описана в POSIX стандарте : https://pubs.opengroup.org/onlinepubs/9699919799/ ). Далее есть файл /etc/passwd где UID пользователей сопоставлены с их именами.
В Linux документацию на stat можно посмотреть командой man 2 stat (В случае если установлены средства разработки на языках C/C++).
Если не ошибаюсь, она находится в библиотеке libc. Значит задача состоит в том, чтобы загрузить "dll" библиотеку libc ( например /usr/lib64/libc.so.6 ) и вызвать функцию stat. Для загрузки динамических библиотек (разделяемых объектов - shared object - so) используется вызов dlopen.
Альтернативный способ состоит в том, чтобы напрямую (без библиотеки libc ) выполнить системный вызов stat, обратившись непосредственно к ядру ОС. Для этого, нужно, найти документацию на системный вызов stat, и вызвать его самому - вы по сути сами реализуете функционал библиотеки libc.
Второй способ, хоть и кажется сложнее, на самом деле реализуется буквально несколькими assembler'ными инструкциями.
Возможно в Delphi это уже сделали (не исключаю, что в какой-то библиотеке, уже есть функция Stat ).
В RAD Studio, в каталоге source\rtl\posix, есть файл SysStatAPI.inc - он включен в posix.sysstat.pas.
Значит просто: Uses Posix.SysStat и используйте функцию stat.
-
15 часов назад, krapotkin сказал:
вроде уж везде написали что ListBox не предназначен для 20+ элементов. используйте ListView
Спасибо за совет, я не видел данного видео. ListView существенно экономнее расходует ОП, но вопрос был о том, имеется ли в FMX функционал, подобный виртуальному ListBox из VCL.
Я посмотрел исходные коды для ListView и наверное, я сумею изобразить, что-то похожее, на виртуальный ListBox, установив свойство Adapter, у ListView, на определенный мной, класс - наследник от IListViewAdapter.
Но увиденное в исходных кодах, немного настораживает, т.к. ListView, в некоторых своих методах, обращается, одновременно, и к элементу номер X, и к элементу номер Y - т.е. предполагается, что в данный момент времени, они оба существуют (Скорее всего, предполагается, что существуют элементы в диапазоне от 0 до Adapter.Count ). Я же, хотел избежать, выделения памяти, для структуры из элементов TListViewItem, содержащей Adapter.Count элементов. Именно этим свойством обладает виртуальный ListBox из VCL.
15 часов назад, krapotkin сказал:ну и да, 50000+ элементов это несколько трешовый UI
Естественно, столько элементов не будет, но потенциально, может быть сколько угодно. И нужно быть к этому готовым.
Данный функционал, нужен для настольного приложения под Linux. В Windows хватает и VCL. На смартфонах приложение разворачивать не планирутся никогда.
-
У управляющего элемента TListBox, в библиотеке VCL, есть возможность, работать в виртуальном режиме ( Style = lbVirtual ), когда данные, для элементов списка, поставляет метод, связанный с событием OnData:
СпойлерUnit main; Interface Uses System.Classes, Vcl.Forms, Vcl.Controls, Vcl.StdCtrls; Type TfmMain = class(TForm) lbItems: TListBox; procedure lbItemsData(Control: TWinControl; Index: Integer; var Data : string); procedure FormShow(Sender: TObject); public constructor Create(AOwner : TComponent); override; end; Var fmMain : TfmMain; Implementation Uses System.SysUtils; {$R *.dfm} Const MaxLines = 65536; {--------------------------------------------------------------------------} constructor TfmMain.Create(AOwner : TComponent); begin inherited Create(AOwner); lbItems.Count := MaxLines; end; {--------------------------------------------------------------------------} procedure TfmMain.FormShow(Sender: TObject); begin lbItems.ItemIndex := MaxLines - 1; end; {--------------------------------------------------------------------------} procedure TfmMain.lbItemsData( Control : TWinControl; Index : Integer; var Data : string); begin Data := 'Item ' + IntToStr(Index); end; End.
Есть ли что-нибудь похожее в FireMonkey (FMX) ?
Или придется для каждого элемента списка создавать объект класса TListBoxItem ?
Попытка создать, таким образом, ListBox на 65536 элементов, приводит к диким расходам ОП - 248 MB:
СпойлерConst MaxLines = 65536; procedure TfmMain.btAddItemsClick(Sender: TObject); var I : Integer; M : TListBoxItem; T0, T1 : TDateTime; begin T0 := Now; lbItems.BeginUpdate; try for I := 0 to MaxLines - 1 do begin M := TListBoxItem.Create(nil); M.Parent := lbItems; M.Text := 'Item ' + IntToStr(I); end; finally lbItems.EndUpdate; end; T1 := Now; edTime.Text := IntToStr(SecondsBetween(T0, T1)); end;
Shared память
в Потоки и распределенные вычисления
Опубликовано · Изменено пользователем Billy Bones
Имя rt используется как параметр для компоновщика (в *nix системах ), а он, в свою очередь, компонует библиотеку, которая называется librt.so или librt.a (если используется статическая, версия библиотеки rt).
Поэтому в Delphi нужно писать так:
PS:
Рекомендую почитать книгу: Уильям Стивенс UNIX взаимодействие процессов. Там описано, если я точно помню, 2 механизма разделяемой памяти для Unix систем: