Wie Kernel Funktionen verwenden?
Wie Kernel Funktionen verwenden?
Hallo,
ich wollte mal anfrage, wie man Kernel- Funktionen verwenden kann. Z.B. zur Verzeichnisüberwachung http://en.wikipedia.org/wiki/Inotify.
Gruß
Justin
ich wollte mal anfrage, wie man Kernel- Funktionen verwenden kann. Z.B. zur Verzeichnisüberwachung http://en.wikipedia.org/wiki/Inotify.
Gruß
Justin
PB 5.11 x64 / Kubuntu 12.10 x64 | Windows 7 x64
Re: Wie Kernel Funktionen verwenden?
Hi,
Für „Kernel Funktionen“ gibt es in der /lib/libc.so bzw /usr/lib/libc.so (von Distri zu Distri verschieden) Wrapper, die man aus Programmen heraus aufrufen kann/soll.
Für C und C++ gibt es unter /usr/include/ jede Menge Dateien, Header genannt, die die Prototypen für die Funktionen in der libc deklarieren. Will man nun die Funktionen aus der libc in Purebasic direkt verwenden, muss man diese für den Compiler erstmal sichtbar machen, sprich deklarieren. Dies geht mit Hilfe des ImportC Keywords. Leider müssen die Header von Hand übersetzt werden. Daher ist Purebasic auch nur bedingt gut für die Entwicklung unter Linux geeignet.
Für Inotify sieht das z.B. so aus:
Für „Kernel Funktionen“ gibt es in der /lib/libc.so bzw /usr/lib/libc.so (von Distri zu Distri verschieden) Wrapper, die man aus Programmen heraus aufrufen kann/soll.
Für C und C++ gibt es unter /usr/include/ jede Menge Dateien, Header genannt, die die Prototypen für die Funktionen in der libc deklarieren. Will man nun die Funktionen aus der libc in Purebasic direkt verwenden, muss man diese für den Compiler erstmal sichtbar machen, sprich deklarieren. Dies geht mit Hilfe des ImportC Keywords. Leider müssen die Header von Hand übersetzt werden. Daher ist Purebasic auch nur bedingt gut für die Entwicklung unter Linux geeignet.
Für Inotify sieht das z.B. so aus:
Code: Alles auswählen
ImportC "/lib/libc.so"
inotify_init.l ()
inotify_add_watch.l (fd.l, pathname.s, mask.l)
inotify_rm_watch.l (fd.l, wd.l)
_os_read.l (fd.l, *buf, count.l) As "read"
EndImport
Structure inotify_event
wd.l
mask.l
cookie.l
len.l
name.s{4096}
EndStructure
#IN_ACCESS = $00000001
#IN_MODIFY = $00000002
#IN_ATTRIB = $00000004
#IN_CLOSE_WRITE = $00000008
#IN_CLOSE_NOWRITE = $00000010
#IN_CLOSE = (#IN_CLOSE_WRITE | #IN_CLOSE_NOWRITE)
#IN_OPEN = $00000020
#IN_MOVED_FROM = $00000040
#IN_MOVED_TO = $00000080
#IN_MOVE = (#IN_MOVED_FROM | #IN_MOVED_TO)
#IN_CREATE = $00000100
#IN_DELETE = $00000200
#IN_DELETE_SELF = $00000400
#IN_MOVE_SELF = $00000800
#IN_UNMOUNT = $00002000
#IN_Q_OVERFLOW = $00004000
#IN_IGNORED = $00008000
#IN_CLOSE = (#IN_CLOSE_WRITE | #IN_CLOSE_NOWRITE)
#IN_MOVE = (#IN_MOVED_FROM | #IN_MOVED_TO)
#IN_ONLYDIR = $01000000
#IN_DONT_FOLLOW = $02000000
#IN_EXCL_UNLINK = $04000000
#IN_MASK_ADD = $20000000
#IN_ISDIR = $40000000
#IN_ONESHOT = $80000000
#IN_ALL_EVENTS = (#IN_ACCESS | #IN_MODIFY | #IN_ATTRIB | #IN_CLOSE_WRITE | #IN_CLOSE_NOWRITE | #IN_OPEN | #IN_MOVED_FROM | #IN_MOVED_TO | #IN_CREATE | #IN_DELETE | #IN_DELETE_SELF | #IN_MOVE_SELF)
;
; EXAMPLE
;
; Der "File Descriptor", der von inotify_init zurück gegeben wird, kann auch
; in einem (e)poll getriebenen reaktor pattern wiederverwendet werden. Das ist
; interessant für asynchrone programmierung.
fd.l = inotify_init()
; Der Kernel wird uns darüber informieren, wenn eine Datei angelegt oder gelöscht
; wurde.
wd.l = inotify_add_watch(fd, "/tmp", #IN_CREATE | #IN_DELETE)
; Die Events sind von dynamischer Größe, da sie Dateinamen enthalten.
; Der Buffer wird daher bestenfalls ~256/64 Events halten können. Sollten
; doch noch mehr vorliegne, werden diese im 2. Durchlaufe eingelesen. Alles Dandy.
*buf.inotify_event = AllocateMemory(SizeOf(inotify_event) * 256)
Repeat
; Lese so viele Events wie möglich und fülle diese in den Buffer
length.l = _os_read(fd, *buf, SizeOf(inotify_event) * 256)
; tmp_buf wird unsere Laufvariable. Sie wird nach jeden Event von uns hoch gezählt
; und zeigt auf das nächste Event.
*tmp_buf.inotify_event = *buf
While *tmp_buf < *buf + length
; \name enthält den \0 terminierten gültigen Dateinamen, der Subjekt
; eines Ereignisses wurde.
; \mask enthält eine Verknüpfung aus den oben definierten Konstanten, die
; das Event beschreiben (Datei gelöscht oder angelegt).
If *tmp_buf\mask & #IN_CREATE = #IN_CREATE
Debug *tmp_buf\name + " Angelegt (" + RSet(Hex(*tmp_buf\mask), 8, "0") + ")"
ElseIf *tmp_buf\mask & #IN_DELETE = #IN_DELETE
Debug *tmp_buf\name + " Gelöscht (" + RSet(Hex(*tmp_buf\mask), 8, "0") + ")"
Else
Debug *tmp_buf\name + " Unbekanntes Event (" + RSet(Hex(*tmp_buf\mask), 8, "0") + ")"
EndIf
; Pointer auf das nächste Event zeigen lassen.
*tmp_buf = *tmp_buf + SizeOf(inotify_event) + *tmp_buf\len
Wend
ForEver
Zuletzt geändert von MVXA am 07.02.2013 22:25, insgesamt 1-mal geändert.
- ts-soft
- Beiträge: 22292
- Registriert: 08.09.2004 00:57
- Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel - Wohnort: Berlin
Re: Wie Kernel Funktionen verwenden?
Hallo Arthur
Ich denke mal, der Import sollte so aussehen:
*buf.s ist nicht mehr erlaubt (ab PB5.10)
// edit: die folgende Zeile trifft auf Linux nicht zu! Source geändert.
Die anderen Datentypen sind lt. Doku Integer, was natürlich nur auf einem 64-Bit Linux wichtig sein sollte.
Gruß
Thomas
Ich denke mal, der Import sollte so aussehen:
Code: Alles auswählen
ImportC "/lib/libc.so"
inotify_init.l ()
inotify_add_watch (fd.l, pathname.s, mask.l)
inotify_rm_watch (fd.l, wd.l)
_os_read (fd.l, *buf, count.l) As "read"
EndImport
// edit: die folgende Zeile trifft auf Linux nicht zu! Source geändert.
Die anderen Datentypen sind lt. Doku Integer, was natürlich nur auf einem 64-Bit Linux wichtig sein sollte.
Gruß
Thomas
Zuletzt geändert von ts-soft am 07.02.2013 22:38, insgesamt 2-mal geändert.
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Re: Wie Kernel Funktionen verwenden?
> Hallo Arthur
Hi
> *buf.s ist nicht mehr erlaubt (ab PB5.10)
Klingt vernünftig, ein String ist es ja im Grunde nicht.
> Die anderen Datentypen sind lt. Doku Integer, was natürlich nur auf einem 64-Bit Linux wichtig sein sollte.
Shit, das müssen eigentlich .l sein in dem Fall dann, da hab ich wohl Mist gebaut. In den Header sind sie als int deklariert und so weit ich mich erinnern kann sind diese immer noch 32Bit breit. Auch unter 64Bit Linux
Hi
> *buf.s ist nicht mehr erlaubt (ab PB5.10)
Klingt vernünftig, ein String ist es ja im Grunde nicht.
> Die anderen Datentypen sind lt. Doku Integer, was natürlich nur auf einem 64-Bit Linux wichtig sein sollte.
Shit, das müssen eigentlich .l sein in dem Fall dann, da hab ich wohl Mist gebaut. In den Header sind sie als int deklariert und so weit ich mich erinnern kann sind diese immer noch 32Bit breit. Auch unter 64Bit Linux
- ts-soft
- Beiträge: 22292
- Registriert: 08.09.2004 00:57
- Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel - Wohnort: Berlin
Re: Wie Kernel Funktionen verwenden?
Sicher bin ich mir da nicht, aber ich verstehe das so, das es Integer sind,
sind ja Handles, diese sind eigentlich immer Integer.
sind ja Handles, diese sind eigentlich immer Integer.
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
- NicTheQuick
- Ein Admin
- Beiträge: 8679
- Registriert: 29.08.2004 20:20
- Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti - Wohnort: Saarbrücken
- Kontaktdaten:
Re: Wie Kernel Funktionen verwenden?
ts-soft hat geschrieben:Sicher bin ich mir da nicht, aber ich verstehe das so, das es Integer sind,
sind ja Handles, diese sind eigentlich immer Integer.
Code: Alles auswählen
#include <stdio.h>
int
main ()
{
printf("%zd\n", sizeof(int));
return 0;
}
Code: Alles auswählen
ask:[~]$ ./test
4
Linux yuno 3.7.5-1-ARCH #1 SMP PREEMPT Mon Jan 28 10:03:32 CET 2013 x86_64 GNU/Linux
Edit:
Damit ist die Verwirrung komplett . Dachte zuerst ich hätte mich vertan, aber die Felder sind ja schon als .l deklariert . Ich passe das Beispiel trotzdem nochmal an.
- ts-soft
- Beiträge: 22292
- Registriert: 08.09.2004 00:57
- Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel - Wohnort: Berlin
Re: Wie Kernel Funktionen verwenden?
Scheint, als wenn Ihr Recht habt. Scheint dann aber nur für Linux zu gelten.
Hier haben wir also die Ausnahme von der RegelInteger (Datentyp) - Wikepedia hat geschrieben:Ein Integer besteht in der Regel aus 8, 16, 32, 64 oder 128 Bits (also 1, 2, 4, 8 oder 16 Bytes) – entsprechend der Wortbreite der jeweiligen CPU
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
- NicTheQuick
- Ein Admin
- Beiträge: 8679
- Registriert: 29.08.2004 20:20
- Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti - Wohnort: Saarbrücken
- Kontaktdaten:
Re: Wie Kernel Funktionen verwenden?
Unter Windows ist es auch so. Das hat hier aber mehr mit der Programmiersprache zu tun und nicht mit der allgemeinen Definition für Ganzzahlen.
Siehe hier: int on a 64-Bit machine
Es gibt sogar Unterschiede zwischen verschiedenen Compilern (What should be the sizeof(int) on a 64-bit machine?). Ich spreche übrigens auch aus Erfahrung.
Wenn ich unter C/C++ mit Pointern oder Handels arbeiten will, dann nutze ich dort auch diesen Datentyp. Der passt sich dann ganz sicher an. Z.B. void*.
Siehe hier: int on a 64-Bit machine
Es gibt sogar Unterschiede zwischen verschiedenen Compilern (What should be the sizeof(int) on a 64-bit machine?). Ich spreche übrigens auch aus Erfahrung.
Wenn ich unter C/C++ mit Pointern oder Handels arbeiten will, dann nutze ich dort auch diesen Datentyp. Der passt sich dann ganz sicher an. Z.B. void*.
Re: Wie Kernel Funktionen verwenden?
Hm, bei mir tut das nicht
Ähnlicher code wie oben auf mein Betriebs system angepasst
liefert leider nur
und hängt dann endlos am _os_read Aufruf.
Weiterhin ist komisch, dass beide Male der selbe watch descriptor (wd1, wd2) nämlich 1 zurückkommt.
Ähnliche code in C funktioniert wie erwartet.
Funktioniert das bei irgendjemand?
Bei mir läuft Ubuntu 13.04 kernel 3.8.0-25-generic #37-Ubuntu SMP i686
Ähnlicher code wie oben auf mein Betriebs system angepasst
Code: Alles auswählen
EnableExplicit
ImportC "/lib/i386-linux-gnu/libc.so.6"
inotify_init.l ()
inotify_add_watch.l (fd.l, pathname.s, mask.l)
inotify_rm_watch.l (fd.l, wd.l)
_os_read.l (fd.l, *buf, count.l) As "read"
EndImport
Structure inotify_event
wd.l
mask.l
cookie.l
len.l
name.s{4096}
EndStructure
#IN_ACCESS = $00000001
#IN_MODIFY = $00000002
#IN_ATTRIB = $00000004
#IN_CLOSE_WRITE = $00000008
#IN_CLOSE_NOWRITE = $00000010
#IN_CLOSE = (#IN_CLOSE_WRITE | #IN_CLOSE_NOWRITE)
#IN_OPEN = $00000020
#IN_MOVED_FROM = $00000040
#IN_MOVED_TO = $00000080
#IN_MOVE = (#IN_MOVED_FROM | #IN_MOVED_TO)
#IN_CREATE = $00000100
#IN_DELETE = $00000200
#IN_DELETE_SELF = $00000400
#IN_MOVE_SELF = $00000800
#IN_UNMOUNT = $00002000
#IN_Q_OVERFLOW = $00004000
#IN_IGNORED = $00008000
#IN_CLOSE = (#IN_CLOSE_WRITE | #IN_CLOSE_NOWRITE)
#IN_MOVE = (#IN_MOVED_FROM | #IN_MOVED_TO)
#IN_ONLYDIR = $01000000
#IN_DONT_FOLLOW = $02000000
#IN_EXCL_UNLINK = $04000000
#IN_MASK_ADD = $20000000
#IN_ISDIR = $40000000
#IN_ONESHOT = $80000000
#IN_ALL_EVENTS = (#IN_ACCESS | #IN_MODIFY | #IN_ATTRIB | #IN_CLOSE_WRITE | #IN_CLOSE_NOWRITE | #IN_OPEN | #IN_MOVED_FROM | #IN_MOVED_TO | #IN_CREATE | #IN_DELETE | #IN_DELETE_SELF | #IN_MOVE_SELF)
;
; EXAMPLE
;
; Der "File Descriptor", der von inotify_init zurück gegeben wird, kann auch
; in einem (e)poll getriebenen reaktor pattern wiederverwendet werden. Das ist
; interessant für asynchrone programmierung.
Define fd.l = inotify_init()
Debug "got fd " + Str(fd)
; Der Kernel wird uns darüber informieren, wenn eine Datei angelegt oder gelöscht
; wurde.
Define wd.l = inotify_add_watch(fd, "/tmp/", #IN_ALL_EVENTS)
Debug "got wd1 " + Str(wd)
Define wd2.l = inotify_add_watch(fd, "/etc/", #IN_ALL_EVENTS)
Debug "got wd2 " + Str(wd2)
; Die Events sind von dynamischer Größe, da sie Dateinamen enthalten.
; Der Buffer wird daher bestenfalls ~256/64 Events halten können. Sollten
; doch noch mehr vorliegne, werden diese im 2. Durchlaufe eingelesen. Alles Dandy.
Define *buf.inotify_event = AllocateMemory(SizeOf(inotify_event) * 256)
Repeat
; Lese so viele Events wie möglich und fülle diese in den Buffer
Debug "read max " + Str(SizeOf(inotify_event) * 256) + " bytes from fd" + Str(fd)
Define length.l = _os_read(fd, *buf, SizeOf(inotify_event) * 256)
Debug "length " + Str(length)
; tmp_buf wird unsere Laufvariable. Sie wird nach jeden Event von uns hoch gezählt
; und zeigt auf das nächste Event.
Define *tmp_buf.inotify_event = *buf
While *tmp_buf < *buf + length
; \name enthält den \0 terminierten gültigen Dateinamen, der Subjekt
; eines Ereignisses wurde.
; \mask enthält eine Verknüpfung aus den oben definierten Konstanten, die
; das Event beschreiben (Datei gelöscht oder angelegt).
If *tmp_buf\mask & #IN_CREATE = #IN_CREATE
Debug *tmp_buf\name + " Angelegt (" + RSet(Hex(*tmp_buf\mask), 8, "0") + ")"
ElseIf *tmp_buf\mask & #IN_DELETE = #IN_DELETE
Debug *tmp_buf\name + " Gelöscht (" + RSet(Hex(*tmp_buf\mask), 8, "0") + ")"
Else
Debug *tmp_buf\name + " Unbekanntes Event (" + RSet(Hex(*tmp_buf\mask), 8, "0") + ")"
EndIf
; Pointer auf das nächste Event zeigen lassen.
*tmp_buf = *tmp_buf + SizeOf(inotify_event) + *tmp_buf\len
Wend
ForEver
Code: Alles auswählen
got fd 3
got wd1 1
got wd2 1
read max 2101248 bytes from fd3
Weiterhin ist komisch, dass beide Male der selbe watch descriptor (wd1, wd2) nämlich 1 zurückkommt.
Ähnliche code in C funktioniert wie erwartet.
Funktioniert das bei irgendjemand?
Bei mir läuft Ubuntu 13.04 kernel 3.8.0-25-generic #37-Ubuntu SMP i686