User: Password:
|
|
Subscribe / Log in / New account

C11 atomic variables and the kernel

C11 atomic variables and the kernel

Posted Feb 20, 2014 8:06 UTC (Thu) by mm7323 (subscriber, #87386)
In reply to: C11 atomic variables and the kernel by wahern
Parent article: C11 atomic variables and the kernel

Not sure if c++ has alloca(), but this looks neater to me:

#define xstrerror(error) strerror_r((error), alloca(256), 256)


(Log in to post comments)

C11 atomic variables and the kernel

Posted Feb 20, 2014 13:29 UTC (Thu) by jzbiciak (subscriber, #5246) [Link]

Well, technically, neither C nor C++ has alloca(), although it's a common extension. Or did C11 add this?

C11 atomic variables and the kernel

Posted Feb 27, 2014 8:02 UTC (Thu) by kevinm (guest, #69913) [Link]

Calling alloca() from a function argument is historically a very iffy thing to do - there were implementations where this crashed and burned very badly (alloca ended up fudging the stack pointer in the middle of the code pushing arguments onto the stack).

C11 atomic variables and the kernel

Posted Feb 27, 2014 8:52 UTC (Thu) by jzbiciak (subscriber, #5246) [Link]

Well, at least among the compiler folk I work with, they'd argue that alloca() is an ugly thing to do, full stop. ;-)

Given that our own compiler doesn't support alloca(), and tries to figure out the total stack frame for the entire function (so that no matter what happens, the SP moves once on entry, once on exit), I can't say I entirely blame them for that opinion. (Or, at least, that's what our compiler did the last time I dug into it at that level.)

Is it just me, or does alloca() mostly just feel like a hack to get around the lack of destructors or other unrolling mechanisms tied to leaving scopes?

C11 atomic variables and the kernel

Posted Feb 27, 2014 8:58 UTC (Thu) by Cyberax (✭ supporter ✭, #52523) [Link]

It also offers very fast allocation and deallocation of arbitrarily-sized arrays within a cache-local area. It's hard to beat that.

C11 atomic variables and the kernel

Posted Feb 27, 2014 17:15 UTC (Thu) by jzbiciak (subscriber, #5246) [Link]

True, but if you already have to limit yourself to a certain maximum size allocation to effectively use alloca(), then declaring a local array gets you that same locality benefit.

I also saw elsewhere a horror story where a function call w/alloca() got inlined and turned into a stack overflow, because apparently the compiler deferred the implicit freeing of the buffer to the end of the parent function. ie:

    void inlined_func(...)
    {
         ... 
         alloca( ... ); 
         ...
         /* implicit free() here */
    }

    void parent( ... )
    {
         for (i = 0; i < 10000000; i++)
             inlined_func();
    }

turned into:

    void parent( ... )
    {
         for (i = 0; i < 10000000; i++)
         {
             ...
             alloca( ... );
             ...
         }
         /* implicit free() here */
    }

Oops.

I've never had that happen with local arrays, though. When the compiler inlines a function with a local array, the result looks more like an array local to the parent that it got inlined within, so it statically becomes part of the stack frame while you're in the parent. That is, if you replace alloca() in the example above with char buf[MAXBUF];:

    void parent( ... )
    {
         for (i = 0; i < 10000000; i++)
         {
             char buf[MAXBUF]; /* becomes a static part of the stack frame */
             ...
             ...
         }
    }

Sure, statically sized buffers have their own issues—buffer overflow attacks—but alloca() is no panacea if it can be used to overflow the stack and crash the app. I guess what I'm saying is that the set of places where alloca() provides an advantage over a statically sized buffer are limited because the places where it's safe to use either have so much overlap, while the places where only one or the other is appropriate are fairly small.

C11 atomic variables and the kernel

Posted Feb 27, 2014 18:00 UTC (Thu) by Cyberax (✭ supporter ✭, #52523) [Link]

Statically sized buffers are way too wasteful. For example, storing path would require MAXPATH of stackspace for all paths.

C11 atomic variables and the kernel

Posted Feb 28, 2014 5:58 UTC (Fri) by jzbiciak (subscriber, #5246) [Link]

And yet, if you do encounter a series of paths that are at or near MAXPATH bytes, you'd still end up wasting that space anyway with alloca(). If you're saying you can't handle so many MAXPATH pathnames, then you're broken if you use alloca(), since it doesn't offer a way to fail gracefully.

If you're manipulating many structures that have potential not to fit on the stack, another approach I've seen is to allocate a static buffer large enough to catch most common cases, and fall back to a malloc()'d buffer if you'd exceed that threshold. It does require a conditional call to free(), but it's more robust than alloca() and avoids the unconditional bloat of overlarge local arrays.

(And, with the explicit malloc() and free(), it won't run afoul of the inlining gotcha I highlighted above.)

C11 atomic variables and the kernel

Posted Feb 28, 2014 11:37 UTC (Fri) by khim (subscriber, #9252) [Link]

Yes, bugs in compilers exist and should be fixed. Just like any other types of bugs. We don't design our programs around old bugs in kernel or libc, why should we design them to support broken compilers?

The rest of discussion sounds so bizzare I can not even believe I hear it on LWN. ALL remaining arguments only make sense for address-space constrained system without overcommit.

On systems with overcommit enabled and with no shortage of the address space (and that's 99.99% of systems out there) alloca is as safe as malloc+free and much, much faster. End of discussion.

C11 atomic variables and the kernel

Posted Feb 28, 2014 15:56 UTC (Fri) by mathstuf (subscriber, #69389) [Link]

Don't you argue that mobile devices are eating other form factor's lunches? They're all 32-bit last I checked where address space is at a premium.

C11 atomic variables and the kernel

Posted Feb 28, 2014 17:01 UTC (Fri) by khim (subscriber, #9252) [Link]

Don't you argue that mobile devices are eating other form factor's lunches?

Well, sure.

They're all 32-bit last I checked where address space is at a premium.

It's good idea to check things more often than once per decade. Have you head about this phone? How about this CPU or that one?

And I don't see where you get the notion that 32-bit implies “address space is at a premium”: typical mobile OS does not use swap and keeps many applications in memory at the same time. Any given application can only use 128MB or so. You can easily give allocate 16MB or 32MB of address space for heavy worker threads - more then enough for alloca.

C11 atomic variables and the kernel

Posted Feb 28, 2014 17:34 UTC (Fri) by jzbiciak (subscriber, #5246) [Link]

On platforms that support it. Still, it's not portable, and doesn't seem to offer truly material advantages in my eyes.

One place I've run into alloca() was in some initialization code of g_doom, the "generic frame buffer" port of Doom. That's pretty much the last place to make a "hot cache efficiency" or any other time-based argument for alloca() over malloc(). It was there pretty much for the purpose of getting an automatic deallocation if it took an early exit from the function.

The system I was porting to, however, didn't (and still doesn't) support alloca(), so I had to convert it to malloc()/free(). (And when I asked our compiler guys about it, they said "Just use malloc()" with the sort of tone that implied they thought alloca() was an abomination.)

Yes, the code was marginally cleaner looking with alloca(), but my point was that that benefit arises from the fact that C doesn't offer any other easy way to say "clean all this up when we leave this scope" other than to put things on the stack and rely on the stack frame unwinding.

Aside from non-portability, alloca() also pretty much requires you to use a frame pointer, since your stack frame size is now variable. Again, not usually a big deal, although it can hurt on register-starved architectures like 32-bit x86. And then there's all these fun comments in alloca()'s own manual page:

BUGS
        The alloca() function is machine and compiler dependent.  On many sys-
        tems its implementation is buggy.  Its use is discouraged.

        On many systems alloca() cannot be used inside the list of arguments of
        a function call, because the stack space reserved by alloca() would
        appear on the stack in the middle of the space for the function argu-
        ments.

I get it, you like alloca(). I see enough things potentially wrong with it that its meager advantages don't seem worth it to me.

C11 atomic variables and the kernel

Posted Feb 28, 2014 18:06 UTC (Fri) by khim (subscriber, #9252) [Link]

I get it, you like alloca(). I see enough things potentially wrong with it that its meager advantages don't seem worth it to me.

I'm not a big alloca lover, but I just don't see what's the big hoopla is all about. I mean: alloca is just a minor syntaxic sugar on top of facilities you have anyway. Yes, it's not portable but it's an interface people are familiar with, so why not?

Before you'll raise the racket about frame pointers and stuff please recall that you compiler must compile, e.g. the following program (from 6.5.3.4 The sizeof oprator part of the C standard):

#include <stddef.h>

size_t fsize(int n)
{
  char b[n+3];
  return sizeof b;
}

It's a 100% standard program. It's included in standard. It's non-optional part of it. It must be supported.

Now on any system where it's supported alloca implementation is trivial, so why not just implement and use it where appropriate?

I'm yet to observe a system which supports the aforementioned program (from the official 15 years old standard - and included again in new C11 one, too!) which does not support working and usable alloca and if you insist on using broken tools you deserve to receive broken programs.

P.S. Note that function in standard is called fsize—this gives you pretty strong hint where and how such facilities are supposed to be used, right?


Copyright © 2018, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds