1/* 2 * Copyright (c) 2011, 2017, 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 */ 25 26package sun.lwawt.macosx; 27 28import java.util.concurrent.locks.Lock; 29import java.util.concurrent.locks.ReadWriteLock; 30import java.util.concurrent.locks.ReentrantReadWriteLock; 31 32/** 33 * Safely holds and disposes of native AppKit resources, using the 34 * correct AppKit threading and Objective-C GC semantics. 35 */ 36public class CFRetainedResource { 37 private static native void nativeCFRelease(final long ptr, final boolean disposeOnAppKitThread); 38 39 private final boolean disposeOnAppKitThread; 40 // TODO this pointer should be private and accessed via CFNativeAction class 41 protected volatile long ptr; 42 43 private final ReadWriteLock lock = new ReentrantReadWriteLock(); 44 private final Lock writeLock = lock.writeLock(); 45 private final Lock readLock = lock.readLock(); 46 47 /** 48 * @param ptr CFRetained native object pointer 49 * @param disposeOnAppKitThread is the object needs to be CFReleased on the main thread 50 */ 51 protected CFRetainedResource(final long ptr, final boolean disposeOnAppKitThread) { 52 this.disposeOnAppKitThread = disposeOnAppKitThread; 53 this.ptr = ptr; 54 } 55 56 /** 57 * CFReleases previous resource and assigns new pre-retained resource. 58 * @param ptr CFRetained native object pointer 59 */ 60 protected void setPtr(final long ptr) { 61 writeLock.lock(); 62 try { 63 if (this.ptr != 0) { 64 dispose(); 65 } 66 this.ptr = ptr; 67 } finally { 68 writeLock.unlock(); 69 } 70 } 71 72 /** 73 * Manually CFReleases the native resource. 74 */ 75 protected void dispose() { 76 long oldPtr = 0L; 77 writeLock.lock(); 78 try { 79 if (ptr == 0) { 80 return; 81 } 82 oldPtr = ptr; 83 ptr = 0; 84 } finally { 85 writeLock.unlock(); 86 } 87 88 nativeCFRelease(oldPtr, disposeOnAppKitThread); // perform outside of the synchronized block 89 } 90 91 /** 92 * The interface which allows to execute some native operations with 93 * assumption that the native pointer will be valid till the end. 94 */ 95 public interface CFNativeAction { 96 97 /** 98 * The native operation should be called from this method. 99 * 100 * @param ptr the pointer to the native data 101 */ 102 void run(long ptr); 103 } 104 105 /** 106 * The interface which allows to execute some native operations and get a 107 * result with assumption that the native pointer will be valid till the 108 * end. 109 */ 110 interface CFNativeActionGet { 111 112 /** 113 * The native operation should be called from this method. 114 * 115 * @param ptr the pointer to the native data 116 * @return result of the native operation 117 */ 118 long run(long ptr); 119 } 120 121 /** 122 * This is utility method which should be used instead of the direct access 123 * to the {@link #ptr}, because this method guaranteed that the pointer will 124 * not be zero and will be valid till the end of the operation.It is highly 125 * recomended to not use any external lock in action. If the current 126 * {@link #ptr} is {@code 0} then action will be ignored. 127 * 128 * @param action The native operation 129 */ 130 public final void execute(final CFNativeAction action) { 131 readLock.lock(); 132 try { 133 if (ptr != 0) { 134 action.run(ptr); 135 } 136 } finally { 137 readLock.unlock(); 138 } 139 } 140 141 /** 142 * This is utility method which should be used instead of the direct access 143 * to the {@link #ptr}, because this method guaranteed that the pointer will 144 * not be zero and will be valid till the end of the operation. It is highly 145 * recomended to not use any external lock in action. If the current 146 * {@link #ptr} is {@code 0} then action will be ignored and {@code} is 147 * returned. 148 * 149 * @param action the native operation 150 * @return result of the native operation, usually the native pointer to 151 * some other data 152 */ 153 final long executeGet(final CFNativeActionGet action) { 154 readLock.lock(); 155 try { 156 if (ptr != 0) { 157 return action.run(ptr); 158 } 159 } finally { 160 readLock.unlock(); 161 } 162 return 0; 163 } 164 165 @Override 166 @SuppressWarnings("deprecation") 167 protected final void finalize() throws Throwable { 168 dispose(); 169 } 170} 171