src/java.base/solaris/classes/sun/nio/ch/EventPortWrapper.java
branchhttp-client-branch
changeset 56347 bac3a660249a
parent 56346 514c68575523
parent 49417 1d3139252c1c
child 56355 bf89fba643d9
equal deleted inserted replaced
56346:514c68575523 56347:bac3a660249a
     1 /*
       
     2  * Copyright (c) 2012, 2018, 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.io.IOException;
       
    29 import java.security.AccessController;
       
    30 import java.util.BitSet;
       
    31 import java.util.HashMap;
       
    32 import java.util.Map;
       
    33 
       
    34 import jdk.internal.misc.Unsafe;
       
    35 import sun.security.action.GetIntegerAction;
       
    36 import static sun.nio.ch.SolarisEventPort.*;
       
    37 
       
    38 /**
       
    39  * Manages a Solaris event port and manipulates a native array of pollfd structs
       
    40  * on Solaris.
       
    41  */
       
    42 
       
    43 class EventPortWrapper {
       
    44     private static final Unsafe unsafe = Unsafe.getUnsafe();
       
    45     private static final int addressSize = unsafe.addressSize();
       
    46 
       
    47     // Maximum number of open file descriptors
       
    48     static final int   OPEN_MAX     = IOUtil.fdLimit();
       
    49 
       
    50     // Maximum number of events to retrive in one call to port_getn
       
    51     static final int   POLL_MAX     =  Math.min(OPEN_MAX-1, 1024);
       
    52 
       
    53     // initial size of the array to hold pending updates
       
    54     private final int INITIAL_PENDING_UPDATE_SIZE = 256;
       
    55 
       
    56     // maximum size of updateArray
       
    57     private static final int MAX_UPDATE_ARRAY_SIZE = AccessController.doPrivileged(
       
    58         new GetIntegerAction("sun.nio.ch.maxUpdateArraySize", Math.min(OPEN_MAX, 64*1024)));
       
    59 
       
    60     // special update status to indicate that it should be ignored
       
    61     private static final byte IGNORE = -1;
       
    62 
       
    63     // port file descriptor
       
    64     private final int pfd;
       
    65 
       
    66     // the poll array (populated by port_getn)
       
    67     private final long pollArrayAddress;
       
    68     private final AllocatedNativeObject pollArray;
       
    69 
       
    70     // required when accessing the update* fields
       
    71     private final Object updateLock = new Object();
       
    72 
       
    73     // the number of pending updates
       
    74     private int updateCount;
       
    75 
       
    76     // queue of file descriptors with updates pending
       
    77     private int[] updateDescriptors = new int[INITIAL_PENDING_UPDATE_SIZE];
       
    78 
       
    79     // events for file descriptors with registration changes pending, indexed
       
    80     // by file descriptor and stored as bytes for efficiency reasons. For
       
    81     // file descriptors higher than MAX_UPDATE_ARRAY_SIZE (unlimited case at
       
    82     // least then the update is stored in a map.
       
    83     private final byte[] eventsLow = new byte[MAX_UPDATE_ARRAY_SIZE];
       
    84     private Map<Integer,Byte> eventsHigh;
       
    85     // Used by release and updateRegistrations to track whether a file
       
    86     // descriptor is registered with /dev/poll.
       
    87     private final BitSet registered = new BitSet();
       
    88 
       
    89     // bit set to indicate if a file descriptor has been visited when
       
    90     // processing updates (used to avoid duplicates calls to port_associate)
       
    91     private BitSet visited = new BitSet();
       
    92 
       
    93     EventPortWrapper() throws IOException {
       
    94         int allocationSize = POLL_MAX * SIZEOF_PORT_EVENT;
       
    95         pollArray = new AllocatedNativeObject(allocationSize, true);
       
    96         pollArrayAddress = pollArray.address();
       
    97         this.pfd = port_create();
       
    98         if (OPEN_MAX > MAX_UPDATE_ARRAY_SIZE)
       
    99             eventsHigh = new HashMap<>();
       
   100     }
       
   101 
       
   102     void close() throws IOException {
       
   103         port_close(pfd);
       
   104         pollArray.free();
       
   105     }
       
   106 
       
   107     private short getSource(int i) {
       
   108         int offset = SIZEOF_PORT_EVENT * i + OFFSETOF_SOURCE;
       
   109         return pollArray.getShort(offset);
       
   110     }
       
   111 
       
   112     int getEventOps(int i) {
       
   113         int offset = SIZEOF_PORT_EVENT * i + OFFSETOF_EVENTS;
       
   114         return pollArray.getInt(offset);
       
   115     }
       
   116 
       
   117     int getDescriptor(int i) {
       
   118         int offset = SIZEOF_PORT_EVENT * i + OFFSETOF_OBJECT;
       
   119         if (addressSize == 4) {
       
   120             return pollArray.getInt(offset);
       
   121         } else {
       
   122             return (int) pollArray.getLong(offset);
       
   123         }
       
   124     }
       
   125 
       
   126     private void setDescriptor(int i, int fd) {
       
   127         int offset = SIZEOF_PORT_EVENT * i + OFFSETOF_OBJECT;
       
   128         if (addressSize == 4) {
       
   129             pollArray.putInt(offset, fd);
       
   130         } else {
       
   131             pollArray.putLong(offset, fd);
       
   132         }
       
   133     }
       
   134 
       
   135     private void setUpdate(int fd, byte events) {
       
   136         if (fd < MAX_UPDATE_ARRAY_SIZE) {
       
   137             eventsLow[fd] = events;
       
   138         } else {
       
   139             eventsHigh.put(Integer.valueOf(fd), Byte.valueOf(events));
       
   140         }
       
   141     }
       
   142 
       
   143     private byte getUpdate(int fd) {
       
   144         if (fd < MAX_UPDATE_ARRAY_SIZE) {
       
   145             return eventsLow[fd];
       
   146         } else {
       
   147             Byte result = eventsHigh.get(Integer.valueOf(fd));
       
   148             // result should never be null
       
   149             return result.byteValue();
       
   150         }
       
   151     }
       
   152 
       
   153     int poll(long timeout) throws IOException {
       
   154         // update registrations prior to poll
       
   155         synchronized (updateLock) {
       
   156 
       
   157             // process newest updates first
       
   158             int i = updateCount - 1;
       
   159             while (i >= 0) {
       
   160                 int fd = updateDescriptors[i];
       
   161                 if (!visited.get(fd)) {
       
   162                     short ev = getUpdate(fd);
       
   163                     if (ev != IGNORE) {
       
   164                         if (ev == 0) {
       
   165                             if (registered.get(fd)) {
       
   166                                 port_dissociate(pfd, PORT_SOURCE_FD, (long)fd);
       
   167                                 registered.clear(fd);
       
   168                             }
       
   169                         } else {
       
   170                             if (port_associate(pfd, PORT_SOURCE_FD, (long)fd, ev)) {
       
   171                                 registered.set(fd);
       
   172                             }
       
   173                         }
       
   174 
       
   175                     }
       
   176                     visited.set(fd);
       
   177                 }
       
   178                 i--;
       
   179             }
       
   180             updateCount = 0;
       
   181         }
       
   182 
       
   183         // poll for events
       
   184         int numEntries;
       
   185         long to = timeout;
       
   186         boolean timedPoll = (to > 0);
       
   187         do {
       
   188             long startTime = timedPoll ? System.currentTimeMillis() : 0;
       
   189             numEntries = port_getn(pfd, pollArrayAddress, POLL_MAX, timeout);
       
   190             if (numEntries == IOStatus.INTERRUPTED && timedPoll) {
       
   191                 // timed poll interrupted so need to adjust timeout
       
   192                 to -= System.currentTimeMillis() - startTime;
       
   193                 if (to <= 0) {
       
   194                     // timeout also expired so no retry
       
   195                     numEntries = 0;
       
   196                 }
       
   197             }
       
   198         } while (numEntries == IOStatus.INTERRUPTED);
       
   199 
       
   200         // after polling we need to queue all polled file descriptors as they
       
   201         // are candidates to register for the next poll.
       
   202         synchronized (updateLock) {
       
   203             for (int i=0; i<numEntries; i++) {
       
   204                 if (getSource(i) == PORT_SOURCE_USER) {
       
   205                     interrupted = true;
       
   206                     setDescriptor(i, -1);
       
   207                 } else {
       
   208                     // the default is to re-associate for the next poll
       
   209                     int fd = getDescriptor(i);
       
   210                     registered.clear(fd);
       
   211                     setInterest(fd);
       
   212                 }
       
   213             }
       
   214         }
       
   215 
       
   216         return numEntries;
       
   217     }
       
   218 
       
   219     private void setInterest(int fd) {
       
   220         assert Thread.holdsLock(updateLock);
       
   221 
       
   222         // record the file descriptor and events, expanding the
       
   223         // respective arrays first if necessary.
       
   224         int oldCapacity = updateDescriptors.length;
       
   225         if (updateCount >= oldCapacity) {
       
   226             int newCapacity = oldCapacity + INITIAL_PENDING_UPDATE_SIZE;
       
   227             int[] newDescriptors = new int[newCapacity];
       
   228             System.arraycopy(updateDescriptors, 0, newDescriptors, 0, oldCapacity);
       
   229             updateDescriptors = newDescriptors;
       
   230         }
       
   231         updateDescriptors[updateCount++] = fd;
       
   232         visited.clear(fd);
       
   233     }
       
   234 
       
   235     void setInterest(int fd, int mask) {
       
   236         synchronized (updateLock) {
       
   237             setInterest(fd);
       
   238             setUpdate(fd, (byte)mask);
       
   239             assert getUpdate(fd) == mask;
       
   240         }
       
   241     }
       
   242 
       
   243     void release(int fd) {
       
   244         synchronized (updateLock) {
       
   245             if (registered.get(fd)) {
       
   246                 try {
       
   247                     port_dissociate(pfd, PORT_SOURCE_FD, (long)fd);
       
   248                 } catch (IOException ioe) {
       
   249                     throw new InternalError(ioe);
       
   250                 }
       
   251                 registered.clear(fd);
       
   252             }
       
   253             setUpdate(fd, IGNORE);
       
   254         }
       
   255     }
       
   256 
       
   257     // -- wakeup support --
       
   258 
       
   259     private boolean interrupted;
       
   260 
       
   261     public void interrupt() {
       
   262         try {
       
   263             port_send(pfd, 0);
       
   264         } catch (IOException ioe) {
       
   265             throw new InternalError(ioe);
       
   266         }
       
   267     }
       
   268 
       
   269     boolean interrupted() {
       
   270         return interrupted;
       
   271     }
       
   272 
       
   273     void clearInterrupted() {
       
   274         interrupted = false;
       
   275     }
       
   276 }