Proposal: POSIX interfaces

5 views
Skip to first unread message

Daniel Barlow

unread,
Apr 13, 2003, 11:03:51 AM4/13/03
to

One topic that crops up every so often on comp.lang.lisp is "standard
interfaces to POSIX". Having looked at the CMUCL UNIX interface, and
the new ACL POSIX stuff, and with input from some Perl and Python
users, SBCL developers are in the process of defining ours.
comp.lang.lisp readers may want to have a look.

Comments appreciated. Comments saying "I represent FooLisp and we
think that's a jolly good interface, so with the following
uncontroversial changes that you could also make, we'd like to add it
to our next version" doubly appreciated ...


* Scope

The scope of this interface is "operating system calls on a typical
Unixlike platform". This is section 2 of the Unix manual, plus
section 3 calls that are (a) typically found in libc, but (b) not part
of the C standard. For example, we intend to provide support for
opendir() and readdir() , but not for printf()

Some facilities are omitted where they offer absolutely no additional
use over some portable function, or would be actively dangerous to the
consistency of Lisp ()low-level signal handling funcitons, possibly).
Not all functions are available on all platforms. [TBD: unavailable
functions should (a) not exist, or (b) exist but signal some kind of
"not available on this platform" error? There may be cases where we
have to do (b) anyway if it's not obvious at compile-time whether a
feature is supported]

The general intent is for a low-level interface. There are three
reasons for this: it's easier to write a high-level interface given a
low-level one than vice versa, there are fewer philosophical
disagreements about what it should look like, and the work of
implementing it is easily parallelisable - and in fact, can be
attempted on an as-needed basis by the various people who want it.

* Function names

The package name for this interface is SB-POSIX. In this package
there is a Lisp function for each supported Unix function, and a
variable or constant for each supported unix constant. A symbol name
is derived from the C binding's name, by (a) uppercasing, then (b)
replacing underscore (#\_) characters with the hyphen (#\-)

No other changes to "Lispify" symbol names are made, so creat()
becomes CREAT, not CREATE

The user is encouraged not to (USE-PACKAGE :SB-POSIX) but instead to
use the SB-POSIX: prefix on all references, as some of our symbols
have the same name as CL symbols (OPEN, CLOSE, SIGNAL etc).

[ Rationale: We use similar names to the C bindings so that unix
manual pages can be used for documentation. To avoid name clashes
with CL or other functions, the approaches considered were (a) prefix
the names of clashing symbols with "POSIX-" or similar, (b) prefix
_all_ symbols with "POSIX-", (c) use the packaging system to resolve
ambiguities. (a) was rejected as the set of symbols we may
potentially clash with is not fixed (for example, if new symbols are
added to SB-EXT) so symbols might have to be renamed over the lifetime
of SB-POSIX, which is not good. The choice between (b) and (c) was
made on the grounds that POSIX-OPEN is about as much typing as
SB-POSIX:OPEN anyway, and symbol munging is, the author feels,
slightly tacky, when there's a package system available to do it more
cleanly ]


* Parameters

The calling convention is modelled after that of CMUCL's UNIX package:
in particular, it's like the C interface except

a) length arguments are omitted or optional where the sensible value
is obvious. For example,

(read fd buffer &optional (length (length buffer))) => bytes-read

b) where C simulates "out" parameters using pointers (for instance, in
pipe() or socketpair()) we may use multiple return values instead.
This doesn't apply to data transfer functions that fill buffers.

c) some functions accept objects such as filenames or file
descriptors. In the C bindings these are strings and small integers
respectively. For the Lisp programmer's convenience we introduce
"filename designators" and "file descriptor designator" concepts such
that CL pathnames or open streams can be passed to these functions.

[ Rationale: Keeping exact 1:1 correspondence with C conventions is
less important here, as the function argument list can easily be
accessed to find out exactly what the arguments are. Designators
are primarily a convenience feature ]

* Return values

The return value is usually the same as for the C binding, except in
error cases: where the C function is defined as returning some
sentinel value and setting "errno" on error, we instead signal an
error of type SYSCALL-ERROR. The actual error value ("errno") is
stored in this condition and can be accessed with SYSCALL-ERRNO.
[TBA: some interface to strerror, to get the user-readable translation
of the error number]

We do not automatically translate the returned value into "Lispy"
objects - for example, SB-POSIX:OPEN returns a small integer, not a
stream.

[ Rationale: This is an interface to POSIX, not a high-level interface
that uses POSIX, and many people using it will actually want to mess
with the file descriptors directly. People needing Lispy interfaces
can implement them atop this - or indeed, use the existing COMMON-LISP
package, which already has many high-level constructs built on top of
the operating system ;-) ]

-dan

--

http://www.cliki.net/ - Link farm for free CL-on-Unix resources

Kalle Olavi Niemitalo

unread,
Apr 13, 2003, 12:01:04 PM4/13/03
to
Daniel Barlow <d...@telent.net> writes:

> For the Lisp programmer's convenience we introduce
> "filename designators" and "file descriptor designator" concepts such
> that CL pathnames or open streams can be passed to these functions.

Do you have public functions for converting the designators to
the designated values? Like the STRING function makes a string
out of any string designator.

Daniel Barlow

unread,
Apr 13, 2003, 12:34:25 PM4/13/03
to
Kalle Olavi Niemitalo <k...@iki.fi> writes:

> Do you have public functions for converting the designators to
> the designated values? Like the STRING function makes a string
> out of any string designator.

In our implementation (most of which doesn't exist yet, actually) we
have standard functions to do the conversions, but they're not
presently exported, so I left this bit out of the proposal.

Should they be part of the interface? I can't see any way in which it
would hurt, but I'm open to arguments

Will Hartung

unread,
Apr 13, 2003, 12:50:26 PM4/13/03
to

"Daniel Barlow" <d...@telent.net> wrote in message
news:87llyeg...@noetbook.telent.net...

> Kalle Olavi Niemitalo <k...@iki.fi> writes:
>
> > Do you have public functions for converting the designators to
> > the designated values? Like the STRING function makes a string
> > out of any string designator.
>
> In our implementation (most of which doesn't exist yet, actually) we
> have standard functions to do the conversions, but they're not
> presently exported, so I left this bit out of the proposal.
>
> Should they be part of the interface? I can't see any way in which it
> would hurt, but I'm open to arguments

They should be included if for no other reason than allowing the programmer
to eat the price of conversion up front, and passing a reference to the
converted element rather than paying the price for each POSIX call. Perhaps
a utility library that lets users manipulate the native POSIX structures
directly within Lisp would be handy as well.

It's a blurry area just because folks are probably better off using Lisp for
string manipulation versus strcat and strcpy, but on the other side of the
coin, if these kinds of structures need to be passed in and out of the
library, it would be nice to have reasonably direct access to them so the
users doesn't have to constantly pay the marshalling penalty to cross the
boudary into POSIX if they don't want to.

Perhaps in the next version.

Regards,

Will Hartung
(wi...@msoft.com)

Adam Warner

unread,
Apr 13, 2003, 7:08:31 PM4/13/03
to
Hi Daniel Barlow,

> The package name for this interface is SB-POSIX. In this package there
> is a Lisp function for each supported Unix function, and a variable or
> constant for each supported unix constant. A symbol name is derived
> from the C binding's name, by (a) uppercasing, then (b) replacing
> underscore (#\_) characters with the hyphen (#\-)
>
> No other changes to "Lispify" symbol names are made, so creat() becomes
> CREAT, not CREATE
>
> The user is encouraged not to (USE-PACKAGE :SB-POSIX) but instead to use
> the SB-POSIX: prefix on all references, as some of our symbols have the
> same name as CL symbols (OPEN, CLOSE, SIGNAL etc).

Sounds fine Daniel. I like to remind myself and others that I am using
language extensions by typing the package prefix. But since this is
eventually intended to be a standard interface to POSIX across
implementations please consider the package prefix POSIX. Code won't be
portable if SBCL has SB-POSIX, CMUCL has CMU-POSIX, ACL has ACL-POSIX,
etc.

As you know you are deliberately creating symbol conflicts in the event
anyone ever wishes to export the functionality. Would it be so bad to
prefix every API symbol with POSIX- and export all the API functionality
by default? There's the same amount of typing (actually less, - isn't
shifted), the same amount of information conveyed, no potentially messy
symbol conflicts down the road and no chance that POSIX:OPEN and
POSIX-OPEN both become used as people figure out ways to export the
package. Finally if a new revision of ANSI Common Lisp standardised upon
this interface it wouldn't have to resolve any symbol conflicts with
existing CL symbols.

This is an exciting project. Thanks Daniel.

Regards,
Adam

Marc Spitzer

unread,
Apr 13, 2003, 7:53:29 PM4/13/03
to
"Adam Warner" <use...@consulting.net.nz> writes:

> As you know you are deliberately creating symbol conflicts in the event
> anyone ever wishes to export the functionality. Would it be so bad to
> prefix every API symbol with POSIX- and export all the API functionality
> by default? There's the same amount of typing (actually less, - isn't
> shifted), the same amount of information conveyed, no potentially messy
> symbol conflicts down the road and no chance that POSIX:OPEN and
> POSIX-OPEN both become used as people figure out ways to export the
> package. Finally if a new revision of ANSI Common Lisp standardised upon
> this interface it wouldn't have to resolve any symbol conflicts with
> existing CL symbols.

Well the answer is, just do not 'use' the posix package, don't import
it and all is well. And as long as you do not import the package
you get posix: as a tag anyway.

marc

Daniel Barlow

unread,
Apr 13, 2003, 8:19:19 PM4/13/03
to
"Adam Warner" <use...@consulting.net.nz> writes:

> Sounds fine Daniel. I like to remind myself and others that I am using
> language extensions by typing the package prefix. But since this is
> eventually intended to be a standard interface to POSIX across
> implementations please consider the package prefix POSIX. Code won't be
> portable if SBCL has SB-POSIX, CMUCL has CMU-POSIX, ACL has ACL-POSIX,
> etc.

This will not become a standard (even a de facto standard) interface
to POSIX until and unless many Lisp implementors adopt it. I expect
that it will undergo changes during the agreement process, and so it'd
be rather rude to preemptively lay claim to the "POSIX" package name
before any of that discussion has happened.

In the meantime, for user code, it's the work of minutes - and a few
of them at most - to add appropriate package nicknames. In fact, you
could probably already get a long way with something like (untested)

(let ((posix (find-package #+excl :excl.osi #+sbcl :sb-posix)))
(rename-package posix (package-name posix)
(cons "POSIX" (package-nicknames posix))))

> As you know you are deliberately creating symbol conflicts in the event
> anyone ever wishes to export the functionality. Would it be so bad to

The functionality is exported - otherwise it'd be POSIX::OPEN, not
POSIX:OPEN. All we're doing is advising people not to USE-PACKAGE the
package.

> prefix every API symbol with POSIX- and export all the API functionality
> by default? There's the same amount of typing (actually less, - isn't
> shifted), the same amount of information conveyed, no potentially messy
> symbol conflicts down the road and no chance that POSIX:OPEN and
> POSIX-OPEN both become used as people figure out ways to export the
> package

I don't see the issue you refer to with "symbol conflicts down the
road", or why people would feel the need to start defining functions
called POSIX-OPEN - can you explain the motivation there?

Maybe I'm dumb, but I really can't see the point of introducing an
ad-hoc POSIX- namespace when the package system gives us a perfectly
good "POSIX:" namespace "for free", and I'd like to know what I'm
missing. Anyone?

> package. Finally if a new revision of ANSI Common Lisp standardised
> upon this interface it wouldn't have to resolve any symbol conflicts
> with existing CL symbols.

I have no expectation that there will ever be a new revision of ANSI
Common Lisp, and to be honest I don't think that system-specific
interfaces ought to be part of that standard (and certainly not in the
COMMON-LISP package) if there is. Maybe someone associated with the
ANSI process could comment there, though. Do they have a specific
remit with regard to portability, or do they just[*] let you
standardise anything that the user/vendor community ask to have
standardised?


-dan

[*] For some suitable value of "just", of course. I don't want to
downplay the amount of work involved in a formal standards process

Adam Warner

unread,
Apr 13, 2003, 9:11:00 PM4/13/03
to
Hi Daniel Barlow,

(Thanks for fixing my incorrect use of packaging terminology).

>> prefix every API symbol with POSIX- and export all the API
>> functionality by default? There's the same amount of typing (actually
>> less, - isn't shifted), the same amount of information conveyed, no
>> potentially messy symbol conflicts down the road and no chance that
>> POSIX:OPEN and POSIX-OPEN both become used as people figure out ways to
>> export the package
>
> I don't see the issue you refer to with "symbol conflicts down the
> road", or why people would feel the need to start defining functions
> called POSIX-OPEN - can you explain the motivation there?

One cannot USE-PACKAGE without the imported symbols conflicting with
essential Common Lisp commands.

> Maybe I'm dumb, but I really can't see the point of introducing an
> ad-hoc POSIX- namespace when the package system gives us a perfectly
> good "POSIX:" namespace "for free", and I'd like to know what I'm
> missing. Anyone?

Packages tend to increase symbol name conflicts that would otherwise be
avoided if there wasn't a package system. CMUCL avoids this by using UNIX-
to prefix exported symbols in the UNIX package (e.g. UNIX:UNIX-CREAT,
UNIX:UNIX-TRUNCATE, UNIX:UNIX-STAT etc.)

You're intending to use the same base symbol names to require the use of
package prefixes or the renaming of imported commands. I was just
proposing a way that allows exported symbols in the package to be easily
imported. But either approach could be achieved from the other with a bit
of macrology (e.g. loop over the exported symbols, create POSIX-* macros
from the symbols exported in the POSIX package and import the POSIX-*
symbols exported from a different package. Perhaps SB-POSIX could be the
original package and POSIX the new package containing the exported POSIX-*
symbols).

You're the one doing the work and you're the one happy with encouraging
the use of a use a package prefix. So go right ahead!

Regards,
Adam

Don Geddis

unread,
Apr 13, 2003, 9:35:51 PM4/13/03
to
> >> prefix every API symbol with POSIX- and export all the API
> >> functionality by default?

Daniel Barlow:


> > I don't see the issue you refer to with "symbol conflicts down the
> > road", or why people would feel the need to start defining functions
> > called POSIX-OPEN - can you explain the motivation there?

"Adam Warner" <use...@consulting.net.nz> writes:
> One cannot USE-PACKAGE without the imported symbols conflicting with
> essential Common Lisp commands.

Why would one want to USE-PACKAGE Daniel's package?

It seems like there are two usage models:

1. [Daniel:] Name the functions just OPEN, put them in a package (SB-)POSIX,
and refer to them in running code as POSIX:OPEN. Never USE-PACKAGE.

2. [Adam:] Name the functions POSIX-OPEN, in the POSIX package. Then
USE-PACKAGE the POSIX package, so instead of having to type
POSIX:POSIX-OPEN you can just type POSIX-OPEN.

Either proposal seems fine, but I think Daniel was asking for problems with
scenario #1. You wouldn't _want_ to USE-PACKAGE the package in that case,
so the fact that it would be difficult to do so isn't really a criticism.

USE-PACKAGE generally allows you to refer to symbols with shorter names,
but in this case scenario #1 (without USE-PACKAGE) gives names of (about)
the same length as scenario #2 (with USE-PACKAGE).

Is there some other benefit to USE-PACKAGE that would help to distinguish
the pros & cons of the two scenarios? (One example might be a kind of implied
documentation: if you see a USE-PACKAGE of POSIX at the top of some file, it
gives you an indication of what you might expect to see in the subsequent code.
This seems like a weak benefit to me, but perhaps some would find it
important.)

-- Don
_______________________________________________________________________________
Don Geddis http://don.geddis.org d...@geddis.org
I bet one of Dracula's least favorite games is croquet, and not just because of
the wooden stakes. It just doesn't move fast enough for him.
-- Deep Thoughts, by Jack Handey [1999]

Adam Warner

unread,
Apr 13, 2003, 10:54:13 PM4/13/03
to
Hi Don Geddis,

I think your spot-on summary has highlighted that either proposal is
simply a matter of taste devoid of any significant consequences. I can see
Daniel's point of view.

I did mention that the package name shouldn't be tied to SBCL but Daniel
has already rejected a POSIX package name as `rather rude to preemptively
lay claim to the "POSIX" package name'. And he pointed out a way to
potentially keep source code portable. Frankly I think he should go ahead
and be as presumptive and rude as he likes in trying to standardise
something as important as a POSIX interface. As he states it's a
"low-level interface" with "fewer philosophical disagreements about what
it should look like" and he might just end up getting it 100% right.
Nothing wrong with a Lisp benevolent dictator every now and then,
especially since Daniel believes that there will never be another ANSI
Common Lisp standard (and I tend to agree--it's pretty much up to us to
define extensions to the standard).

Regards,
Adam

Marc Spitzer

unread,
Apr 14, 2003, 12:50:20 AM4/14/03
to
"Adam Warner" <use...@consulting.net.nz> writes:

> especially since Daniel believes that there will never be another ANSI
> Common Lisp standard (and I tend to agree--it's pretty much up to us to
> define extensions to the standard).
>
> Regards,
> Adam

From what I have learned of the standards process, it was a process
that codified existing mac lisp stuff into 1 package ANSI CL. The
work I see going on with networking, posix, etc is the precursor to
the next round of lisp standardization.

marc

Peter Seibel

unread,
Apr 14, 2003, 1:17:56 AM4/14/03
to
"Adam Warner" <use...@consulting.net.nz> writes:

> I did mention that the package name shouldn't be tied to SBCL but
> Daniel has already rejected a POSIX package name as `rather rude to
> preemptively lay claim to the "POSIX" package name'. And he pointed
> out a way to potentially keep source code portable. Frankly I think
> he should go ahead and be as presumptive and rude as he likes in
> trying to standardise something as important as a POSIX interface.
> As he states it's a "low-level interface" with "fewer philosophical
> disagreements about what it should look like" and he might just end
> up getting it 100% right. Nothing wrong with a Lisp benevolent
> dictator every now and then, especially since Daniel believes that
> there will never be another ANSI Common Lisp standard (and I tend to
> agree--it's pretty much up to us to define extensions to the
> standard).

If I had $.02 to put in here, I'd agree. Assuming you (Daniel) are
willing to deal with and interested in feedback from other
implementors, I imagine that other folks would be more likely to look
at a proposal for a POSIX package as something they might have a stake
in than SB-POSIX. Speaking as a user, and as someone who's spent a
fair bit of time lately trying to spread the Lisp gospel it'd be nice
to both:

a) Have a standard (in the sense of widely adopted community
standard) way of doing something important and obvious like
accessing the POSIX APIs.

b) Have a nice concrete sign like the development of such an API
showing that the "Lisp community" can work together to standardize
stuff like this.

So if you'd like either a) or b) to happen, I'd say grab the good name
and see if anyone rises to the bait. ;-)

