Re: UVM typedef struct

Previous thread: UVM emap implementation by Mindaugas Rasiukevicius on Monday, June 15, 2009 - 12:05 pm. (2 messages)

Next thread: Proposed changes to acpi_tz sensor behavior by Paul Goyette on Monday, June 15, 2009 - 2:41 pm. (1 message)
From: Mindaugas Rasiukevicius
Date: Monday, June 15, 2009 - 12:09 pm

Hello,

I would like to typedef and replace the struct usage in UVM, so that
struct vm_map would become vm_map_t, struct vm_anon - vm_anon_t, and so
on. It increases readability and makes UVM consistent in this respect
with other subsystems (cf. sys/kern). Any concerns?

I would like to do this in one go, since <chs> has mentioned that "slow"
diverge would prolong his pain. :)

-- 
Best regards,
Mindaugas
From: der Mouse
Date: Monday, June 15, 2009 - 12:13 pm

This sounds good.  But I would utter a plea to please _not_ start
creating similar typedefs for pointers to those structures.  I, for
one, find it borders on crippling for readability to see something like
"foobar_t something;" and not realize until much later that it's
actually a pointer.

/~\ The ASCII				  Mouse
\ / Ribbon Campaign
 X  Against HTML		mouse@rodents-montreal.org
/ \ Email!	     7D C8 61 52 5D E7 2D 39  4E F1 31 3E E8 B3 27 4B
From: Masao Uebayashi
Date: Monday, June 15, 2009 - 9:43 pm

Hi!

Sort answer:

I strongly support "typedef struct vm_page *vm_page_t".

Long answer:

I've been looking deeply into UVM pager and the fault routine.  I plan
to extend pagers to handle not only page cache but also non-cache
page, that is memory-mappable, directly-accessible page, like
character devices or NAND FlashROM.  To achieve this, I want pagers to
return a magic (struct vm_page *) to tell callers that "there is no
(struct vm_page *) object; we tell you my physical address other
way!".  Here (struct vm_page *) is actually a magic uintptr_t.

I think that there're many benefits by making struct vm_page opaque.
Its content is touched from ~everywhere including filesystem layers,
which violates abstraction.  I'd propose to make vm_page_t opaque and
make users to always use accessor routines.

If once vm_page_t internal is hidden, page handling would be much
extensible - locking improvements, accounting, or variable sized
pages, etc.

Masao
From: Jason Thorpe
Date: Monday, August 10, 2009 - 5:42 pm

Agreed!

-- thorpej

From: Jason Thorpe
Date: Monday, August 10, 2009 - 5:43 pm

I would like to see NetBSD do that with ~all of its data structures.

-- thorpej

From: David Holland
Date: Monday, August 10, 2009 - 11:37 pm

Making data structures opaque is a completely different issue from
creating an unnecessary and misleading layer of magic aliased names
for them.

-- 
David A. Holland
dholland@netbsd.org
From: Antti Kantee
Date: Monday, June 15, 2009 - 10:37 pm

Strongly opposed to the _t mania.  I actually had a longer mail written
about the subject a few days ago, but I managed to lose it.  My two main
reasons for opposition were:

1) obfuscates code.  there is no reason to tell if silly_t is an int,
   struct or pointer to something just by looking at the type
2) impossible to provide forward declarations for interfaces using
   silly_t
From: Peter Seebach
Date: Monday, June 15, 2009 - 10:45 pm

This is not necessarily a bad thing.  It is sometimes unimportant to know

?

int foo(silly_t);

-s
From: Eric Haszlakiewicz
Date: Tuesday, June 16, 2009 - 7:55 am

Or maybe Antti means:

struct mystruct;
int foo(struct mystruct *);

That works with typedefs too, but you need to duplicate the typedef line:

struct mystruct;
typedef struct mystruct mystruct_t;
int foo(mystruct_t *);

eric
From: matthew green
Date: Tuesday, June 16, 2009 - 8:16 am

On Tue, Jun 16, 2009 at 12:45:22AM -0500, Peter Seebach wrote:
   > In message <20090616053752.GA8944@cs.hut.fi>, Antti Kantee writes:
   > >2) impossible to provide forward declarations for interfaces using
   > >   silly_t
   > 
   > int foo(silly_t);
   
   Or maybe Antti means:
   
   struct mystruct;
   int foo(struct mystruct *);
   
   That works with typedefs too, but you need to duplicate the typedef line:
   
   struct mystruct;
   typedef struct mystruct mystruct_t;
   int foo(mystruct_t *);


duplicate typedefs generate an error.


.mrg.
From: Eric Haszlakiewicz
Date: Tuesday, June 16, 2009 - 9:47 pm

hmm.. you're right.  It worked fine on the machines at work, but those
are linux, not NetBSD.  Still, I kind of figured gcc would behave the
same.  Oh well, I stand corrected.

eric
From: matthew green
Date: Tuesday, June 16, 2009 - 11:02 pm

