[Mono-list] PInvoke:TNG

Rhys Weatherley rweather@zip.com.au
Thu, 26 Jul 2001 15:05:29 +1000

I've been updating "pinvoke.html" with the feedback I received
in the last week.  While experimenting with Miguel's "PosixProto"
proposal, and the suggestions from Fergus, a new idea occurred to me.

So far we've been concentrating on annotating the method definition
with information on how to marshal parameters and return values.
The new idea turns this on its head and annotates the types instead.

Consider the following two C# value type definitions:

    public struct off_t
        private long value;

        public off_t(long x) { value = x; }

        public static operator implicit off_t(long x)
            { return new off_t(x); }
        public static operator implicit long(off_t x)
            { return x.value; }

    public struct int_t
        private int value;

        public int_t(int x) { value = x; }

        public static operator implicit off_t(int x)
            { return new int_t(x); }
        public static operator implicit int(int_t x)
            { return x.value; }

and the following new definition for "lseek":

    extern public static off_t lseek(int_t fd, off_t offset, int_t

This is probably the "prettiest" so far out of all the proposals.
The presence of the "PosixType" attribute tells the runtime engine
that it needs to adjust the representation of the type to match
the same-named Posix type ("off_t" and "int" in these examples).

The implicit conversion operators take care of integrating the types
into C#'s type system in such a way that they act like regular
numeric types.

A small drawback of this approach is that it does involve a little
extra overhead to convert between primitive numeric values and
managed values.  However, the JIT should be able to optimize this
overhead away.

I think we can also extend this to handle the "hell case" of "stat".
Consider the following definition:

    public struct stat
        public dev_t st_dev;
        public ino_t st_ino;
        public mode_t st_mode;
        public nlink_t st_nlink;
        public uid_t st_uid;
        public gid_t st_gid;
        public dev_t st_rdev;
        public dev_t st_rdev;
        public off_t st_size;
        public blksize_t st_blksize;
        public time_t st_atime;
        public time_t st_ctime;
        public time_t st_mtime;

We'll assume that all of the "XXX_t" types have been defined as above.

When the runtime engine sees the "PosixStructType", it adjusts its
layout algorithm to map the fields to the correct offsets in the
underlying OS type.

The above definition does not include any of the padding and unused
fields that are present on Linux.  But this doesn't matter because
the runtime engine only cares about things for which it has a name
match.  Everything else is left as a gap.

I've also reversed the usual order for "st_mtime" and "st_ctime" above,
and this doesn't matter either.  The engine will assign offsets based
on their real positions, not their declaration order.

The "stat" method is declared as follows:

    extern unsafe public static int_t stat(string pathname, stat *buf);

I think this should solve most of the nasty cases in mapping to
and from Posix types.  Thoughts?