[comp.std.unix] ANSI vs POSIX on <sys/types.h>

ast@cs.vu.nl (Andy Tanenbaum) (05/28/90)

From:  Andy Tanenbaum <ast@cs.vu.nl>

We have gone through this before, but I still haven't gotten an unambiguous
answer.  Let me try a specific example to make it clearer.

Suppose you want to write a routine raise() that is ANSI conformant and also
POSIX conformant.  Raise calls the POSIX kill function, so it includes
<signal.h>.  The <signal.h> header contains the prototype for kill(), which
uses pid_t, a type defined in <sys/types.h>.  POSIX mandates <sys/types.h>
but ANSI does not require it.  Thus it is probably not ANSI-legal to put

#include <sys/types.h>

in raise(), since an ANSI routine cannot depend on something that ANSI
doesn't require.  The raise routine would not be portable then, and maybe
not even conformant.  On the other hand, putting the #include in <signal.h>
probably isn't legal either, and certainly not portable to non POSIX
systems.  

The question is: it has to go somewhere, but where?  I have thought about
putting it in <signal.h> but protected by #ifdef _POSIX_SOURCE, just as
the prototype for kill is.  However, our earlier discussion in this group
suggested that this wasn't legal either.  Does anybody know what the story
is?

Andy Tanenbaum (ast@cs.vu.nl)

Volume-Number: Volume 20, Number 20

gwyn@smoke.brl.mil (Doug Gwyn) (05/30/90)

From:  Doug Gwyn <gwyn@smoke.brl.mil>

In article <711@longway.TIC.COM> Andy Tanenbaum <ast@cs.vu.nl> writes:
>We have gone through this before, but I still haven't gotten an unambiguous
>answer.  Let me try a specific example to make it clearer.

I'm sure I've given unambiguous answers.
The rules are really quite clear and simple.

>Suppose you want to write a routine raise() that is ANSI conformant and also
>POSIX conformant.  Raise calls the POSIX kill function, so it includes
><signal.h>.  The <signal.h> header contains the prototype for kill(), which
>uses pid_t, a type defined in <sys/types.h>.  POSIX mandates <sys/types.h>
>but ANSI does not require it.  Thus it is probably not ANSI-legal to put
>#include <sys/types.h>
>in raise(), since an ANSI routine cannot depend on something that ANSI
>doesn't require.  The raise routine would not be portable then, and maybe
>not even conformant.  On the other hand, putting the #include in <signal.h>
>probably isn't legal either, and certainly not portable to non POSIX
>systems.  
>The question is: it has to go somewhere, but where?  I have thought about
>putting it in <signal.h> but protected by #ifdef _POSIX_SOURCE, just as
>the prototype for kill is.  However, our earlier discussion in this group
>suggested that this wasn't legal either.  Does anybody know what the story
>is?

The above description makes no sense.  The run-time code for raise
does not "include <signal.h>".  In fact, it must not even (in a
conventional linkage environment) invoke the POSIX kill() function,
because the external identifier "kill" is not in the name space
reserved for ANSI C implementations (and thus is reserved for use
by programs, with perhaps totally non-POSIX meaning).  It could,
however, invoke a function named "_kill" or some other such name
reserved for use by implementations.

<signal.h> must not define extra garbage such as the kill() interface
or the POSIX *_t typedefs, except under control of some "feature test
macro" such as _POSIX_SOURCE.  In the case of the typedefs, I would
urge that they not be defined as a side effect of #including <signal.h>
even in the presence of _POSIX_SOURCE.  You don't need pid_t to properly
declare getpid() or kill() in an implementation; instead, simply use the
equivalent type derived from basic types (in this case, probably "int").
Note that this is essential also for the ANSI C declaration of vprintf()
in <stdio.h>, since the va_* identifiers must NOT be defined as a side
effect of #including <stdio.h>, so the implementation of <stdio.h> must
not #include <stdarg.h>.

On the other hand, the implementation of an ANSI C library routine can
certainly depend on things not mentioned in the C standard, such as
for example _kill() and <sys/types.h>.  The following is valid source
code to implement ANSI C conformant raise() in a hypothetical POSIX
implementation:

/*
	raise() -- send a signal to the current process

	public-domain implementation

	last edit:	16-Jan-1990	Gwyn@BRL.MIL

	complies with the following standards:
		ANSI X3.159-1989
		IEEE Std 1003.1-1988
		SVID Issue 3
 */
#define	getpid	_getpid			/* required support for ANSI C */
#define	kill	_kill			/* required support for ANSI C */

#include	<sys/types.h>		/* for pid_t */

extern pid_t	getpid();		/* UNIX/POSIX system call */
extern int	kill();			/* UNIX/POSIX system call */

int
raise(sig)
	int	sig;
	{
	return kill(getpid(), sig);	/* set errno to EINVAL if sig invalid */
	}

Volume-Number: Volume 20, Number 21

ast@cs.vu.nl (Andy Tanenbaum) (06/01/90)

From:  Andy Tanenbaum <ast@cs.vu.nl>

In article <712@longway.TIC.COM> Doug Gwyn <gwyn@smoke.brl.mil> writes:
><signal.h> must not define extra garbage such as the kill() interface
>or the POSIX *_t typedefs, except under control of some "feature test
>macro" such as _POSIX_SOURCE.  In the case of the typedefs, I would
>urge that they not be defined as a side effect of #including <signal.h>
>even in the presence of _POSIX_SOURCE.  You don't need pid_t to properly
>declare getpid() or kill() in an implementation; instead, simply use the
>equivalent type derived from basic types (in this case, probably "int").