On Wed, Jun 17, 2009 at 01:16:20AM +1000, matthew green wrote:
   >    Or maybe Antti means:
   >    
   >    struct mystruct;
   >    int foo(struct mystruct *);
   >    
   >    That works with typedefs too, but you need to duplicate the typedef line:
   >    
   >    struct mystruct;
   >    typedef struct mystruct mystruct_t;
   >    int foo(mystruct_t *);
   > 
   > duplicate typedefs generate an error.
   
   hmm.. you're right.  It worked fine on the machines at work, but those
   are linux, not NetBSD.  Still, I kind of figured gcc would behave the
   same.  Oh well, I stand corrected.


i've never seen this work on any C platform.


.mrg.
From: David Laight
Date: Tuesday, June 16, 2009 - 11:42 pm

I think Microsoft's compilers allow it.

	David

-- 
David Laight: david@l8s.co.uk
From: David Laight
Date: Tuesday, June 16, 2009 - 8:46 am

The fact that the latter is a bug, means that you can only define
a typedef in one place  This is a problem if the functions that
use the type need to be in several header files - since you end up
either putting the typedef in a global file, of a file of its own.

In some places you'll see a 'struct foo' definition before a function
prototype where everywhere else the typedef is used!

From a language point of view there is little difference (other than
the number of characters needed) between using 'struct foo' and 'foo_t'
once 'typedef struct foo foo_t' is in scope.
(Except that, in C (but not C++), the struct namespace is separate
from all others.)

	David

-- 
David Laight: david@l8s.co.uk
From: Reinoud Zandijk
Date: Wednesday, June 17, 2009 - 4:01 am

what about :

typedef struct {
....
} mystruct_t;

Though i dont know how to cleanly pre-define them other than

typedef struct mystruct_t;

Reinoud

From: Mindaugas Rasiukevicius
Date: Tuesday, June 16, 2009 - 2:19 am

Just to make this clear, I do not want to typedef structs as pointers.
I agree that it is confusing (although it has a good rationale for some

I am not sure what do you mean. Each typedef, eg. vm_page_t would be a
structure, where vm_page_t * a pointer to it. No intention to typedef

Why not? Note that struct declarations wont be removed (cf. struct lwp
and lwp_t).

-- 
Best regards,
Mindaugas
From: Antti Kantee
Date: Tuesday, June 16, 2009 - 12:02 pm

The underlying problem is that I do not see any benefit from arbitrary

There are plenty of places in the kernel where _t is a pointer.  How are
you supposed to distinguish between them?  More specifically to this case,
when vm_page_t existed in NetBSD with the Mach vm, it was a pointer.

And, actually, opaque foo_t struct pointer is the only place where I

... see mrg's mail in this thread.
From: Mindaugas Rasiukevicius
Date: Tuesday, June 16, 2009 - 1:00 pm

I understand that it is a personal preference, but at least to me, it would
increase readability. It would be good to hear opinions of more people who
are working in sys/uvm.

Also, as already mentioned, this would be consistent with other core parts,

I do not see a necessity to have any _t which would be a pointer in sys/uvm.
Keep things simple. Historical point should not disturb, we have UVM now,

Why do you need typedefs there? What's wrong with struct vm_page; ? As said,
struct definitions stay, eg. your rump would not require any changes.

-- 
Best regards,
Mindaugas
From: matthew green
Date: Tuesday, June 16, 2009 - 1:14 pm

Antti Kantee <pooka@cs.hut.fi> wrote:
   > > Just to make this clear, I do not want to typedef structs as pointers.
   > > I agree that it is confusing (although it has a good rationale for some
   > > cases, eg. when structure size is dynamic).
   > 
   > The underlying problem is that I do not see any benefit from arbitrary
   > typedefs such as struct x -> x_t.  Will we get u32_t next?
   
   I understand that it is a personal preference, but at least to me, it would
   increase readability. It would be good to hear opinions of more people who

i generally prefer "struct foo".  "foo_t" almost always send me off
looking into some header file to see what it really means.

   > There are plenty of places in the kernel where _t is a pointer.  How are
   > you supposed to distinguish between them?  More specifically to this case,
   > when vm_page_t existed in NetBSD with the Mach vm, it was a pointer.
   
   I do not see a necessity to have any _t which would be a pointer in sys/uvm.
   Keep things simple. Historical point should not disturb, we have UVM now,
   not Mach VM. Solaris VM, for example, has structures typedef'ed.

honestly, if you going to do this, please rename all the "struct vm_foo"'s
to "struct uvm_foo".  the current method with some of each is historical
baggage to the integration of UVM and it has always bothered me.

that would also avoid any confusion for folks with mach vm knowledge.


.mrg.
From: Masao Uebayashi
Date: Tuesday, June 16, 2009 - 5:28 pm

If we rename struct vm_map to uvm_map, it conflicts with uvm_map().
Semantically fine, but lose readability, greppability, and
ctags-ability.

Masao
From: Antti Kantee
Date: Tuesday, June 16, 2009 - 4:21 pm

No, your argument is personal preference, mine is technical.  This was
already hinted a few times, but here we go again:

If you have typedef struct foo foo_t; and use foo_t * in an interface,
you must always expose the implementation struct foo since you cannot
typedef twice.  With struct foo * you have no such problems since you can
use forward declarations.  Now, either you will implicitly create rules
about type exposure, need to have two sets of prototypes, some #ifdef
magic, or you will have inconsitency in code (interface has struct foo*,
code uses foo_t and foo_t *).

This is *especially* problematic if you want to provide an interface which
takes foo_t *, but cannot include the headers which provide the type due
to collisions.  Now you have a mismatch between the caller and the callee.
See *for example* sys/rump/include/rump/rump.h for a few examples of
current lossage with useless_t.  In addition to the #ifdef crap at the
top, notice how struct lwp interfaces take struct lwp * instead of lwp_t *
and remember what I said above about silly_t *reducing* consistency.
If there was no ridiculous_t, there would be no problem.

Only if struct foo is never ever a part of any public interface, this
does not apply.  Even then I'd say that foo_t obfuscates, but that *is* a
matter of personal preference and I don't care enough to argue about it.
Still, it is difficult to know that 100 years from now we don't want
struct foo in an interface.

Hopefully that was clear and verbose enough.
From: der Mouse
Date: Tuesday, June 16, 2009 - 4:42 pm

You must expose the struct tag name, but there's no need to expose the
struct itself.  This is not because you can't typedef twice but rather
because you can't use foo_t without defining it, and the incomplete
struct is not interface-compatible with the complete struct unless the
struct tags are the same.

This works fine (I've done it often enough):

foo.h:

struct foo;
typedef struct foo foo_t;
void foo_something(foo_t *, int);

foo.c:

#include "foo.h" /* or <foo.h> */
struct foo {
	...
};


I don't see any such.  What I see there are problems with trying to use
interfaces _without_ including the files exporting the interface
definitions in question, which is bound to have problems no matter what

So?  That's because there's no "typedef struct lwp lwp_t;" line.  I
can't see why not; because of the edict against including the proper
definition file, there's no reason not to typedef it alongside the

I still can't see the typedefs as being the problem.  The problem I see
is an attempt to use interfaces without including the files declaring
the relevant types.  That this breaks less visibly when using struct
tags strikes me as a reason to use foo_t, to render the bustification
blatant, rather than the converse.

"Then there's no hope of this working off NetBSD" is not an excuse to
avoid including the interface definitions.  Rather, it's a reason to
build an include-file glue layer, or an include-file link farm, some
such, so you can get the interface from wherever it needs to come from
for the environment you're trying to build in.  Perhaps on the next

If there were no types, there would be no problem.  (BLISS, anyone?)

When you have a symptom and you find something that, if different,
would make the symptom go away, it does not necessarily follow that you
have found the problem.  Say it's summer, and I'm uncomfortably hot;
perhaps the problem is not that my city is too far south but instead is
this overcoat I'm wearing.

/~\ The ASCII				  Mouse
\ / ...
From: Terry Moore
Date: Wednesday, June 17, 2009 - 2:05 pm

With all respect, this is not true.  The following pattern works well.

1) You put "typedef struct foo foo_t;" in a header file named 
"foo_type.h", and #include that in every header file where you want 
foo_t to be used as a forward type (i.e., where you need to use foo_t *).

2) Then in the header file ("foo.h") where you define the contents of 
struct foo, you also #include "foo_type.h" before you define the contents.

