1/*
2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25package sun.java2d;
26
27import java.lang.ref.Reference;
28
29/**
30* This ReentrantContextProvider implementation uses a ThreadLocal to hold
31 * the first ReentrantContext per thread and a ReentrantContextProviderCLQ to
32 * store child ReentrantContext instances needed during recursion.
33 *
34 * Note: this implementation may keep up to one context in memory per thread.
35 * Child contexts for recursive uses are stored in the queue using a WEAK
36 * reference by default unless specified in the 2 argument constructor.
37 *
38 * @param <K> ReentrantContext subclass
39 */
40public abstract class ReentrantContextProviderTL<K extends ReentrantContext>
41    extends ReentrantContextProvider<K>
42{
43    // Thread-local storage:
44    private final ThreadLocal<Reference<K>> ctxTL
45        = new ThreadLocal<Reference<K>>();
46
47    // ReentrantContext CLQ provider for child contexts:
48    private final ReentrantContextProviderCLQ<K> ctxProviderCLQ;
49
50    /**
51     * Create a new ReentrantContext provider using the given reference type
52     * among hard, soft or weak.
53     * It uses weak reference for the child contexts.
54     *
55     * @param refType reference type
56     */
57    public ReentrantContextProviderTL(final int refType) {
58        this(refType, REF_WEAK);
59    }
60
61    /**
62     * Create a new ReentrantContext provider using the given reference types
63     * among hard, soft or weak
64     *
65     * @param refTypeTL reference type used by ThreadLocal
66     * @param refTypeCLQ reference type used by ReentrantContextProviderCLQ
67     */
68    public ReentrantContextProviderTL(final int refTypeTL, final int refTypeCLQ)
69    {
70        super(refTypeTL);
71
72        final ReentrantContextProviderTL<K> parent = this;
73
74        this.ctxProviderCLQ = new ReentrantContextProviderCLQ<K>(refTypeCLQ) {
75            @Override
76            protected K newContext() {
77                return parent.newContext();
78            }
79        };
80    }
81
82    /**
83     * Give a ReentrantContext instance for the current thread
84     *
85     * @return ReentrantContext instance
86     */
87    @Override
88    public final K acquire() {
89        K ctx = null;
90        final Reference<K> ref = ctxTL.get();
91        if (ref != null) {
92            ctx = ref.get();
93        }
94        if (ctx == null) {
95            // create a new ReentrantContext if none is available
96            ctx = newContext();
97            // update thread local reference:
98            ctxTL.set(getOrCreateReference(ctx));
99        }
100        // Check reentrance:
101        if (ctx.usage == USAGE_TL_INACTIVE) {
102           ctx.usage = USAGE_TL_IN_USE;
103        } else {
104            // get or create another ReentrantContext from CLQ provider:
105            ctx = ctxProviderCLQ.acquire();
106        }
107        return ctx;
108    }
109
110    /**
111     * Restore the given ReentrantContext instance for reuse
112     *
113     * @param ctx ReentrantContext instance
114     */
115    @Override
116    public final void release(final K ctx) {
117        if (ctx.usage == USAGE_TL_IN_USE) {
118           ctx.usage = USAGE_TL_INACTIVE;
119        } else {
120            ctxProviderCLQ.release(ctx);
121        }
122    }
123}
124