Obviously it's more work to try to gather consensus around an API than
to just write one for your own implementation. I'm pretty busy with
another Lisp project at the moment but in the interest of putting a
bit of my money where my mouth is (assuming (equalp time money)) I'd
be happy to set up a mailing list and/or host web pages for such a
project on the lispniks.com domain.[1] And participating as time allows.

-Peter

[1] Okay, so neither is such a huge offer as there are plenty of other
ways to get a mailing list set up or pages on the web. But it'll save
you some hassle.

--
Peter Seibel pe...@javamonkey.com

The intellectual level needed for system design is in general
grossly underestimated. I am convinced more than ever that this
type of work is very difficult and that every effort to do it with
other than the best people is doomed to either failure or moderate
success at enormous expense. --Edsger Dijkstra

Kaz Kylheku

unread,
Apr 14, 2003, 8:47:46 PM4/14/03
to
Daniel Barlow <d...@telent.net> wrote in message news:<87u1d2h...@noetbook.telent.net>...

> One topic that crops up every so often on comp.lang.lisp is "standard
> interfaces to POSIX". Having looked at the CMUCL UNIX interface, and
> the new ACL POSIX stuff, and with input from some Perl and Python
> users, SBCL developers are in the process of defining ours.
> comp.lang.lisp readers may want to have a look.

How about changing the package name from SB-POSIX to a vendor-neutral
CL-POSIX (as a nickname for COMMON-LISP-POSIX).

> Comments appreciated. Comments saying "I represent FooLisp and we
> think that's a jolly good interface, so with the following
> uncontroversial changes that you could also make, we'd like to add it
> to our next version" doubly appreciated ...
>
>
> * Scope
>
> The scope of this interface is "operating system calls on a typical
> Unixlike platform".

[ snip ]

You seem to be trying to reduce the bindings to a few axioms, which if
adhered to will cause everyone to generate compatible bindings. So a
discussion about any potential holes in these axioms would be useful.

One hole is the treatment of structures. For example ``struct stat''
becomes what type? CL-POSIX:STAT? Is it a class or struct? Are the
slot symbols all in the CL-POSIX package?

What about some of the completely opaque types, like sigset_t? The
implementor should have some latitude how these are represented; they
should remain opaque in Lisp, subject to functional accessors that
mirror the C ones.

Here is another omission: what to do with variable-length functions
like execvp()? Do they take a list, or vector or either?

> b) where C simulates "out" parameters using pointers (for instance, in
> pipe() or socketpair()) we may use multiple return values instead.

May is not good enough; this is a hole. Say ``shall''. Also, in what
order? Primary return value always first, then the others in left to
right order.

But in addition to data transfer functions, there are functions whose
semantics are to initialize a C object, like sigemptyset(). You
probably want to keep it that way, rather than turn sigemptyset() into
a constructor that returns a a brand new, empty signal set. Or it
could have both behaviors: the set could be returned as a second
value, which is identical to the optional argument if it is present,
or a new object if the argument is missing.

We can distil this to one unified axiom: reference parameters that
have out semantics are always reflected in additional return values,
even for data-transfer operations like read. If the parameter list has
a suitable structure such that these parameters can be made optional,
and there is enough information in the required parameters to
construct the appropriate objects, then this shall be supported. The
structure of the multiple value will be the same as if the optional
parameters were present.

Thus the CL-POSIX:READ function will have a mandatory buffer
parameter, because if it is left out, there is no way to deduce how
large a buffer to allocate.

Alternative: let these parameters *always* be optional if the
structure of the argument list allows it (there are no removable
required parameters that follow). If there is not enough information
to construct an object, the implementation supplies reasonable
defaults. For example (CL-POSIX:READ 1), not having a buffer, might
substitute some implementation-defined size like 1024 and make a
buffer that large. The filled buffer will be returned as a second
value, regardless of whether it was implicitly allocated by the call,
or specified by the caller.

I believe that this axiom handles a large number of possible C
interfaces without much ambiguity.

> The return value is usually the same as for the C binding, except in
> error cases: where the C function is defined as returning some
> sentinel value and setting "errno" on error, we instead signal an
> error of type SYSCALL-ERROR. The actual error value ("errno") is
> stored in this condition and can be accessed with SYSCALL-ERRNO.
> [TBA: some interface to strerror, to get the user-readable translation
> of the error number]

I vote for a global symbol-macro called CL-POSIX:ERRNO, which expands
to an implementation-defined place that is thread-specific and all
that. For example, on some fictitious Lisp system, this could expand
to (SYSTEM::GET-ERRNO) which calls a C function that retrieves the
value of the errno macro, and (SETF (SYSETM::GETERRNO)) would call a
function that assigns to the errno macro. I have successfully
implemented an errno interface this way.

The strerror interface will be handled in a straightforward way.
Integer parameter in, string object out.

The SYSCALL-ERRNO accessor is a good idea; having the error replicated
in the condition means that if something in the handlnig chain affects
errno, the handler which takes the condition still has a copy of the
original errno. Moreover, it's cheaper to access that copy than to
call down into the C to get it. It's hard to implement an efficient
errno accessor without getting very chummy with the C library. It's
not a simple global integer; in a multithreaded libc, it expands to
something like (*__errno_location()) which calls a function to obtain
the thread-specific pointer to errno and dereferences it.

> We do not automatically translate the returned value into "Lispy"
> objects - for example, SB-POSIX:OPEN returns a small integer, not a
> stream.