(MCCI actually uses slightly different names, and we of course group 
all the forward structures for a single API into a "{module}_types.h" 
header file; but this illustrates the idea.)

Files that include "foo_type.h" (including the header files that 
define prototypes) don't see the implementation unless they include 
"foo.h" explicitly.

This works well.  It's portable to every C compiler I've come across 
(dozens, and not just GCC).  Compile speeds are not noticeably 
affected -- our products that use this technique already have roughly 
a thousand header files (for other reasons) and this has caused problems.

This technique has the additional advantage of hiding struct/union 
decisions from all the modules except the modules that have the 
implementation in-scope.  (Otherwise, everyone who wants a pointer 
has to know whether it's struct foo or union foo that's wanted.)  We 
have found this to be very convenient.

Best regards,
--Terry 

From: Terry Moore
Date: Wednesday, June 17, 2009 - 4:22 pm

Paul Goyette kindly pointed out that there was a "no" missing below, as marked.

--Terry



From: James Chacon
Date: Wednesday, June 17, 2009 - 3:14 pm

This is untrue. There is no requirement to expose the contents of a  
FILE * for instance in order for API's to use it as an opaque data  
structure. On the pieces that actually need internals need the  
implementation exposed.

James

From: Jason Thorpe
Date: Monday, August 10, 2009 - 5:45 pm

No, the real benefit is "x * -> x_t".

-- thorpej

From: David Laight
Date: Monday, August 10, 2009 - 11:44 pm

Actually that is the one you must not do ...
Since you can't then define 'const x *' etc.

But I agree that most code shouldn't be dependant on the offsets of the
majority of the members of most functions, and definitely not on the
size of such structures.

For example the contents of 'struct proc' and 'struct lwp' should not
be exposed to any driver code, just to some parts of kern.
Possibly you have a sub-structure which is exposed, and can grow, that
contains fields that are commonly needed.

	David

