sysctl
int sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen);Модуль sysctl содержит функции для получения/установки системной информации; типы данных, возвращаемые функцией sysctl - целые числа (int32, int64), строки (AnsiString) и записи (records). Данная функция объявлена в модуле Posix.SysSysctl (SysSysctlAPI.inc).
Примечание: модуль Posix.SysSysctl - частичное портирование файла sysctl.h.
function sysctl(name: PInteger; namelen: cardinal; oldp: Pointer; oldlen: Psize_t; newp: Pointer; newlen: size_t): Integer; cdecl; external libc name _PU + 'sysctl';name: указатель на Management Information Base (MIB), который "внутри" является массивом Integer. Каждый элемент массива должен быть заполнен значениями, связанными с какими-либо данными для чтения/записи. Количество элементов массива зависит от читаемой/записываемой информации, в большинстве случаев используется 2 первых значения: первый элемент отражает позицию данных в MIB (тип информации), второй содержит значение.
Существует несколько значений первого элемента в MIB (все они прописаны в модуле Posix.SysSysctl):
Идентификатор Значение Описание CTL_DEBUG $00000005 Debugging CTL_VFS $00000003 File system CTL_HW $00000006 Generic CPU, I/O CTL_KERN $00000001 High kernel limits CTL_MACHDEP $00000007 Machine dependent CTL_NET $00000004 Networking CTL_USER $00000008 User-level CTL_VM $00000002 Virtual memory
Итак, если нужно получить информацию о ядре, необходимо заполнить массив следующим образом:
var mib : array[0..1] of Integer; ... ... mib[0] := CTL_KERN;
Второй элемент массива связан с первым, его возможные значения также определены в модуле Posix.SysSysctl. Так, например, для получения величины максимального количества поддерживаемых процессов необходимо использовать значение KERN_MAXPROC($00000006).
var mib : array[0..1] of Integer; ... ... mib[0] := CTL_KERN; mib[1] := KERN_MAXPROC;
Теперь рассмотрим остальные параметры функции sysctl.
namelen: размер записи mib.
oldp: указатель на получаемые данные типа Integer, int64, AnsiString (MarshaledAString) или записью.
oldlen: размер параметра oldp.
newp: указатель на записываемые данные. Если ничего не изменяется - необходимо передать nil.
newlen: размер параметра newp.
С учетом рассмотренного выше, приведем функцию для получения величины максимального количества поддерживаемых процессов:
function MaxProcesses : Integer; var mib: array[0..1] of Integer; res: Integer; len: size_t; begin mib[0] := CTL_KERN; mib[1] := KERN_MAXPROC; len := sizeof(Result); res := sysctl(@mib, Length(mib), @Result, @len, nil, 0); if res <> 0 then RaiseLastOSError; end;Получить Int64-значение можно аналогично, в качестве примера рассмотрим код для получения размера установленной памяти, использую идентификаторы CTL_HW и HW_MEMSIZE.
function MemSize : Int64; var mib: array[0..1] of Integer; res: Integer; len: size_t; begin mib[0] := CTL_HW; mib[1] := HW_MEMSIZE; len := sizeof(Result); res := sysctl(@mib, Length(mib), @Result, @len, nil, 0); if res <> 0 then RaiseLastOSError; end;Для получения строкового значения, в первую очередь необходимо передать длину предполагаемой строки для создания буфера, сделать это можно следующим образом (передав nil в качестве параметра oldp):
sysctl(@mib, Length(mib), nil, @len, nil, 0)Следующий пример демонстрирует получения строки (ASCII), используя функцию sysctl.
function KernelVersion : AnsiString; var mib: array[0..1] of Integer; res: Integer; len: size_t; p: MarshaledAString; // в XE2 можно использовать PAnsiChar begin mib[0] := CTL_KERN; mib[1] := KERN_VERSION; // получаем размер буфера res := sysctl(@mib, Length(mib), nil, @len, nil, 0); if res<>0 then RaiseLastOSError; // устанавливаем размер буфера GetMem(p, len); try res := sysctl(@mib, Length(mib), p, @len, nil, 0); if res <> 0 then RaiseLastOSError; Result := p; finally FreeMem(p); end; end;Наконец, функцию sysctl можно использовать для получения записей, передавая указатель на заранее подготовленный record.
Рассмотрим пример получения значений тактовой частоты из ядра.
procedure GetClockInfo; type clockinfo = record hz : Integer; tick : Integer; tickadj : Integer; stathz : Integer; profhz : Integer; end; (* struct clockinfo { int hz; int tick; int tickadj; int stathz; int profhz; }; *) var mib: array[0..1] of Integer; res: Integer; len: size_t; clock: clockinfo; begin FillChar(clock, sizeof(clock), 0); mib[0] := CTL_KERN; mib[1] := KERN_CLOCKRATE; len := sizeof(clock); res := sysctl(@mib, Length(mib), @clock, @len, nil, 0); if res <> 0 then RaiseLastOSError; Writeln(Format('clock frequency %d',[clock.hz])); Writeln(Format('micro-seconds per hz tick %d',[clock.tick])); Writeln(Format('clock skew rate for adjtime %d',[clock.tickadj])); Writeln(Format('statistics clock frequency %d',[clock.stathz])); Writeln(Format('profiling clock frequency %d',[clock.profhz])); end;sysctlbyname
int sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen);Функция sysctlbyname работает по тому же принципу, что и sysctl, однако получение значений осуществляется путем передачи специального строкового идентификатора. Это в свою очередь позволяет избежать передачи в функцию mib-записи и ее размера.
function sysctlbyname(Name: MarshaledAString; oldp: Pointer; oldlen: Psize_t; newp: Pointer; newlen: size_t): Integer; cdecl; external libc name _PU + 'sysctlbyname';name: идентификатор, определяющий возвращаемое значение и состоящий из двух "уровней".
В качестве элементов "первого" уровня, могут использоваться следующие идентификаторы:
Идентификатор Строка CTL_DEBUG debug CTL_VFS vfs CTL_HW hw CTL_KERN kern CTL_MACHDEP machdep CTL_NET net CTL_USER user CTL_VM vmПриведенные идентификаторы также необходимо дополнить идентификатором "второго" уровня, конкретизирующим информацию, которую нужно получить/записать.
В качестве примера рассмотрим следующие возможные значения, которые могут использоваться в качестве идентификатора name:
Идентификатор Тип kern.ostype string kern.osrelease string kern.osrevision integer kern.version string kern.maxvnodes integer kern.maxproc integer kern.maxfiles integer kern.argmax integer kern.securelevel integer kern.hostname string kern.hostid integer kern.clockrate struct kern.posix1version integer kern.ngroups integer kern.job_control integer kern.saved_ids integer kern.link_max integer kern.max_canon integer kern.max_input integer kern.name_max integer kern.path_max integer kern.pipe_buf integer kern.chown_restricted integer kern.no_trunc integer kern.vdisable integer kern.boottime struct vm.loadavg struct vm.swapusage struct machdep.console_device dev_t net.inet.ip.forwarding integer net.inet.ip.redirect integer net.inet.ip.ttl integer net.inet.icmp.maskrepl integer net.inet.udp.checksum integer hw.machine string hw.model string hw.ncpu integer hw.byteorder integer hw.physmem integer hw.usermem integer hw.memsize integer hw.pagesize integer user.cs_path string user.bc_base_max integer user.bc_dim_max integer user.bc_scale_max integer user.bc_string_max integer user.coll_weights_max integer user.expr_nest_max integer user.line_max integer user.re_dup_max integer user.posix2_version integer user.posix2_c_bind integer user.posix2_c_dev integer user.posix2_char_term integer user.posix2_fort_dev integer user.posix2_fort_run integer user.posix2_localedef integer user.posix2_sw_dev integer user.posix2_upe integerПримечание: получить полный список поддерживаемых команд можно путем ввода sysctl -A в терминале операционной системы.
Приведенный ниже код показывает, как использовать SysCtlByName для получения количества установленных процессоров.
function NumberOfCPU: Integer; var res: Integer; len: size_t; begin len := SizeOf(Result); res := SysCtlByName('hw.ncpu', @Result, @len, nil, 0); if res <> 0 then RaiseLastOSError; end;Примечание: функция sysctl выполняется примерно в 3 раза быстрее, чем sysctlbyname, поэтому, если производительность является ключевым аспектом - лучше использовать sysctl.
sysctlnametomib
int sysctlnametomib(const char *name, int *mibp, size_t *sizep);Функция sysctlnametomib заполняет mib по строковому идентификатору. Обычно, данная функция используется в приложениях, часто работающих с одними и теми же значениями.
function sysctlnametomib(name: MarshaledAString; mibp: PInteger; sizep: Psize_t): Integer; cdecl; external libc name _PU + 'sysctlnametomib';name: строковый идентификатор значения (см. предыдущий пункт).
mibp: указатель на mib-запись.
sizep: указатель на длину mib-записи.
var mib : array[0..1] of Integer; res : Integer; len : size_t; begin len := Length(mib); sysctlnametomib('hw.physicalcpu', @mib, @len); // теперь mib-запись правильно заполнена и готова для передачи в функцию sysctlError Handling
Все указанные выше функции возвращают 0, если выполнились успешно, и код ошибки в противном случае. Такой код может быть получен через Posix.Errno или с использованием функции GetLastError.
Возможные коды ошибок могут быть найдены в файле C:\Program Files (x86)\Embarcadero\RAD Studio\{ВЕРСИЯ}\source\rtl\posix\osx\ErrnoTypes.inc (при установке IDE по умолчанию).
И наконец, итоговый пример, задействующий все положения настоящей статьи:
{$APPTYPE CONSOLE} uses //System.Classes, //System.Types, //Posix.Errno, Posix.SysTypes, Posix.SysSysctl, System.SysUtils; //https://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man3/sysctl.3.html //https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man8/sysctl.8.html function NumberOfCPU: Integer; var res: Integer; len: size_t; begin len := SizeOf(Result); res := SysCtlByName('hw.ncpu', @Result, @len, nil, 0); if res <> 0 then RaiseLastOSError; end; function MaxProcesses: Integer; var mib: array[0..1] of Integer; res: Integer; len: size_t; begin mib[0] := CTL_KERN; mib[1] := KERN_MAXPROC; len := sizeof(Result); res := sysctl(@mib, Length(mib), @Result, @len, nil, 0); if res <> 0 then RaiseLastOSError; end; function MemSize : Int64; var mib: array[0..1] of Integer; res: Integer; len: size_t; begin mib[0] := CTL_HW; mib[1] := HW_MEMSIZE; len := sizeof(Result); res := sysctl(@mib, Length(mib), @Result, @len, nil, 0); if res <> 0 then RaiseLastOSError; end; function KernelVersion : AnsiString; var mib: array[0..1] of Integer; res: Integer; len: size_t; p: MarshaledAString; // в XE2 используйте PAnsiChar begin mib[0] := CTL_KERN; mib[1] := KERN_VERSION; res := sysctl(@mib, Length(mib), nil, @len, nil, 0); if res <> 0 then RaiseLastOSError; GetMem(p, len); try res := sysctl(@mib, Length(mib), p, @len, nil, 0); if res <> 0 then RaiseLastOSError; Result := p; finally FreeMem(p); end; end; procedure GetClockInfo; type clockinfo = record hz : Integer; tick : Integer; tickadj : Integer; stathz : Integer; profhz : Integer; end; var mib: array[0..1] of Integer; res: Integer; len: size_t; clock: clockinfo; begin FillChar(clock, sizeof(clock), 0); mib[0] := CTL_KERN; mib[1] := KERN_CLOCKRATE; len := sizeof(clock); res := sysctl(@mib, Length(mib), @clock, @len, nil, 0); if res <> 0 then RaiseLastOSError; Writeln(Format('clock frequency %d',[clock.hz])); Writeln(Format('micro-seconds per hz tick %d',[clock.tick])); Writeln(Format('clock skew rate for adjtime %d',[clock.tickadj])); Writeln(Format('statistics clock frequency %d',[clock.stathz])); Writeln(Format('profiling clock frequency %d',[clock.profhz])); end; begin try Writeln(Format('max processes %d',[MaxProcesses])); Writeln(Format('number of cpus %d',[NumberOfCPU])); Writeln(Format('physical ram size %s',[FormatFloat('#,', MemSize)])); Writeln(Format('Kernel Version %s',[KernelVersion])); GetClockInfo; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; end.
Источник: http://theroadtodelphi.wordpress.com/2013/05/31/getting-system-information-in-osx-and-ios-using-delphi-xe2-xe3-xe4-part-1/
Комментариев нет:
Отправить комментарий