Good. But it would be nice to have something like the moral equivalent
of fdopen(); say you have a file descriptor already and want to bind
it to a Lisp stream. Maybe you are writing a program that inherits a
file descriptor across exec, who knows. There are ways of obtaining an
open file descriptor that are not mirrored nicely in the stream
system. Also, an accessor function that pulls out the POSIX descriptor
from the Lisp stream. This is a kind of ``abstraction leakiness''
which is sometimes necessary to get a job done. Suppose you want to
determine whether your *terminal-io* is really bound to a tty device,
and fiddle with the termios settings? The POSIX interface extends C
streams with the fileno() function for this purpose.

Kaz Kylheku

unread,
Apr 14, 2003, 8:47:46 PM4/14/03
to
Daniel Barlow <d...@telent.net> wrote in message news:<87u1d2h...@noetbook.telent.net>...
> One topic that crops up every so often on comp.lang.lisp is "standard
> interfaces to POSIX". Having looked at the CMUCL UNIX interface, and
> the new ACL POSIX stuff, and with input from some Perl and Python
> users, SBCL developers are in the process of defining ours.
> comp.lang.lisp readers may want to have a look.

How about changing the package name from SB-POSIX to a vendor-neutral


CL-POSIX (as a nickname for COMMON-LISP-POSIX).

> Comments appreciated. Comments saying "I represent FooLisp and we


> think that's a jolly good interface, so with the following
> uncontroversial changes that you could also make, we'd like to add it
> to our next version" doubly appreciated ...
>
>
> * Scope
>
> The scope of this interface is "operating system calls on a typical
> Unixlike platform".

[ snip ]

You seem to be trying to reduce the bindings to a few axioms, which if
adhered to will cause everyone to generate compatible bindings. So a
discussion about any potential holes in these axioms would be useful.

One hole is the treatment of structures. For example ``struct stat''
becomes what type? CL-POSIX:STAT? Is it a class or struct? Are the
slot symbols all in the CL-POSIX package?

What about some of the completely opaque types, like sigset_t? The
implementor should have some latitude how these are represented; they
should remain opaque in Lisp, subject to functional accessors that
mirror the C ones.

Here is another omission: what to do with variable-length functions
like execvp()? Do they take a list, or vector or either?

> b) where C simulates "out" parameters using pointers (for instance, in


> pipe() or socketpair()) we may use multiple return values instead.

May is not good enough; this is a hole. Say ``shall''. Also, in what

> The return value is usually the same as for the C binding, except in


> error cases: where the C function is defined as returning some
> sentinel value and setting "errno" on error, we instead signal an
> error of type SYSCALL-ERROR. The actual error value ("errno") is
> stored in this condition and can be accessed with SYSCALL-ERRNO.
> [TBA: some interface to strerror, to get the user-readable translation
> of the error number]

I vote for a global symbol-macro called CL-POSIX:ERRNO, which expands


to an implementation-defined place that is thread-specific and all
that. For example, on some fictitious Lisp system, this could expand
to (SYSTEM::GET-ERRNO) which calls a C function that retrieves the
value of the errno macro, and (SETF (SYSETM::GETERRNO)) would call a
function that assigns to the errno macro. I have successfully
implemented an errno interface this way.

The strerror interface will be handled in a straightforward way.
Integer parameter in, string object out.

The SYSCALL-ERRNO accessor is a good idea; having the error replicated
in the condition means that if something in the handlnig chain affects
errno, the handler which takes the condition still has a copy of the
original errno. Moreover, it's cheaper to access that copy than to
call down into the C to get it. It's hard to implement an efficient
errno accessor without getting very chummy with the C library. It's
not a simple global integer; in a multithreaded libc, it expands to
something like (*__errno_location()) which calls a function to obtain
the thread-specific pointer to errno and dereferences it.

> We do not automatically translate the returned value into "Lispy"


> objects - for example, SB-POSIX:OPEN returns a small integer, not a
> stream.

Good. But it would be nice to have something like the moral equivalent

Kaz Kylheku

unread,
Apr 14, 2003, 9:05:40 PM4/14/03
to
"Adam Warner" <use...@consulting.net.nz> wrote in message news:<pan.2003.04.14....@consulting.net.nz>...

> Hi Daniel Barlow,
>
> (Thanks for fixing my incorrect use of packaging terminology).
>
> >> prefix every API symbol with POSIX- and export all the API
> >> functionality by default? There's the same amount of typing (actually
> >> less, - isn't shifted), the same amount of information conveyed, no
> >> potentially messy symbol conflicts down the road and no chance that
> >> POSIX:OPEN and POSIX-OPEN both become used as people figure out ways to
> >> export the package
> >
> > I don't see the issue you refer to with "symbol conflicts down the
> > road", or why people would feel the need to start defining functions
> > called POSIX-OPEN - can you explain the motivation there?
>
> One cannot USE-PACKAGE without the imported symbols conflicting with
> essential Common Lisp commands.

That is true; but it does not constitute a reason for pretending that
packages are useless, and adopting a single namespace approach with
prefixes!

It is an argument against indiscriminate use of USE-PACKAGE!

> > Maybe I'm dumb, but I really can't see the point of introducing an
> > ad-hoc POSIX- namespace when the package system gives us a perfectly
> > good "POSIX:" namespace "for free", and I'd like to know what I'm
> > missing. Anyone?
>
> Packages tend to increase symbol name conflicts that would otherwise be
> avoided if there wasn't a package system.

There is your problem: you believe this bit of nonsense to be true. If
packages increase symbol conflicts, then the package system is
useless. There is no reason for it to exist. But that is in fact
wrong; the CL package system is very good and if only it is used
properly, it fights clashes.

The clashes occur only when someone wants to effectively defeat part
of the package mechanism by merging together separate spaces, making
them both visible in one package, for the sake of convenience. But
this is something you *cannot* do with prefixes (without an extremely
obtuse pattern-match-and-rename hack). So your argument basically
boils down to this: without the package system, USE-PACKAGE goes away,
and everyone uses fully qualified names via prefixes. This is cleaner,
because people are *prevented* from doing something convenient and
sensible; since the convenience doesn't exist, the issues associated
with that convenience do not exist also.

Down this road lies all kinds of madness. Static typing, single
dispatch, ``pure'' FP, whitespace-based indentation and all kinds of
other idiocies introduced as knee-jerk reactions against any sort of
convenience in programming that carries a shred of responsibility.

Name prefixes do nothing other than badly reinvent a package system,
using strings to express its structure rather than data structures!

> CMUCL avoids this by using UNIX-
> to prefix exported symbols in the UNIX package (e.g. UNIX:UNIX-CREAT,
> UNIX:UNIX-TRUNCATE, UNIX:UNIX-STAT etc.)

Which is a stupidity; you already have the UNIX package name. So now
you *have* to use importing if you want convenient access to these
identifiers, otherwise you are doomed to always repeat the word UNIX.

They could just have kept the short names, and leave it to the user to
qualify the names: (UNIX:OPEN ...) and so on. Those of us who don't
like to perform wholesale package importing end up writing
(UNIX:UNIX-OPEN ...) everywhere. No thanks, I don't want to make the
whole damn UNIX package visible in my package!

If you are writing your own package, you have things like
:shadowing-import-from; you can make visible in your package precisely
that set of symbols from a given package which you want, and no
others.

> You're intending to use the same base symbol names to require the use of
> package prefixes or the renaming of imported commands.

No renaming is needed; if in your package you want to use different
OPEN functions from different packages, you simply choose which one
you want to use by its short name and make that one visible in your
package. References to the others will be qualified.

This is a notch better than using compound names for all different
OPEN functions, so that *all* references have to be (effectively)
qualified. At least you have a choice to make the most frequently used
one unqualified. And you also have the choice of using nicknames.
Imagine if all symbols in the CL package were instead marked by a
"COMMON-LISP-" prefix. Not only do you have to use the prefix
everywhere, but you have to use *that* prefix and not some nicknamed
one. Nicknaming is nice; the C++ people even copied it, badly.

> I was just
> proposing a way that allows exported symbols in the package to be easily
> imported.

What? The package system has this feature already. The :use argument
in make-package or defpackage causes only the external symbols of a
package to be inherited. This is what USE-PACKAGE does also: it takes
only the exported symbols from the source package, the ones that can
be reached in the read syntax using just one colon instead of two.

Of course, different packages can have external symbols of the same
name, and so when you import from these, you get a clash. So, either
don't do that, or selectively import what you want.

There are enough pieces in the package system that you can build
something at a higher level, like Tim Bradshaw's ``conduits'' package.
Something which lets you easily say: I want to make things visible
from packages X Y Z. If there are conflicts, the winner will always be
Y, except that in the case of symbols A B C, package Z will dominate.

But even without such a thing, it's not exceedingly difficult to sort
out the conflicts by a suitable defpackage construct. In the worst
case you can be very conservative. That is, :use nothing at all other
than perhaps "CL", and use :shadowing-import-from to specifically
obtain anything else from other packages that you want to use by its
unqualified name.