-- 
David Laight: david@l8s.co.uk
From: David Holland
Date: Monday, August 10, 2009 - 11:45 pm

That is not a benefit. What does it buy you? Absolutely nothing. What
does it cost you? A lot of clarity. It invites memory leaks, refcount
bugs, accidental sharing of things you meant to have your own copy of,
sometimes accidental copying of things you meant to share, and worse,
all because you're wilfully and gratuitously blurring the distinction
between a value and a pointer to a value.

If you want to think in Java it's your lookout but please don't force
it down everyone else's throat.

-- 
David A. Holland
dholland@netbsd.org
From: Peter Seebach
Date: Tuesday, August 11, 2009 - 12:18 am

It can be.

In particular, it encourages you to use the API, rather than trying to
outsmart it.  If you are quite sure whether x_t is a pointer or not, you may
take steps based on your expectations of how to manage pointers (or
non-pointers).  This can be an advantage, especially for other people who
may need to update an API you were supposed to be using...

-s
From: David Holland
Date: Tuesday, August 11, 2009 - 12:48 am

On Tue, Aug 11, 2009 at 02:18:47AM -0500, Peter Seebach wrote:
 >> That is not a benefit.
 > 
 > It can be.
 > 
 > In particular, it encourages you to use the API, rather than trying to
 > outsmart it.

If the public header for the API declares the structure in question,
but does not define it, as should be the case for anything calling
itself an opaque type, it's sufficient to write

   struct thingy;  /* Opaque. */

and dressing it up any further just obscures what's really going on.

 > If you are quite sure whether x_t is a pointer or not, you may
 > take steps based on your expectations of how to manage pointers (or
 > non-pointers).  This can be an advantage, especially for other people who
 > may need to update an API you were supposed to be using...

If you don't know whether it's a pointer, you can't use it correctly,
except in a very limited set of cases for very simple APIs. You get
bitten by both memory management and sharing.

Consider:

   silly_t foo, bar;

   foo = get_silly_thing();
   bar = foo;
   change_silly_stuff(foo);
   /* Ok, at this point, has bar been changed? Guess away. */
   /* And for that matter, is bar even valid any more? */

If you're coding in Haskell, where nothing is mutable and everything
is garbage-collected, you can genuinely do without this distinction.
But most people don't want to code in Haskell.

-- 
David A. Holland
dholland@netbsd.org
From: Peter Seebach
Date: Tuesday, August 11, 2009 - 1:10 am

Let's say we commit to you that, definitely, silly_t is a pointer.

Do you now know, without checking the API docs, whether or not bar is
valid?  Well, uhm.  No.  (And if the function is a function-like macro,
you don't even know that foo and bar are still equal.)

Okay, but what if we say that, for sure, silly_t is not a pointer, but an
opaque non-pointer object.  Now do you know?  ... Well, actually, you still
don't know, because it could be that silly_t is a structure CONTAINING at
least one pointer.  In which case bar might well now contain an invalid
pointer, or a pointer to an obsolete object, or... well, we just don't know.

So in short, if types can be opaque, you have already lost.

-s
From: David Holland
Date: Tuesday, August 11, 2009 - 9:35 am

On Tue, Aug 11, 2009 at 03:10:11AM -0500, Peter Seebach wrote:
 > In message <20090811074826.GA16058@netbsd.org>, David Holland writes:
 >> If you don't know whether it's a pointer, you can't use it correctly,
 >> except in a very limited set of cases for very simple APIs. You get
 >> bitten by both memory management and sharing.
 > 
 > True.

Zackly :-)

 >> Consider:
 >> 
 >>    silly_t foo, bar;
 >> 
 >>    foo = get_silly_thing();
 >>    bar = foo;
 >>    change_silly_stuff(foo);
 >>    /* Ok, at this point, has bar been changed? Guess away. */
 >>    /* And for that matter, is bar even valid any more? */
 > 
 > Let's say we commit to you that, definitely, silly_t is a pointer.
 > 
 > Do you now know, without checking the API docs, whether or not bar is
 > valid?  Well, uhm.  No.

No, but if you know it's a pointer you'll go check, and ideally the
API will be designed so the name and circumstances of the call tell
you. E.g. after "silly_destroy(foo)" or "foo = munge_silly_tree(foo)"
you'd reasonably expect that bar would no longer be valid, but after
"if (is_silly_ok(foo))" you'd expect the converse. This is why it's
generally a bad idea to write functions that consume references unless
they're participating in a naming convention that makes it clear
what's going on.

Meanwhile, if you've been persuaded that silly_t is a plain value,
because you copied it obviously bar is (1) independent of foo and (2)
still valid. Which is fine if it really is... but if it's really a
pointer, (1) is certainly false and (2) may be or become false without
much warning, and then you end up in the weeds.

 > (And if the function is a function-like macro,
 > you don't even know that foo and bar are still equal.)

That's why macros of that kind are eeevil.

 > Okay, but what if we say that, for sure, silly_t is not a pointer, but an
 > opaque non-pointer object.  Now do you know?  ... Well, actually, you still
 > don't know, because it could be that silly_t is a structure ...
From: Peter Seebach
Date: Tuesday, August 11, 2009 - 10:16 am

Ahh, yes.

... Nonetheless, it's possible to have a non-pointer that has the same
type management issues as a pointer.  :)

