Hi Martin,

Thanks for the cheers!  :-)

I am incorporating your comments.
Thanks for spotting these issues!

best regards,

-- daniel

On 9/5/13 6:49 PM, Martin Buchholz wrote:
Random review comments:

Let me cheerlead your efforts to clean up j.u.logging.  It's not easy.
  Previous efforts (including by myself) have been incomplete because of
failure to fully understand the big picture.

I've thought that the right approach for write-mostly data structure
like in j.u.logging (and in e.g. classloading) is to have
mostly-immutable parts with volatile pointers that are updated using CAS.

You have some typos:
LogMnager
initalization
initializationCalled

+     *
+     **/

=>

       */



On Thu, Sep 5, 2013 at 7:43 AM, Daniel Fuchs <daniel.fu...@oracle.com
<mailto:daniel.fu...@oracle.com>> wrote:

    Hi,

    Here is the new patch. It uses an additional volatile flag
    to avoid synchronizing once the log manager is fully initialized.
    I have added some comments to spell out the purpose of the flags,
    as well as some assertion that should make it clear what is expected,
    what is possible, and what is not.

    I have also implemented the other remarks from David, Peter, and Mandy.

    <http://cr.openjdk.java.net/~__dfuchs/webrev_8023168/webrev.__01/
    <http://cr.openjdk.java.net/~dfuchs/webrev_8023168/webrev.01/>>

    Testing is still under way - but the results so far are looking good.
    I also ran the JCK for api/java_util - nothing jumped at my face.

    I have modified my NetBeans configuration to run NetBeans 7.3 over
    my private build - and I'm not seeing any troubles either so far.

    (I had done that with the previous patch too)

    best regards,

    -- daniel



    On 9/5/13 2:43 PM, Daniel Fuchs wrote:

        On 9/5/13 1:51 PM, Peter Levart wrote:

                Threads that call ensureLogManagerInitialized() after
                that will find
                the flag
                is true before entering the synchronized block and will
                return directly.


            ...and such threads can see rootLogger field being either
            still null or
            not null but the Logger instance that is obtained via such
            data race can
            be half-initialized.


        I don't think so, because the flag isn't set to true until
        the initialization is finished.

        BTW - there was a reason for having both an initializationCalled
        *and* a synchronized at method level. The purpose of
        initializationCalled flag was to prevent infinite recursion in the
        same thread - because addLogger within ensureLogManagerInitialized
        will trigger a new call to ensureLogManagerInitialized that the
        synchronized won't block - since it's in the same thread.

        So I need in fact two flags: one initializationDone - which will
        be volatile - the other initializationCalled - which doesn't need
        to be since it will be always written/read from within the
        synchronized block.

        I toyed with the idea of using a single volatile three valued byte
        instead:

        initialization: 0 => uninitialized, 1 => initializing, 2 =>
        initialized

        I opted for the two booleans - but the three valued byte might
        be more
        efficient:

        1)

        volatile byte initialization = 0;

        ensureLogManagerInitialized() {
            if (initialization == 2) return; // already done
            synchronized(this) {
              if (initialization > 0) return;
              initialization = 1; // avoids recursion
              try {
                // do stuff which might recurse on
                // ensureLogManagerInitialized()
              } finally {
                initialization = 2; // mark as done
              }
            }
        }

        vs 2)

        volatile boolean initializationDone = false;
        boolean initializationCalled = false;

        ensureLogManagerInitialized() {
            if (initializationDone) return; // already done
            synchronized(this) {
              if (initializedCalled || initializationDone) return;
              initializedCalled = true; // avoids recursion
              try {
                // do stuff which might recurse on
                // ensureLogManagerInitialized()
              } finally {
                  initializationDone = true; // mark as done.
              }
            }
        }

        Don't know if you have a preference for one or the other.
        My current impl (still under test) is 2)

        best regards,

        -- daniel


                I can make rootLogger volatile. I'm not 100% sure it is
                required - but
                I think
                it is more correct, and as such it will make the code
                more maintainable.
                Good point. It's probably  something I would have
                overlooked.



            I think volatile rootLogger field is required for correct
            publication of
            RootLogger instances if double-checked locking is used...


            Regards, Peter





Reply via email to