public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Avi Kivity <avi@argo.co.il>
To: Kyle Moffett <mrmacman_g4@mac.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>, linux-kernel@vger.kernel.org
Subject: Re: Compiling C++ modules
Date: Tue, 25 Apr 2006 19:46:02 +0300	[thread overview]
Message-ID: <444E524A.10906@argo.co.il> (raw)
In-Reply-To: <9E05E1FA-BEC8-4FA8-811E-93CBAE4D47D5@mac.com>

Kyle Moffett wrote:
> On Apr 25, 2006, at 03:08:02, Avi Kivity wrote:
>> Kyle Moffett wrote:
>>> The "advantages" of the former over the latter:
>>>
>>> (1)  Without exceptions (which are fragile in a kernel), the former 
>>> can't return an error instead of initializing the Foo.
>> Don't discount exceptions so fast. They're exactly what makes the 
>> code clearer and more robust.
>
> Except making exceptions work in the kernel is exceptionally 
> nontrivial (sorry about the pun).
My experience with exceptions in kernel-like code (a distributed 
filesystem) was excellent.
>
>> A very large proportion of error handling consists of:
>> - detect the error
>> - undo local changes (freeing memory and unlocking spinlocks)
>> - propagate the error/
>>
>> Exceptions make that fully automatic. The kernel uses a mix of gotos 
>> and alternate returns which bloat the code and are incredibly error 
>> prone. See the recent 2.6.16.x for examples.
>
> You talk about code bloat here.  Which of the following fits better 
> into a 4k stack?  
The C++ code. See below.
> Which of the following shows the flow of code better?
Once you accept the idea that an exception can occur (almost) anywhere, 
the C++ code shows you what the code does in the normal case without 
obfuscating it with error handling. Pretend that after every semicolon 
there is a comment of the form:

    /* possible exceptional return */

