This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Solving mt_allocator's static initialization ordering problem


On Thu, May 06, 2004 at 12:11:14PM -0300, Brad Spencer wrote:
> I've been trying to the (trunk) mt_allocator within the gcc-3.4.0
> sources (in another email thread) for alignment reasons on SPARC, and
> so far, I haven't had problems there.  However, on i686-pc-linux-gnu,
> I've encountered problems with static initialization of the
> mt_allocator's _S_options structure.
> 
> For example, using gdb on the following small program will reveal that
> when _S_initialize() runs on line 12, _S_options' constructor appears
> to have not been run.  (I don't have a lot of luck setting breakpoints
> on such things, so I am not 100% positive.)
> 
>   #include <memory>
>   
>   std::allocator<int *> alloc;
>   struct init
>   {
>     init()
>     {
>       // Here, alloc._S_options is not initialized, so the constructor
>       // makes a broken allocator.
>       alloc.allocate(1);
>     }
>   
>   } ini;
>   
>   int
>   main()
>   {
>     std::allocator<void *> alloc2;
>   
>     // Here, this _S_options is initialized.
>     alloc2.allocate(1);
>     
>     return 0;
>   }

I finally got back to this issue, and started using the head of the
gcc-3.4-branch, which includes the latest mt_allocator changes.  The
problem was still happening, but I managed to prove to myself that it
was static initialization order.  The nub of the problem is that _Tune
is a class, so its members can't have values before
__static_initialization_and_destruction_0() runs.  It looks like this
happens too late:

Breakpoint 2, init (this=0x2ea81) at foo.cc:10
10          alloc.allocate(1);
(gdb) p __gnu_cxx::__mt_alloc<int*>::_S_options
$2 = {
  _M_align = 0, 
  _M_max_bytes = 0, 
  _M_min_bin = 0, 
  _M_chunk_size = 0, 
  _M_max_threads = 0, 
  _M_freelist_headroom = 0, 
  _M_force_new = false
}

I tried applying __attribute__((init_priority (101))) in several
places, but those that the compiler accepted seemed to have no
effect.  The assembly for __static_initialization_and_destruction_0()
still showed init::init() running before _Tune::Tune().

All I could come up with was this hack of looking to see if
_S_options is still uninitialized in _S_initialize(), and if so,
running an in-place construction to use the default values.
It's ugly, but it does work.  Is it safe?

I didn't go any further with change because I hit upon a couple of
questions that I couldn't answer:

 1. When exactly are are you allowed to call _S_set_options() and what
    exactly will it do?  It would seem you have to be after the static
    initialization of _S_options, but before the first allocation.
    Tricky.  

 2. Is there a cleaner way to do the same thing without reworking how
    the tunable parameters are set?  Perhaps things could be changed so
    _S_options is _only_ initialized by this lazy init?  This
    probably depends on the answer to question 1.

-- 
------------------------------------------------------------------
Brad Spencer - spencer@infointeractive.com - "It's quite nice..."
Systems Architect | InfoInterActive Corp. | A Canadian AOL Company

Attachment: gcc-3.4.1-mt_allocator-lazy-initialization.patch
Description: Text document


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]