> But either approach could be achieved from the other with a bit
> of macrology (e.g. loop over the exported symbols, create POSIX-* macros
> from the symbols exported in the POSIX package and import the POSIX-*
> symbols exported from a different package.

Aha! See my earlier comment regarding ``extremely obtuse
pattern-match-and rename hack''. Don't you think that renaming hacks
can create their own conflict problems?

Kaz Kylheku

unread,
Apr 14, 2003, 9:05:42 PM4/14/03
to
"Adam Warner" <use...@consulting.net.nz> wrote in message news:<pan.2003.04.14....@consulting.net.nz>...
> Hi Daniel Barlow,
>
> (Thanks for fixing my incorrect use of packaging terminology).
>
> >> prefix every API symbol with POSIX- and export all the API
> >> functionality by default? There's the same amount of typing (actually
> >> less, - isn't shifted), the same amount of information conveyed, no
> >> potentially messy symbol conflicts down the road and no chance that
> >> POSIX:OPEN and POSIX-OPEN both become used as people figure out ways to
> >> export the package
> >
> > I don't see the issue you refer to with "symbol conflicts down the
> > road", or why people would feel the need to start defining functions
> > called POSIX-OPEN - can you explain the motivation there?
>
> One cannot USE-PACKAGE without the imported symbols conflicting with
> essential Common Lisp commands.

That is true; but it does not constitute a reason for pretending that


packages are useless, and adopting a single namespace approach with
prefixes!

It is an argument against indiscriminate use of USE-PACKAGE!

> > Maybe I'm dumb, but I really can't see the point of introducing an


> > ad-hoc POSIX- namespace when the package system gives us a perfectly
> > good "POSIX:" namespace "for free", and I'd like to know what I'm
> > missing. Anyone?
>
> Packages tend to increase symbol name conflicts that would otherwise be
> avoided if there wasn't a package system.

There is your problem: you believe this bit of nonsense to be true. If


packages increase symbol conflicts, then the package system is
useless. There is no reason for it to exist. But that is in fact
wrong; the CL package system is very good and if only it is used
properly, it fights clashes.

The clashes occur only when someone wants to effectively defeat part
of the package mechanism by merging together separate spaces, making
them both visible in one package, for the sake of convenience. But
this is something you *cannot* do with prefixes (without an extremely
obtuse pattern-match-and-rename hack). So your argument basically
boils down to this: without the package system, USE-PACKAGE goes away,
and everyone uses fully qualified names via prefixes. This is cleaner,
because people are *prevented* from doing something convenient and
sensible; since the convenience doesn't exist, the issues associated
with that convenience do not exist also.

Down this road lies all kinds of madness. Static typing, single
dispatch, ``pure'' FP, whitespace-based indentation and all kinds of
other idiocies introduced as knee-jerk reactions against any sort of
convenience in programming that carries a shred of responsibility.

Name prefixes do nothing other than badly reinvent a package system,
using strings to express its structure rather than data structures!

> CMUCL avoids this by using UNIX-


> to prefix exported symbols in the UNIX package (e.g. UNIX:UNIX-CREAT,
> UNIX:UNIX-TRUNCATE, UNIX:UNIX-STAT etc.)

Which is a stupidity; you already have the UNIX package name. So now


you *have* to use importing if you want convenient access to these
identifiers, otherwise you are doomed to always repeat the word UNIX.

They could just have kept the short names, and leave it to the user to
qualify the names: (UNIX:OPEN ...) and so on. Those of us who don't
like to perform wholesale package importing end up writing
(UNIX:UNIX-OPEN ...) everywhere. No thanks, I don't want to make the
whole damn UNIX package visible in my package!

If you are writing your own package, you have things like
:shadowing-import-from; you can make visible in your package precisely
that set of symbols from a given package which you want, and no
others.

> You're intending to use the same base symbol names to require the use of


> package prefixes or the renaming of imported commands.

No renaming is needed; if in your package you want to use different


OPEN functions from different packages, you simply choose which one
you want to use by its short name and make that one visible in your
package. References to the others will be qualified.

This is a notch better than using compound names for all different
OPEN functions, so that *all* references have to be (effectively)
qualified. At least you have a choice to make the most frequently used
one unqualified. And you also have the choice of using nicknames.
Imagine if all symbols in the CL package were instead marked by a
"COMMON-LISP-" prefix. Not only do you have to use the prefix
everywhere, but you have to use *that* prefix and not some nicknamed
one. Nicknaming is nice; the C++ people even copied it, badly.

> I was just


> proposing a way that allows exported symbols in the package to be easily
> imported.

What? The package system has this feature already. The :use argument


in make-package or defpackage causes only the external symbols of a
package to be inherited. This is what USE-PACKAGE does also: it takes
only the exported symbols from the source package, the ones that can
be reached in the read syntax using just one colon instead of two.

Of course, different packages can have external symbols of the same
name, and so when you import from these, you get a clash. So, either
don't do that, or selectively import what you want.

There are enough pieces in the package system that you can build
something at a higher level, like Tim Bradshaw's ``conduits'' package.
Something which lets you easily say: I want to make things visible
from packages X Y Z. If there are conflicts, the winner will always be
Y, except that in the case of symbols A B C, package Z will dominate.

But even without such a thing, it's not exceedingly difficult to sort
out the conflicts by a suitable defpackage construct. In the worst
case you can be very conservative. That is, :use nothing at all other
than perhaps "CL", and use :shadowing-import-from to specifically
obtain anything else from other packages that you want to use by its
unqualified name.

> But either approach could be achieved from the other with a bit


> of macrology (e.g. loop over the exported symbols, create POSIX-* macros
> from the symbols exported in the POSIX package and import the POSIX-*
> symbols exported from a different package.

Aha! See my earlier comment regarding ``extremely obtuse

Peter Seibel

unread,
Apr 14, 2003, 11:48:16 PM4/14/03
to
k...@ashi.footprints.net (Kaz Kylheku) writes:

> Daniel Barlow <d...@telent.net> wrote in message news:<87u1d2h...@noetbook.telent.net>...
> > One topic that crops up every so often on comp.lang.lisp is "standard
> > interfaces to POSIX". Having looked at the CMUCL UNIX interface, and
> > the new ACL POSIX stuff, and with input from some Perl and Python
> > users, SBCL developers are in the process of defining ours.
> > comp.lang.lisp readers may want to have a look.
>
> How about changing the package name from SB-POSIX to a vendor-neutral
> CL-POSIX (as a nickname for COMMON-LISP-POSIX).

Do we really need to stick the CL- on there? It's not like we're going
to forget what language we're using. ;-) This is, on the one hand a
quibble on the other, IMHO, names are important. It seems a shorter
name is better. Especially as (assuming sanity prevails vis a vis
using the package system for what it's designed for) using the symbols
in this package is going to require fully qualified names.

Perhaps the right thing to do is for anyone who's implementing this
"standard" to make the real name of their package a reverse-domain
style package name like "COM.FOO.POSIX" (where FOO.COM is some domain
they have some sort of claim to) with a nickname "POSIX". Then if the
community rallies around the standard, everyone using the code will
already be using the name POSIX but different implementation will be
able to coexist during the development and testing, etc. (With a bit
of package renaming to take off the nicknames.) If it becames
standardized enough, then the various Lisp implementations that run on
posix systems can include it under the actual name POSIX if they
really want.

-Peter

Christopher Browne

unread,
Apr 15, 2003, 12:36:30 AM4/15/03
to
Quoth k...@ashi.footprints.net (Kaz Kylheku):

> Daniel Barlow <d...@telent.net> wrote in message news:<87u1d2h...@noetbook.telent.net>...
>> One topic that crops up every so often on comp.lang.lisp is "standard
>> interfaces to POSIX". Having looked at the CMUCL UNIX interface, and
>> the new ACL POSIX stuff, and with input from some Perl and Python
>> users, SBCL developers are in the process of defining ours.
>> comp.lang.lisp readers may want to have a look.
>
> How about changing the package name from SB-POSIX to a vendor-neutral
> CL-POSIX (as a nickname for COMMON-LISP-POSIX).

If it's supposed to be a POSIX binding for CL, what reason is there to
put "CL-" in there? Are you expecting someone to start writing
code...

(defmethod frobozz (c filespec)
(posix:open c 235 7)
foreach $i (<c>) {
print $i, "\n";
}))

.. and suddenly exclaim ....

"Quel dommage!!! I was writing some code, and because we left "CL-"
out of the function name, I completely forgot I was writing Lisp, and
started writing Perl code instead. What idiots we were to forget to
keep reminding ourselves what language we are using."

I don't see it being too likely that anyone will accidentally try to
#include <posix.lisp>
in their C/C++ program.

It seems really silly to have such a redundant prefix in the name
space unless you're expecting that there might be other POSIX
interface implementations that somehow won't be designed for use with
Common Lisp.
--
output = ("cbbrowne" "@ntlug.org")
http://www3.sympatico.ca/cbbrowne/spiritual.html
Rules of the Evil Overlord #229. "If I have several diabolical schemes
to destroy the hero, I will set all of them in motion at once rather
than wait for them to fail and launch them successively."
<http://www.eviloverlord.com/>

Friedrich Dominicus

unread,
Apr 15, 2003, 12:56:49 AM4/15/03
to
Peter Seibel <pe...@javamonkey.com> writes:

> k...@ashi.footprints.net (Kaz Kylheku) writes:
>
> > Daniel Barlow <d...@telent.net> wrote in message news:<87u1d2h...@noetbook.telent.net>...
> > > One topic that crops up every so often on comp.lang.lisp is "standard
> > > interfaces to POSIX". Having looked at the CMUCL UNIX interface, and
> > > the new ACL POSIX stuff, and with input from some Perl and Python
> > > users, SBCL developers are in the process of defining ours.
> > > comp.lang.lisp readers may want to have a look.
> >
> > How about changing the package name from SB-POSIX to a vendor-neutral
> > CL-POSIX (as a nickname for COMMON-LISP-POSIX).
>
> Do we really need to stick the CL- on there? It's not like we're going
> to forget what language we're using. ;-) This is, on the one hand a
> quibble on the other, IMHO, names are important. It seems a shorter
> name is better.

How about PB than (Posix-bindings?) maybe as a nickname?


Regards
Friedrich

Peter Seibel

unread,
Apr 15, 2003, 1:17:01 AM4/15/03
to
Friedrich Dominicus <fr...@q-software-solutions.com> writes:

Okay, so I'm the one who said shorter is better but if it were up to
me, I'd leave it at POSIX. It's nice and clear what POSIX:OPEN does.
PB:OPEN, less so. And it's unlikely that there'd be any conflict over
the package name POSIX while there might be other packages with an
equally legitimate claims on the PB abbreviation. (Say, the
PEANUT-BUTTER package). Anyway, it's short enough for me.

In general I prefer not to use abbreviations in APIs. Okay, okay, so
POSIX is *already* an abbreviation. But it's a well understood one.
Probably more people know what POSIX is than know what it stands for.
PB is just abbreviation for abbreviation sake.

Someone who really wants to can always RENAME-PACKAGE to add the PB
nickname if they really want. All this naming stuff is a matter of
taste so all I can say, is, to my taste, POSIX is better than CL-POSIX
*and* better than PB. YTMV.

Friedrich Dominicus

unread,
Apr 15, 2003, 4:48:27 AM4/15/03
to
Peter Seibel <pe...@javamonkey.com> writes:

>
> Someone who really wants to can always RENAME-PACKAGE to add the PB
> nickname if they really want. All this naming stuff is a matter of
> taste so all I can say, is, to my taste, POSIX is better than CL-POSIX
> *and* better than PB. YTMV.

POSIX is fine for me too ;-)

Regards
Friedrich

Daniel Barlow

unread,
Apr 15, 2003, 10:09:33 AM4/15/03
to
k...@ashi.footprints.net (Kaz Kylheku) writes:

> You seem to be trying to reduce the bindings to a few axioms, which if
> adhered to will cause everyone to generate compatible bindings. So a
> discussion about any potential holes in these axioms would be useful.

Yay! Discussion about some aspect other than the package name :-)
Thanks.

> One hole is the treatment of structures. For example ``struct stat''
> becomes what type? CL-POSIX:STAT? Is it a class or struct? Are the
> slot symbols all in the CL-POSIX package?

Good questions. Yes. Maybe. Unspecified. I propose making these
essentially opaque, with an allocator TBD, and accessors STAT-DEV,
STAT-INO etc. (Another symbol naming rule: where the fields of a C
structure all have a common prefix (in this case, "st_"), we omit it)

"Something should be done" to make sure they get deallocated, too.
Either allocate them from GCable space, or use finalizers, but I think
this is the implementation's job, not the user's.

> What about some of the completely opaque types, like sigset_t? The
> implementor should have some latitude how these are represented; they
> should remain opaque in Lisp, subject to functional accessors that
> mirror the C ones.

Ditto these, yes.

> Here is another omission: what to do with variable-length functions
> like execvp()? Do they take a list, or vector or either?

"Either" sounds good. Which is to say, a sequence.

[ "Out" parameters ]


> We can distil this to one unified axiom: reference parameters that
> have out semantics are always reflected in additional return values,
> even for data-transfer operations like read. If the parameter list has
> a suitable structure such that these parameters can be made optional,
> and there is enough information in the required parameters to
> construct the appropriate objects, then this shall be supported. The
> structure of the multiple value will be the same as if the optional
> parameters were present.

[...]


> Alternative: let these parameters *always* be optional if the
> structure of the argument list allows it (there are no removable
> required parameters that follow). If there is not enough information
> to construct an object, the implementation supplies reasonable
> defaults. For example (CL-POSIX:READ 1), not having a buffer, might
> substitute some implementation-defined size like 1024 and make a
> buffer that large. The filled buffer will be returned as a second
> value, regardless of whether it was implicitly allocated by the call,
> or specified by the caller.

I like the first version. I'm less wild about the second. It seems
to make sense for read(), where the optimal block size could depend on
factors known only to the implementation (OS buffers, page size,
filesystem block size, etc), but I'm not sure how it would work out in
other cases. Mind you, the "smart defaults" can be ignored anyway by
any programmer who specifies his own values, so I don't think it'd do
any real harm.

> I vote for a global symbol-macro called CL-POSIX:ERRNO, which expands
> to an implementation-defined place that is thread-specific and all
> that. For example, on some fictitious Lisp system, this could expand
> to (SYSTEM::GET-ERRNO) which calls a C function that retrieves the
> value of the errno macro, and (SETF (SYSETM::GETERRNO)) would call a
> function that assigns to the errno macro. I have successfully
> implemented an errno interface this way.

I don't see the point of this. errno is a kludge introduced by the C
bindings to work around the lack of exception handling or multiple
return values in that language, and I don't see why we need to
perpetuate it.

What's the usage scenario for this? Why can't you just look in the
condition object?

If you do a syscall directly (with int 0x80) on Linux/x86, you get a
return value or -EFOO returned to you - there is no global variable
called "errno". If anyone wants to implement a CL POSIX interface on
that platform which ignores the C library (I am, on occasion, sorely
tempted to), it'd be silly to make them have to fake a
global-but-actually-thread-local variable for it.


> The strerror interface will be handled in a straightforward way.
> Integer parameter in, string object out.

Yup.

>> We do not automatically translate the returned value into "Lispy"
>> objects - for example, SB-POSIX:OPEN returns a small integer, not a
>> stream.
>
> Good. But it would be nice to have something like the moral equivalent
> of fdopen(); say you have a file descriptor already and want to bind

It would. I bet that most implementations have this already, but all
under different names. (MAKE-STREAM FILE-DESCRIPTOR ... ) with
keyword arguments as for CL:OPEN?

