Was fiddling with gambit's c-ffi and noticed that wills I attached to ports made with ##open-predefined weren't executing so I wrote some test code, if there's something wrong with my code please let me know.
# cat fdes.scm
(c-declare #<<c-declare-end
#include <sys/stat.h> #include <fcntl.h> #include <unistd.h>
c-declare-end )
(define-macro (c-macro var) `(define ,var ((c-lambda () int ,(string-append "___return(" (symbol->string var) ");")))))
;; posix open flags (c-macro O_RDONLY) (c-macro O_WRONLY) (c-macro O_RDWR) (c-macro O_CREAT)
;; filename flags mode -> fdes | -1 (define posix-open (c-lambda (nonnull-char-string int int) int "open")) ;; fdes -> 0 | -1 (define posix-close (c-lambda (int) int "close"))
(define in 1) (define out 2) (define inout 3)
;;; ;;; The will only executes if direction is in
(define (test-posix-open filename direction) (let* ((fd (case direction ((1) (posix-open filename (bitwise-ior O_RDONLY O_CREAT) #o755)) ((2) (posix-open filename (bitwise-ior O_WRONLY O_CREAT) #o755)) ((3) (posix-open filename (bitwise-ior O_RDWR O_CREAT) #o755)))) (port (##open-predefined direction filename fd))) (println "fd: " fd " port: " port) (make-will port (lambda (p) (println "[WILL] closing port " p) (posix-close fd)))) (##gc))
;;; when run with direction other than in this eats up all my ram
(define (test-loop filename direction) (let ((fd (case direction ((1) (posix-open filename (bitwise-ior O_RDONLY O_CREAT) #o755)) ((2) (posix-open filename (bitwise-ior O_WRONLY O_CREAT) #o755)) ((3) (posix-open filename (bitwise-ior O_RDWR O_CREAT) #o755))))) (let loop () (##open-predefined direction filename fd) (loop))))
Afficher les réponses par date
The ##open-predefined procedure is meant for internal use by the runtime system. It is intended to open one of the standard input/output file descriptors (i.e. with the “index” parameter is equal to -1, -2, -3, or -4). For output file descriptors it registers an “exit job” that forces output on the file descriptor when the program terminates. So the output ports created by ##open-predefined will always be reachable until the end of the program’s execution, and the will never detects that the port is unreachable, so it is never executed.
Note that the fact that ##open-predefined allows passing an “index” that is really a file descriptor is not something that you can rely upon, and in particular it will not work on Windows and when Gambit is configured with --enable-ansi-c.
Perhaps the ##open-predefined procedure could be augmented with an optional parameter to enable/disable the automatic forcing of output ports (a will can’t be used for this functionality because the termination of the program does not cause a “final gc” to determine which wills need to trigger).
BTW, why do you need this?
Marc
On Apr 4, 2020, at 10:49 PM, santana@mailbox.org wrote:
Was fiddling with gambit's c-ffi and noticed that wills I attached to ports made with ##open-predefined weren't executing so I wrote some test code, if there's something wrong with my code please let me know.
# cat fdes.scm
(c-declare #<<c-declare-end
#include <sys/stat.h> #include <fcntl.h> #include <unistd.h>
c-declare-end )
(define-macro (c-macro var) `(define ,var ((c-lambda () int ,(string-append "___return(" (symbol->string var) ");")))))
;; posix open flags (c-macro O_RDONLY) (c-macro O_WRONLY) (c-macro O_RDWR) (c-macro O_CREAT)
;; filename flags mode -> fdes | -1 (define posix-open (c-lambda (nonnull-char-string int int) int "open")) ;; fdes -> 0 | -1 (define posix-close (c-lambda (int) int "close"))
(define in 1) (define out 2) (define inout 3)
;;; ;;; The will only executes if direction is in
(define (test-posix-open filename direction) (let* ((fd (case direction ((1) (posix-open filename (bitwise-ior O_RDONLY O_CREAT) #o755)) ((2) (posix-open filename (bitwise-ior O_WRONLY O_CREAT) #o755)) ((3) (posix-open filename (bitwise-ior O_RDWR O_CREAT) #o755)))) (port (##open-predefined direction filename fd))) (println "fd: " fd " port: " port) (make-will port (lambda (p) (println "[WILL] closing port " p) (posix-close fd)))) (##gc))
;;; when run with direction other than in this eats up all my ram
(define (test-loop filename direction) (let ((fd (case direction ((1) (posix-open filename (bitwise-ior O_RDONLY O_CREAT) #o755)) ((2) (posix-open filename (bitwise-ior O_WRONLY O_CREAT) #o755)) ((3) (posix-open filename (bitwise-ior O_RDWR O_CREAT) #o755))))) (let loop () (##open-predefined direction filename fd) (loop))))
Gambit-list mailing list Gambit-list@iro.umontreal.ca https://mailman.iro.umontreal.ca/cgi-bin/mailman/listinfo/gambit-list
Thanks for the explanation.
BTW, why do you need this?
Just learning scheme and c. I wanted to have gambit receive s-exps over a unix domain socket. I figured it would be simplest if I could turn the file descriptor returned from accept into a port and call scheme's read on it. I can do without this though and I'd rather not have ports piling up.
I'm curious though if there's a better way to turn a file descriptor into a port. ##open-predefined is what I saw mentioned when I searched the mailing list.
On Apr 5, 2020, at 1:59 AM, Alejandro Santana santana@mailbox.org wrote:
Thanks for the explanation.
BTW, why do you need this?
Just learning scheme and c. I wanted to have gambit receive s-exps over a unix domain socket. I figured it would be simplest if I could turn the file descriptor returned from accept into a port and call scheme's read on it. I can do without this though and I'd rather not have ports piling up.
No need to muck around with file descriptors to do this. The following program is better as it is portable to linux, macOS and Windows:
(define (start-server local-address handler) (let ((listen-port (open-tcp-server local-address))) (let loop () (handler (read listen-port)) (loop))))
(start-server "*:12345" (lambda (conn) (pretty-print (list 'msg= (read conn))) (close-port conn)))
In another terminal you can send a message to the server with:
% echo "(hello world)" | nc localhost 12345
A server for handling incoming connections can be created even more simply with tcp-service-register! :
(thread-join! (tcp-service-register! "*:12345" (lambda () (pp (list 'msg= (read))))))
I'm curious though if there's a better way to turn a file descriptor into a port. ##open-predefined is what I saw mentioned when I searched the mailing list.
I have added a commit (4a9c3f8dbbbb13d587e6ffec51c5bc87bc9dc666) that fixes this issue. Now the automatic forcing on program termination will no longer happen on file descriptors passed to ##open-predefined. Your fdes.scm program no longer “leaks” memory.
Marc
Hi Alejandro & Marc,
this is exactly the use case I had when I asked the list and likely Alejandro referred to Marcs answer to my question.
So I'm afraid this is really something we need [Q]:
How would I turn a file descriptor, as exported from some library and ready/intented to be used with poll(2)/select(2) into a port?
Thanks sooo much.
/Jörg
Background:
Since when I'm using this ##open-predefined and have on my list to ask why this seems not to integrate into gambit's threading as good as I had hoped for.
Nevertheless Marcs suggestion to use open-tcp-server does not work for me. I really need a unix domain socket. Actually an abstract socket on Linux. No way around. :-/
But I'd like it to block the calling thread on input. Which did not work out for me. (There is lambdanative and Android in the mix too, but my current _guess_ is that neither is to blame here.)
Which leaves me with the question above.
On Sat, 4 Apr 2020 22:59:42 -0700 (PDT) Alejandro Santana santana@mailbox.org wrote:
Thanks for the explanation.
BTW, why do you need this?
Just learning scheme and c. I wanted to have gambit receive s-exps over a unix domain socket. I figured it would be simplest if I could turn the file descriptor returned from accept into a port and call scheme's read on it. I can do without this though and I'd rather not have ports piling up.
I'm curious though if there's a better way to turn a file descriptor into a port. ##open-predefined is what I saw mentioned when I searched the mailing list.
You might be interested in the gerbil socket library a spin; there is support for UNIX domain sockets through raw devices
-- vyzo
On Fri, Apr 10, 2020 at 9:06 PM Jörg F. Wittenberger < Joerg.Wittenberger@softeyes.net> wrote:
Hi Alejandro & Marc,
this is exactly the use case I had when I asked the list and likely Alejandro referred to Marcs answer to my question.
So I'm afraid this is really something we need [Q]:
How would I turn a file descriptor, as exported from some library and ready/intented to be used with poll(2)/select(2) into a port?
Thanks sooo much.
/Jörg
Background:
Since when I'm using this ##open-predefined and have on my list to ask why this seems not to integrate into gambit's threading as good as I had hoped for.
Nevertheless Marcs suggestion to use open-tcp-server does not work for me. I really need a unix domain socket. Actually an abstract socket on Linux. No way around. :-/
But I'd like it to block the calling thread on input. Which did not work out for me. (There is lambdanative and Android in the mix too, but my current _guess_ is that neither is to blame here.)
Which leaves me with the question above.
On Sat, 4 Apr 2020 22:59:42 -0700 (PDT) Alejandro Santana santana@mailbox.org wrote:
Thanks for the explanation.
BTW, why do you need this?
Just learning scheme and c. I wanted to have gambit receive s-exps over a unix domain socket. I figured it would be simplest if I could turn the file descriptor returned from accept into a port and call scheme's read on it. I can do without this though and I'd rather not have ports piling up.
I'm curious though if there's a better way to turn a file descriptor into a port. ##open-predefined is what I saw mentioned when I searched the mailing list.
Gambit-list mailing list Gambit-list@iro.umontreal.ca https://mailman.iro.umontreal.ca/cgi-bin/mailman/listinfo/gambit-list
On Apr 10, 2020, at 2:19 PM, Dimitris Vyzovitis vyzo@hackzen.org wrote:
You might be interested in the gerbil socket library a spin; there is support for UNIX domain sockets through raw devices
-- vyzo
It would be nice if that socket library was a Gambit module so that other Gambit users can use it! :-)
In fact it would be great to have a way for (most) Gerbil modules to be directly accessible from pure Gambit code with an (import (gerbil xxx)) or something like that. That would lessen the community split between Gerbil and pure Gambit users.
Something to consider is to turn Gerbil into a Gambit module so it can be installed directly using Gambit’s package manager. This is already the model for Termite Scheme which was initially designed as a separate language but is now a Gambit module. I’ve also approached Guillaume Cartier to turn JazzScheme into a Gambit module. Note that I’m not talking about a builtin module, but rather a module hosted on its own git repository and installable with “gsi -install github.com/user/my-great-lang”.
If anyone is interested in contributing towards this goal, please let me know!
Marc
I would wholeheartedly welcome such an initiative, and I would gladly help out anyone interested to take it on. I am currently swamped with work (and will be for the forseeable future), so I can't do it on my own.
-- vyzo
On Fri, Apr 10, 2020 at 11:08 PM Marc Feeley feeley@iro.umontreal.ca wrote:
On Apr 10, 2020, at 2:19 PM, Dimitris Vyzovitis vyzo@hackzen.org
wrote:
You might be interested in the gerbil socket library a spin; there is
support for UNIX domain sockets through raw devices
-- vyzo
It would be nice if that socket library was a Gambit module so that other Gambit users can use it! :-)
In fact it would be great to have a way for (most) Gerbil modules to be directly accessible from pure Gambit code with an (import (gerbil xxx)) or something like that. That would lessen the community split between Gerbil and pure Gambit users.
Something to consider is to turn Gerbil into a Gambit module so it can be installed directly using Gambit’s package manager. This is already the model for Termite Scheme which was initially designed as a separate language but is now a Gambit module. I’ve also approached Guillaume Cartier to turn JazzScheme into a Gambit module. Note that I’m not talking about a builtin module, but rather a module hosted on its own git repository and installable with “gsi -install github.com/user/my-great-lang”.
If anyone is interested in contributing towards this goal, please let me know!
Marc
As a first step it would be sufficient to find a way to automatically export the Gerbil standard library as a gambit module. This would bring all the libraries to the wider gambit ecosystem, sans the macrology (which is a little harder to do).
-- vyzo
On Fri, Apr 10, 2020 at 11:19 PM Dimitris Vyzovitis vyzo@hackzen.org wrote:
I would wholeheartedly welcome such an initiative, and I would gladly help out anyone interested to take it on. I am currently swamped with work (and will be for the forseeable future), so I can't do it on my own.
-- vyzo
On Fri, Apr 10, 2020 at 11:08 PM Marc Feeley feeley@iro.umontreal.ca wrote:
On Apr 10, 2020, at 2:19 PM, Dimitris Vyzovitis vyzo@hackzen.org
wrote:
You might be interested in the gerbil socket library a spin; there is
support for UNIX domain sockets through raw devices
-- vyzo
It would be nice if that socket library was a Gambit module so that other Gambit users can use it! :-)
In fact it would be great to have a way for (most) Gerbil modules to be directly accessible from pure Gambit code with an (import (gerbil xxx)) or something like that. That would lessen the community split between Gerbil and pure Gambit users.
Something to consider is to turn Gerbil into a Gambit module so it can be installed directly using Gambit’s package manager. This is already the model for Termite Scheme which was initially designed as a separate language but is now a Gambit module. I’ve also approached Guillaume Cartier to turn JazzScheme into a Gambit module. Note that I’m not talking about a builtin module, but rather a module hosted on its own git repository and installable with “gsi -install github.com/user/my-great-lang”.
If anyone is interested in contributing towards this goal, please let me know!
Marc
Great! Let’s make it happen.
Marc
On Apr 10, 2020, at 4:19 PM, Dimitris Vyzovitis vyzo@hackzen.org wrote:
I would wholeheartedly welcome such an initiative, and I would gladly help out anyone interested to take it on. I am currently swamped with work (and will be for the forseeable future), so I can't do it on my own.
-- vyzo
On Fri, Apr 10, 2020 at 11:08 PM Marc Feeley feeley@iro.umontreal.ca wrote:
On Apr 10, 2020, at 2:19 PM, Dimitris Vyzovitis vyzo@hackzen.org wrote:
You might be interested in the gerbil socket library a spin; there is support for UNIX domain sockets through raw devices
-- vyzo
It would be nice if that socket library was a Gambit module so that other Gambit users can use it! :-)
In fact it would be great to have a way for (most) Gerbil modules to be directly accessible from pure Gambit code with an (import (gerbil xxx)) or something like that. That would lessen the community split between Gerbil and pure Gambit users.
Something to consider is to turn Gerbil into a Gambit module so it can be installed directly using Gambit’s package manager. This is already the model for Termite Scheme which was initially designed as a separate language but is now a Gambit module. I’ve also approached Guillaume Cartier to turn JazzScheme into a Gambit module. Note that I’m not talking about a builtin module, but rather a module hosted on its own git repository and installable with “gsi -install github.com/user/my-great-lang”.
If anyone is interested in contributing towards this goal, please let me know!
Marc
Hi,
I'm afraid I don't grock the documentation wrt. memory management of foreign bjects.
I really need a unix domain socket. Actually an abstract socket on Linux.
The example at at hand: a `struct sockaddr_storage`. That is, in general, any kind of C struct to allocate.
Likely I'm doing it all wrong. My great excuse(TM): I learned gambit's FFI from `gamsock` while adding domain socket support. No, Mam, it's not been me. ;-)
# Part I, the easy thing
(c-define-type socket-address (pointer (struct "sockaddr_storage") socket-address))
(c-lambda (...) socket-address "... ___result_voidstar = malloc(sizeof(struct sockaddr_storage))); ...")
That seems to work. But I'd bet this leaks memory as gamsock never frees this memory.
Q: Does it leak? Or is there some gambit magic default?
# Part II, the crazy thing
If I got that right, than what I'd need to fix the leak was to attach a /will/ to the socket-address, which would free the storage and return ___NO_ERR.
Q: Correct?
If yes, is this a good idea? I'd assume that allocating short lived objects from the Scheme heap should be much less expesive. Isn't it?
# Part III, how?
1. How would I allocate a short lived object on the scheme heap? 2. Still have it properly tagges as foreign object for type checking. (I.e., I know I could allocate a u8vector of the size I need. But this is an u8vector for Scheme, which I don't want.)
Thanks
/Jörg
There are a few issues with your code. First of all, you should use “___return(…);” to return a result (the assignment to ___result_voidstar is deprecated). When Scheme code receives a foreign pointer, there is no “automatic freeing” of the memory done by Gambit. You need to program that explicitly, for example using a will. An alternative would be to create your own type with a release function, but that is probably overkill in this situation. Here’s how I would write the code:
(c-declare "#include <stdlib.h>") (c-declare "#include <sys/socket.h>")
(c-define-type sockaddr_storage (struct "sockaddr_storage")) (c-define-type socket-address (pointer sockaddr_storage socket-address))
(define alloc-socket-address (c-lambda () socket-address "___return(malloc(sizeof(struct sockaddr_storage)));"))
(define free-socket-address (c-lambda (socket-address) void "free(___arg1);"))
(define (make-socket-address) (let ((sa (alloc-socket-address))) (if sa (make-will sa (lambda (sa) (pp (list 'freeing sa)) (free-socket-address sa)))) sa))
(println "-----------") (pp (make-socket-address)) (define foo (make-socket-address)) (pp foo) (println "-----------") (##gc) (println "-----------") (pp (make-socket-address)) (println "-----------") (##gc) (println "-----------")
;; prints: ;; ;; ----------- ;; #<socket-address #2 0x7fe723405010> ;; #<socket-address #3 0x7fe7234050f0> ;; ----------- ;; (freeing #<socket-address #2 0x7fe723405010>) ;; ----------- ;; #<socket-address #4 0x7fe723405010> ;; ----------- ;; (freeing #<socket-address #4 0x7fe723405010>) ;; -----------
Marc
On Apr 10, 2020, at 3:12 PM, Jörg F. Wittenberger Joerg.Wittenberger@softeyes.net wrote:
Hi,
I'm afraid I don't grock the documentation wrt. memory management of foreign bjects.
I really need a unix domain socket. Actually an abstract socket on Linux.
The example at at hand: a `struct sockaddr_storage`. That is, in general, any kind of C struct to allocate.
Likely I'm doing it all wrong. My great excuse(TM): I learned gambit's FFI from `gamsock` while adding domain socket support. No, Mam, it's not been me. ;-)
# Part I, the easy thing
(c-define-type socket-address (pointer (struct "sockaddr_storage") socket-address))
(c-lambda (...) socket-address "... ___result_voidstar = malloc(sizeof(struct sockaddr_storage))); ...")
That seems to work. But I'd bet this leaks memory as gamsock never frees this memory.
Q: Does it leak? Or is there some gambit magic default?
# Part II, the crazy thing
If I got that right, than what I'd need to fix the leak was to attach a /will/ to the socket-address, which would free the storage and return ___NO_ERR.
Q: Correct?
If yes, is this a good idea? I'd assume that allocating short lived objects from the Scheme heap should be much less expesive. Isn't it?
# Part III, how?
- How would I allocate a short lived object on the scheme heap?
- Still have it properly tagges as foreign object for type checking.
(I.e., I know I could allocate a u8vector of the size I need. But this is an u8vector for Scheme, which I don't want.)
Thanks
/Jörg
Gambit-list mailing list Gambit-list@iro.umontreal.ca https://mailman.iro.umontreal.ca/cgi-bin/mailman/listinfo/gambit-list
Thanks for your reply.
On Fri, 10 Apr 2020 15:49:15 -0400 Marc Feeley feeley@iro.umontreal.ca wrote:
There are a few issues with your code. First of all, you should use “___return(…);” to return a result (the assignment to ___result_voidstar is deprecated).
OK. Is there some documentation wrt. these things?
An alternative would be to create your own type with a release function, but that is probably overkill in this situation.
Interesting: you consider a type with release function to be the overkill? I had the impression that the use of wills would be the overly complex way.
Nevertheless: In your suggestion you still use malloc to allocate. I do see situations where I'd tend to do this too. Still I wonder if it was cheaper/faster to allocate on the Scheme heap. And if so, how?
Jörg
On Apr 11, 2020, at 6:16 AM, Jörg F. Wittenberger Joerg.Wittenberger@softeyes.net wrote:
Thanks for your reply.
On Fri, 10 Apr 2020 15:49:15 -0400 Marc Feeley feeley@iro.umontreal.ca wrote:
There are a few issues with your code. First of all, you should use “___return(…);” to return a result (the assignment to ___result_voidstar is deprecated).
OK. Is there some documentation wrt. these things?
The Gambit manual (doc/gambit.pdf) has this to say:
When c-name-or-code is not a valid C identifier, it is treated as an arbitrary piece of C code. Within the C code the variables ‘___arg1’, ‘___arg2’, etc. can be referenced to access the converted arguments. Note that the C return statement can’t be used to return from the procedure. Instead, the ___return macro must be used. A procedure whose result-type is not void must pass the procedure’s result as the single argument to the ___return macro, for example ‘___return(123);’ to return the value 123. When result-type is void, the ___return macro must be called without a parameter list, for example ‘___return;’.
An alternative would be to create your own type with a release function, but that is probably overkill in this situation.
Interesting: you consider a type with release function to be the overkill? I had the impression that the use of wills would be the overly complex way.
Nevertheless: In your suggestion you still use malloc to allocate. I do see situations where I'd tend to do this too. Still I wonder if it was cheaper/faster to allocate on the Scheme heap. And if so, how?
In your C code you could allocate a “still” u8vector object using:
___SCMOBJ obj = ___EXT(___alloc_scmobj) (___PSTATE, ___sU8VECTOR, length_in_bytes);
/* * '___alloc_scmobj (___ps, subtype, bytes)' allocates a permanent or * still Scheme object (depending on '___ps') of subtype ‘subtype' * with a body containing 'bytes' bytes, and returns it as an encoded * Scheme object. When '___ps' is NULL, a permanent object is * allocated, and when '___ps' is not NULL, a still object is * allocated in the heap of that processor's VM. The initialization * of the object's body must be done by the caller. In the case of * still objects this initialization must be done before the next * allocation is requested. The 'refcount' field of still objects is * initially 1. A fixnum error code is returned when there is an * error. */
and then decrement the reference count so that in the future the Gambit garbage collector will be solely responsible for determining if the object can be reclaimed:
___EXT(___release_scmobj) (obj);
To access the content of the object you can use the ___BODY(obj) macro to get a pointer to the content of the object:
char *body = ___CAST(char*,___BODY(obj)); body[0] = 11; body[1] = 22;
I don’t know if there is a significant performance difference between this and the other method I explained (but it does a single call to malloc rather than two). You’ll have to benchmark it to see which one is faster.
Marc
On Apr 10, 2020, at 1:59 PM, Jörg F. Wittenberger Joerg.Wittenberger@softeyes.net wrote:
Background:
Since when I'm using this ##open-predefined and have on my list to ask why this seems not to integrate into gambit's threading as good as I had hoped for.
Nevertheless Marcs suggestion to use open-tcp-server does not work for me. I really need a unix domain socket. Actually an abstract socket on Linux. No way around. :-/
But I'd like it to block the calling thread on input. Which did not work out for me. (There is lambdanative and Android in the mix too, but my current _guess_ is that neither is to blame here.)
On POSIX systems, you can use ##open-predefined to create a port from a file descriptor.
Then, when you want to wait for input to be available you can call ##wait-input-port with that port. This is the definition in lib/_io.scm:
(define-prim (##wait-input-port port)
;; The thread will wait until there is data available to read on the ;; port's device or the port's timeout is reached. The value #f is ;; returned when the timeout is reached. The value #t is returned ;; when there is data available to read on the port's device or the ;; thread was interrupted (for example with thread-interrupt!).
…)
This is fully integrated with the thread system, so it only blocks the calling thread. Note also that you can use input-port-timeout-set! if you want to block for a limited time.
Marc
On Fri, 10 Apr 2020 16:16:23 -0400 Marc Feeley feeley@iro.umontreal.ca wrote:
On Apr 10, 2020, at 1:59 PM, Jörg F. Wittenberger Joerg.Wittenberger@softeyes.net wrote:
Background:
Since when I'm using this ##open-predefined and have on my list to ask why this seems not to integrate into gambit's threading as good as I had hoped for.
... Then, when you want to wait for input to be available you can call ##wait-input-port with that port. This is the definition in lib/_io.scm:
(define-prim (##wait-input-port port)
This is what I'm using so far.
This is fully integrated with the thread system, so it only blocks the calling thread. Note also that you can use input-port-timeout-set! if you want to block for a limited time.
My observation (on Linux) was that ##wait-input-port did not block the current thread at all. Thus gambit was sitting in a tight loop until data arrives.
Jörg
On Apr 11, 2020, at 6:05 AM, Jörg F. Wittenberger Joerg.Wittenberger@softeyes.net wrote:
On Fri, 10 Apr 2020 16:16:23 -0400 Marc Feeley feeley@iro.umontreal.ca wrote:
On Apr 10, 2020, at 1:59 PM, Jörg F. Wittenberger Joerg.Wittenberger@softeyes.net wrote:
Background:
Since when I'm using this ##open-predefined and have on my list to ask why this seems not to integrate into gambit's threading as good as I had hoped for.
... Then, when you want to wait for input to be available you can call ##wait-input-port with that port. This is the definition in lib/_io.scm:
(define-prim (##wait-input-port port)
This is what I'm using so far.
This is fully integrated with the thread system, so it only blocks the calling thread. Note also that you can use input-port-timeout-set! if you want to block for a limited time.
My observation (on Linux) was that ##wait-input-port did not block the current thread at all. Thus gambit was sitting in a tight loop until data arrives.
Jörg
It should work. Can you show me a minimal version of your code?
Marc
On Sat, 11 Apr 2020 09:30:30 -0400 Marc Feeley feeley@iro.umontreal.ca wrote:
My observation (on Linux) was that ##wait-input-port did not block the current thread at all. Thus gambit was sitting in a tight loop until data arrives.
... It should work. Can you show me a minimal version of your code?
I shall destill. (Too much praise actually: gamsock is not really "my code".)
Though while walking the dog it occured to me that the gamsock code reads the data directly from the file descriptor using recvfrom(2).
It could have easily escaped me that the first attempt to ##wait-input-port did actually block. If there was the need to reset the port state (or go to the trouble to figure out how to change the heritage to read via gambit -- whatever is simpler) in order to inform the threading system that it should actually check the file descriptor again, then maybe we can shortcut the session.
Best
/Jörg
On Apr 11, 2020, at 1:01 PM, Jörg F. Wittenberger Joerg.Wittenberger@softeyes.net wrote:
On Sat, 11 Apr 2020 09:30:30 -0400 Marc Feeley feeley@iro.umontreal.ca wrote:
My observation (on Linux) was that ##wait-input-port did not block the current thread at all. Thus gambit was sitting in a tight loop until data arrives.
... It should work. Can you show me a minimal version of your code?
I shall destill. (Too much praise actually: gamsock is not really "my code".)
Though while walking the dog it occured to me that the gamsock code reads the data directly from the file descriptor using recvfrom(2).
It could have easily escaped me that the first attempt to ##wait-input-port did actually block. If there was the need to reset the port state (or go to the trouble to figure out how to change the heritage to read via gambit -- whatever is simpler) in order to inform the threading system that it should actually check the file descriptor again, then maybe we can shortcut the session.
Best
/Jörg
Are you communicating with UDP? If that is the case then maybe you can use Gambit’s UDP ports directly:
(open-udp port-number-or-address-or-settings)
This procedure opens a socket for doing network communication with the UDP protocol. The default value of the direction: setting is input-output, i.e. the Scheme program can send information and receive information on the socket. The sending direction can be closed using the close-output-port procedure and the receiving direction can be closed using the close-input-port procedure. The close-port procedure closes both directions.
The resulting port designates a UDP socket. Each call to read and udp-read-subu8vector causes the reception of a single datagram on the designated UDP socket, and each call to write and udp-write-subu8vector sends a single datagram. UDP ports are a direct subtype of object-ports (i.e. they are not character-ports) and read and write transfer u8vectors. If read is called and a timeout occurs before a datagram is transferred and the timeout thunk returns #f (see the procedure input-port-timeout-set!) then the end-of-file object is returned.
On Sat, 11 Apr 2020 13:08:23 -0400 Marc Feeley feeley@iro.umontreal.ca wrote:
On Apr 11, 2020, at 1:01 PM, Jörg F. Wittenberger Joerg.Wittenberger@softeyes.net wrote:
... Are you communicating with UDP? If that is the case then maybe you can use Gambit’s UDP ports directly:
No, it's abstract unix domain sockets in the case at hand.
But I'm more interested to learn how to get the low level things straight in principle.
(open-udp port-number-or-address-or-settings)
At another currently questionable code spot (after all, may code fails currenlty with confused malloc in short order:-/ ) I actually tried to used gambit's UDP.
But I failed to find out how to bind the outgoing port to the one I'm listening on for the reply. So I went back to use gamsock again.
/Jörg
This procedure opens a socket for doing network communication with the UDP protocol. The default value of the direction: setting is input-output, i.e. the Scheme program can send information and receive information on the socket. The sending direction can be closed using the close-output-port procedure and the receiving direction can be closed using the close-input-port procedure. The close-port procedure closes both directions.
The resulting port designates a UDP socket. Each call to read and udp-read-subu8vector causes the reception of a single datagram on the designated UDP socket, and each call to write and udp-write-subu8vector sends a single datagram. UDP ports are a direct subtype of object-ports (i.e. they are not character-ports) and read and write transfer u8vectors. If read is called and a timeout occurs before a datagram is transferred and the timeout thunk returns #f (see the procedure input-port-timeout-set!) then the end-of-file object is returned.
Just re-read this. Still no clue.
On Apr 11, 2020, at 2:16 PM, Jörg F. Wittenberger Joerg.Wittenberger@softeyes.net wrote:
On Sat, 11 Apr 2020 13:08:23 -0400 Marc Feeley feeley@iro.umontreal.ca wrote:
On Apr 11, 2020, at 1:01 PM, Jörg F. Wittenberger Joerg.Wittenberger@softeyes.net wrote:
... Are you communicating with UDP? If that is the case then maybe you can use Gambit’s UDP ports directly:
No, it's abstract unix domain sockets in the case at hand.
But I'm more interested to learn how to get the low level things straight in principle.
(open-udp port-number-or-address-or-settings)
At another currently questionable code spot (after all, may code fails currenlty with confused malloc in short order:-/ ) I actually tried to used gambit's UDP.
But I failed to find out how to bind the outgoing port to the one I'm listening on for the reply. So I went back to use gamsock again.
/Jörg
This procedure opens a socket for doing network communication with the UDP protocol. The default value of the direction: setting is input-output, i.e. the Scheme program can send information and receive information on the socket. The sending direction can be closed using the close-output-port procedure and the receiving direction can be closed using the close-input-port procedure. The close-port procedure closes both directions.
The resulting port designates a UDP socket. Each call to read and udp-read-subu8vector causes the reception of a single datagram on the designated UDP socket, and each call to write and udp-write-subu8vector sends a single datagram. UDP ports are a direct subtype of object-ports (i.e. they are not character-ports) and read and write transfer u8vectors. If read is called and a timeout occurs before a datagram is transferred and the timeout thunk returns #f (see the procedure input-port-timeout-set!) then the end-of-file object is returned.
Just re-read this. Still no clue.
Maybe you should read that section of the Gambit manual which has examples, such as:
(define p (open-udp (list local-address: "*" address: "time.nist.gov:37"))) (write '#u8() p) (read p)
#u8(222 27 158 226)
Marc
On Apr 11, 2020, at 1:01 PM, Jörg F. Wittenberger Joerg.Wittenberger@softeyes.net wrote:
It could have easily escaped me that the first attempt to ##wait-input-port did actually block. If there was the need to reset the port state (or go to the trouble to figure out how to change the heritage to read via gambit -- whatever is simpler) in order to inform the threading system that it should actually check the file descriptor again, then maybe we can shortcut the session.
If ##wait-input-port returns, it means (it is likely) there is something to read from the file descriptor. You’ll have to read the file descriptor (through C or Scheme code) if you want ##wait-input-port to block again. Otherwise it will return immediately because there is still something available on the file descriptor.
Marc