blob: bacaa59f85f9e29aaff9aa066faceb4d6fa48178 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2000-2007 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.nio.ch;
27
28import java.lang.ref.SoftReference;
29import java.lang.reflect.*;
30import java.io.IOException;
31import java.nio.ByteBuffer;
32import java.nio.MappedByteBuffer;
33import java.nio.channels.*;
34import java.nio.channels.spi.*;
35import java.security.AccessController;
36import java.security.PrivilegedAction;
37import java.util.*;
38import sun.misc.Unsafe;
39import sun.misc.Cleaner;
40import sun.security.action.GetPropertyAction;
41
42
43class Util {
44
45
46 // -- Caches --
47
48 // The number of temp buffers in our pool
49 private static final int TEMP_BUF_POOL_SIZE = 3;
50
51 // Per-thread soft cache of the last temporary direct buffer
52 private static ThreadLocal[] bufferPool;
53
54 static {
55 bufferPool = new ThreadLocal[TEMP_BUF_POOL_SIZE];
56 for (int i=0; i<TEMP_BUF_POOL_SIZE; i++)
57 bufferPool[i] = new ThreadLocal();
58 }
59
60 static ByteBuffer getTemporaryDirectBuffer(int size) {
61 ByteBuffer buf = null;
62 // Grab a buffer if available
63 for (int i=0; i<TEMP_BUF_POOL_SIZE; i++) {
64 SoftReference ref = (SoftReference)(bufferPool[i].get());
65 if ((ref != null) && ((buf = (ByteBuffer)ref.get()) != null) &&
66 (buf.capacity() >= size)) {
67 buf.rewind();
68 buf.limit(size);
69 bufferPool[i].set(null);
70 return buf;
71 }
72 }
73
74 // Make a new one
75 return ByteBuffer.allocateDirect(size);
76 }
77
78 static void releaseTemporaryDirectBuffer(ByteBuffer buf) {
79 if (buf == null)
80 return;
81 // Put it in an empty slot if such exists
82 for (int i=0; i<TEMP_BUF_POOL_SIZE; i++) {
83 SoftReference ref = (SoftReference)(bufferPool[i].get());
84 if ((ref == null) || (ref.get() == null)) {
85 bufferPool[i].set(new SoftReference(buf));
86 return;
87 }
88 }
89 // Otherwise replace a smaller one in the cache if such exists
90 for (int i=0; i<TEMP_BUF_POOL_SIZE; i++) {
91 SoftReference ref = (SoftReference)(bufferPool[i].get());
92 ByteBuffer inCacheBuf = (ByteBuffer)ref.get();
93 if ((inCacheBuf == null) || (buf.capacity() > inCacheBuf.capacity())) {
94 bufferPool[i].set(new SoftReference(buf));
95 return;
96 }
97 }
98 }
99
100 private static class SelectorWrapper {
101 private Selector sel;
102 private SelectorWrapper (Selector sel) {
103 this.sel = sel;
104 Cleaner.create(this, new Closer(sel));
105 }
106 private static class Closer implements Runnable {
107 private Selector sel;
108 private Closer (Selector sel) {
109 this.sel = sel;
110 }
111 public void run () {
112 try {
113 sel.close();
114 } catch (Throwable th) {
115 throw new Error(th);
116 }
117 }
118 }
119 public Selector get() { return sel;}
120 }
121
122 // Per-thread cached selector
123 private static ThreadLocal localSelector = new ThreadLocal();
124 // Hold a reference to the selWrapper object to prevent it from
125 // being cleaned when the temporary selector wrapped is on lease.
126 private static ThreadLocal localSelectorWrapper = new ThreadLocal();
127
128 // When finished, invoker must ensure that selector is empty
129 // by cancelling any related keys and explicitly releasing
130 // the selector by invoking releaseTemporarySelector()
131 static Selector getTemporarySelector(SelectableChannel sc)
132 throws IOException
133 {
134 SoftReference ref = (SoftReference)localSelector.get();
135 SelectorWrapper selWrapper = null;
136 Selector sel = null;
137 if (ref == null
138 || ((selWrapper = (SelectorWrapper) ref.get()) == null)
139 || ((sel = selWrapper.get()) == null)
140 || (sel.provider() != sc.provider())) {
141 sel = sc.provider().openSelector();
142 localSelector.set(new SoftReference(new SelectorWrapper(sel)));
143 } else {
144 localSelectorWrapper.set(selWrapper);
145 }
146 return sel;
147 }
148
149 static void releaseTemporarySelector(Selector sel)
150 throws IOException
151 {
152 // Selector should be empty
153 sel.selectNow(); // Flush cancelled keys
154 assert sel.keys().isEmpty() : "Temporary selector not empty";
155 localSelectorWrapper.set(null);
156 }
157
158
159 // -- Random stuff --
160
161 static ByteBuffer[] subsequence(ByteBuffer[] bs, int offset, int length) {
162 if ((offset == 0) && (length == bs.length))
163 return bs;
164 int n = length;
165 ByteBuffer[] bs2 = new ByteBuffer[n];
166 for (int i = 0; i < n; i++)
167 bs2[i] = bs[offset + i];
168 return bs2;
169 }
170
171 static <E> Set<E> ungrowableSet(final Set<E> s) {
172 return new Set<E>() {
173
174 public int size() { return s.size(); }
175 public boolean isEmpty() { return s.isEmpty(); }
176 public boolean contains(Object o) { return s.contains(o); }
177 public Object[] toArray() { return s.toArray(); }
178 public <T> T[] toArray(T[] a) { return s.toArray(a); }
179 public String toString() { return s.toString(); }
180 public Iterator<E> iterator() { return s.iterator(); }
181 public boolean equals(Object o) { return s.equals(o); }
182 public int hashCode() { return s.hashCode(); }
183 public void clear() { s.clear(); }
184 public boolean remove(Object o) { return s.remove(o); }
185
186 public boolean containsAll(Collection<?> coll) {
187 return s.containsAll(coll);
188 }
189 public boolean removeAll(Collection<?> coll) {
190 return s.removeAll(coll);
191 }
192 public boolean retainAll(Collection<?> coll) {
193 return s.retainAll(coll);
194 }
195
196 public boolean add(E o){
197 throw new UnsupportedOperationException();
198 }
199 public boolean addAll(Collection<? extends E> coll) {
200 throw new UnsupportedOperationException();
201 }
202
203 };
204 }
205
206
207 // -- Unsafe access --
208
209 private static Unsafe unsafe = Unsafe.getUnsafe();
210
211 private static byte _get(long a) {
212 return unsafe.getByte(a);
213 }
214
215 private static void _put(long a, byte b) {
216 unsafe.putByte(a, b);
217 }
218
219 static void erase(ByteBuffer bb) {
220 unsafe.setMemory(((DirectBuffer)bb).address(), bb.capacity(), (byte)0);
221 }
222
223 static Unsafe unsafe() {
224 return unsafe;
225 }
226
227 private static int pageSize = -1;
228
229 static int pageSize() {
230 if (pageSize == -1)
231 pageSize = unsafe().pageSize();
232 return pageSize;
233 }
234
235 private static volatile Constructor directByteBufferConstructor = null;
236
237 private static void initDBBConstructor() {
238 AccessController.doPrivileged(new PrivilegedAction() {
239 public Object run() {
240 try {
241 Class cl = Class.forName("java.nio.DirectByteBuffer");
242 Constructor ctor = cl.getDeclaredConstructor(
243 new Class[] { int.class,
244 long.class,
245 Runnable.class });
246 ctor.setAccessible(true);
247 directByteBufferConstructor = ctor;
248 } catch (ClassNotFoundException x) {
249 throw new InternalError();
250 } catch (NoSuchMethodException x) {
251 throw new InternalError();
252 } catch (IllegalArgumentException x) {
253 throw new InternalError();
254 } catch (ClassCastException x) {
255 throw new InternalError();
256 }
257 return null;
258 }});
259 }
260
261 static MappedByteBuffer newMappedByteBuffer(int size, long addr,
262 Runnable unmapper)
263 {
264 MappedByteBuffer dbb;
265 if (directByteBufferConstructor == null)
266 initDBBConstructor();
267 try {
268 dbb = (MappedByteBuffer)directByteBufferConstructor.newInstance(
269 new Object[] { new Integer(size),
270 new Long(addr),
271 unmapper });
272 } catch (InstantiationException e) {
273 throw new InternalError();
274 } catch (IllegalAccessException e) {
275 throw new InternalError();
276 } catch (InvocationTargetException e) {
277 throw new InternalError();
278 }
279 return dbb;
280 }
281
282 private static volatile Constructor directByteBufferRConstructor = null;
283
284 private static void initDBBRConstructor() {
285 AccessController.doPrivileged(new PrivilegedAction() {
286 public Object run() {
287 try {
288 Class cl = Class.forName("java.nio.DirectByteBufferR");
289 Constructor ctor = cl.getDeclaredConstructor(
290 new Class[] { int.class,
291 long.class,
292 Runnable.class });
293 ctor.setAccessible(true);
294 directByteBufferRConstructor = ctor;
295 } catch (ClassNotFoundException x) {
296 throw new InternalError();
297 } catch (NoSuchMethodException x) {
298 throw new InternalError();
299 } catch (IllegalArgumentException x) {
300 throw new InternalError();
301 } catch (ClassCastException x) {
302 throw new InternalError();
303 }
304 return null;
305 }});
306 }
307
308 static MappedByteBuffer newMappedByteBufferR(int size, long addr,
309 Runnable unmapper)
310 {
311 MappedByteBuffer dbb;
312 if (directByteBufferRConstructor == null)
313 initDBBRConstructor();
314 try {
315 dbb = (MappedByteBuffer)directByteBufferRConstructor.newInstance(
316 new Object[] { new Integer(size),
317 new Long(addr),
318 unmapper });
319 } catch (InstantiationException e) {
320 throw new InternalError();
321 } catch (IllegalAccessException e) {
322 throw new InternalError();
323 } catch (InvocationTargetException e) {
324 throw new InternalError();
325 }
326 return dbb;
327 }
328
329
330 // -- Bug compatibility --
331
332 private static volatile String bugLevel = null;
333
334 static boolean atBugLevel(String bl) { // package-private
335 if (bugLevel == null) {
336 if (!sun.misc.VM.isBooted())
337 return false;
338 String value = AccessController.doPrivileged(
339 new GetPropertyAction("sun.nio.ch.bugLevel"));
340 bugLevel = (value != null) ? value : "";
341 }
342 return bugLevel.equals(bl);
343 }
344
345
346
347 // -- Initialization --
348
349 private static boolean loaded = false;
350
351 static void load() {
352 synchronized (Util.class) {
353 if (loaded)
354 return;
355 loaded = true;
356 java.security.AccessController
357 .doPrivileged(new sun.security.action.LoadLibraryAction("net"));
358 java.security.AccessController
359 .doPrivileged(new sun.security.action.LoadLibraryAction("nio"));
360 // IOUtil must be initialized; Its native methods are called from
361 // other places in native nio code so they must be set up.
362 IOUtil.initIDs();
363 }
364 }
365
366}