Hmm. CL:OPEN as per the standard doesn't support setting buffering
modes, which would be nice for MAKE-STREAM. In the context of Lisp
implementations that run on unixlike systems it'd be nice for CL:OPEN
too, though ...

> system. Also, an accessor function that pulls out the POSIX descriptor
> from the Lisp stream.

Yes. Thomas Burdick (and others) argued for this on sbcl-devel. In
general, we'll export the functions used to coerce FOO designators
into actual FOOs. So far this means we have functions called
FILENAME and FILE-DESCRIPTOR

Marco Antoniotti

unread,
Apr 15, 2003, 11:09:08 AM4/15/03
to

Daniel Barlow wrote:

> k...@ashi.footprints.net (Kaz Kylheku) writes:
>
>
>
> >One hole is the treatment of structures. For example ``struct stat''
> >becomes what type? CL-POSIX:STAT? Is it a class or struct? Are the
> >slot symbols all in the CL-POSIX package?
>
>
> Good questions. Yes. Maybe. Unspecified. I propose making these
> essentially opaque, with an allocator TBD, and accessors STAT-DEV,
> STAT-INO etc. (Another symbol naming rule: where the fields of a C
> structure all have a common prefix (in this case, "st_"), we omit it)
>
> "Something should be done" to make sure they get deallocated, too.
> Either allocate them from GCable space, or use finalizers, but I think
> this is the implementation's job, not the user's.


What about using the intently more cumbersome

POSIX:|STRUCT STAT|
or
(POSIX:STRUCT POSIX:STAT)
?

after all, I think you should resort to this kind of stuff only in
extreme circumstances.

--
Marco Antoniotti

Kaz Kylheku

unread,
Apr 15, 2003, 12:21:04 PM4/15/03
to
Christopher Browne <cbbr...@acm.org> wrote in message news:<b7g28e$8rhg$2...@ID-125932.news.dfncis.de>...

> Quoth k...@ashi.footprints.net (Kaz Kylheku):
> > Daniel Barlow <d...@telent.net> wrote in message news:<87u1d2h...@noetbook.telent.net>...
> >> One topic that crops up every so often on comp.lang.lisp is "standard
> >> interfaces to POSIX". Having looked at the CMUCL UNIX interface, and
> >> the new ACL POSIX stuff, and with input from some Perl and Python
> >> users, SBCL developers are in the process of defining ours.
> >> comp.lang.lisp readers may want to have a look.
> >
> > How about changing the package name from SB-POSIX to a vendor-neutral
> > CL-POSIX (as a nickname for COMMON-LISP-POSIX).
>
> If it's supposed to be a POSIX binding for CL, what reason is there to
> put "CL-" in there? Are you expecting someone to start writing
> code...

You're all forgetting that Lisp implementors may already have packages
called POSIX, whose contents might be slightly incompatible with the
proposed interface. These packages will have to go through an
obsolescence stage. CLISP has a package called POSIX, for instance.

There are probably good reasons why the cltl1 LISP package was renamed
COMMON-LISP, and COMMON-LISP-USER isn't just USER, even though the
user typically knows what language she is using.

Joe Marshall

unread,
Apr 15, 2003, 1:19:32 PM4/15/03
to
k...@ashi.footprints.net (Kaz Kylheku) writes:

> You're all forgetting that Lisp implementors may already have packages
> called POSIX, whose contents might be slightly incompatible with the
> proposed interface. These packages will have to go through an
> obsolescence stage. CLISP has a package called POSIX, for instance.


How about "NEGIX"?

Kent M Pitman

unread,
Apr 15, 2003, 1:51:24 PM4/15/03
to
k...@ashi.footprints.net (Kaz Kylheku) writes:

> There are probably good reasons why the cltl1 LISP package was renamed
> COMMON-LISP, and COMMON-LISP-USER isn't just USER, even though the
> user typically knows what language she is using.

Yes.

The Symbolics Genera has the 'syntax' system for distinguishing dialects.
Genera has both CLTL1 and ANSI CL implementations loaded at the same time.
The user can decide on a per-program basis which dialect to use.

Most implementations don't have that. We renamed the packages so that
an implementation that wants to can offer both CLTL and ANSI CL loaded
together. Had we made them use the same name, implementations would have
been forced to either have only one loaded or to be non-conforming for
one or the other.

Thomas F. Burdick

unread,
Apr 15, 2003, 3:04:18 PM4/15/03
to
Marco Antoniotti <mar...@cs.nyu.edu> writes:

> Daniel Barlow wrote:
>
> > k...@ashi.footprints.net (Kaz Kylheku) writes:
> >
> > >One hole is the treatment of structures. For example ``struct stat''
> > >becomes what type? CL-POSIX:STAT? Is it a class or struct? Are the
> > >slot symbols all in the CL-POSIX package?
> >
> > Good questions. Yes. Maybe. Unspecified. I propose making these
> > essentially opaque, with an allocator TBD, and accessors STAT-DEV,
> > STAT-INO etc. (Another symbol naming rule: where the fields of a C
> > structure all have a common prefix (in this case, "st_"), we omit it)

I think I like this, as a portable interface. Really, how you should
get to the members of a C struct is an FFI issue -- but we can dodge
FFI standardization here, because IIRC POSIX doesn't define anything
where this would introduce name conflicts. Although just to be on the
safe side, maybe these accessor functions should be ST-DEV, ST-INO,
etc. (Ick)

> What about using the intently more cumbersome
>
> POSIX:|STRUCT STAT|
> or
> (POSIX:STRUCT POSIX:STAT)
> ?
>
> after all, I think you should resort to this kind of stuff only in
> extreme circumstances.

I think the example of POSIX:STAT was a good one -- that's hardly
something to be used only in extreme cases.