POSIX specifically defines kill's first argument as type pid_t, so it
would seem to be poor programming practice to use int, even if this is legal.
If one replaced the *_t types by their definitions everywhere, then a
decision to change pid_t from, say, int, to, say, long, would require
a real expert to dig through all the code to find those int's that really
are pid_t's.  Maintenance of such code would be exceedingly difficult.
I think that the only realistic way is to use pid_t in the prototype of 
kill.  This prototype is required in <signal.h> (protected by
#ifdef _POSIX_SOURCE).

This then raises the question of how to make pid_t known.  In the example
implementation given, <sys/types.h> is included in raise.c.  If this is
indeed legal, then that is clearly one way to do it, as presumably all the
names introduced by <sys/types.h> are not present in the object file,
raise.o, and thus do not pollute the name space.

However, why do you urge not to put #include <sys/types.h> into <signal.h>
under protection of #ifdef _POSIX_SOURCE?

Andy Tanenbaum (ast@cs.vu.nl)

Volume-Number: Volume 20, Number 23

gwyn@smoke.brl.mil (Doug Gwyn) (06/05/90)

From:  Doug Gwyn <gwyn@smoke.brl.mil>

In article <714@longway.TIC.COM> From:  Andy Tanenbaum <ast@cs.vu.nl>
>If one replaced the *_t types by their definitions everywhere, then a
>decision to change pid_t from, say, int, to, say, long, would require
>a real expert to dig through all the code to find those int's that really
>are pid_t's.

You miss an important point -- we're talking about system code provided
by the IMPLEMENTOR, not application code.  Presumably the implementor
IS a real expert, and furthermore is in charge of the decision about
what specific typedefs will be used.  I suspect that many implementors
will provide (for implementation use only) additional headers, say
<sys/_types.h>, that define identifiers such as __pid_t that are just
like the POSIX ones but taken from the name space reserved for use by
implementations.  Then, for example, <sys/types.h> could contain:
	/* <sys/types.h>: */
	#include <sys/_types.h>
	#define pid_t __pid_t
and <signal.h> could contain:
	/* <signal.h>: */
	#include <sys/_types.h>
	#ifdef _POSIX_SOURCE
	extern int kill(__pid_t, int);
	#endif
which addresses the maintenance issue that the implementor might be
faced with.  (Applications are oblivious to all this substructure,
which is the way things SHOULD be.)

>This then raises the question of how to make pid_t known.  In the example
>implementation given, <sys/types.h> is included in raise.c.  If this is
>indeed legal, then that is clearly one way to do it, as presumably all the
>names introduced by <sys/types.h> are not present in the object file,
>raise.o, and thus do not pollute the name space.

Yes, that was one of the points of the example.

>However, why do you urge not to put #include <sys/types.h> into <signal.h>
>under protection of #ifdef _POSIX_SOURCE?

Because I don't think that use of _POSIX_SOURCE should pollute the
name space beyond the minimum required for POSIX.

Volume-Number: Volume 20, Number 26

karl@IMA.IMA.ISC.COM (Karl Heuer) (06/07/90)

From:  karl@IMA.IMA.ISC.COM (Karl Heuer)

In article <717@longway.TIC.COM> From:  Doug Gwyn <gwyn@smoke.brl.mil>
>In article <714@longway.TIC.COM> From:  Andy Tanenbaum <ast@cs.vu.nl>
>>However, why do you urge not to put #include <sys/types.h> into <signal.h>
>>under protection of #ifdef _POSIX_SOURCE?
>
>Because I don't think that use of _POSIX_SOURCE should pollute the
>name space beyond the minimum required for POSIX.

In an earlier thread in this newsgroup, it was decided that this is in fact a
requirement of POSIX.  (Clarified in the Supplement, I believe.)  If the user
himself has not included <sys/types.h>, then the name `pid_t' is not reserved
to the implementation, and so it falls in the user's namespace.

Karl W. Z. Heuer (karl@ima.ima.isc.com or harvard!ima!karl), The Walking Lint

Volume-Number: Volume 20, Number 27

rml@hpfcdc.fc.hp.com (Bob Lenk) (06/13/90)

From:  Bob Lenk <rml@hpfcdc.fc.hp.com>

In article <719@longway.TIC.COM> karl@IMA.IMA.ISC.COM (Karl Heuer) writes:

> In an earlier thread in this newsgroup, it was decided that this is in fact a
> requirement of POSIX.  (Clarified in the Supplement, I believe.)  If the user
> himself has not included <sys/types.h>, then the name `pid_t' is not reserved
> to the implementation, and so it falls in the user's namespace.

It is worth pointing out that official interpretations of an IEEE
standard can only be issued by the IEEE.  Discussions in this newsgroup
(including this posting) can be very informative and useful, but they do
not decide the meaning of the standard.  In fact, there has been an
official request for an interpretation in this area, and I understand
the interpretation being issued is that all namespace reserved for the
implementation by the 1003.1-1988 standard is reserved whenever any
header mentioned in the standard is #included with _POSIX_SOURCE
#defined.

Draft 5 of the 1003.1a revision (actually 1003.1-199x) makes some changes
in this area, but clearly reserves names ending in _t when any POSIX.1
header is included.

		Bob Lenk
		rml@hpfcla.hp.com
		hplabs!hpfcla!rml

Volume-Number: Volume 20, Number 28