<div>Dear Marc and list,</div><div><br></div><div>(</div><div>There are times when extracting the file descriptor for instance from a Gambit TCP port is extremely useful. One example of this would be when using OpenSSL, where OpenSSL reads and writes directly to and from the socket, thus saving us from a round of buffering and thereby increasing performance. There ought to be loads and loads of other C libraries where this is of great use also.</div>

<div><br></div><div>Also, it ought to be useful for doing lowlevel configuration of fd:s and sockets using OS API:s, like turning on or off keepalives, etc.</div><div><br></div><div>Gambit's IO system scales excellently for C code to do socket reads and writes, in the sense that Gambit not interferes with it with any background buffering or alike. Gambit can even 'multiplex' sockets managed in C thanks to that the user can make Gambit include selected Gambit TCP ports in its IO scheduler's <font face="courier new, monospace">select()</font> calls, still without doing any reads or writes due to buffering, using the  <font face="courier new, monospace">|##device-port-wait-for-input!|</font> (and <font face="courier new, monospace">|##device-port-wait-for-output!|</font>, currently in a pull request to the Gambit repo) procedures.</div>

<div><br></div><div><br></div><div>Currently, extracting the socket FD requires a quite ugly hack that relies on the user code having access to <font face="courier new, monospace">os_io.h</font>. This is ugly both considering that compiled Gambit distributions don't include <font face="courier new, monospace">os_io.h</font> (by good reasons, as it's an internal file), considering that <font face="courier new, monospace">os_io.h</font> may change and also <font face="courier new, monospace">#include</font> does not have a reference to Gambit's installation directory so the hack would not be future-proof ever.</div>

<div><br></div><div>Fd:s never change during the course of the lifetime of a Gambit port object, so this kind of use is clearly good design.</div><div>)</div><div><br></div><div><br></div><div>What about adding support for Gambit port file descriptor retrieval by adding to Gambit a procedure (<span style="font-family:'courier new',monospace">##os-device-get-fd port) => socket-fd-int</span> ?</div>

<div><br></div><div><br></div><div>Even if this is not like the 'recommended official way' of doing IO in Gambit, I think it's of great value that it is in the box, and again, it does work perfectly already, just that a ugly hack needs to be used to make it go around in this moment, and this would be completely remedied by the addition of such a procedure.</div>

<div><br></div><div><br></div><div><br></div><div>As regards how to implement it, my current best understanding is this would be done by something like:</div><div><br></div><div> * Adding to <font face="courier new, monospace">lib/_kernel.scm</font> row 4124 (here bc. this is where all of Gambit's internal <font face="courier new, monospace">c-lambda</font>:s are and C code is required to deliver this):</div>

<div><br></div><blockquote style="margin:0 0 0 40px;border:none;padding:0px"><div><div><font face="courier new, monospace">(define-prim ##os-device-get-fd</font></div></div><div><div><font face="courier new, monospace">  (c-lambda (scheme-object) scheme-object</font></div>

</div><div><div><font face="courier new, monospace">   "___os_device_get_fd"))</font></div></div></blockquote><div><br></div><div> * Adding to <font face="courier new, monospace">lib/os_io.h</font> row 680:</div>

<div><blockquote style="margin:0 0 0 40px;border:none;padding:0px"><div><div><br></div><div><font face="courier new, monospace">extern ___SCMOBJ ___os_device_get_fd</font></div><div><font face="courier new, monospace">   ___P((___SCMOBJ dev),</font></div>

<div><font face="courier new, monospace">        ());</font></div></div><div><br></div></blockquote></div><div> * Adding to <font face="courier new, monospace">lib/os_io.c</font> row 7500 (possibly the 'logics' code in this procedure would be split out and put at row 1405 or so):</div>

<div><br></div><div><blockquote style="margin:0 0 0 40px;border:none;padding:0px"><div><font face="courier new, monospace">___SCMOBJ </font><span style="font-family:'courier new',monospace">___os_device_get_fd</span></div>

<div><font face="courier new, monospace">   ___P((___SCMOBJ dev),</font></div><div><font face="courier new, monospace">        (dev)</font></div><div><font face="courier new, monospace">___SCMOBJ dev;)</font></div><div><font face="courier new, monospace">{</font></div>

<div><font face="courier new, monospace">  ___device *d = ___CAST(___device*,___FIELD(dev,___FOREIGN_PTR));</font></div><div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">  switch ___device_kind(d) {</font></div>

<div><font face="courier new, monospace">    case ___FILE_DEVICE_KIND:</font></div><div><font face="courier new, monospace">      ___device_file *d = ___CAST(___device_file*,d);</font></div><div><div><font face="courier new, monospace">#ifdef USE_POSIX</font></div>

</div><font face="courier new, monospace">      return d->fd;</font><div><font face="courier new, monospace">#elif USE_WIN32</font></div><font face="courier new, monospace">      return d->handle;</font><div><font face="courier new, monospace">#else</font></div>

<div><font face="courier new, monospace">      return ___UNIMPL_ERR;</font></div><div><font face="courier new, monospace">#endif</font></div><div><span style="font-family:'courier new',monospace">    case ___TTY_DEVICE_KIND:</span></div>

<div><font face="courier new, monospace">      </font><span style="font-family:'courier new',monospace">___device_tty *d = ___CAST(___device_tty*,d);</span></div><div><font face="courier new, monospace">      return d->t;</font></div>

<div><font face="courier new, monospace">    case ___SERIAL_DEVICE_KIND:</font></div><div><font face="courier new, monospace">      ___device_serial *d = ___CAST(___device_serial*,d);</font></div><div><font face="courier new, monospace">      return d->h;</font></div>

<div><font face="courier new, monospace">    case ___TCP_CLIENT_DEVICE_KIND:</font></div><div><font face="courier new, monospace">      ___device_tcp_client *d = ___CAST(___device_tcp_client*,d);</font></div><div><font face="courier new, monospace">      return d->s;</font></div>

<div><font face="courier new, monospace">    case ___TCP_SERVER_DEVICE_KIND:</font></div><div><font face="courier new, monospace">      ___device_tcp_server *d = ___CAST(___device_tcp_server*,d);</font></div><div><font face="courier new, monospace">      return d</font><span style="font-family:'courier new',monospace">-</span><span style="font-family:'courier new',monospace">>s;</span></div>

<div><font face="courier new, monospace">    else:</font></div><div><font face="courier new, monospace">      return __</font><span style="font-family:'courier new',monospace">_FAL;</span></div><div><font face="courier new, monospace">  }</font></div>

<div><font face="courier new, monospace">}</font></div></blockquote></div><div><br></div><div>I did not try to compile the code above, though I believe it would compile and work with only minor modifications.</div><div><br>

</div><div>The returned value currently is not converted to a Scheme object so will cause Gambit to crash. I did not add <font face="courier new, monospace">___FIX()</font> here as the returned value could just be bigger than <font face="courier new, monospace">___FIX_MAX</font> .</div>

<div><br></div><div>Is there any straightforward way to do <font face="courier new, monospace">unsigned int</font> (or <font face="courier new, monospace">___U64</font>) to <font face="courier new, monospace">___SCMOBJ</font> conversion? I don't find <font face="courier new, monospace">___UINT_to_SCMOBJ</font>'s (or <font face="courier new, monospace">___U64_to_SCMOBJ</font>'s) definition anywhere.</div>

<div><br></div><div><br></div><div>Thoughts?</div><div><br></div><div>Best regards,</div><div>Mikael</div><div><br></div>