Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 26 Oct 1995 15:20:48 +1000
From:      Bruce Evans <bde@zeta.org.au>
To:        bde@zeta.org.au, terry@lambert.org
Cc:        CVS-commiters@freefall.freebsd.org, bde@freefall.freebsd.org, cvs-sys@freefall.freebsd.org, hackers@freebsd.org, swallace@ece.uci.edu
Subject:   Re: SYSCALL IDEAS [Was: cvs commit: src/sys/kern sysv_msg.c sysv_sem.c sysv_shm.c]
Message-ID:  <199510260520.PAA07866@godzilla.zeta.org.au>

next in thread | raw e-mail | index | archive | help
>> Which one?  In NetBSD it's register_t, which may be longer than an
>> int.  This causes problems.

>Yeah.  They ignored the definition of "int".  That's a problem.

"int" is machine-dependent.  On 68000's you would have to support
some user compilers using 16 bit ints (for speed) and others using
32 bit ints (for easy porting).  We're close to having the same
problems with 32 vs 64 bit ints.

>The real problem is the lack of atomic sized types and the use of "short"
>as a synonym for "16 bit value", "long" for "32 bit value" and "quad"
>for "64 bit value".

NetBSD has fixed this.  It uses the typedefs in <machine/types.h>
(int16_t, int32_t, int64_t) a lot.

>The real screwup is when int goes greater than 32 bits, the standard
>*stupidly* requires long to go up as well because it can concieve of
>a maximally sized type named anything other than "long".

This is fundamental.  longs are at least as large as ints.

>> Inlining should remove the hit.  Perhaps given smarter encapsulation

>I suppose this assumes that the compiler will correctly adjust the
>register graph for the inlined assembly's register usage?  I don't
>believe GCC is capable of this now, and I *know* Microsoft's compiler
>dies when this happens.

Everything assumes a correct compiler.  gcc justs produces slower code
when you give it a register allocation problem that is too hard for it.

>I think using registers for calls and inlining are antithetical.  You

Calls to inline functions don't use the standard calling convention.

>> >I'd argue that 'int' was the wrong size [on the alpha], not that
>> >there was extraneous
>> >padding.
>> 
>> This may be true if you control the ABI.

>You *do* control the ABI.  You are either running a known ABI paradigm
>(ie: int push, sizeof(int) == sizeof(register_t), etc.), or you are
>running a compatability ABI, in which case you know at binary load time

You know it but you don't control it.

>and can force alternate argument call gating without much trouble (but
>some runtime overhead: to be expected in any case of non-native code
>execution anyway).

I've thought of using alternative gates to stop the compatibility
interface (for other OS's) from slowing down the standard interface.
We plan to use trap gates instead of call gates for standard syscalls.
We already support int 0x80 for Linux and NetBSD uses int 0x80 for
its native syscalls.  If everything used int 0x80, then decoding would
be expensive.  The expense can be pushed to image activation time using
alternative TSS's and gates.  We might end up with the following:

	int 0x80 (trap gate) for native syscalls
	int 0x80 (trap gate) for NetBSD syscalls
	int 0x80 (trap gate) for Linux syscalls
	lcall(7, 0) (call gate) for ibcs2 compatibility and slowness
	...

>The main issue I'm trying to consider here is emulated execution
>environments on the order of Xenix 286 support.  Specifically, I
>...
>to be native rather than emulated as well.  It's a sound concept,
>but it goes to hell under close approach, like what you'd have in
>wrappering all the system calls, or using register passing.

Er, you have this exactly backwards.  My wrappers provide part of
what is required to handle nontrivial conversions from a 16 bit
ABI to a 32 bit one.

>Structure casts are not a portability problem (as below).

>> >The answer is to compile with the packing being the default for data
>> >matchup -- in the alpha case, 64 bits.  For devices that need it, use
>> >packing #pragma's to tighten them up on a case by case basis, in the
>> >header file defining the structure.
>> 
>> That won't help much.  The problem is that syscall args don't form
>> a struct.  Even if they are in memory, the packing may be different.

>This is not allowed to be the case.  Either the nature of the push
>must be changed to ensure a register_t sized push, or the structure

Yeah, right.  Change the Xenix 286 ABI to push 386 register_t's.

>packing must be specifiable at declaration time, or (preferrably) both.

Packing can't be specified in C.  That's why my my machine generated
wrappers are required - to provide portability.  It isn't worth
supporting both because if you support the worst case (weird packing)
then it just takes more code to support the array case.

>> This can probably be handled by using __attribute__ ((packed)) for
>> every arg to enforce a particular layout.  But that would only work
>> with gcc.  I suggest using machine-generated code of the form
>> `*(type *)(base + OFFSET)' where `type' and OFFSET depend on the arg.

>Code readability is an issue.  The vnode_if.h file is an allowable
>exception because of the export layering used in vnode.h's inclusion
>of the file.  The general case of machine generated code is a bad one
>for code readability.

My ideas for syscalls are based on what is done for vnodes :-).  It
is possible to do better for syscalls (remove the uap's from the non-
machine-generated code) because stacking isn't required.  Stacking
seems to require passing around uap's because one layer might modify
*uap.  This is too hard to do with call-by-value function call args.