--
/|_ .-----------------------.
,' .\ / | No to Imperialist war |
,--' _,' | Wage class war! |
/ / `-----------------------'
( -. |
| ) |
(`-. '--.)
`. )----'

Joerg Hoehle

unread,
Apr 16, 2003, 4:55:27 AM4/16/03
to
Peter Seibel <pe...@javamonkey.com> writes:
> in than SB-POSIX. Speaking as a user, and as someone who's spent a
> fair bit of time lately trying to spread the Lisp gospel it'd be nice
> to both:
> a) Have a standard (in the sense of widely adopted community
> standard) way of doing something important and obvious like
> accessing the POSIX APIs.

Here's a challenge to Lisp POSIX API design

Interfacing to read(2)

What should the POSIX interface to read(2) do w.r.t. to the buffer argument?
a) Accept a foreign/alien pointer
b) Accept a Lisp string
c) Accept a Lisp vector of (unsigned-byte 8)
d) any element-type (unsigned/signed-byte x)
e) any combination of the above
f) other ...

In other words, any attempt to deal with a POSIX package portably across
implementations running on UNIX inevitably has to deal with the local FFI.

And UFFI version 1 is not what I hope for as a basis for FFI
standardization. UFFI version 2 maybe - but that has yet to be designed.

Interfacing to readlink(2)

For other POSIX functions, a Lisp only layer may be all what users
want. E.g. I bet many people would expect the following signature for
the Lisp side of readlink(2):
- accept 1 arguments, a string (maybe a pathname?)
- return a Lisp string
- or signal an error/condition (posix-error?)
Alternatively, if you don't like having low-level functions raise
errors, maybe devise a multiple-values return à la ignore-errors,
e.g. return either (values string nil) or (values nil errno).

In other words: at Lisp-level, I don't want to deal with the
idiosyncracies of C,
- like taking care of passing readlink(2) a buffer large enough, and
possibly repeating with a larger buffer otherwise
- like having -1 or NULL "bottom" return values instead of signaling errors.
Is that too much to ask for a POSIX package?
Would users be happy with really thin layers instead and all want
to deal with ENAMETOOLONG themselves?

IMHO, a POSIX effort in Lisp offers the chance to provide a portable
*Lisp-style* interface to many POSIX functions, which I oppose to
writing C programs in Lisp syntax. I'm almost always in favour of
thick interfaces, e.g. the above sketched Lisp version readlink.

What do you think?

BTW, I long forgot what CMUCL's unix:unix-readlink function signature
looks like.

Regards,
Jorg Hohle
Telekom/T-Systems Technology Center

Joerg Hoehle

unread,
Apr 16, 2003, 5:09:22 AM4/16/03
to
Don Geddis <d...@geddis.org> writes:
> It seems like there are two usage models:
> 1. [Daniel:] Name the functions just OPEN, put them in a package (SB-)POSIX,
> and refer to them in running code as POSIX:OPEN. Never USE-PACKAGE.

> 2. [Adam:] Name the functions POSIX-OPEN, in the POSIX package. Then
> USE-PACKAGE the POSIX package, so instead of having to type
> POSIX:POSIX-OPEN you can just type POSIX-OPEN.

Code containing EXT:CD or POSIX:OPEN seems fahionable these days.

However, my experience with porting foreign code is that I prefer to
find FOO-OPEN in portable code instead of FOO:OPEN.

The reason is that with FOO:OPEN, I have to provide both an equivalent
function *and* a package with identical exports (which I usually had
to guess), if I don't want to modify all references in the source code
that I'm porting.

With FOO-OPEN and use-package, I only have to provide the function and
modify the defpackage/use-package forms of the code that I'm
porting. This has cost me less effort in past porting projects.

However, in the case of a well-defined POSIX package, I could agree
that POSIX:OPEN is the way to go. The package's symbols and the
semantics of the functions would be well-defined.

Yet problems will arise around the corner if the POSIX package starts
to export errno symbols which are not found in all
implementations... Every UNIX has EINVAL, but what about EILSEQ or
ENOTSUP? It's not nice to hit a reader-error while porting. I much
prefer warnings about undefined functions. YMMV.

Joerg Hoehle

unread,
Apr 16, 2003, 7:31:34 AM4/16/03
to
k...@ashi.footprints.net (Kaz Kylheku) writes:
> Here is another omission: what to do with variable-length functions
> like execvp()? Do they take a list, or vector or either?
Good question, but independent on variable-length
a) vector vs. list
b) variable-length indeed: using &rest where applicable, e.g.

Don't forget that execlp etc. IMHO have no place in a foreign language
binding. These are just C wrappers to execv(), execve() and execv(),
because traditional C lacks means to comfortably build an array
dynamically in source code.

To me interfacing to execlp() is like attempting to interface to a Lisp
macro without having EVAL. TRT is to access the functional interface,
not the macro level which is mere syntactic sugar for programmers.

(defun posix:execlp (path &rest args)
;;TODO append terminating NULL
(posix:execvp path (coerce args 'vector)))

Similarly, interfacing to [f]printf() is superfluous. vfprintf() is
mandatory when coming from a foreign language. Which is *not* to say
that there should be no POSIX:PRINTF. I'm all in favour of it! But it
is more likely to expand to a call to vprintf(), especially in some
implementations which create calls at run-time, instead of
generating compile-time native-code.

(defun posix:fprintf (fp format &rest args)
(posix:vfprintf fp format (coerce args 'vector)))

A compiler-macro optimization might handle the case when posix:printf
is called literally, i.e. with a known number of arguments, on those
systems which generate native-code.

I have yet to see non-wrapper FFI definitions for variable-arg functions.


Which leads to another question: how to deal with [vsnf]printf and its
sisters' arguments which are all polymorphic??
a) (typecase
((unsigned-int 32) ...
(signed-int 32) ...
single-float ...
string ...
(array fixnum)
(array ...
...
FFI-pointer
b) ?


> > b) where C simulates "out" parameters using pointers (for instance, in
> > pipe() or socketpair()) we may use multiple return values instead.

[...]


> We can distil this to one unified axiom: reference parameters that
> have out semantics are always reflected in additional return values,
> even for data-transfer operations like read. If the parameter list has
> a suitable structure such that these parameters can be made optional,
> and there is enough information in the required parameters to

There are a few cases where C parameters are "optional out",
e.g. sigaction(). C programmers can elect to pass in either a NULL or
a data pointer. I'm not sure whether this is covered by your rule.

sigaction() is more like [newact] [oldact] whereas &optional always
implies [newact [oldact]], i.e. you cannot leave out the first.
The performance penalty of choosing to always create and return a
sigact structure vs. the C programmer's freedom to choose is debatable.

> Alternative: let these parameters *always* be optional if the

[...]


> defaults. For example (CL-POSIX:READ 1), not having a buffer, might
> substitute some implementation-defined size like 1024 and make a

Oh, no! No randomness please.


> I vote for a global symbol-macro called CL-POSIX:ERRNO, which expands

I vote against, since it will be implementation-dependent whether
POSIX:ERRNO will return the value of the last call via the POSIX
package, or the underlying errno, set by whatever was last called by
the implementation internally. I would find the former caching
behaviour stupid, not meeting user expectations about returning the
true errno left from calls not via the POSIX package.

E.g.
> (linux:get-errno)
22
> (linux:set-errno 0)
0
> (linux:get-errno)
22
> (progn (linux:set-errno 0) (linux:get-errno))
0 ; No guarantee ever

Remember: the errno corresponding to a POSIX call must be delivered at
the same time as the function returns (and/or saved in the
SYSCALL-ERRNO slot of the condition object). Daniel Barlow is very
right here.

(progn
(posix:open ...)
(unless (zerop posix:errno)
(error "open failed")))
is broken by design (cannot expect to portably work to say the least,
which is the same in my book).

OTOH, there are a few legitimate uses of posix:errno and (setf errno).
But not in code as the above!


> > objects - for example, SB-POSIX:OPEN returns a small integer, not a

TRT again


> Good. But it would be nice to have something like the moral equivalent
> of fdopen(); say you have a file descriptor already and want to bind
> it to a Lisp stream. Maybe you are writing a program that inherits a

That's not part of POSIX. That's to be found in the implementation's
EXTENSIONS package - if provided at all:
MAKE-LISP-STREAM-FROM-FD
MAKE-LISP-STREAM-FROM-SOCKET (needed, only on UNIX will that be the
same as FD
FILE/PIPE-STREAM-FD ; if any, could be a pointer in some non-UNIX
implementations (MS-Windows?
SOCKET-STREAM-SOCKET-DESCRIPTOR for sockets
Only on UNIX are file/pipe fd and socket numbers merged and read()
applicable to both.

OTOH, since Dan wants to have POSIX:/-xyz accept both Lisp open
streams and UNIX file descriptors, he will need half of this
functionality anyway. So he might as well export it.

Joerg Hoehle

unread,
Apr 16, 2003, 7:53:40 AM4/16/03
to
I'm not sure this comes out clear in my two other posts in this
thread: I'm all in a favour of a Lispyfied yet relatively thin API
layer for POSIX!

I'd have people stop using CLISP's current 1:1 linux.lisp module any
day, and have POSIX integrated into UNIX CLISP distributions.

Two features that would distinguish your POSIX package from the
current linux.lisp:

Daniel Barlow <d...@telent.net> writes:
> a) length arguments are omitted or optional where the sensible value
> is obvious.

> The return value is usually the same as for the C binding, except in
> error cases: where the C function is defined as returning some
> sentinel value and setting "errno" on error, we instead signal an
> error of type SYSCALL-ERROR.

CLISP's linux.lisp maps everything but :out parameters strictly 1:1 to
C usage, which is not how I feel like programming in Lisp.


POSIX looks like a wrapper library around the current linux.lisp
with the worthwhile purpose of providing a more Lisp-like API.
E.g.
(defun posix:read (fd buffer &optional (length (length buffer)))
;;TODO unclear whether buffer is foreign pointer or Lisp array
(let ((return (linux:read fd buffer length)))
(if (= -1 return) (error 'posix:syscall-error :syscall-errno ...)
return)))


> (read fd buffer &optional (length (length buffer))) => bytes-read
This seems workable if buffer is a Lisp array (LENGTH works).
But people will certainly also want to read() using pointers to
foreign memory. How do you achieve this polymorphism?

Also, reading into Lisp string buffers may be very
problematic. E.g. CLISP internally uses 16 or 32 bit characters
because it supports UNICODE, whereas most western day-to-day use
involves one byte ASCII or ISO-8859-1.
Do you plan to support reading into existing Lisp strings as part of
your API? Or would you just return new strings (using which encoding?)?

Daniel Barlow

unread,
Apr 16, 2003, 8:26:37 AM4/16/03
to
Joerg Hoehle <hoe...@users.sourceforge.net> writes:

> Yet problems will arise around the corner if the POSIX package starts
> to export errno symbols which are not found in all
> implementations... Every UNIX has EINVAL, but what about EILSEQ or
> ENOTSUP? It's not nice to hit a reader-error while porting. I much
> prefer warnings about undefined functions. YMMV.

Surely that should cause an undefined variable warning, not a reader
error.


-dan

Daniel Barlow

unread,
Apr 16, 2003, 8:53:19 AM4/16/03
to
Joerg Hoehle <hoe...@users.sourceforge.net> writes:

> Don't forget that execlp etc. IMHO have no place in a foreign language
> binding. These are just C wrappers to execv(), execve() and execv(),

I hadn't ;-)

> Similarly, interfacing to [f]printf() is superfluous. vfprintf() is
> mandatory when coming from a foreign language. Which is *not* to say
> that there should be no POSIX:PRINTF. I'm all in favour of it! But it

Hmm. Actually, printf() is outside the scope as initially defined:
"functionality on POSIX systems typically found in libc but not part
of Standard C". What does it do that can't be done in Lisp?

> sigaction() is more like [newact] [oldact] whereas &optional always
> implies [newact [oldact]], i.e. you cannot leave out the first.
> The performance penalty of choosing to always create and return a
> sigact structure vs. the C programmer's freedom to choose is debatable.

You can supply NIL for the first.

That said, I don't think this is the best example. It's very easy to
break SBCL in strange ways by redefining signal handlers without
telling it, and I suspect that other Lisps work in similar ways. I'm
not sure that signal handling functions should be part of this
standard anyway.

>> Good. But it would be nice to have something like the moral equivalent
>> of fdopen(); say you have a file descriptor already and want to bind
>> it to a Lisp stream. Maybe you are writing a program that inherits a
>
> That's not part of POSIX. That's to be found in the implementation's
> EXTENSIONS package - if provided at all:

I tend to agree with Kaz here. A POSIX interface is all well and
good, but if you then have to dip into implementation-specific
functions to actually get the data from the POSIX world into the Lisp
world, you're still not writing portable code.

> MAKE-LISP-STREAM-FROM-FD
> MAKE-LISP-STREAM-FROM-SOCKET (needed, only on UNIX will that be the
> same as FD
> FILE/PIPE-STREAM-FD ; if any, could be a pointer in some non-UNIX
> implementations (MS-Windows?
> SOCKET-STREAM-SOCKET-DESCRIPTOR for sockets
> Only on UNIX are file/pipe fd and socket numbers merged and read()
> applicable to both.

My manual page for accept() says "allocates a file descriptor", and
that POSIX 1003.1g has standardised this function (along with a great
long rant about the stupidity of socklen_t). So, it may be that some
Windowes system has somehow managed to claim Posix compliance without
actually doing this, but I don't see how and I don't really have the
motivation to do much about it.

Windows users?

Peter Seibel

unread,
Apr 16, 2003, 1:34:03 PM4/16/03
to
[aploogies if this gets posted twice (or thrice)--my news server has
been a bit flaky.]

Joerg Hoehle <hoe...@users.sourceforge.net> writes:

> Peter Seibel <pe...@javamonkey.com> writes:
> > in than SB-POSIX. Speaking as a user, and as someone who's spent a
> > fair bit of time lately trying to spread the Lisp gospel it'd be nice
> > to both:
> > a) Have a standard (in the sense of widely adopted community
> > standard) way of doing something important and obvious like
> > accessing the POSIX APIs.
>
> Here's a challenge to Lisp POSIX API design
>
> Interfacing to read(2)
>
> What should the POSIX interface to read(2) do w.r.t. to the buffer argument?
> a) Accept a foreign/alien pointer

Yuck. Though I guess if it was *one* of the options it might be useful.

> b) Accept a Lisp string

Okay.

> c) Accept a Lisp vector of (unsigned-byte 8)

Okay.

> d) any element-type (unsigned/signed-byte x)

Better.

> e) any combination of the above

b, c, or d sounds good to me. And a too if possible. Especially if you
can pass a displaced array. (I'm thinking purely from the what makes a
nice Lisp API point of view.)

> f) other ...


> In other words, any attempt to deal with a POSIX package portably
> across implementations running on UNIX inevitably has to deal with
> the local FFI.
>
> And UFFI version 1 is not what I hope for as a basis for FFI
> standardization. UFFI version 2 maybe - but that has yet to be
> designed.
>
> Interfacing to readlink(2)

Just out of curiosity, does anyone know why my POSIX Programmer's
Guide published by O'Reilly and purporting to document POSIX.1 doesn't
have an entry for readlink? Is it part of some later standard?

> For other POSIX functions, a Lisp only layer may be all what users
> want. E.g. I bet many people would expect the following signature for
> the Lisp side of readlink(2):
> - accept 1 arguments, a string (maybe a pathname?)
> - return a Lisp string
> - or signal an error/condition (posix-error?)
> Alternatively, if you don't like having low-level functions raise
> errors, maybe devise a multiple-values return à la ignore-errors,
> e.g. return either (values string nil) or (values nil errno).
>
> In other words: at Lisp-level, I don't want to deal with the
> idiosyncracies of C,
> - like taking care of passing readlink(2) a buffer large enough, and
> possibly repeating with a larger buffer otherwise
> - like having -1 or NULL "bottom" return values instead of signaling errors.
> Is that too much to ask for a POSIX package?

I'd hope it's not.

> Would users be happy with really thin layers instead and all want
> to deal with ENAMETOOLONG themselves?

Not me.

> IMHO, a POSIX effort in Lisp offers the chance to provide a portable
> *Lisp-style* interface to many POSIX functions, which I oppose to
> writing C programs in Lisp syntax. I'm almost always in favour of
> thick interfaces, e.g. the above sketched Lisp version readlink.
>
> What do you think?

I agree. Lisp in Lisp good; C in Lisp bad.

-Peter

Daniel Barlow

unread,
Apr 16, 2003, 2:39:40 PM4/16/03
to
Peter Seibel <pe...@javamonkey.com> writes:

> [aploogies if this gets posted twice (or thrice)--my news server has
> been a bit flaky.]
>
> Joerg Hoehle <hoe...@users.sourceforge.net> writes:
>> Here's a challenge to Lisp POSIX API design
>>
>> Interfacing to read(2)
>>
>> What should the POSIX interface to read(2) do w.r.t. to the buffer argument?

>> b) Accept a Lisp string
>
> Okay.

OK, and for Lisps where a character is not just an octet (e.g. unicode
support) ...

Francois-Rene Rideau

unread,
Apr 16, 2003, 3:42:47 PM4/16/03
to
Joerg Hoehle <hoe...@users.sourceforge.net> writes:
> Yet problems will arise around the corner if the POSIX package starts
> to export errno symbols which are not found in all
> implementations... Every UNIX has EINVAL, but what about EILSEQ or
> ENOTSUP? It's not nice to hit a reader-error while porting. I much
> prefer warnings about undefined functions. YMMV.
Is it essential to use symbols in the POSIX (or whatever) package?
Why not use keywords here? They would seem to me as the obvious choice
for error markers. Or am I missing something?

[ François-René ÐVB Rideau | Reflection&Cybernethics | http://fare.tunes.org ]
[ TUNES project for a Free Reflective Computing System | http://tunes.org ]
No matter what language you use, a Sufficiently Smart Compiler(TM) will be
able to find an efficient implementation for whatever apparently difficult
problem you specify. However, a Sufficiently Smart Compiler(TM) for
arbitrary problems is itself an AI-complete problem.

Kaz Kylheku

unread,
Apr 16, 2003, 3:53:19 PM4/16/03
to
Daniel Barlow <d...@telent.net> wrote in message news:<87ptnmb...@noetbook.telent.net>...

> Joerg Hoehle <hoe...@users.sourceforge.net> writes:
>
> > Don't forget that execlp etc. IMHO have no place in a foreign language
> > binding. These are just C wrappers to execv(), execve() and execv(),
>
> I hadn't ;-)
>
> > Similarly, interfacing to [f]printf() is superfluous. vfprintf() is
> > mandatory when coming from a foreign language. Which is *not* to say
> > that there should be no POSIX:PRINTF. I'm all in favour of it! But it
>
> Hmm. Actually, printf() is outside the scope as initially defined:
> "functionality on POSIX systems typically found in libc but not part
> of Standard C". What does it do that can't be done in Lisp?

However, some sort of targetting of ANSI C streams might be useful;
the getc, putc, fread and fread functions, as well as the POSIX
extensions for locking: putc_unlocked, getc_unlocked, flockfile,
funlockfile. Also fopen, fdopen, fclose, popen, pclose.

What can you do with putc that can't be done in Lisp? Send a character
to a POSIX stream, that's what!

But if you have a way to bind a FILE * stream to a Lisp stream, you of
course use FORMAT on it.

Kaz Kylheku

unread,
Apr 16, 2003, 4:08:02 PM4/16/03
to
Joerg Hoehle <hoe...@users.sourceforge.net> wrote in message news:<un0iqv...@dont.t-systems.UCE.spam.no.com>...

> > I vote for a global symbol-macro called CL-POSIX:ERRNO, which expands
>
> I vote against, since it will be implementation-dependent whether
> POSIX:ERRNO will return the value of the last call via the POSIX
> package, or the underlying errno, set by whatever was last called by
> the implementation internally. I would find the former caching
> behaviour stupid, not meeting user expectations about returning the
> true errno left from calls not via the POSIX package.
>
> E.g.
> > (linux:get-errno)
> 22
> > (linux:set-errno 0)
> 0
> > (linux:get-errno)

Yeah, but this isn't a program, but rather individual expressions
typed into the read-eval-print loop. That read-eval-print loop talks
to your tty device via system calls. A lot of evaluation happens in
between the forms!

> 22
> > (progn (linux:set-errno 0) (linux:get-errno))
> 0 ; No guarantee ever

This is working right, because you have a mini program. I think that
if errno is modified in between the call to set-errno and get-errno,
the implementation simply has a bug. Its evaluator should not be
screwing around with errno, nor making system calls. The same goes for
the garbage collector; if it must make system calls that might fail,
it should save and restore the errno value.



> (progn
> (posix:open ...)
> (unless (zerop posix:errno)
> (error "open failed")))
> is broken by design (cannot expect to portably work to say the least,
> which is the same in my book).

You must test the function for failure, and only then inspect errno.
Since we agreed that errors will signal conditions, the only way the
UNLESS can be reached is if POSIX:OPEN succeeds. In that case, errno
is whatever it was before the POSIX:OPEN call.

> > > objects - for example, SB-POSIX:OPEN returns a small integer, not a
> TRT again
> > Good. But it would be nice to have something like the moral equivalent
> > of fdopen(); say you have a file descriptor already and want to bind
> > it to a Lisp stream. Maybe you are writing a program that inherits a
>
> That's not part of POSIX. That's to be found in the implementation's
> EXTENSIONS package - if provided at all:

I'm quite sure that fdopen is POSIX.

> Only on UNIX are file/pipe fd and socket numbers merged and read()
> applicable to both.

Distinct file and socket descriptors is just Windows braindamage.
Windows sockers don't conform to anything, not POSIX, not The Single
UNIX Specification, not even the original BSD sockets interface.

The POSIX package need not support Microsoft Windows, except for Lisp
systems that are based on a POSIX implementation for Windows. For
example on Cygwin, file and socket descriptors are uniformly treated.

Concerns about who provides the actual POSIX environment are squarely
outside of the scope of a project whose aim is to just define the
syntax and semantics of the bindings. The concern is purely about
Lisp systems that are used in a POSIX environment, so that among these
Lisp systems, we can write portable code to access that platform.

However, some of the interface-generating axioms could be applied to
other interfaces like Win32.

Joe Marshall

unread,
Apr 16, 2003, 4:29:45 PM4/16/03
to
Joerg Hoehle <hoe...@users.sourceforge.net> writes:

> Here's a challenge to Lisp POSIX API design
>
> Interfacing to read(2)
>
> What should the POSIX interface to read(2) do w.r.t. to the buffer argument?
> a) Accept a foreign/alien pointer
> b) Accept a Lisp string
> c) Accept a Lisp vector of (unsigned-byte 8)
> d) any element-type (unsigned/signed-byte x)
> e) any combination of the above
> f) other ...

My $.02:

One goal of your API is to eliminate having to understand and
implement POSIX functionality with the existing FFI. Option A is
antithetical to that.

Lisp strings are not necessarily octets, so option B implies some
sort of mapping.

Does POSIX define the width of bytes in a file? If it does, then
option C seems correct.

Option D again implies some sort of mapping if the byte size doesn't
match what is in the file.

> In other words: at Lisp-level, I don't want to deal with the
> idiosyncracies of C,
> - like taking care of passing readlink(2) a buffer large enough, and
> possibly repeating with a larger buffer otherwise
> - like having -1 or NULL "bottom" return values instead of signaling errors.
> Is that too much to ask for a POSIX package?

No, the user should NOT have to worry about buffer allocation or
EINTR.

`Unusual' conditions should definitely signal something, but things
that are often expected to fail might just want to return NIL.

