Linux Kernel Device Driver With C and C++

Discussion in 'C Programming' started by deech, Nov 2, 2012.

  1. deech

    deech Guest

    Hi all,
    I hope this is the right place to ask this, but I want to write a device driver for Linux that offloads the main portion of the logic to a C++ file and `extern` the relevant pieces for inclusion in the main `C` file.

    I've successfully created a `hello world` executable but I don't know how to write the Makefile that will include the C++ library and compile it to a `.ko`. The simple tutorials don't seem to help.

    Any help is appreciated.
    -deech
     
    deech, Nov 2, 2012
    #1
    1. Advertising

  2. deech

    Noob Guest

    Noob, Nov 2, 2012
    #2
    1. Advertising

  3. deech

    Angel Guest

    On 2012-11-02, deech <> wrote:
    > Hi all,
    > I hope this is the right place to ask this, but I want to write a device
    > driver for Linux that offloads the main portion of the logic to a C++ file
    > and `extern` the relevant pieces for inclusion in the main `C` file.
    >
    > I've successfully created a `hello world` executable but I don't know how
    > to write the Makefile that will include the C++ library and compile it to
    > a `.ko`. The simple tutorials don't seem to help.


    Try this site:
    http://kernelnewbies.org/

    Just a word of warning; Linux kernel development is done in C only and
    many there are pretty hostile to any suggestions that it should be done
    in C++. (I personally take no stance on the matter, whatever works for
    you is good enough.) Be prepared for some pretty harsh reactions.


    --
    "C provides a programmer with more than enough rope to hang himself.
    C++ provides a firing squad, blindfold and last cigarette."
    - seen in comp.lang.c
     
    Angel, Nov 2, 2012
    #3
  4. In article <>,
    Angel <> wrote:
    >
    >Try this site:
    >http://kernelnewbies.org/
    >
    >Just a word of warning; Linux kernel development is done in C only and
    >many there are pretty hostile to any suggestions that it should be done
    >in C++.


    Good advice. Be aware that kernel programming is a radically different
    environment from user-level programming. Most significantly, there is
    no libc so many of the system services you take for granted in your usual
    programming environment are not available. This will go double for C++,
    and frankly, I'd be surprised if you could make it work unless you're
    very very careful.

    --
    -Ed Falk,
    http://thespamdiaries.blogspot.com/
     
    Edward A. Falk, Nov 2, 2012
    #4
  5. On 02/11/2012 10:18, Angel wrote:
    > On 2012-11-02, deech <> wrote:
    >> Hi all,
    >> I hope this is the right place to ask this, but I want to write a device
    >> driver for Linux that offloads the main portion of the logic to a C++ file
    >> and `extern` the relevant pieces for inclusion in the main `C` file.
    >>
    >> I've successfully created a `hello world` executable but I don't know how
    >> to write the Makefile that will include the C++ library and compile it to
    >> a `.ko`. The simple tutorials don't seem to help.

    >
    > Try this site:
    > http://kernelnewbies.org/
    >
    > Just a word of warning; Linux kernel development is done in C only and
    > many there are pretty hostile to any suggestions that it should be done
    > in C++. (I personally take no stance on the matter, whatever works for
    > you is good enough.) Be prepared for some pretty harsh reactions.
    >
    >


    As a Xen hypervisor and Linux kernel developer myself, I offer this rule
    of thumb. Only stuff which absolutely must be in the kernel should be
    in the kernel. Everything else should be in userspace.

    On a technical note, your chances of getting C++ working at all as a
    kernel module is virtually 0. You certainly wont be able to do
    exceptions or RTTI, and I cant offhand think of a way you would
    implement even the simple things like global constructors/destructors.
    On top of that, you will not have any libraries, and good luck using the
    kernel internal headers with C++ (given all of the C-only syntax they use).

    Dare I ask what your device driver is attempting to do?

    ~Andrew
     
    Andrew Cooper, Nov 2, 2012
    #5
  6. deech

    James Kuyper Guest

    On 11/02/2012 06:05 PM, Andrew Cooper wrote:
    > On a technical note, your chances of getting C++ working at all as a
    > kernel module is virtually 0. You certainly wont be able to do
    > exceptions or RTTI, and I cant offhand think of a way you would
    > implement even the simple things like global constructors/destructors.
    > On top of that, you will not have any libraries, and good luck using the
    > kernel internal headers with C++ (given all of the C-only syntax they use).


    Ordinarily, I'd expect that if I used a C++ compiler essential as if it
    were C compiler - using only features that C++ shares with C, and using
    them only in ways that have the same meaning in C as in C++, and making
    appropriate use of extern "C" - that it shouldn't be a problem.
    However, your comment about "C-only syntax" would suggest otherwise.
    What specific types of syntax are you referring to? Are these C90
    features that were dropped in C99, such as implicit int, or C99 features
    which have not yet been added to C++, such as restrict, or C features
    that were never supported in C++, but which few sane C programmers have
    voluntarily used for at least a decade, such as non-prototyped function
    declarations, or something else?

    When I think of how C++ differs from C, ctors and dtors are an important
    part of it, but I also think about member functions, inheritance,
    (single and multiple), function overloading, operator overloads,
    template classes. template functions, member access restrictions,
    virtual members, and virtual inheritance. Do any of these features cause
    problems for kernal programming? Most of these features can be emulated
    in C code; which is in fact how the earliest C++ compilers were
    implemented, which is why I'd be surprised if they were problematic. If
    they are, would the corresponding C code be equally problematic?
     
    James Kuyper, Nov 2, 2012
    #6
  7. deech

    Ian Collins Guest

    On 11/03/12 11:45, James Kuyper wrote:
    > On 11/02/2012 06:05 PM, Andrew Cooper wrote:
    >> On a technical note, your chances of getting C++ working at all as a
    >> kernel module is virtually 0. You certainly wont be able to do
    >> exceptions or RTTI, and I cant offhand think of a way you would
    >> implement even the simple things like global constructors/destructors.
    >> On top of that, you will not have any libraries, and good luck using the
    >> kernel internal headers with C++ (given all of the C-only syntax they use).

    >
    > Ordinarily, I'd expect that if I used a C++ compiler essential as if it
    > were C compiler - using only features that C++ shares with C, and using
    > them only in ways that have the same meaning in C as in C++, and making
    > appropriate use of extern "C" - that it shouldn't be a problem.
    > However, your comment about "C-only syntax" would suggest otherwise.
    > What specific types of syntax are you referring to? Are these C90
    > features that were dropped in C99, such as implicit int, or C99 features
    > which have not yet been added to C++, such as restrict, or C features
    > that were never supported in C++, but which few sane C programmers have
    > voluntarily used for at least a decade, such as non-prototyped function
    > declarations, or something else?
    >
    > When I think of how C++ differs from C, ctors and dtors are an important
    > part of it, but I also think about member functions, inheritance,
    > (single and multiple), function overloading, operator overloads,
    > template classes. template functions, member access restrictions,
    > virtual members, and virtual inheritance. Do any of these features cause
    > problems for kernal programming? Most of these features can be emulated
    > in C code; which is in fact how the earliest C++ compilers were
    > implemented, which is why I'd be surprised if they were problematic. If
    > they are, would the corresponding C code be equally problematic?


    I can't speak for Linux modules, but in the BSD/Solaris world your
    observations are correct. As long as the C++ code does not require
    runtime library support, it is fine to use in kernel land. If you do
    accidentally use a feature that does require runtime library support,
    your code won't load and you soon realise the error of your ways. Been
    there and done that!

    In BSD/Solaris drivers, there are per-driver and per-instance interfaces
    and variables that map well to static and non-static class members.

    --
    Ian Collins
     
    Ian Collins, Nov 2, 2012
    #7
  8. deech

    Lew Pitcher Guest

    On Friday 02 November 2012 00:07, in comp.lang.c,
    wrote:

    Sorry clc, but this thread has gone on long enough


    > Hi all,
    > I hope this is the right place to ask this,


    No. It isn't.

    > but I want to write a device
    > driver for Linux that offloads the main portion of the logic to a C++ file
    > and `extern` the relevant pieces for inclusion in the main `C` file.


    Not a good idea. You might want to read the Linux-kernel Mailinglist faq,
    especially question 15.3 (http://www.tux.org/lkml/#s15-3)

    > I've successfully created a `hello world` executable but I don't know how
    > to write the Makefile that will include the C++ library and compile it to
    > a `.ko`. The simple tutorials don't seem to help.


    There are no tutorials because it is discouraged (read "forbidden by the
    lead kernel developers).

    The basic point is that, for various reasons (good or bad), the Linux kernel
    developers do not want, and do not support, kernel development using C++ in
    any form. If, as you say in a later post, you intend to code your C++
    in 'extern "C" ' format, there is no reason to avoid coding your kernel
    development directly in C /instead of/ C++.

    OTOH, if you intend to use /even one/ feature of C++ that is not supported
    directly in C, then you are out of luck. And, name-mangling counts as a
    feature.

    HTH
    --
    Lew Pitcher
    "In Skills, We Trust"
     
    Lew Pitcher, Nov 2, 2012
    #8
  9. deech

    Melzzzzz Guest

    On Sat, 03 Nov 2012 12:13:24 +1300
    Ian Collins <> wrote:

    >
    > I can't speak for Linux modules, but in the BSD/Solaris world your
    > observations are correct.


    Linus is hostile toward C++ , so they would not accept
    any driver written in C++ ;)
    For home use I think there is no problem to write driver
    in any language, even modify kernel to support rtti
    and exceptions ;)


    --
    drwxr-xr-x 2 bmaxa bmaxa 4096 Oct 31 23:14 .
     
    Melzzzzz, Nov 2, 2012
    #9
  10. deech

    Ian Collins Guest

    On 11/03/12 12:39, Lew Pitcher wrote:
    > On Friday 02 November 2012 00:07, in comp.lang.c,
    > wrote:
    >
    > Sorry clc, but this thread has gone on long enough
    >
    >
    >> Hi all,
    >> I hope this is the right place to ask this,

    >
    > No. It isn't.
    >
    >> but I want to write a device
    >> driver for Linux that offloads the main portion of the logic to a C++ file
    >> and `extern` the relevant pieces for inclusion in the main `C` file.

    >
    > Not a good idea. You might want to read the Linux-kernel Mailinglist faq,
    > especially question 15.3 (http://www.tux.org/lkml/#s15-3)
    >
    >> I've successfully created a `hello world` executable but I don't know how
    >> to write the Makefile that will include the C++ library and compile it to
    >> a `.ko`. The simple tutorials don't seem to help.

    >
    > There are no tutorials because it is discouraged (read "forbidden by the
    > lead kernel developers).
    >
    > The basic point is that, for various reasons (good or bad), the Linux kernel
    > developers do not want, and do not support, kernel development using C++ in
    > any form. If, as you say in a later post, you intend to code your C++
    > in 'extern "C" ' format, there is no reason to avoid coding your kernel
    > development directly in C /instead of/ C++.


    That does not make sense. In C++, extern "C" is merely a means to
    provide linkage compatibility with C. It does not influence what goes
    on inside a function or module.

    > OTOH, if you intend to use /even one/ feature of C++ that is not supported
    > directly in C, then you are out of luck. And, name-mangling counts as a
    > feature.


    Name mangling is a consequence of C++ features, not a feature. If all
    the public interfaces of a module are declared extern "C", what goes on
    inside is irrelevant.

    --
    Ian Collins
     
    Ian Collins, Nov 2, 2012
    #10
  11. On 02/11/2012 22:45, James Kuyper wrote:
    > On 11/02/2012 06:05 PM, Andrew Cooper wrote:
    >> On a technical note, your chances of getting C++ working at all as a
    >> kernel module is virtually 0. You certainly wont be able to do
    >> exceptions or RTTI, and I cant offhand think of a way you would
    >> implement even the simple things like global constructors/destructors.
    >> On top of that, you will not have any libraries, and good luck using the
    >> kernel internal headers with C++ (given all of the C-only syntax they use).

    >
    > Ordinarily, I'd expect that if I used a C++ compiler essential as if it
    > were C compiler - using only features that C++ shares with C, and using
    > them only in ways that have the same meaning in C as in C++, and making
    > appropriate use of extern "C" - that it shouldn't be a problem.
    > However, your comment about "C-only syntax" would suggest otherwise.
    > What specific types of syntax are you referring to? Are these C90
    > features that were dropped in C99, such as implicit int, or C99 features
    > which have not yet been added to C++, such as restrict, or C features
    > that were never supported in C++, but which few sane C programmers have
    > voluntarily used for at least a decade, such as non-prototyped function
    > declarations, or something else?


    I was thinking of C99 struct initializer syntax which is invalid in C++,
    although thinking about it, I am failing to think of any Linux examples
    offhand. (The Xen headers are full of useful macros, such as the
    spinlock ones, which wrap this functionality.)

    However, the Linux headers certainly do have variables called 'new' in
    prototypes and structure declarations, which are sure to spoil the day
    of any well meaning C++ compiler.

    >
    > When I think of how C++ differs from C, ctors and dtors are an important
    > part of it, but I also think about member functions, inheritance,
    > (single and multiple), function overloading, operator overloads,
    > template classes. template functions, member access restrictions,
    > virtual members, and virtual inheritance. Do any of these features cause
    > problems for kernal programming? Most of these features can be emulated
    > in C code; which is in fact how the earliest C++ compilers were
    > implemented, which is why I'd be surprised if they were problematic. If
    > they are, would the corresponding C code be equally problematic?
    >


    Local static variables and global ctors and dtors require runtime
    support, and the usual trick for c/dtors of trying to play section magic
    to make this happen would require you to roll your own linked kernel
    module rather than using the regular Kbuild system.

    Local c/dtors are fine, as are most of the of the other language
    features you list from a "it will compile" standpoint (other than
    needing a symbol to link against for pure virtual calls)

    A lot of these feature can be emulated in C code, and one could argue
    that certain design patterns in the kernel are moving closer towards a
    C++ way of thinking, most notably the PVOPS code looks very much like
    virtual inheritance.


    There are issues which arise from the C++ mentality. In code where
    brevity and cache alignment is key for performance, the concept of
    private member variables is unhelpful. The concept of inheritance tends
    to lump some X along with something Y which is half-similar, but this is
    not a data pattern commonly encountered. I am struggling to think of a
    single situation where operator overloading would be useful, or indeed
    clear in its context, given the typical data us.

    And from a technical viewpoint, templates are fantastically bad for
    compiled code and data size, typically making N identical or almost
    identical copies of each different instantiation. Constructing objects
    in C++ is far more work than making a new stuct in C, especially if
    there is any inheritance involved. Optimising C++ is harder than
    optimising C; The compiler, in general, cannot inline even the most
    simple one-line virtual function call.


    So overall, (other than the inclusion problem), excluding the C++
    features which require runtime support, you can get a working solution.
    However, because of the differences between C and C++, there is a large
    difference between working and working well.

    Don't get me wrong - there are times and places for both C and C++ and I
    use both frequently, but in my opinion, a kernel is not a place for C++.

    ~Andrew
     
    Andrew Cooper, Nov 3, 2012
    #11
  12. deech

    Jorgen Grahn Guest

    On Fri, 2012-11-02, Edward A. Falk wrote:
    > In article <>,
    > Angel <> wrote:
    >>
    >>Try this site:
    >>http://kernelnewbies.org/
    >>
    >>Just a word of warning; Linux kernel development is done in C only and
    >>many there are pretty hostile to any suggestions that it should be done
    >>in C++.

    >
    > Good advice. Be aware that kernel programming is a radically different
    > environment from user-level programming. Most significantly, there is
    > no libc so many of the system services you take for granted in your usual
    > programming environment are not available.


    That part is not so bad IME. Most of the relevant parts are there. The
    irrelevant ones are not, of course; there is no normal file I/O
    because there is no normal file system, and so on.

    /Jorgen

    --
    // Jorgen Grahn <grahn@ Oo o. . .
    \X/ snipabacken.se> O o .
     
    Jorgen Grahn, Nov 3, 2012
    #12
  13. deech

    Jorgen Grahn Guest

    On Sat, 2012-11-03, Andrew Cooper wrote:

    [C++ in Linux kernel code]

    > There are issues which arise from the C++ mentality.

    [...]

    There are different C++ mentalities. You seem to be thinking of
    heavy-handed object-oriented programming, but that's not the only way
    to use the language.

    /Jorgen

    --
    // Jorgen Grahn <grahn@ Oo o. . .
    \X/ snipabacken.se> O o .
     
    Jorgen Grahn, Nov 3, 2012
    #13
  14. deech

    James Kuyper Guest

    On 11/02/2012 10:34 PM, Andrew Cooper wrote:
    > On 02/11/2012 22:45, James Kuyper wrote:

    ....
    >> Ordinarily, I'd expect that if I used a C++ compiler essential as if it
    >> were C compiler - using only features that C++ shares with C, and using
    >> them only in ways that have the same meaning in C as in C++, and making
    >> appropriate use of extern "C" - that it shouldn't be a problem.
    >> However, your comment about "C-only syntax" would suggest otherwise.
    >> What specific types of syntax are you referring to? Are these C90
    >> features that were dropped in C99, such as implicit int, or C99 features
    >> which have not yet been added to C++, such as restrict, or C features
    >> that were never supported in C++, but which few sane C programmers have
    >> voluntarily used for at least a decade, such as non-prototyped function
    >> declarations, or something else?

    ....
    > However, the Linux headers certainly do have variables called 'new' in
    > prototypes and structure declarations, which are sure to spoil the day
    > of any well meaning C++ compiler.


    Yes, use of C++ reserved identifiers would certainly be a problem.

    >> When I think of how C++ differs from C, ctors and dtors are an important
    >> part of it, but I also think about member functions, inheritance,
    >> (single and multiple), function overloading, operator overloads,
    >> template classes. template functions, member access restrictions,
    >> virtual members, and virtual inheritance. Do any of these features cause
    >> problems for kernal programming? Most of these features can be emulated
    >> in C code; which is in fact how the earliest C++ compilers were
    >> implemented, which is why I'd be surprised if they were problematic. If
    >> they are, would the corresponding C code be equally problematic?
    >>

    >
    > Local static variables and global ctors and dtors require runtime
    > support, ...



    I've never had to do any kernal programming, so I don't understand what
    the relevant restrictions are, or why they exist. What is problematic
    about local static variables? They're not specific to C++, so I assume
    that the following C code would also be problematic?:

    int save_val(int i)
    {
    static int saved;
    int retval = saved;
    saved = i;
    return retval;
    }

    > There are issues which arise from the C++ mentality. In code where
    > brevity and cache alignment is key for performance, the concept of
    > private member variables is unhelpful. The concept of inheritance tends
    > to lump some X along with something Y which is half-similar, but this is
    > not a data pattern commonly encountered. I am struggling to think of a
    > single situation where operator overloading would be useful, or indeed
    > clear in its context, given the typical data us.


    The built-in C types fall into a number of categories, based upon which
    operators work on them: arithmetic types, pointer types, array types,
    functions. Operator overloads work best when they make something that is
    of class type work like a member of one of those categories: extended
    numeric types such as quaternions or arrays, smart pointers, containers,
    or function objects. They only lead to confusion when used for other
    purposes. I don't imagine there's much need for extended arithmetic
    types in kernal programming. However, it seems to me that various kinds
    of smart pointers or containers could be useful, unless they can't be
    properly implemented. If there's any place where kernel code passes
    around function pointers, passing around function objects might be a
    reasonable alternative.

    > And from a technical viewpoint, templates are fantastically bad for
    > compiled code and data size, typically making N identical or almost
    > identical copies of each different instantiation.


    The point of having a template is that you have code that needs to be
    duplicated, depending upon the template's parameters. Properly used, you
    shouldn't be able to avoid the duplication by using C (or the C subset
    of C++). If there's code that wouldn't have to be duplicated if you were
    using C, then in C++ that code should be factored outside of the template.
    Of course, not everything that should be done, is done - I've seen that
    a lot in C, and now that I've working on a C++ project, I'm seeing the
    same thing in C++. But that's due to misuse of templates, not because of
    templates themselves.

    > ... Constructing objects
    > in C++ is far more work than making a new stuct in C, especially if
    > there is any inheritance involved.


    If you can construct an object in C without much work, you can write C++
    code that requires no more work than the C code to construct it; it
    will, in general, be the same (or almost the same) code. The only reason
    why C++ construction gets more complicated is if you want to make use of
    a C++ feature not supported by C, and if you're sane, you only do that
    if that feature provides some benefit that justifies the extra work. I
    don't see that as justifying an avoidance of C++.


    > Optimising C++ is harder than
    > optimising C; The compiler, in general, cannot inline even the most
    > simple one-line virtual function call.


    It's only meaningful to compare optimization of equivalent code. C
    doesn't support virtual function calls; the closest equivalent is C
    requires use of a function pointer. Can a typical C compiler do any
    better of a job inlining calls through function pointers than a C++
    compiler can do of inlining virtual function calls?
    --
    James Kuyper
     
    James Kuyper, Nov 3, 2012
    #14
  15. On 03/11/2012 13:33, James Kuyper wrote:
    >>
    >> Local static variables and global ctors and dtors require runtime
    >> support, ...

    >
    >
    > I've never had to do any kernal programming, so I don't understand what
    > the relevant restrictions are, or why they exist. What is problematic
    > about local static variables? They're not specific to C++, so I assume
    > that the following C code would also be problematic?:


    Sorry - let me be more clear. In an environment you completely control,
    adding 'runtime support' for global c/dtors and local static variables
    is quite easy (See http://wiki.osdev.org/C ). My issue, in this case,
    with them is that I cant think of a way of a Linux kernel module adding
    its own runtime support (other than bypassing the Kbuild system and
    attempting to link it up yourself)

    >
    > int save_val(int i)
    > {
    > static int saved;
    > int retval = saved;
    > saved = i;
    > return retval;
    > }


    There is a difference between how GCC and G++ treat static local
    variables. G++ generates extra code to put a mutex around it to prevent
    concurrent initialisation, and this is what requires the runtime
    support. (Admittedly this is only G++. Other C++ compilers wont, but
    best of luck to you trying to compile even the kernel header files

    >
    >> There are issues which arise from the C++ mentality. In code where
    >> brevity and cache alignment is key for performance, the concept of
    >> private member variables is unhelpful. The concept of inheritance tends
    >> to lump some X along with something Y which is half-similar, but this is
    >> not a data pattern commonly encountered. I am struggling to think of a
    >> single situation where operator overloading would be useful, or indeed
    >> clear in its context, given the typical data us.

    >
    > The built-in C types fall into a number of categories, based upon which
    > operators work on them: arithmetic types, pointer types, array types,
    > functions. Operator overloads work best when they make something that is
    > of class type work like a member of one of those categories: extended
    > numeric types such as quaternions or arrays, smart pointers, containers,
    > or function objects.


    And this is all perfectly reasonable in userspace, but not in kernel
    space. Floating point calculations are to be avoided at almost any
    cost, because they are not useful in the vast majority of cases, and
    incur extra overhead if the kernel needs to save/restore its own
    floating point state as well as that of the tasks it is scheduling.

    > ...They only lead to confusion when used for other
    > purposes. I don't imagine there's much need for extended arithmetic
    > types in kernal programming. However, it seems to me that various kinds
    > of smart pointers or containers could be useful, unless they can't be
    > properly implemented. If there's any place where kernel code passes
    > around function pointers, passing around function objects might be a
    > reasonable alternative.


    What form of smart pointers? I assume you mean shared_ptr. They are
    just a pointer and a reference count. In the C++ world, the refcount
    lives with the pointer, while in the kernel, objects needing refcounting
    have a ref count in them. The C world has better locality of data in
    the cache, while the C++ world also suffers from the same indirection
    problem as function pointer objects.

    Lets consider the difference between passing a function pointer in C
    (which fits in a register, or single word on the stack), with passing a
    C++ function pointer object. The C++ function pointer object is
    necessarily as large.

    How about calling this function pointer? In C, you would load it off
    the stack, or from ram, into a register, and 'call's the address in the
    register. In C++, you grab a pointer to the function pointer object,
    pass it to the operator() function for your object, which deferences the
    pointer, finds the function pointer member variable, loads this into a
    register and 'call's the address in the register.

    So yes - both of these will indeed work, but see the difference between
    working and working and working well. One of the worst things a kernel
    can do is needlessly follow pointers, as this takes more time, and leads
    to cache misses. The C way of doing things results in less memory
    overhead, (both in terms of code size and data size), involves fewer
    pointers to follow, and has better cache locality.

    >
    >> And from a technical viewpoint, templates are fantastically bad for
    >> compiled code and data size, typically making N identical or almost
    >> identical copies of each different instantiation.

    >
    > The point of having a template is that you have code that needs to be
    > duplicated, depending upon the template's parameters. Properly used, you
    > shouldn't be able to avoid the duplication by using C (or the C subset
    > of C++). If there's code that wouldn't have to be duplicated if you were
    > using C, then in C++ that code should be factored outside of the template.
    > Of course, not everything that should be done, is done - I've seen that
    > a lot in C, and now that I've working on a C++ project, I'm seeing the
    > same thing in C++. But that's due to misuse of templates, not because of
    > templates themselves.


    Agreed, subject to your statement of "Properly used". However, I cant
    think of a single case where templates would be useful.

    >
    >> ... Constructing objects
    >> in C++ is far more work than making a new stuct in C, especially if
    >> there is any inheritance involved.

    >
    > If you can construct an object in C without much work, you can write C++
    > code that requires no more work than the C code to construct it; it
    > will, in general, be the same (or almost the same) code. The only reason
    > why C++ construction gets more complicated is if you want to make use of
    > a C++ feature not supported by C, and if you're sane, you only do that
    > if that feature provides some benefit that justifies the extra work. I
    > don't see that as justifying an avoidance of C++.
    >
    >
    >> Optimising C++ is harder than
    >> optimising C; The compiler, in general, cannot inline even the most
    >> simple one-line virtual function call.

    >
    > It's only meaningful to compare optimization of equivalent code. C
    > doesn't support virtual function calls; the closest equivalent is C
    > requires use of a function pointer. Can a typical C compiler do any
    > better of a job inlining calls through function pointers than a C++
    > compiler can do of inlining virtual function calls?
    >


    Ok - fair points. As with templates, I cant think of a useful use case
    for compound objects. From a naive point of view, virtual functions via
    an interface design model could seem very attractive and useful in a
    kernel environment. However, a virtual function call is 2 pointers to
    follow rather than one, going back to the performance aspect.

    The point I was trying to get across is that C++ opens up a whole
    toolkit of new and shiny features which are not needed and when used
    with the best of intentions lead to poor performance. This alone is the
    biggest reason why I believe C++ should not be used.
     
    Andrew Cooper, Nov 3, 2012
    #15
  16. deech

    Öö Tiib Guest

    On Saturday, 3 November 2012 17:44:23 UTC+2, Andrew Cooper wrote:
    > On 03/11/2012 13:33, James Kuyper wrote:
    > > ...They only lead to confusion when used for other
    > > purposes. I don't imagine there's much need for extended arithmetic
    > > types in kernal programming. However, it seems to me that various kinds
    > > of smart pointers or containers could be useful, unless they can't be
    > > properly implemented. If there's any place where kernel code passes
    > > around function pointers, passing around function objects might be a
    > > reasonable alternative.

    >
    > What form of smart pointers? I assume you mean shared_ptr.


    I expect with "smart_pointer" mentioned that std::unique_ptr is used.
    It causes minimal overhead compared to raw pointer (one instruction per
    access) but adds lot of clarity and safety.

    > They are
    > just a pointer and a reference count. In the C++ world, the refcount
    > lives with the pointer, while in the kernel, objects needing refcounting
    > have a ref count in them. The C world has better locality of data in
    > the cache, while the C++ world also suffers from the same indirection
    > problem as function pointer objects.


    std::shared_ptr? It is truly heavyweight so one should not use it just like
    that for everything (like lot of noobs seem to do). It has separate dynamic
    object for containing weak_count, shared_count, deleter functor and raw
    pointer.

    You assign to it also some sins that you think it has but it does not have.
    Locality equal to C of that ref-counter object is gained by using
    std::make_shared that achieves that both objects are allocated adjacent
    in memory with a single malloc.

    > Lets consider the difference between passing a function pointer in C
    > (which fits in a register, or single word on the stack), with passing a
    > C++ function pointer object. The C++ function pointer object is
    > necessarily as large.


    "Function pointer object"??? You are confused here. Function object, usually
    passed by value. The function if it is simple is often inlined by optimizing
    compiler to point of usage and the optimization will cause efficiency
    gain. That is the reason why std::sort<>() usually outperforms qsort().

    In general, noobs needing tutorials should start with something simpler
    than writing drivers for OS kernels on any case, neither C nor C++ can
    help them enough there.
     
    Öö Tiib, Nov 3, 2012
    #16
  17. deech

    James Kuyper Guest

    On 11/03/2012 11:44 AM, Andrew Cooper wrote:
    > On 03/11/2012 13:33, James Kuyper wrote:

    ....
    >> The built-in C types fall into a number of categories, based upon which
    >> operators work on them: arithmetic types, pointer types, array types,
    >> functions. Operator overloads work best when they make something that is
    >> of class type work like a member of one of those categories: extended
    >> numeric types such as quaternions or arrays, smart pointers, containers,
    >> or function objects.

    ....
    >> ...They only lead to confusion when used for other
    >> purposes. I don't imagine there's much need for extended arithmetic
    >> types in kernal programming. However, it seems to me that various kinds
    >> of smart pointers or containers could be useful, unless they can't be
    >> properly implemented.

    ....
    > What form of smart pointers? I assume you mean shared_ptr.


    I meant smart pointers in general: any class type that uses operator
    overloads to emulate a pointer type, but with extra features added. Any
    feature that reduces the likelihood of dereferencing a pointer that
    cannot be safely dereferenced, or of producing a memory leak, has some
    potential value in user space programming, though it's always a matter o
    judgment whether the value is worth the associated cost. Is there no
    such feature that would be of any use in kernel programming?
    --
    James Kuyper
     
    James Kuyper, Nov 3, 2012
    #17
  18. deech

    Ian Collins Guest

    On 11/04/12 04:44, Andrew Cooper wrote:
    > On 03/11/2012 13:33, James Kuyper wrote:
    >>
    >> The built-in C types fall into a number of categories, based upon which
    >> operators work on them: arithmetic types, pointer types, array types,
    >> functions. Operator overloads work best when they make something that is
    >> of class type work like a member of one of those categories: extended
    >> numeric types such as quaternions or arrays, smart pointers, containers,
    >> or function objects.

    >
    > And this is all perfectly reasonable in userspace, but not in kernel
    > space. Floating point calculations are to be avoided at almost any
    > cost, because they are not useful in the vast majority of cases, and
    > incur extra overhead if the kernel needs to save/restore its own
    > floating point state as well as that of the tasks it is scheduling.
    >
    >> ...They only lead to confusion when used for other
    >> purposes. I don't imagine there's much need for extended arithmetic
    >> types in kernal programming. However, it seems to me that various kinds
    >> of smart pointers or containers could be useful, unless they can't be
    >> properly implemented. If there's any place where kernel code passes
    >> around function pointers, passing around function objects might be a
    >> reasonable alternative.

    >
    > What form of smart pointers? I assume you mean shared_ptr. They are
    > just a pointer and a reference count. In the C++ world, the refcount
    > lives with the pointer, while in the kernel, objects needing refcounting
    > have a ref count in them. The C world has better locality of data in
    > the cache, while the C++ world also suffers from the same indirection
    > problem as function pointer objects.


    In C++, you can choose how you associate the object pointer and the
    reference count, so there's no loss of efficiency there. There isn't
    any loss with access either (modulo any optional error checking).

    > Lets consider the difference between passing a function pointer in C
    > (which fits in a register, or single word on the stack), with passing a
    > C++ function pointer object. The C++ function pointer object is
    > necessarily as large.


    If the function pointer object isn't reference counted, it will be the
    same size as the equivalent raw pointer.

    > How about calling this function pointer? In C, you would load it off
    > the stack, or from ram, into a register, and 'call's the address in the
    > register. In C++, you grab a pointer to the function pointer object,
    > pass it to the operator() function for your object, which deferences the
    > pointer, finds the function pointer member variable, loads this into a
    > register and 'call's the address in the register.


    Er, no. Calling a function pointer compiles to the exact same code a
    calling a raw pointer, modulo any optional error checking. The caveat
    is important there, with a C++ smart pointer you can globally enable
    access checking without an awful lot of messy conditional compilations.

    > So yes - both of these will indeed work, but see the difference between
    > working and working and working well. One of the worst things a kernel
    > can do is needlessly follow pointers, as this takes more time, and leads
    > to cache misses. The C way of doing things results in less memory
    > overhead, (both in terms of code size and data size), involves fewer
    > pointers to follow, and has better cache locality.


    In practice, the two techniques have the same overhead.

    >> The point of having a template is that you have code that needs to be
    >> duplicated, depending upon the template's parameters. Properly used, you
    >> shouldn't be able to avoid the duplication by using C (or the C subset
    >> of C++). If there's code that wouldn't have to be duplicated if you were
    >> using C, then in C++ that code should be factored outside of the template.
    >> Of course, not everything that should be done, is done - I've seen that
    >> a lot in C, and now that I've working on a C++ project, I'm seeing the
    >> same thing in C++. But that's due to misuse of templates, not because of
    >> templates themselves.

    >
    > Agreed, subject to your statement of "Properly used". However, I cant
    > think of a single case where templates would be useful.


    The case we have just been discussing: resource management.

    > The point I was trying to get across is that C++ opens up a whole
    > toolkit of new and shiny features which are not needed and when used
    > with the best of intentions lead to poor performance. This alone is the
    > biggest reason why I believe C++ should not be used.


    Any more capable tool used incorrectly can cause you problems. Using
    that argument as the justification for not using it is poor reasoning.

    I've been countering the same FUD (usually be actually using C++ in
    those areas) for more than a decade now in the embedded/driver/kernel
    space and I'm amazed it's still being propagated.

    --
    Ian Collins
     
    Ian Collins, Nov 3, 2012
    #18
  19. Andrew Cooper <> writes:
    > On 03/11/2012 13:33, James Kuyper wrote:

    [...]
    >> int save_val(int i)
    >> {
    >> static int saved;
    >> int retval = saved;
    >> saved = i;
    >> return retval;
    >> }

    >
    > There is a difference between how GCC and G++ treat static local
    > variables. G++ generates extra code to put a mutex around it to prevent
    > concurrent initialisation, and this is what requires the runtime
    > support. (Admittedly this is only G++. Other C++ compilers wont, but
    > best of luck to you trying to compile even the kernel header files

    [...]

    I just compiled the above function with both gcc and g++ (version
    4.7.0). The generated code was identical apart from a few different
    identifiers.

    Is there some g++ option that tells it to create a mutex?

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Will write code for food.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Nov 3, 2012
    #19
  20. deech

    SG Guest

    Am 03.11.2012 21:22, schrieb Keith Thompson:
    > Andrew Cooper <> writes:
    >> On 03/11/2012 13:33, James Kuyper wrote:

    > [...]
    >>> int save_val(int i)
    >>> {
    >>> static int saved;
    >>> int retval = saved;
    >>> saved = i;
    >>> return retval;
    >>> }

    >>
    >> There is a difference between how GCC and G++ treat static local
    >> variables. G++ generates extra code to put a mutex around it to prevent
    >> concurrent initialisation, and this is what requires the runtime
    >> support. (Admittedly this is only G++. Other C++ compilers wont, but
    >> best of luck to you trying to compile even the kernel header files

    > [...]
    >
    > I just compiled the above function with both gcc and g++ (version
    > 4.7.0). The generated code was identical apart from a few different
    > identifiers.
    >
    > Is there some g++ option that tells it to create a mutex?


    It does not surprize me that the code is equal. There is no dynamic
    initialization of 'saved' going on. What C++11 guarantees is that a
    dynamic initialization is thread-safe. But C doesn't even allow this
    kind of dynamic initializations. What do I mean by "dynamic
    initialization"? Here's a C++ example:

    int reverse_increment_256(int j)
    {
    int bitmask = 128;
    while (bitmask) {
    j ^= bitmask;
    if ((j & bitmask)!=0) break;
    bitmask >>= 1;
    }
    return j;
    }

    const unsigned char* get_bit_reverse_256_table()
    {
    static const int* table = []()->unsigned char*{
    unsigned char* table = new int[256];
    for (int i=0, j=0; i<256; ++i) {
    table = j;
    j = reverse_increment(j);
    }
    return table;
    }();
    return table;
    }

    (untested)

    Here, the initializer of the static variable 'table' is dynamic in the
    sense that the function call has to be performed during runtime. C++11
    makes sure that this dynamic initialization is properly locked so that
    in case the table has not yet been computed and two threads invoke
    get_bit_reverse_256_table concurrently, the table is just computed once
    properly.

    I don't know whether G++ already supports that. Maybe you have to turn
    on this behaviour by using -std=c++0x or -std=c++11 .

    Cheers!
    SG
     
    SG, Nov 3, 2012
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. nbhalala

    Write Linux Device Driver

    nbhalala, Aug 7, 2004, in forum: C Programming
    Replies:
    2
    Views:
    391
    lxrocks
    Aug 10, 2004
  2. wilson
    Replies:
    3
    Views:
    978
    wilson
    Aug 10, 2004
  3. Pravin Shetty

    Question on Linux Device Driver ?

    Pravin Shetty, Jan 5, 2005, in forum: C Programming
    Replies:
    1
    Views:
    328
    Jack Klein
    Jan 5, 2005
  4. yogesh
    Replies:
    3
    Views:
    612
    Kenny McCormack
    Feb 12, 2006
  5. Concepts Systems
    Replies:
    0
    Views:
    289
    Concepts Systems
    Jul 1, 2008
Loading...

Share This Page