[Mono-devel-list] Overcoming PInvoke limitations in e.g. Mono.Posix

Jonathan Pryor jonpryor at vt.edu
Fri Oct 8 07:39:16 EDT 2004


On Fri, 2004-10-08 at 03:24, Alan Jenkins wrote:
<snip/>
> > It should be noted that *any* interop layer will rely on binary
> > compatibility, *unless* you distribute only as source code (and require
> > that your users have a compiler available at install- or run-time for
> > source compatibility).
> Yup.  The *nix way.  Binary compatability is virtually nonexistant, even on 
> diferent versions of the same platform, 

This *shouldn't* be true.  Binary compatibility is why there's the iBCS
(Intel Binary Compatibility Standard) for x86 Unix systems, which
specified the way system calls should be performed, the values for
symbolic constants, structure layout, etc.

However, (1) such binary compatibility rules are only for a single
platform (x86 will differ from Sparc, for example), and (2) Linux
ignored iBCS when it was developed, and thus has a different (more
efficient) system-call mechanism and different values for constants. :-)

Between different versions of the same OS, though, there normally
shouldn't be binary compatibility issues.  Linux 1.0 programs continue
to work on Linux 2.6, and Solaris has been stable since at least 2.6
(currently about to ship v10).

<snip/>

> > Worse is coping with standardization, or lack thereof.  Consider the
> > dirent structure (see readdir(3)).  The man page says that only d_name
> > can be assumed, and d_ino is an XSI extension.  Meanwhile linux also has
> > members d_off, d_reclen, and d_type.  AIX has others.
> 
> Three solutions.  One: generate only the fields which can be assumed to be 
> there (bail out if they aren't).  Two: generate all fields, and have programs 
> check explicitly (through reflection) that they exist.  

Yuck.  *Requiring* Reflection to use your structures is broken. 
Especially if we want to implement CAS (Code Access Security) at some
point and allow access to Mono.Posix.  Reflection requires a CAS
permission to be used.

<snip what="lots"/>

I'd try to quote something appropriate, but that would lead to lots of
noise.

The problem with your approach, *as I understand your approach*, is
primarily with structures.  For a portable program, you *can't* know:

  1.  Member sizes.  C# typedefs partially solve this.
  2.  Member offsets.
  3.  Member ordering.

You'd think (2) is dependent on (1), but it isn't -- padding can be 
inserted into the structure, both explicitly and by the compiler, so a
structure member offset is NOT just the sum of the sizes of the previous
members.

And even if (2) wasn't a problem, (3) certainly is.

For example, Foo's dirent could be:

	struct dirent {
		ino_t d_ino;
		char  d_name[NAME_MAX];
	};

Bar's dirent could be:

	struct dirent {
		char  d_name[NAME_MAX];
		char  d_padding[2];
		ino_t d_ino;
	};

Baz's dirent could be:

	struct dirent {
		struct some_nested_struct d_extension;
		off_t d_len;
		ino_t d_ino;
		char  d_name[NAME_MAX];
	};

There is a lot of potential for variation between platforms, and I don't
see how you can actually solve this *only* from C# (because you'd have
to parse the system header files to determine structure layout, and if
you're actually going to do *that*, you might as well use C).

If we accept that a pure C# solution isn't possible (in the general
case), then we can either: (1) not solve the general case, but create a
solution that's "good enough" for most cases.  I don't see this
happening.  (2) Use a mixed C/C# solution.

My principal thought is that, as soon as you're using C as part of the
solution, you might as well run with it (like I did with Mono.Posix) and
create cross-platform C# code and platform-specific C code.  C is much
better suited for the platform-specific code (since our target platforms
export C structure declarations, not C#), and is easily used from C#.

> Thanks for a reality check :).  I think you may have misinterpreted me on some 
> points: I really think that native glue code can be avoided.  

I'm quite convinced that native glue *can't* be avoided.  I'd love to be
proven wrong, though. :-)

> I 
> underestimated the job; looks like function calls need to be handled as well 
> as data types, at least for Mono.Posix.  I think I'm best off expressing my 
> ideas through code right now, so I'll try to make it as clear & well 
> commented as possible.  Til then!

I look forward to seeing your code.

 - Jon





More information about the Mono-devel-list mailing list