-s
From: Matthew Mondor
Date: Tuesday, August 11, 2009 - 12:19 am

On Tue, 11 Aug 2009 06:45:11 +0000

I agree, I see the benefit of exposing public structures of an API as
typedefs, but it isn't good practice to me to hide the pointer inside,
unless the name specifically contains addr or ptr in it (and I've seen
cases where *addr_t typedefs were long, uint32_t or the like instead of
a pointer, so addr is still not obvious)...
-- 
Matt
From: der Mouse
Date: Tuesday, August 11, 2009 - 12:38 am

Yes.  But that benefit can be obtained in other, arguably, better ways.
In particular, incomplete structs enforce API use, without hiding what
is and isn't a pointer (which is the thing I most dislike about the _t
paradigm as outlined upthread).

To pick on sys/proc.h as a possibly-inappropriate example, this
paradigm has sys/proc.h containing

struct proc;
...API declarations...

and then something else - perhaps a .c file if there's just one, or if
not then sys/proc-impl.h or some such - includes sys/proc.h and adds

struct proc {
	...details, private to the implementation...
};

But this depends on having a well-defined API in the first place, and
that is something that is woefully lacking in most of the kernel.  I'd
put effort into creating well-defined APIs at all before worrying about
how to encourage/enforce use of them.  (Actually, it's not quite that
bad; there are some moderately well-defined APIs in the kernel, such as
the whole bus-space infrastructure.  But there are a lot of cases,
mostly historical from what I've seen, where the "API" is ill-defined
and consists of a struct which is exposed to a whole lot of code.)

/~\ The ASCII				  Mouse
\ / Ribbon Campaign
 X  Against HTML		mouse@rodents-montreal.org
/ \ Email!	     7D C8 61 52 5D E7 2D 39  4E F1 31 3E E8 B3 27 4B
From: David Holland
Date: Tuesday, August 11, 2009 - 12:50 am

On Tue, Aug 11, 2009 at 03:38:40AM -0400, der Mouse wrote:
 > But this depends on having a well-defined API in the first place, and
 > that is something that is woefully lacking in most of the kernel.

I'm working on it!

-- 
David A. Holland
dholland@netbsd.org
From: Eric Haszlakiewicz
Date: Tuesday, August 11, 2009 - 10:42 am

If anything like this is done, I'd like to kindly request that
there be an option to expose the contents of the structure with a 
config or compile flag.  It is very annoying to try to debug a
program where you can't print out a structure unless you're in
the "right" stack frame.

eric
From: David Holland
Date: Tuesday, August 11, 2009 - 11:00 am

On Tue, Aug 11, 2009 at 12:42:33PM -0500, Eric Haszlakiewicz wrote:
 > > struct proc {
 > > 	...details, private to the implementation...
 > > };
 > 
 > If anything like this is done, I'd like to kindly request that
 > there be an option to expose the contents of the structure with a 
 > config or compile flag.  It is very annoying to try to debug a
 > program where you can't print out a structure unless you're in
 > the "right" stack frame.

gdb is usually pretty good about this, IME. If ddb needs fixing, let's
fix it.

-- 
David A. Holland
dholland@netbsd.org
From: Eric Haszlakiewicz
Date: Wednesday, August 12, 2009 - 9:42 am

I *was* using gdb, but maybe it was due to it being an old version.
argh, and now gdb just hangs when I try to debug anything so I can't 
try it out.   something must be messed up with my machine. :(

eric
From: David Holland
Date: Wednesday, August 12, 2009 - 9:50 am

On Wed, Aug 12, 2009 at 11:42:07AM -0500, Eric Haszlakiewicz wrote:
 > > > > struct proc {
 > > > > 	...details, private to the implementation...
 > > > > };
 > > > 
 > > > If anything like this is done, I'd like to kindly request that
 > > > there be an option to expose the contents of the structure with a 
 > > > config or compile flag.  It is very annoying to try to debug a
 > > > program where you can't print out a structure unless you're in
 > > > the "right" stack frame.
 > > 
 > > gdb is usually pretty good about this, IME. If ddb needs fixing, let's
 > > fix it.
 > 
 > I *was* using gdb, but maybe it was due to it being an old version.

It's been a long while since I noticed this problem, and given my
general coding practices I think I'd trip on it regularly. I haven't
had any problem looking inside the opaque structs in the code I've
been working on recently, anyhow.

 > argh, and now gdb just hangs when I try to debug anything so I can't 
 > try it out.   something must be messed up with my machine. :(

Not necessarily. It's probably PR 40594, and note that there's a
workaround.

-- 
David A. Holland
dholland@netbsd.org
From: Eric Haszlakiewicz
Date: Wednesday, August 12, 2009 - 11:29 am

ah, yes that appears to be my hanging problem.  Thanks!

I guess you're right about gdb working.  The case I ran into before where
it wasn't was where I was compiling my program with debugging turned on,
but the library that actually had the structure definition in it wasn't
compiled with -g, so I suppose gdb didn't have anywhere to get the actual
structure definition from.
Obviously, that case can't happen when debugging a kernel (unless modules
are involved).

eric
From: Tonnerre LOMBARD
Date: Wednesday, August 12, 2009 - 1:32 pm

Salut,


Apart from this question, which I don't think I will comment on,
I recently encountered a problem extending an api_t and have a
question:

 - bla_t contains a list of references to blubb_t
 - blubb_t contains a pointer back to bla_t

How would that ever work?

				Tonnerre
From: Iain Hibbert
Date: Wednesday, August 12, 2009 - 2:17 pm

Oh, you can work that something like this

typedef struct bla	bla_t;
typedef struct bla *	blaptr_t;
typedef struct blubb	blubb_t;
typedef struct blubb *	blubbptr_t;

struct bla {
	blubb_t 	blubb;
	blubb_t	*	blubbptr1;
	blubbptr_t	blubbptr2;
	bla_t *		blaptr1;
	blaptr_t	blaptr2;
};

struct blubb {
	bla_t		bla;
	bla_t *		blaptr1;
	blaptr_t 	blaptr2;
	blubb_t *	blubbptr1;
	blubbptr_t	blubbptr2;
};

is that what you meant?

iain

From: Tonnerre LOMBARD
Date: Wednesday, August 12, 2009 - 3:07 pm

Salut,


I mean:

typedef struct {
	...
	blubb_t blubbs[MAX_BLUBBS];
	...
} bla_t;

typedef struct {
	...
	bla_t owner;
	...
} blubb_t;

				Tonnerre
From: James Chacon
Date: Wednesday, August 12, 2009 - 5:21 pm

Typedefs have nothing to do with that. You cannot create structures  
like this in C since in this setup you need to know the size which you  
can't define up front.

James

From: Tonnerre LOMBARD
Date: Thursday, August 13, 2009 - 11:55 am

Salut,


Sorry, I forgot an asterisk; of course I meant

 bla_t *owner;

Anything else would be pointless.

If you want to do that with typedefs, you have to use the names of
the structs, which contradicts the idea that you don't need to know
what's behind the type.

Thus, typedefs should be considered as having defunct reasoning in
favor of them while bringing disadvantages for both readability and
understandability.

				Tonnerre
From: Iain Hibbert
Date: Wednesday, August 12, 2009 - 11:19 pm

As James said, you can't do exactly that as two structures cannot fully
contain each other (mumble .. laws of physics :).. but your original

So, you just need to declare the structure name first and define the
structure content afterwards which requires a structure tag:

typedef struct bla	bla_t;
typedef struct blubb	blubb_t;

struct bla {
	...
	blubb_t		blubbs[MAX_BLUBBS];	/* array of blubbs */
	...
	blubb_t		*pblubs[MAX_BLUBBS];	/* array of pointers */
	...
};

struct blubb {
	...
	bla_t		*owner;			/* pointer to bla is ok */
	...
};

you are not obliged to use "blubb" and "bla" again and the structure
namespace is separate so it won't collide with anything else.

or if you wanted only pointers you could typedef the pointer:

typedef struct bla *	bla_t;
typedef struct blubb *	blubb_t;

struct bla {
	...
	blubb_t		blubbs[MAX_BLUBBS];	/* array of pointers */
	...
};

struct blubb {
	...
	bla_t		owner;			/* pointer to bla */
	...
};

but as noted elsewhere that is flirting with obfustication (which may be
the intention in an interface that provides a 'cookie')

iain

From: Alan Barrett
Date: Thursday, August 13, 2009 - 12:00 am

Do you mean "how could you declare such a thing?"

    /* in bla.h */
    typedef struct bla bla_t;
    #define BLUBBS_PER_BLA 8

    /* in blubb.h */
    typedef struct blubb blubb_t;

    /* in bla-private.h */
    #incude "bla.h"
    #incude "blubb.h"
    struct bla {
        blubb_t * blubblist[BLUBBS_PER_BLA];
    }

    /* in blubb-private.h */
    #incude "bla.h"
    #incude "blubb.h"
    struct blubb {
	bla_t * blaptr;
    }

--apb (Alan Barrett)
From: Tonnerre LOMBARD
Date: Thursday, August 13, 2009 - 11:57 am

Salut,


I wouldn't want to name the structs, that would be against the
idea of having a typedef, right?

				Tonnerre
From: David Holland
Date: Friday, June 19, 2009 - 10:18 am

On Tue, Jun 16, 2009 at 10:19:06AM +0100, Mindaugas Rasiukevicius wrote:
 > > > I would like to typedef and replace the struct usage in UVM, so that
 > > > struct vm_map would become vm_map_t, struct vm_anon - vm_anon_t, and so
 > > > on. <...>
 > 
 > Just to make this clear, I do not want to typedef structs as pointers.
 > I agree that it is confusing (although it has a good rationale for some
 > cases, eg. when structure size is dynamic).

I'm not convinced, but that's a different argument :-)

 > > 1) obfuscates code.  there is no reason to tell if silly_t is an int,
 > >    struct or pointer to something just by looking at the type
 > 
 > I am not sure what do you mean. Each typedef, eg. vm_page_t would be a
 > structure, where vm_page_t * a pointer to it. No intention to typedef
 > non-structures in UVM.