once you think like that, you can see what the code actually does rather 
than how it handles errors. A 15-line function can do something 
meaningful, not just call two functions.
>
> C version:
>     int result;
>     spin_lock(&lock);
>     
>     result = do_something();
>     if (result)
>         goto out;
>     
>     result = do_something_else();
>     if (result)
>         goto out;
>     
>     out:
>     spin_unlock(&lock);
>     return result;
>
> C++ version:
>     int result;
not needed unless you actually return something.
>     TakeLock l(&lock);
>     
>     do_something();
>     do_something_else();
>
> First of all, that extra TakeLock object chews up stack, at least 4 or 
> 8 bytes of it, depending on your word size.
No, it's optimized out. gcc notices that &lock doesn't change and that 
'l' never escapes the function.
>   Secondly with standard integer error returns you have one or two 
> easily-predictable assembly instructions at each step of the way, 
> whereas with exceptions you trade the absence of error handling in the 
> rest of the code for a lot of extra instructions at the exception 
> throw and catch points.
The extra code is out of line (not even an if (unlikely())). So yes, 
total code grows, but the exceptional paths can be in a .text.exception 
section and not consume cache or TLB space.
>   Secondly, while the former is much longer it shows _explicitly_ 
> exactly where the flow of code can go.  In an OS kernel, that is 
> critical;  your debugability is directly dependent on how easy it is 
> to see where the flow of code is going.
>
I can only say that I had very positive experience with code that used 
exceptions. Having less code to view actually improves visibility.
>>> (2)  You can't control when you initialize the Foo.  For example in 
>>> this code, the "Foo item;" declarations seem to be trivially 
>>> relocatable, even if they're not.
>>>     spin_lock(&foo_lock);
>>>     Foo item1;
>>>     Foo item2;
>>>     spin_unlock(&foo_lock);
>>
>> They only seem relocatable with your C glasses on. Put on your C++ 
>> glasses (much thicker), and initialization no longer seems trivially 
>> movable.
>
> This is a really _really_ bad idea for a kernel.  Having simple 
> declaration statements have big side effects (like the common TakeLock 
> object example I gave above) is bound to lead to people screwing up 
> and forgetting about the side effects.  In C it's impossible to miss 
> the side effects of a statement; function calls are obvious, as is 
> global memory modification.
>
In C++ you just have to treat declarations as executable statements. 
Just as you can't compile the code with a C compiler, you can't read it 
with a C mindset. Once you get used to it, it isn't surprising at all.
>> On the other hand, you can replace the C code
>>
>> {
>>    Foo item1, item2;
>>    int r;
>>
>>    spin_lock(&foo_lock);
>>    if ((r = foo_init(&item1)) < 0) {
>>        spin_unlock(&foo_lock);
>>        return r;
>>    }
>>    if ((r = foo_init(&item2)) < 0) {
>>        foo_destroy(&item1);
>>        spin_unlock(&foo_lock);
>>        return r;
>>    }
>>    foo_destroy(&item2);
>>    foo_destroy(&item1);
>>    spin_unlock(&foo_lock);
>>    return 0;
>> }
>>
>> with
>>
>> {
>>    spinlock_t::guard foo_guard(foo_lock);
>>    Foo item1;
>>    Foo item2;
>> }
>
> Let me point out _again_ how unobvious and fragile the flow of code 
> there is.  Not to mention the fact that the C++ compiler can easily 
> notice that item1 and item2 are never used and optimize them out entirely.
Excellent! If there are no side effects, I want it out. If there are 
side effects, it won't optimize them out.
>   You also totally missed the "int flags" argument you're supposed to 
> pass to object specifying allocation parameters,
There is no allocation here (both the C and the C++ code allocate on the 
stack.

Should you want to allocate from the heap, try this:

{
    spinlock_t::guard g(some_lock);
    auto_ptr<Foo> item(new (gfp_mask) Foo);   /* or pass a kmem_cache_t */
    item->do_something();
    item->do_something_else();
    return item.release();
}
 
contrast with

{
    Foo *item = 0;
    int r;

    spin_lock(&some_lock);
    item = kmalloc(sizeof(Foo), gfp_flags);
    if (!item) {
         item = PTR_ERR(ENOMEM);  
         goto out;
    }
    if ((r = foo_do_something(item))) {
        foo_destroy(item);
        kfree(item);
        item = PTR_ERR(-r);
        goto out;
    }
    if ((r = foo_do_something_else(item))) {
        foo_destroy(item);
        kfree(item);
        item = PTR_ERR(-r);
    }
out:
    spin_unlock(&some_lock);
    return item;
}

(oops, you wrote another version further on...)
> not to mention the fact that you just allocated 2 objects of unknown 
> size on the stack (which is limited to 4k).
So did the C code. I was just side-by-side comparisons of *equivalent* code.
>   AND there's the fact that the order of destruction of foo_guard, 
> item1, and item2 is implementation-defined and can't easily be relied 
> upon without adding massive amounts of excess braces:
It is well defined. guard ctor, item1 ctor, item2 ctor, item2 dtor, 
item1 dtor, guard dtor.

It is also well defined that if a constructor is executed for an 
automatic variable, so will its destructor. That makes the "guard" work 
so well with exceptions.
>
> {
>     spinlock_t::guard foo_guard(&foo_lock);
>     {
>         Foo item1;
>         {
>             Foo item2;
>         }
>     }
> }
>
Absolutely unneeded braces there.
> Also, your spinlock_t::guard chews up stack space that otherwise 
> wouldn't be used.  It would be much better to rewrite your above C 
> function like this:
>
> {
>     struct foo *item1, *item2;
>     int result;
>     spin_lock(&foo_lock);
>     
>     item1 = kmalloc(sizeof(*item1), GFP_KERNEL);
>     item2 = kmalloc(sizeof(*item2), GFP_KERNEL);
>     if (!item1 || !item2)
>         goto out;
>     
>     result = foo_init(item1, GFP_KERNEL);
>     if (result)
>         goto out;
>     
>     result = foo_init(item2, GFP_KERNEL);
>     if (result)
>         goto out;
>     
> out:
>     /* If alloc and init went ok, register them */
>     if (item1 && item2 && !result) {
>         result = register_foo_pair(item1, item2);
>     }
>     
>     /* If anything failed, free resources */
>     if (!item1 || !item2 || result) {
>         kfree(item1);
>         kfree(item2);
>     }
>     
>     spin_unlock(&foo_lock);
>     return result;
> }
>
>> 14 lines vs 3, one variable eliminated. How many potential security 
>> vulnerabilities? How much time freed to work on the algorithm/data 
>> structure, not on error handling?
>
> Yeah, sure, yours is 3 lines when you omit the following:
> (1)  Handling allocation flags like GFP_KERNEL
done
> (2)  Not allocating things on the stack
done
> (3)  Proper cleanup ordering
done, without lifting a finger
> (4)  Reference counting, garbage collection, or another way to 
> selectively free the allocated objects based on success or failure of 
> other code.
Reference counting is ridiculously to do in C++. I'll spare you the details.
>
> Those are all critical things that we want to force people to think 
> about; in many cases the exact ordering of operations _is_ important 
> and that needs to be specified _and_ commented on.  How often do you 
> think people write comments talking about things that don't even 
> appear in the source code?
C++ preserves the order (unless it can prove the order doesn't matter, 
same as C)
>
> Also, since when is error handling _not_ a critical part of the 
> algorithm?  You can see in my more complicated example that you only 
> want to free the items if the registration was unsuccessful.  How do 
> you handle that without adding a refcount to everything (bloat) or 
> implementing garbage collection (worse bloat).
Use auto_ptr<>.

Yes, error handling is critical. That's why I want language help. Just 
like I don't want to:
- calculate the carry for 64 bit addition on a 32 bit machine
- calculate structure offsets for structs (even though struct layout is 
important)

I faced exactly these problems (fibre channel and ethernet cables pulled 
out during I/O) and C++ made error handling easier, not more difficult.

>
>>> Does that actually make it any easier to understand the code?  How 
>>> does it make it more obvious to be able to write a "+" operator that 
>>> allocates memory?
>>
>> Not all C++ features need to be used in the kernel. In fact, not all 
>> C++ features need to be used, period. Ever tried to understand code 
>> which uses overloaded operator,() (the comma operator)?
>
> The very fact that the language provides such features mean that 
> people would try to get code using them into the kernel.  Have you 
> ever looked at all the ugly debugging macros that various people use?  
> The C preprocessor provides few features at all, and yet people still 
> abuse those, I don't see why C++ would be any different.
Probably not. I agree C++ is much more abusable.

BTW, under C++ preprocessor abuse drops significantly as it can be 
replaced by safer and cleaner constructs.

-- 
Do not meddle in the internals of kernels, for they are subtle and quick to panic.


  reply	other threads:[~2006-04-25 16:46 UTC|newest]

Thread overview: 200+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-04-24 19:16 Compiling C++ modules Gary Poppitz
2006-04-24 19:27 ` Greg KH
2006-04-24 20:02   ` C++ pushback Gary Poppitz
2006-04-24 20:15     ` Christoph Hellwig
2006-04-24 20:16     ` Greg KH
2006-04-24 20:18     ` Martin Mares
2006-04-24 21:36       ` Jeff V. Merkey
2006-04-24 21:28         ` J.A. Magallon
2006-04-24 21:43           ` Harald Arnesen
2006-04-24 21:52         ` Alan Cox
2006-04-24 22:16           ` J.A. Magallon
2006-04-25  0:05             ` Harald Arnesen
2006-04-25  0:46               ` Diego Calleja
2006-04-25  9:12                 ` Harald Arnesen
2006-04-25  1:30             ` linux-os (Dick Johnson)
2006-04-25  2:58               ` marty fouts
2006-04-27 22:55               ` Bill Davidsen
2006-05-02 15:58                 ` Randy.Dunlap
2006-05-02 20:36                 ` David Schwartz
2006-04-25  8:15             ` Xavier Bestel
2006-04-25  8:42               ` Avi Kivity
2006-04-25  8:52                 ` Martin Mares
2006-04-25  9:00                   ` Avi Kivity
2006-04-25  9:05                     ` Martin Mares
2006-04-25  9:13                       ` Avi Kivity
2006-04-25  9:22                         ` Xavier Bestel
2006-04-25 20:20                           ` J.A. Magallon
2006-04-25 20:31                             ` Barry Kelly
2006-04-25  9:09             ` Nikita Danilov
2006-04-25 20:10               ` J.A. Magallon
2006-04-25 18:02             ` Geert Uytterhoeven
2006-04-27  9:09             ` Alexander E. Patrakov
2006-04-24 22:39           ` Willy Tarreau
2006-04-24 22:57           ` Jeff V. Merkey
2006-04-24 23:02       ` David Schwartz
2006-04-25  8:55         ` Martin Mares
2006-04-25  8:59           ` Jan Engelhardt
2006-04-25 14:37           ` David Schwartz
2006-04-25 19:50             ` Martin Mares
2006-04-26  2:33               ` David Schwartz
2006-04-26  3:42                 ` Matthew Frost
2006-04-26 19:25                   ` David Schwartz
2006-04-26 20:01                     ` Jan-Benedict Glaw
2006-04-26 20:09                       ` Linus Torvalds
2006-04-26 20:19                         ` Al Viro
2006-04-26 21:37                           ` Sam Ravnborg
2006-04-28  9:23                             ` Avi Kivity
2006-04-28 12:00                               ` linux-os (Dick Johnson)
2006-04-28 12:46                                 ` Jan-Benedict Glaw
2006-04-26 20:25                         ` Jan-Benedict Glaw
2006-04-26 20:43                         ` David Schwartz
2006-04-26 23:00                         ` Roman Kononov
2006-04-27  0:38                           ` Kyle Moffett
2006-04-27  2:05                             ` Roman Kononov
2006-04-27  3:37                               ` Kyle Moffett
2006-04-27  5:37                                 ` Roman Kononov
2006-04-27 13:58                                   ` Michael Buesch
2006-04-27 14:22                                     ` linux-os (Dick Johnson)
2006-04-27  8:07                                 ` Avi Kivity
2006-04-27 13:55                                   ` Denis Vlasenko
2006-04-27 14:27                                     ` Avi Kivity
2006-04-27 14:56                                       ` Denis Vlasenko
2006-04-27 15:54                                         ` Bob Copeland
2006-04-27 16:03                                         ` Avi Kivity
2006-04-27 15:00                                       ` Martin Mares
2006-04-27 15:31                                         ` Avi Kivity
2006-04-27 15:38                                           ` Martin Mares
2006-04-28  8:16                                             ` Avi Kivity
2006-04-28  8:30                                               ` Avi Kivity
2006-04-28 15:47                                               ` Jan Engelhardt
2006-04-28 15:51                                       ` Jan Engelhardt
2006-04-28 16:51                                         ` Avi Kivity
2006-04-27 14:50                                 ` Sam Ravnborg
2006-04-27  8:50                               ` Martin Mares
2006-04-27  3:57                           ` Willy Tarreau
2006-04-27  5:53                             ` Roman Kononov
2006-04-27  7:55                           ` Jan-Benedict Glaw
2006-04-27 17:20                           ` C++ pushback (when does this religious thread end?) Leonard Peterson
2006-04-30 17:48                           ` C++ pushback Jan Harkes
2006-04-30 20:55                             ` David Schwartz
2006-04-26 20:05                     ` linux-os (Dick Johnson)
2006-04-26 20:09                     ` Xavier Bestel
2006-04-26 20:44                       ` Randy.Dunlap
2006-05-02 20:09                         ` C++ pushback + sparse Randy.Dunlap
2006-04-27  7:49                       ` C++ pushback Jiri Kosina
2006-04-26 21:05                     ` Martin Mares
2006-04-25  7:33       ` Avi Kivity
2006-04-25  7:47         ` Nick Piggin
2006-05-13 16:21         ` Esben Nielsen
2006-04-24 20:36     ` Thiago Galesi
2006-04-24 21:38     ` Kurt Wall
2006-04-27 16:17     ` Roman Kononov
2006-04-27 21:59       ` Grant Coady
2006-04-27 22:09     ` Bill Davidsen
2006-04-27 23:19       ` Jan Knutar
2006-04-24 19:30 ` Compiling C++ modules Al Viro
2006-04-24 19:40 ` linux-os (Dick Johnson)
2006-04-24 20:54   ` Geert Uytterhoeven
2006-04-24 19:42 ` Alexey Dobriyan
2006-04-24 20:30 ` Daniel Barkalow
2006-04-24 20:35 ` C++ is in US [Re: Compiling C++ modules] Jiri Slaby
2006-04-24 20:45 ` Compiling C++ modules Alan Cox
2006-04-24 21:03   ` Avi Kivity
2006-04-24 21:23     ` Joshua Hudson
2006-04-24 21:29     ` Kyle Moffett
2006-04-24 21:50       ` marty fouts
2006-04-24 22:09         ` Martin Mares
2006-04-24 22:30           ` Willy Tarreau
2006-04-24 22:32           ` Joshua Hudson
2006-04-24 22:45           ` marty fouts
2006-04-25 15:32         ` Michael Buesch
2006-04-25  7:08       ` Avi Kivity
2006-04-25 10:23         ` James Courtier-Dutton
2006-04-25 15:59         ` Kyle Moffett
2006-04-25 16:46           ` Avi Kivity [this message]
2006-04-25 17:10             ` Dmitry Torokhov
2006-04-25 17:19               ` Avi Kivity
2006-04-25 17:28                 ` Dmitry Torokhov
2006-04-25 17:53                   ` Avi Kivity
2006-04-25 18:04                     ` Dmitry Torokhov
2006-04-25 18:08                     ` Valdis.Kletnieks
2006-04-25 18:26                       ` Avi Kivity
2006-04-25 18:38                         ` Avi Kivity
2006-04-25 18:52                           ` Michael Poole
2006-04-25 19:13                             ` Avi Kivity
2006-04-27 15:10                     ` Denis Vlasenko
2006-04-27 20:15                       ` Willy Tarreau
2006-04-27 21:08                         ` Davi Arnaut
2006-04-28  9:33                           ` Avi Kivity
2006-04-28 10:03                             ` Avi Kivity
2006-04-28 11:27                               ` Sergei Organov
2006-04-28 11:03                             ` Martin Mares
2006-04-28 11:30                               ` Avi Kivity
2006-04-28 15:56                                 ` Jan Engelhardt
2006-04-28 17:02                                   ` Avi Kivity
2006-04-28 17:38                                     ` linux-os (Dick Johnson)
2006-04-29  2:50                                       ` Christer Weinigel
2006-05-01 17:46                                       ` Dave Neuer
2006-05-01 20:21                                         ` Jan Engelhardt
2006-05-01 23:53                                         ` David Schwartz
2006-05-02  5:12                                           ` Willy Tarreau
2006-05-02 10:32                                             ` Avi Kivity
2006-05-02 11:15                                               ` Martin Mares
2006-05-02 11:26                                                 ` Avi Kivity
2006-05-02 11:40                                                   ` linux-os (Dick Johnson)
2006-05-02 12:42                                                   ` David Woodhouse
2006-05-02 16:27                                                     ` Christer Weinigel
2006-05-02 12:48                                                   ` Martin Mares
2006-05-02 13:52                                                     ` Avi Kivity
2006-05-02 14:13                                                       ` Al Viro
2006-05-02 14:54                                                         ` Avi Kivity
2006-05-02 16:16                                                   ` Brian Beattie
2006-05-02 16:21                                                     ` Avi Kivity
2006-05-02 13:21                                               ` Willy Tarreau
2006-05-02 14:41                                                 ` Avi Kivity
2006-05-02 22:25                                                   ` Diego Calleja
2006-05-02 13:34                                               ` Al Viro
2006-05-02 14:02                                                 ` Avi Kivity
2006-05-02 14:34                                                   ` Al Viro
2006-05-02 15:04                                                     ` Avi Kivity
2006-05-02 15:15                                                       ` Al Viro
2006-05-02 15:19                                                         ` Avi Kivity
2006-05-02 15:27                                                           ` Kyle Moffett
2006-05-02 15:30                                                             ` Avi Kivity
2006-05-02 15:28                                                           ` Al Viro
2006-05-02 15:51                                                             ` Avi Kivity
2006-05-02 15:24                                                         ` Kyle Moffett
2006-05-03 13:13                                           ` Mark Lord
2006-05-03 20:51                                             ` David Schwartz
2006-04-30 21:15                               ` Eric W. Biederman
2006-04-25 17:54                 ` linux-os (Dick Johnson)
2006-04-26  8:30                   ` Jan Engelhardt
2006-04-26 11:36                     ` linux-os (Dick Johnson)
2006-04-25 19:22             ` Kyle Moffett
2006-04-25 19:54               ` Michael Buesch
2006-04-25 20:24               ` Avi Kivity
2006-04-25 20:11             ` Bongani Hlope
2006-04-25 20:26               ` Avi Kivity
2006-04-25 21:02                 ` Valdis.Kletnieks
2006-04-25 21:15                   ` Avi Kivity
     [not found]                     ` <71a0d6ff0604251646g4fc90b3dr30a03b8606360e7f@mail.gmail.com>
2006-04-26  4:39                       ` Avi Kivity
2006-04-25 17:55           ` Geert Uytterhoeven
2006-04-24 21:58     ` Alan Cox
2006-04-25  7:20       ` Avi Kivity
2006-04-25  9:06         ` Matt Keenan
2006-04-25 20:29           ` Bongani Hlope
2006-04-25 20:37             ` Avi Kivity
2006-04-25 21:08               ` Bongani Hlope
2006-04-25  4:17     ` Martin J. Bligh
2006-04-25  5:30       ` Avi Kivity
2006-04-25  8:58         ` Sam Ravnborg
2006-04-25  7:56     ` Jakob Oestergaard
2006-04-25  9:03     ` Jan Engelhardt
2006-04-24 21:36   ` J.A. Magallon
     [not found] <65eLE-GJ-21@gated-at.bofh.it>
     [not found] ` <65zwH-61W-51@gated-at.bofh.it>
     [not found]   ` <65zZH-6Bw-23@gated-at.bofh.it>
     [not found]     ` <66grR-2DK-27@gated-at.bofh.it>
2006-04-28  0:03       ` Robert Hancock
  -- strict thread matches above, loose matches on Subject: below --
2006-04-28  9:37 Khushil Dep
2006-05-02 18:21 Al Boldi
2006-05-02 20:28 ` J.A. Magallon
2006-05-02 23:55 ` Peter Williams
2006-05-03  8:09 ` Steven Rostedt

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=444E524A.10906@argo.co.il \
    --to=avi@argo.co.il \
    --cc=alan@lxorguk.ukuu.org.uk \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mrmacman_g4@mac.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox