Home » openjdk-7 » sun » nio » ch » [javadoc | source]

    1   /*
    2    * Copyright (c) 2000, 2010, 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   
   26   package sun.nio.ch;
   27   
   28   import java.lang.ref.SoftReference;
   29   import java.lang.reflect;
   30   import java.io.IOException;
   31   import java.io.FileDescriptor;
   32   import java.nio.ByteBuffer;
   33   import java.nio.MappedByteBuffer;
   34   import java.nio.channels;
   35   import java.security.AccessController;
   36   import java.security.PrivilegedAction;
   37   import java.util;
   38   import sun.misc.Unsafe;
   39   import sun.misc.Cleaner;
   40   import sun.security.action.GetPropertyAction;
   41   
   42   
   43   class Util {
   44   
   45       // -- Caches --
   46   
   47       // The number of temp buffers in our pool
   48       private static final int TEMP_BUF_POOL_SIZE = 8;
   49   
   50       // Per-thread cache of temporary direct buffers
   51       private static ThreadLocal<BufferCache> bufferCache =
   52           new ThreadLocal<BufferCache>()
   53       {
   54           @Override
   55           protected BufferCache initialValue() {
   56               return new BufferCache();
   57           }
   58       };
   59   
   60       /**
   61        * A simple cache of direct buffers.
   62        */
   63       private static class BufferCache {
   64           // the array of buffers
   65           private ByteBuffer[] buffers;
   66   
   67           // the number of buffers in the cache
   68           private int count;
   69   
   70           // the index of the first valid buffer (undefined if count == 0)
   71           private int start;
   72   
   73           private int next(int i) {
   74               return (i + 1) % TEMP_BUF_POOL_SIZE;
   75           }
   76   
   77           BufferCache() {
   78               buffers = new ByteBuffer[TEMP_BUF_POOL_SIZE];
   79           }
   80   
   81           /**
   82            * Removes and returns a buffer from the cache of at least the given
   83            * size (or null if no suitable buffer is found).
   84            */
   85           ByteBuffer get(int size) {
   86               if (count == 0)
   87                   return null;  // cache is empty
   88   
   89               ByteBuffer[] buffers = this.buffers;
   90   
   91               // search for suitable buffer (often the first buffer will do)
   92               ByteBuffer buf = buffers[start];
   93               if (buf.capacity() < size) {
   94                   buf = null;
   95                   int i = start;
   96                   while ((i = next(i)) != start) {
   97                       ByteBuffer bb = buffers[i];
   98                       if (bb == null)
   99                           break;
  100                       if (bb.capacity() >= size) {
  101                           buf = bb;
  102                           break;
  103                       }
  104                   }
  105                   if (buf == null)
  106                       return null;
  107                   // move first element to here to avoid re-packing
  108                   buffers[i] = buffers[start];
  109               }
  110   
  111               // remove first element
  112               buffers[start] = null;
  113               start = next(start);
  114               count--;
  115   
  116               // prepare the buffer and return it
  117               buf.rewind();
  118               buf.limit(size);
  119               return buf;
  120           }
  121   
  122           boolean offerFirst(ByteBuffer buf) {
  123               if (count >= TEMP_BUF_POOL_SIZE) {
  124                   return false;
  125               } else {
  126                   start = (start + TEMP_BUF_POOL_SIZE - 1) % TEMP_BUF_POOL_SIZE;
  127                   buffers[start] = buf;
  128                   count++;
  129                   return true;
  130               }
  131           }
  132   
  133           boolean offerLast(ByteBuffer buf) {
  134               if (count >= TEMP_BUF_POOL_SIZE) {
  135                   return false;
  136               } else {
  137                   int next = (start + count) % TEMP_BUF_POOL_SIZE;
  138                   buffers[next] = buf;
  139                   count++;
  140                   return true;
  141               }
  142           }
  143   
  144           boolean isEmpty() {
  145               return count == 0;
  146           }
  147   
  148           ByteBuffer removeFirst() {
  149               assert count > 0;
  150               ByteBuffer buf = buffers[start];
  151               buffers[start] = null;
  152               start = next(start);
  153               count--;
  154               return buf;
  155           }
  156       }
  157   
  158       /**
  159        * Returns a temporary buffer of at least the given size
  160        */
  161       static ByteBuffer getTemporaryDirectBuffer(int size) {
  162           BufferCache cache = bufferCache.get();
  163           ByteBuffer buf = cache.get(size);
  164           if (buf != null) {
  165               return buf;
  166           } else {
  167               // No suitable buffer in the cache so we need to allocate a new
  168               // one. To avoid the cache growing then we remove the first
  169               // buffer from the cache and free it.
  170               if (!cache.isEmpty()) {
  171                   buf = cache.removeFirst();
  172                   free(buf);
  173               }
  174               return ByteBuffer.allocateDirect(size);
  175           }
  176       }
  177   
  178       /**
  179        * Releases a temporary buffer by returning to the cache or freeing it.
  180        */
  181       static void releaseTemporaryDirectBuffer(ByteBuffer buf) {
  182           offerFirstTemporaryDirectBuffer(buf);
  183       }
  184   
  185       /**
  186        * Releases a temporary buffer by returning to the cache or freeing it. If
  187        * returning to the cache then insert it at the start so that it is
  188        * likely to be returned by a subsequent call to getTemporaryDirectBuffer.
  189        */
  190       static void offerFirstTemporaryDirectBuffer(ByteBuffer buf) {
  191           assert buf != null;
  192           BufferCache cache = bufferCache.get();
  193           if (!cache.offerFirst(buf)) {
  194               // cache is full
  195               free(buf);
  196           }
  197       }
  198   
  199       /**
  200        * Releases a temporary buffer by returning to the cache or freeing it. If
  201        * returning to the cache then insert it at the end. This makes it
  202        * suitable for scatter/gather operations where the buffers are returned to
  203        * cache in same order that they were obtained.
  204        */
  205       static void offerLastTemporaryDirectBuffer(ByteBuffer buf) {
  206           assert buf != null;
  207           BufferCache cache = bufferCache.get();
  208           if (!cache.offerLast(buf)) {
  209               // cache is full
  210               free(buf);
  211           }
  212       }
  213   
  214       /**
  215        * Frees the memory for the given direct buffer
  216        */
  217       private static void free(ByteBuffer buf) {
  218           ((DirectBuffer)buf).cleaner().clean();
  219       }
  220   
  221       private static class SelectorWrapper {
  222           private Selector sel;
  223           private SelectorWrapper (Selector sel) {
  224               this.sel = sel;
  225               Cleaner.create(this, new Closer(sel));
  226           }
  227           private static class Closer implements Runnable {
  228               private Selector sel;
  229               private Closer (Selector sel) {
  230                   this.sel = sel;
  231               }
  232               public void run () {
  233                   try {
  234                       sel.close();
  235                   } catch (Throwable th) {
  236                       throw new Error(th);
  237                   }
  238               }
  239           }
  240           public Selector get() { return sel;}
  241       }
  242   
  243       // Per-thread cached selector
  244       private static ThreadLocal<SoftReference<SelectorWrapper>> localSelector
  245           = new ThreadLocal<SoftReference<SelectorWrapper>>();
  246       // Hold a reference to the selWrapper object to prevent it from
  247       // being cleaned when the temporary selector wrapped is on lease.
  248       private static ThreadLocal<SelectorWrapper> localSelectorWrapper
  249           = new ThreadLocal<SelectorWrapper>();
  250   
  251       // When finished, invoker must ensure that selector is empty
  252       // by cancelling any related keys and explicitly releasing
  253       // the selector by invoking releaseTemporarySelector()
  254       static Selector getTemporarySelector(SelectableChannel sc)
  255           throws IOException
  256       {
  257           SoftReference<SelectorWrapper> ref = localSelector.get();
  258           SelectorWrapper selWrapper = null;
  259           Selector sel = null;
  260           if (ref == null
  261               || ((selWrapper = ref.get()) == null)
  262               || ((sel = selWrapper.get()) == null)
  263               || (sel.provider() != sc.provider())) {
  264               sel = sc.provider().openSelector();
  265               selWrapper = new SelectorWrapper(sel);
  266               localSelector.set(new SoftReference<SelectorWrapper>(selWrapper));
  267           }
  268           localSelectorWrapper.set(selWrapper);
  269           return sel;
  270       }
  271   
  272       static void releaseTemporarySelector(Selector sel)
  273           throws IOException
  274       {
  275           // Selector should be empty
  276           sel.selectNow();                // Flush cancelled keys
  277           assert sel.keys().isEmpty() : "Temporary selector not empty";
  278           localSelectorWrapper.set(null);
  279       }
  280   
  281   
  282       // -- Random stuff --
  283   
  284       static ByteBuffer[] subsequence(ByteBuffer[] bs, int offset, int length) {
  285           if ((offset == 0) && (length == bs.length))
  286               return bs;
  287           int n = length;
  288           ByteBuffer[] bs2 = new ByteBuffer[n];
  289           for (int i = 0; i < n; i++)
  290               bs2[i] = bs[offset + i];
  291           return bs2;
  292       }
  293   
  294       static <E> Set<E> ungrowableSet(final Set<E> s) {
  295           return new Set<E>() {
  296   
  297                   public int size()                 { return s.size(); }
  298                   public boolean isEmpty()          { return s.isEmpty(); }
  299                   public boolean contains(Object o) { return s.contains(o); }
  300                   public Object[] toArray()         { return s.toArray(); }
  301                   public <T> T[] toArray(T[] a)     { return s.toArray(a); }
  302                   public String toString()          { return s.toString(); }
  303                   public Iterator<E> iterator()     { return s.iterator(); }
  304                   public boolean equals(Object o)   { return s.equals(o); }
  305                   public int hashCode()             { return s.hashCode(); }
  306                   public void clear()               { s.clear(); }
  307                   public boolean remove(Object o)   { return s.remove(o); }
  308   
  309                   public boolean containsAll(Collection<?> coll) {
  310                       return s.containsAll(coll);
  311                   }
  312                   public boolean removeAll(Collection<?> coll) {
  313                       return s.removeAll(coll);
  314                   }
  315                   public boolean retainAll(Collection<?> coll) {
  316                       return s.retainAll(coll);
  317                   }
  318   
  319                   public boolean add(E o){
  320                       throw new UnsupportedOperationException();
  321                   }
  322                   public boolean addAll(Collection<? extends E> coll) {
  323                       throw new UnsupportedOperationException();
  324                   }
  325   
  326           };
  327       }
  328   
  329   
  330       // -- Unsafe access --
  331   
  332       private static Unsafe unsafe = Unsafe.getUnsafe();
  333   
  334       private static byte _get(long a) {
  335           return unsafe.getByte(a);
  336       }
  337   
  338       private static void _put(long a, byte b) {
  339           unsafe.putByte(a, b);
  340       }
  341   
  342       static void erase(ByteBuffer bb) {
  343           unsafe.setMemory(((DirectBuffer)bb).address(), bb.capacity(), (byte)0);
  344       }
  345   
  346       static Unsafe unsafe() {
  347           return unsafe;
  348       }
  349   
  350       private static int pageSize = -1;
  351   
  352       static int pageSize() {
  353           if (pageSize == -1)
  354               pageSize = unsafe().pageSize();
  355           return pageSize;
  356       }
  357   
  358       private static volatile Constructor directByteBufferConstructor = null;
  359   
  360       private static void initDBBConstructor() {
  361           AccessController.doPrivileged(new PrivilegedAction<Void>() {
  362                   public Void run() {
  363                       try {
  364                           Class<?> cl = Class.forName("java.nio.DirectByteBuffer");
  365                           Constructor ctor = cl.getDeclaredConstructor(
  366                               new Class[] { int.class,
  367                                             long.class,
  368                                             FileDescriptor.class,
  369                                             Runnable.class });
  370                           ctor.setAccessible(true);
  371                           directByteBufferConstructor = ctor;
  372                       } catch (ClassNotFoundException x) {
  373                           throw new InternalError();
  374                       } catch (NoSuchMethodException x) {
  375                           throw new InternalError();
  376                       } catch (IllegalArgumentException x) {
  377                           throw new InternalError();
  378                       } catch (ClassCastException x) {
  379                           throw new InternalError();
  380                       }
  381                       return null;
  382                   }});
  383       }
  384   
  385       static MappedByteBuffer newMappedByteBuffer(int size, long addr,
  386                                                   FileDescriptor fd,
  387                                                   Runnable unmapper)
  388       {
  389           MappedByteBuffer dbb;
  390           if (directByteBufferConstructor == null)
  391               initDBBConstructor();
  392           try {
  393               dbb = (MappedByteBuffer)directByteBufferConstructor.newInstance(
  394                 new Object[] { new Integer(size),
  395                                new Long(addr),
  396                                fd,
  397                                unmapper });
  398           } catch (InstantiationException e) {
  399               throw new InternalError();
  400           } catch (IllegalAccessException e) {
  401               throw new InternalError();
  402           } catch (InvocationTargetException e) {
  403               throw new InternalError();
  404           }
  405           return dbb;
  406       }
  407   
  408       private static volatile Constructor directByteBufferRConstructor = null;
  409   
  410       private static void initDBBRConstructor() {
  411           AccessController.doPrivileged(new PrivilegedAction<Void>() {
  412                   public Void run() {
  413                       try {
  414                           Class<?> cl = Class.forName("java.nio.DirectByteBufferR");
  415                           Constructor ctor = cl.getDeclaredConstructor(
  416                               new Class[] { int.class,
  417                                             long.class,
  418                                             FileDescriptor.class,
  419                                             Runnable.class });
  420                           ctor.setAccessible(true);
  421                           directByteBufferRConstructor = ctor;
  422                       } catch (ClassNotFoundException x) {
  423                           throw new InternalError();
  424                       } catch (NoSuchMethodException x) {
  425                           throw new InternalError();
  426                       } catch (IllegalArgumentException x) {
  427                           throw new InternalError();
  428                       } catch (ClassCastException x) {
  429                           throw new InternalError();
  430                       }
  431                       return null;
  432                   }});
  433       }
  434   
  435       static MappedByteBuffer newMappedByteBufferR(int size, long addr,
  436                                                    FileDescriptor fd,
  437                                                    Runnable unmapper)
  438       {
  439           MappedByteBuffer dbb;
  440           if (directByteBufferRConstructor == null)
  441               initDBBRConstructor();
  442           try {
  443               dbb = (MappedByteBuffer)directByteBufferRConstructor.newInstance(
  444                 new Object[] { new Integer(size),
  445                                new Long(addr),
  446                                fd,
  447                                unmapper });
  448           } catch (InstantiationException e) {
  449               throw new InternalError();
  450           } catch (IllegalAccessException e) {
  451               throw new InternalError();
  452           } catch (InvocationTargetException e) {
  453               throw new InternalError();
  454           }
  455           return dbb;
  456       }
  457   
  458   
  459       // -- Bug compatibility --
  460   
  461       private static volatile String bugLevel = null;
  462   
  463       static boolean atBugLevel(String bl) {              // package-private
  464           if (bugLevel == null) {
  465               if (!sun.misc.VM.isBooted())
  466                   return false;
  467               String value = AccessController.doPrivileged(
  468                   new GetPropertyAction("sun.nio.ch.bugLevel"));
  469               bugLevel = (value != null) ? value : "";
  470           }
  471           return bugLevel.equals(bl);
  472       }
  473   
  474   
  475   
  476       // -- Initialization --
  477   
  478       private static boolean loaded = false;
  479   
  480       static void load() {
  481           synchronized (Util.class) {
  482               if (loaded)
  483                   return;
  484               loaded = true;
  485               java.security.AccessController
  486                   .doPrivileged(new sun.security.action.LoadLibraryAction("net"));
  487               java.security.AccessController
  488                   .doPrivileged(new sun.security.action.LoadLibraryAction("nio"));
  489               // IOUtil must be initialized; Its native methods are called from
  490               // other places in native nio code so they must be set up.
  491               IOUtil.initIDs();
  492           }
  493       }
  494   
  495   }

Home » openjdk-7 » sun » nio » ch » [javadoc | source]