Historically, *_t types are primitive types, which means essentially
integers. Some exceptions that currently exist (e.g. in the pthreads
API and some inappropriate typedefs of pointers in the kernel) are
bugs.

Historically also structures are always used as "struct foo"; but
preserving this convention is not as important as not treading on
other related conventions.

So, if we want to do this, which I don't have a strong opinion about,
can we use some naming convention other than _t?

My suggestion would be to just do

   typedef struct vm_page vm_page;

and leave it at that.

-- 
David A. Holland
dholland@netbsd.org
From: Greg A. Woods
Date: Friday, June 19, 2009 - 10:51 am

No, not really, especially not in C generally (perhaps in Unix, but
there are perhaps other explanations for why Unix code failed to use

Well, maybe, if you go back in time so far that "typedef" didn't exist.

Of course if you go back that far you'll find even header include files
were poorly used (in Unix code, that is) and full "struct" definitions

I really strongly disagree with the idea of not using "_t" for typedef
names.

Historically the real reason for appending "_t" to typedef names is to
mark the identifier as being a "type" -- i.e. it's a special identifier
that exists in a unique namespace.

This is useful for _all_ types of syntax highlighting, including that
done implicitly by the human eye and brain.

In your example "vm_page" is by default a variable name to me, not a
type name.

The use of the "_t" suffix on typedef names is an incredibly important
idiom that should be used everywhere possible.


FWIW, I do also disagree with including the "*" pointer qualifier in the
typedef unless the name somehow reflects this fact, such as fooptr_t,
foop_t, foo_p_t, or foo_pt, or something like that (so long as it's
consistent, especially with existing code, from anywhere, if indeed
there's anything already statistically consistent, which would in my
experience be the "fooptr_t" form).

--=20
						Greg A. Woods
						Planix, Inc.

<woods@planix.com>       +1 416 218-0099        http://www.planix.com/
From: David Holland
Date: Friday, June 19, 2009 - 11:21 am

On Fri, Jun 19, 2009 at 01:51:27PM -0400, Greg A. Woods wrote:
 > > Historically, *_t types are primitive types
 > 
 > No, not really, especially not in C generally (perhaps in Unix, but
 > there are perhaps other explanations for why Unix code failed to use
 > this powerful idiom as uniformly as it should have).

Historically in Unix, though, which is the point.

 > > Historically also structures are always used as "struct foo"; but
 > > preserving this convention is not as important as not treading on
 > > other related conventions.
 > 
 > Well, maybe, if you go back in time so far that "typedef" didn't exist.

Again, historically in Unix.

 > > So, if we want to do this, which I don't have a strong opinion about,
 > > can we use some naming convention other than _t?
 > 
 > I really strongly disagree with the idea of not using "_t" for typedef
 > names.
 > 
 > Historically the real reason for appending "_t" to typedef names is to
 > mark the identifier as being a "type" -- i.e. it's a special identifier
 > that exists in a unique namespace.

Yes, it is a type, but it is a *primitive* type. Non-primitive types
have been, historically, marked with 'struct' or 'union', and the
desire to retain this visual distinction is why Unix code does not do
the "typedef struct { ... } foo" idiom that much other C code does.

Structs and particularly pointers are not used the same way (no matter
how abstract they are!) and should be tagged, if tagged, with
something other than _t.

Myself, I don't see any great need to tag them, as the distinction
between types and values is abundantly clear from syntax, but I don't
have anywhere near such a strong opinion about that.

-- 
David A. Holland
dholland@netbsd.org
From: Greg A. Woods
Date: Friday, June 19, 2009 - 11:57 am

Historically in Unix it doesn't matter though -- Unix had too much
baggage carried forward from the days before the invention of "typedef".

I'd guess dmr might even agree with me and also close by saying
"practice what I preach, not what I do".

Just because Unix has/had poor programming practises as extra baggage
doesn't mean NetBSD needs to carry it all, or even some, forward as well.

Well, yes, up to the point where "typedef" came into being at least.

Since then "typedef" offers a way to name any kind of type, primitive or
otherwise.

Perhaps historically the only really good reason to ever use "typedef"
for primitive types where where they might have to change size within
the same class of primitive type for some variant implementation such as
to mask underlying hardware differences, or to support scaling, etc.

However the reasons for using "typedef" to alias struct or union
definitions are far more numerous and perhaps more vaporous as well, but
now those reasons are generally accepted they apply to primitive data

The point with "_t" is to distinguish the type alias name as being a
typedef name, not in how the underlying data structure is used
regardless of whether it is a pointer, struct, or union.  Use of "_t"
for all typedef names is a convention that helps both human and computer
distinguish the unique properties of these unique identifiers.  They are
not labels on storage (text or data) they are labels on language
constructs and as such it is critically important that they be treated

I certainly don't agree at all with the use of "abundantly" there.

Indeed the tagging of typdef names is not necessary for the compiler,
but neither is the use of meaningful nouns in identifiers (instead of
just creating them from random alphabetic sequences for example) -- I'm
not talking about syntax, I'm talking about human factors and
non-compiler partial parsers used to support human factors (such as
syntax highlighters, etc.)

--=20
						Greg A. ...
From: David Holland
Date: Friday, June 19, 2009 - 12:04 pm

On Fri, Jun 19, 2009 at 02:57:14PM -0400, Greg A. Woods wrote:
 > > > > Historically, *_t types are primitive types
 > > > 
 > > > No, not really, especially not in C generally (perhaps in Unix, but
 > > > there are perhaps other explanations for why Unix code failed to use
 > > > this powerful idiom as uniformly as it should have).
 > > 
 > > Historically in Unix, though, which is the point.
 > 
 > Historically in Unix it doesn't matter though -- Unix had too much
 > baggage carried forward from the days before the invention of "typedef".

Yes, and that baggage was kept precisely because of the distinctions
I've cited.

 > >  > Historically the real reason for appending "_t" to typedef names is to
 > >  > mark the identifier as being a "type" -- i.e. it's a special identifier
 > >  > that exists in a unique namespace.
 > > 
 > > Yes, it is a type, but it is a *primitive* type. Non-primitive types
 > > have been, historically, marked with 'struct' or 'union', and the
 > 
 > Well, yes, up to the point where "typedef" came into being at least.
 > 
 > Since then "typedef" offers a way to name any kind of type, primitive or
 > otherwise.

You are talking about what is possible; I am talking about historic
practice in the kernel and the ... more important parts of userland.

 > > Structs and particularly pointers are not used the same way (no matter
 > > how abstract they are!) and should be tagged, if tagged, with
 > > something other than _t.
 > 
 > The point with "_t" is to distinguish the type alias name as being a
 > typedef name, not in how the underlying data structure is used
 > regardless of whether it is a pointer, struct, or union.

This is entirely pointless.

 > Use of "_t"
 > for all typedef names is a convention that helps both human 

Not likely. Or do you also advocate full Hungarian notation?

 > and computer

Bollocks.

 > distinguish the unique properties of these unique identifiers.  They are
 > not labels on storage (text or data) they are ...
From: tlaronde
Date: Saturday, June 20, 2009 - 3:05 am

FWIW, in Plan9 for example, a complex, composed type is lexically
identified by a first capital letter ; while primitive types are all 
lower case.

So:

typedef struct Tm {} Tm;

This is IMHO sound, since complex, composite type are special,
extensions of the language in some sense.
-- 
tHIerry Laronde (Alceste) <tlaronde +AT+ polynum +dot+ com>
                 http://www.kergis.com/
Key fingerprint = 0FF7 E906 FBAF FE95 FD89  250D 52B1 AE95 6006 F40C
From: Chuck Cranor
Date: Wednesday, July 22, 2009 - 9:39 am

I can explain why the code is the way it is:

Before I wrote the UVM code, I spent alot of time studying other VM
code.   I found that having these kinds of typedefs for structures 
made the code harder to read (because you don't know if you are dealing
with a structure, or a pointer to a structure --- folks do it both ways).
So when I wrote UVM I attempted to remove as much of this ambiguity as 
possible.  I think the "struct"'s and "*"'s are useful semantic cues
that make it easier for new folks to understand the code.


If we feel typedef structs are important, I would be in favor of
some sort of hungarian notation for the type names, so the semantic
information is not lost (e.g. struct vs struct *).   But is it worth
the effort to do that?


chuck
From: David Holland
Date: Wednesday, July 22, 2009 - 9:45 am

On Wed, Jul 22, 2009 at 04:39:54PM +0000, Chuck Cranor wrote:
 > I can explain why the code is the way it is:
 > 
 > Before I wrote the UVM code, I spent alot of time studying other VM
 > code.   I found that having these kinds of typedefs for structures 
 > made the code harder to read (because you don't know if you are dealing
 > with a structure, or a pointer to a structure --- folks do it both ways).
 > So when I wrote UVM I attempted to remove as much of this ambiguity as 
 > possible.  I think the "struct"'s and "*"'s are useful semantic cues
 > that make it easier for new folks to understand the code.

This is what I've been saying also, but I haven't been getting much
traction. :-|

-- 
David A. Holland
dholland@netbsd.org
From: Jason Thorpe
Date: Monday, August 10, 2009 - 5:50 pm

If the APIs are designed well, you:

1- Won't be dealing with structs directly, only through accessors /  
mutators (ABI stability).

2- Won't have to know / care what underlying type you're dealing with  
anyway.

If we ever want to have a chance of supporting a modular kernel really  
well, then we need to have better ABI stability in our kernel, which  

-- thorpej

Previous thread: UVM emap implementation by Mindaugas Rasiukevicius on Monday, June 15, 2009 - 12:05 pm. (2 messages)

Next thread: Proposed changes to acpi_tz sensor behavior by Paul Goyette on Monday, June 15, 2009 - 2:41 pm. (1 message)