>> The ABI is a convention, and can't be changed.

>The ABI is an agreement between user and kernel space, and is abstracted
>from implementation by (1) binary file identification, (2) execution
>class, and (3) call gate.

>That means we can vary it without changing the underlying implementation,
>with the cost being restricted to the abstraction layering (already in
>place as additional overhead anyway for ABI class emulation) and
>additional overhead for non-native ABI's.

You can't vary Xenix 286's syscall parameter passing conventions!

>> >I have to point out that it would then be impossible to make system
>> >calls without prototype references.  If this is a "fix" for the quad
>> >word passing problem (which is a "non-use of system call prototype"
>> >problem), then, isn't this just making things worse?
>> 
>> It requires either prototypes or passing parameters of the correct
>> type just like it always did.  Since there is a lot of broken code
>> out there, most compilers use inferior parameter passing conventions
>> to support the broken code.

>And?

>I don't see that as a problem.  It's not possible for FreeBSD to dictate
>coding practices; unlike Microsoft, it isn't 70% of the market.  Because
>of this, it is necessary to compromise to make the code run.  We already
>do this in a number of cases.

I write Standard code and don't wan't it slowed down by inferior parameter
passing conventions required for broken code.  Unfortunately the parameter
passing convention must be the same as the libraries, and the library
must use a portable convention internally as well as to interface because
using variant conventions would be too hard and isn't fully supported.  I
don't want the library code cluttered with __attribute((__fast__calling_
convention__)) anyway.

>I wouldn't have a problem with an alternate execution class, and potentially
>trap gate, to cause there to be a "very fast" calling mechanism that is
>there *as*an*aternative*to*the*default* "portable" calling mechanism.
>But mandating that the default be such that the majority of code on the
>net would require patching to make it run (admittedly, mostly header
>files) is *bogus*.

The default should be fast.  Since the convention is enforced by mostly
machine generated glue in /usr/src/lib/libc/i386, the C convention is
irrelevant except for its impact on the complexity of the glue.

>I object to needing to include standard system call prototypes to allow
>their use.  I put up with lseek/truncate/ftruncate/mmap BS because it's

It isn't required.  However, passing of args that have the correct type
(after the default promotions) is required.  The second arg to lseek
must be off_t, not long, except of course if off_t is long.

>Note that prototypes of system calls screw up your ability to properly
>utilize the syscall(2) call gate mechanism the way it was intended.  A

The use of syscall() in general requires handling all the messy conversion
issues that we have been discussing in your own code.

>user space checkpointing mechanism that defines it's own open interface
>and calls the real open call via syscall (to remember the file names)
>will fail to compiler when the inlined open conflicts with the user
>definition.

Yes, it can't work in general :-].  It assumes all machines are vaxes.

>Probably a "correct" approach would be to either (1) push 64 bits per
>for all arguments, using type identification to decide on pushing a 0
>for the quad high order dword or pushing a value that really exists at
>the time of the call, or

This would be slow and is beside the point.  It's easy to implement a
good ABI for a particular when you can design it.  We'll have just
one chance to redesigned the ABI when we switch to int 0x80 syscalls.

(2) choose a different violation of the ANSI C
>and POSIX standards -- interface extension -- instead of passing quad's

POSIX allows most reasonable extensions.

>for the default truncate/seek/mmap call interfaces.  The additional

It even allows nonstandard syscalls such as truncate/mmap :-).

>without prototypes (qtruncate/qftruncate/qseek/qlseek/qmmap).  And
>you wouldn't even implement qmmap until the vmio file windowing is fixed
>in the kernel VM system.

Linux has llseek.  That way leads to many ifdefs.

>In any case, I think the benefits are questionable, and should be
>explored as an execution class other than the default execution class
>(ABI) before they are integrated.  Even after they are integrated,
>portability would dictate that their use be optional.

This discussion has become sidetracked.  Please restrict durther discussion
to the original point, which is to simplify the apparent interface to
syscalls without changing the actual interface at all and without reducing
efficiency significantly.

Bruce



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199510260520.PAA07866>