> Would users be happy with really thin layers instead and all want
> to deal with ENAMETOOLONG themselves?

I certainly wouldn't.

> IMHO, a POSIX effort in Lisp offers the chance to provide a portable
> *Lisp-style* interface to many POSIX functions, which I oppose to
> writing C programs in Lisp syntax. I'm almost always in favour of
> thick interfaces, e.g. the above sketched Lisp version readlink.
>
> What do you think?

If I wanted to write in C, I'd write in C. The `thick' interface you
describe seems pretty thin to me, but you might want to provide
`unsafe' versions as well for people that like being closer to the
metal.

Peter Seibel

unread,
Apr 16, 2003, 5:21:02 PM4/16/03
to
Daniel Barlow <d...@telent.net> writes:

> Peter Seibel <pe...@javamonkey.com> writes:
>
> > [aploogies if this gets posted twice (or thrice)--my news server has
> > been a bit flaky.]
> >
> > Joerg Hoehle <hoe...@users.sourceforge.net> writes:
> >> Here's a challenge to Lisp POSIX API design
> >>
> >> Interfacing to read(2)
> >>
> >> What should the POSIX interface to read(2) do w.r.t. to the
> >> buffer argument? b) Accept a Lisp string
> >
> > Okay.
>
> OK, and for Lisps where a character is not just an octet (e.g. unicode
> support) ...

Hmmm. Good point. I guess somewhere you'd want to have a raw-bytes-in-
whatever-encoding to internal-string-character-representation
conversion function but perhaps it shouldn't be built into POSIX:READ.

Kevin Layer

unread,
Apr 16, 2003, 6:11:53 PM4/16/03
to
Daniel Barlow <d...@telent.net> writes:

> One topic that crops up every so often on comp.lang.lisp is "standard
> interfaces to POSIX". Having looked at the CMUCL UNIX interface, and
> the new ACL POSIX stuff,

Are you referring to the new Allegro `osi' and `shell' modules, or
something else (I saw a reference to ACL-POSIX in a later post)?

> ...
> * Scope
>
> The scope of this interface is "operating system calls on a typical
> Unixlike platform". This is section 2 of the Unix manual, plus
> section 3 calls that are (a) typically found in libc, but (b) not part
> of the C standard. For example, we intend to provide support for
> opendir() and readdir() , but not for printf()

The problem I have with the name `POSIX' is that some things in
section 2 and 3 of the UNIX manual are not part of POSIX. That's why
we named our module "osi" for "operating system interface" (the name
of the package is excl.osi).

> * Function names
>
> The package name for this interface is SB-POSIX. In this package
> there is a Lisp function for each supported Unix function, and a
> variable or constant for each supported unix constant. A symbol name
> is derived from the C binding's name, by (a) uppercasing, then (b)
> replacing underscore (#\_) characters with the hyphen (#\-)

Similar to what we did, with the following exceptions:

- remove leading underscores. For example, Windows defines _O_APPEND
and not O_APPEND.

- wrap *'s around constants

- downcase

So O_APPEND and _O_APPEND become *o-append*.

> The user is encouraged not to (USE-PACKAGE :SB-POSIX) but instead to
> use the SB-POSIX: prefix on all references, as some of our symbols
> have the same name as CL symbols (OPEN, CLOSE, SIGNAL etc).

We decided to rename symbols when there was a conflict (e.g., os-open
instead of open), so users would not have to either fully package
qualify or deal with shadowing if they wanted to use the package.

> * Parameters
>
> The calling convention is modelled after that of CMUCL's UNIX package:
> in particular, it's like the C interface except


>
> a) length arguments are omitted or optional where the sensible value

> is obvious. For example,

>
> (read fd buffer &optional (length (length buffer))) => bytes-read

Same for us, though we don't implement `read'. More on this later.

> b) where C simulates "out" parameters using pointers (for instance, in
> pipe() or socketpair()) we may use multiple return values instead.

> This doesn't apply to data transfer functions that fill buffers.

Ditto.

> c) some functions accept objects such as filenames or file
> descriptors. In the C bindings these are strings and small integers
> respectively. For the Lisp programmer's convenience we introduce
> "filename designators" and "file descriptor designator" concepts such
> that CL pathnames or open streams can be passed to these functions.

For us, any function that accepts a file will accept a pathname,
string or stream. Any function that accepts a file description
accepts a Lisp stream (opened with cl:open).

Our rationale was seemless interfacing with other Lisp code.

We didn't implement an interace to read() because it's not needed
given that streams are accepted by all file descriptor-based APIs.
There's a good reason not to use read(), too: it would have bad
blocking behavior with respect to multiprocessing, whereas read, et
al, have very good behavior (you can read from a stream and not block
other Lisp processes).

> * Return values


>
> The return value is usually the same as for the C binding, except in
> error cases: where the C function is defined as returning some
> sentinel value and setting "errno" on error, we instead signal an

> error of type SYSCALL-ERROR. The actual error value ("errno") is
> stored in this condition and can be accessed with SYSCALL-ERRNO.

Same for us.

Kevin Layer

unread,
Apr 16, 2003, 6:31:54 PM4/16/03
to
I meant to give an URL for our interface:

http://www.franz.com/rz/6.2/doc/os-interface.htm

with the new stuff starting in section 7.0:

http://www.franz.com/rz/6.2/doc/os-interface.htm#osi-module-1

Daniel Barlow

unread,
Apr 16, 2003, 7:13:06 PM4/16/03
to
Kevin Layer <layer@*n*o*s*p*a*m*franz.com> writes:

> Are you referring to the new Allegro `osi' and `shell' modules, or
> something else (I saw a reference to ACL-POSIX in a later post)?

The 'osi' module, yes

> The problem I have with the name `POSIX' is that some things in
> section 2 and 3 of the UNIX manual are not part of POSIX. That's why
> we named our module "osi" for "operating system interface" (the name
> of the package is excl.osi).

That's a pretty good argument (according to the scsh manual, _symbolic
links_ are not part of POSIX - things may have changed since then, though).
I'm not sure that "osi" is the best name either, though: do you
support the same interface on, say, VMS, even when the underlying OS
is different, or does the specification of the "osi" interface change
dramatically according to the OS in use?

Perhaps we just want to call it the "any-reputable-unixlike" interface ...

>> * Function names


> Similar to what we did, with the following exceptions:
>
> - remove leading underscores. For example, Windows defines _O_APPEND
> and not O_APPEND.

Yes, I'd agree with that

> - wrap *'s around constants

Hmm.

> - downcase
>
> So O_APPEND and _O_APPEND become *o-append*.

I assume this is something to do with ACL modern mode. In an ANSI CL
with the default reader settings, I'd have to type
|*o-append*| to get at that symbol, which doesn't seem so convenient.

> We decided to rename symbols when there was a conflict (e.g., os-open
> instead of open), so users would not have to either fully package
> qualify or deal with shadowing if they wanted to use the package.

Are we talking about conflicts with symbols in COMMON-LISP, or also
with other ACL packages that people may want to use?

The problem i see with this approach for a standard "posixish"
interface is that it'd either need to say "we renamed symbols where
there's a conflict with COMMON-LISP, but you're on your own for
conflicts with vendor packages", or know about the union of all
symbols of all the vendor's packages. Neither strikes me as a
particularly great solution.

> We didn't implement an interace to read() because it's not needed
> given that streams are accepted by all file descriptor-based APIs.

That's a pretty good reason.

> There's a good reason not to use read(), too: it would have bad
> blocking behavior with respect to multiprocessing, whereas read, et
> al, have very good behavior (you can read from a stream and not block
> other Lisp processes).

(Although I suspect that with appropriate mucking around with
O_NONBLOCK it should be possible to do this safely. But I don't know
ACL and am only speaking in generalities)

Similar "should it take a Lisp string or an array or what?" questions
apply to, say, recvfrom(), though, and presumably there you don't tell
people to use a stream - stream semantics on an unconnected datagram
socket would be kind of weird.

Lars Brinkhoff

unread,
Apr 16, 2003, 7:11:34 PM4/16/03
to
Joe Marshall <j...@ccs.neu.edu> writes:
> Does POSIX define the width of bytes in a file?

SUSv3 specifies CHAR_BIT in <limits.h> to be 8.

Mark Jason Dominus

unread,
Apr 16, 2003, 7:19:30 PM4/16/03
to
In article <m3znmsf...@javamonkey.com>,

Peter Seibel <pe...@javamonkey.com> wrote:
>Do we really need to stick the CL- on there? It's not like we're going
>to forget what language we're using. ;-)

And particularly not if one is using CLOS features.

Kevin Layer

unread,
Apr 16, 2003, 8:14:19 PM4/16/03
to
Daniel Barlow <d...@telent.net> writes:

> Kevin Layer <layer@*n*o*s*p*a*m*franz.com> writes:
>
> > Are you referring to the new Allegro `osi' and `shell' modules, or
> > something else (I saw a reference to ACL-POSIX in a later post)?
>
> The 'osi' module, yes

That confused me since our module is not a POSIX implementation, but
rather includes some POSIX API elements. Using the phrase "ACL-POSIX"
will be very confusing to us and potentially those familiar with
our `osi' module.

> > The problem I have with the name `POSIX' is that some things in
> > section 2 and 3 of the UNIX manual are not part of POSIX. That's why
> > we named our module "osi" for "operating system interface" (the name
> > of the package is excl.osi).
>
> That's a pretty good argument (according to the scsh manual, _symbolic
> links_ are not part of POSIX - things may have changed since then, though).
> I'm not sure that "osi" is the best name either, though: do you
> support the same interface on, say, VMS, even when the underlying OS
> is different, or does the specification of the "osi" interface change
> dramatically according to the OS in use?

First, we struggled with the name, too, so I feel better. :)

We do smooth over some minor differences between implementations, but
not all. The file locking on Windows and *NIX is very different, so
we provide `lockf' and `locking', but we define a higher-level
function lock-stream and a macro with-stream-lock, that call the
appropriate functions on the particular platform.

> Perhaps we just want to call it the "any-reputable-unixlike" interface ...
>
> >> * Function names
> > Similar to what we did, with the following exceptions:
> >
> > - remove leading underscores. For example, Windows defines _O_APPEND
> > and not O_APPEND.
>
> Yes, I'd agree with that
>
> > - wrap *'s around constants
>
> Hmm.
>
> > - downcase
> >
> > So O_APPEND and _O_APPEND become *o-append*.
>
> I assume this is something to do with ACL modern mode.

No. It means that the defconstant that is evaluated is this:

(defconstant *o-append* ...)

and not

(defconstant *O-APPEND* ...)

so that it will be more friendly to mixed case Lisps. It does the
right thing in ANSI mode.

> In an ANSI CL
> with the default reader settings, I'd have to type
> |*o-append*| to get at that symbol, which doesn't seem so convenient.

No, see above.

>
> > We decided to rename symbols when there was a conflict (e.g., os-open
> > instead of open), so users would not have to either fully package
> > qualify or deal with shadowing if they wanted to use the package.
>
> Are we talking about conflicts with symbols in COMMON-LISP, or also
> with other ACL packages that people may want to use?

COMMON-LISP. Specifically, `open', `remove', etc.

> The problem i see with this approach for a standard "posixish"
> interface is that it'd either need to say "we renamed symbols where
> there's a conflict with COMMON-LISP, but you're on your own for
> conflicts with vendor packages", or know about the union of all
> symbols of all the vendor's packages. Neither strikes me as a
> particularly great solution.

For us, excl.osi only uses the COMMON-LISP and EXCL packages, so we
needed to insure no conflicts for only those packages.

> > We didn't implement an interace to read() because it's not needed
> > given that streams are accepted by all file descriptor-based APIs.
>
> That's a pretty good reason.
>
> > There's a good reason not to use read(), too: it would have bad
> > blocking behavior with respect to multiprocessing, whereas read, et
> > al, have very good behavior (you can read from a stream and not block
> > other Lisp processes).
>
> (Although I suspect that with appropriate mucking around with
> O_NONBLOCK it should be possible to do this safely. But I don't know
> ACL and am only speaking in generalities)

I don't believe this would be the case. You'd have to reproduce some
of the ACL low-level I/O code and that would be very difficult.

Consider this (something I forgot before): I/O on sockets is very
tricky to get right. There are big differences between *NIX and
Windows, but still various smaller differences among the *NIX
implementations.

> Similar "should it take a Lisp string or an array or what?" questions
> apply to, say, recvfrom(), though, and presumably there you don't tell
> people to use a stream - stream semantics on an unconnected datagram
> socket would be kind of weird.

I'll defer to Duane on this one.

Alan Shutko

unread,
Apr 16, 2003, 8:38:04 PM4/16/03
to
Daniel Barlow <d...@telent.net> writes:

> That's a pretty good argument (according to the scsh manual, _symbolic
> links_ are not part of POSIX - things may have changed since then,
> though).

They weren't part of the old one, I think, but they're part of the
new draft....

This isn't the actual standard, but it may be of help:

http://wwwold.dkuug.dk/jtc1/sc22/open/n3161/

> Perhaps we just want to call it the "any-reputable-unixlike"
> interface ...

Single Unix Specification might be sufficient....

--
Alan Shutko <a...@acm.org> - I am the rocks.
Looking for a developer in St. Louis? http://web.springies.com/~ats/
Don't Think!!!!! SCHEME !!!!!

Duane Rettig

unread,
Apr 16, 2003, 8:47:51 PM4/16/03
to
Kevin Layer <layer@*n*o*s*p*a*m*franz.com> writes:

> Daniel Barlow <d...@telent.net> writes:

> > Similar "should it take a Lisp string or an array or what?" questions
> > apply to, say, recvfrom(), though, and presumably there you don't tell
> > people to use a stream - stream semantics on an unconnected datagram
> > socket would be kind of weird.
>
> I'll defer to Duane on this one.

For read, our streams are bivalent, so the answer to the question is
"yes" (string / octet-array - read-byte / read-char - it really
shouldn't matter).

For datagram sockets, we use streams, but they are of datagram subclasses,
and read-char/read-byte don't make sense; instead we define receive-from
methods to get the chunks of data. You can either supply the buffer or
not, and whether the buffer is a string or binary array doesn't matter,
although if you are using our 16-bit-character lisp and give it a string
as a buffer, then receive-from will allocate an octet buffer and then
convert to character data using octets-to-string before returning.

--
Duane Rettig du...@franz.com Franz Inc. http://www.franz.com/
555 12th St., Suite 1450 http://www.555citycenter.com/
Oakland, Ca. 94607 Phone: (510) 452-2000; Fax: (510) 452-0182

Gabe Garza

unread,
Apr 16, 2003, 9:02:30 PM4/16/03
to
Joe Marshall <j...@ccs.neu.edu> writes:

> Joerg Hoehle <hoe...@users.sourceforge.net> writes:
>
> > Here's a challenge to Lisp POSIX API design
> >
> > Interfacing to read(2)
> >
> > What should the POSIX interface to read(2) do w.r.t. to the buffer
> > argument?
> >

> > c) Accept a Lisp vector of (unsigned-byte 8)
>

> Does POSIX define the width of bytes in a file? If it does, then
> option C seems correct.

And an efficiently implemented, compiler-known MAKE-STRING-FROM-OCTETS
operator would be icing on the cake...

Gabe Garza

Håkon Alstadheim

unread,
Apr 16, 2003, 7:46:33 PM4/16/03
to
Daniel Barlow <d...@telent.net> writes:

> Joerg Hoehle <hoe...@users.sourceforge.net> writes:
>
> > Yet problems will arise around the corner if the POSIX package starts
> > to export errno symbols which are not found in all
> > implementations... Every UNIX has EINVAL, but what about EILSEQ or
> > ENOTSUP? It's not nice to hit a reader-error while porting. I much
> > prefer warnings about undefined functions. YMMV.
>
> Surely that should cause an undefined variable warning, not a reader
> error.

* (setf *a* nil)
Warning: Declaring *A* special.

NIL
* (eql a posix:foo)

Reader error on ...
Package "POSIX" not found.

--
Håkon Alstadheim, hjemmepappa.

Friedrich Dominicus

unread,
Apr 17, 2003, 1:21:13 AM4/17/03
to
Peter Seibel <pe...@javamonkey.com> writes:

> [aploogies if this gets posted twice (or thrice)--my news server has
> been a bit flaky.]
>
> Joerg Hoehle <hoe...@users.sourceforge.net> writes:
>
> > Peter Seibel <pe...@javamonkey.com> writes:
> > > in than SB-POSIX. Speaking as a user, and as someone who's spent a
> > > fair bit of time lately trying to spread the Lisp gospel it'd be nice
> > > to both:
> > > a) Have a standard (in the sense of widely adopted community
> > > standard) way of doing something important and obvious like
> > > accessing the POSIX APIs.
> >
> > Here's a challenge to Lisp POSIX API design
> >
> > Interfacing to read(2)

Let me put in a question, why won't you take SCSH approach as
guideline? SCSH is quite nice for shell scripting, and IMHO the SCSH
developers have mad a real nice job to wrapping up the POSIX stuff.


Regards
Friedrich

Duane Rettig

unread,
Apr 17, 2003, 2:50:08 AM4/17/03
to
Gabe Garza <g_g...@ix.netcom.com> writes:

Nah; the icing on the cake would be if the intermediate octet vector
were stack allocated ...

Nils Goesche

unread,
Apr 17, 2003, 8:17:31 AM4/17/03
to
k...@ashi.footprints.net (Kaz Kylheku) writes:

> > > (progn (linux:set-errno 0) (linux:get-errno))


> > 0 ; No guarantee ever
>
> This is working right, because you have a mini program. I think that
> if errno is modified in between the call to set-errno and get-errno,
> the implementation simply has a bug. Its evaluator should not be
> screwing around with errno, nor making system calls. The same goes
> for the garbage collector; if it must make system calls that might
> fail, it should save and restore the errno value.

What if the Lisp scheduler decides to preempt between the two forms?

> > (progn
> > (posix:open ...)
> > (unless (zerop posix:errno)
> > (error "open failed")))
> > is broken by design (cannot expect to portably work to say the
> > least, which is the same in my book).
>
> You must test the function for failure, and only then inspect errno.
> Since we agreed that errors will signal conditions, the only way the
> UNLESS can be reached is if POSIX:OPEN succeeds. In that case, errno
> is whatever it was before the POSIX:OPEN call.

You might write C wrappers for the POSIX calls that check for failure
and remember errno for you:

int call_close(int fd, const char **fun, int *err)
{
if (close(fd)) {
*fun = "close";
*err = errno;
return -1;
}
return 0;
}

Then, in Lisp, you could write a macro for your foreign-calls that
will automatically provide the `fun´ and `err´ arguments, check the
return value for failure, and compose and signal an error condition
containing the name of the failing system call, errno and maybe the
result of strerror(errno), all converted to Lisp values. That's what
I usually end up doing when I FFI-call to some C library, anyway.

Regards,
--
Nils Gösche
"Don't ask for whom the <CTRL-G> tolls."

PGP key ID 0x0655CFA0

Joe Marshall

unread,
Apr 17, 2003, 9:39:42 AM4/17/03
to
Daniel Barlow <d...@telent.net> writes:

>
> Perhaps we just want to call it the "any-reputable-unixlike" interface ...
>

I don't think I could type `reputable' and `unix' in the same identifier.

Will Hartung

unread,
Apr 17, 2003, 11:44:25 AM4/17/03