1 /* 2 * Copyright (c) 2000, 2013, 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.FileDescriptor; 29 import java.io.IOException; 30 import java.nio.ByteBuffer; 31 32 33 /** 34 * File-descriptor based I/O utilities that are shared by NIO classes. 35 */ 36 37 public class IOUtil { 38 39 /** 40 * Max number of iovec structures that readv/writev supports 41 */ 42 static final int IOV_MAX; 43 44 private IOUtil() { } // No instantiation 45 46 static int write(FileDescriptor fd, ByteBuffer src, long position, 47 NativeDispatcher nd) 48 throws IOException 49 { 50 if (src instanceof DirectBuffer) 51 return writeFromNativeBuffer(fd, src, position, nd); 52 53 // Substitute a native buffer 54 int pos = src.position(); 55 int lim = src.limit(); 56 assert (pos <= lim); 57 int rem = (pos <= lim ? lim - pos : 0); 58 ByteBuffer bb = Util.getTemporaryDirectBuffer(rem); 59 try { 60 bb.put(src); 61 bb.flip(); 62 // Do not update src until we see how many bytes were written 63 src.position(pos); 64 65 int n = writeFromNativeBuffer(fd, bb, position, nd); 66 if (n > 0) { 67 // now update src 68 src.position(pos + n); 69 } 70 return n; 71 } finally { 72 Util.offerFirstTemporaryDirectBuffer(bb); 73 } 74 } 75 76 private static int writeFromNativeBuffer(FileDescriptor fd, ByteBuffer bb, 77 long position, NativeDispatcher nd) 78 throws IOException 79 { 80 int pos = bb.position(); 81 int lim = bb.limit(); 82 assert (pos <= lim); 83 int rem = (pos <= lim ? lim - pos : 0); 84 85 int written = 0; 86 if (rem == 0) 87 return 0; 88 if (position != -1) { 89 written = nd.pwrite(fd, 90 ((DirectBuffer)bb).address() + pos, 91 rem, position); 92 } else { 93 written = nd.write(fd, ((DirectBuffer)bb).address() + pos, rem); 94 } 95 if (written > 0) 96 bb.position(pos + written); 97 return written; 98 } 99 100 static long write(FileDescriptor fd, ByteBuffer[] bufs, NativeDispatcher nd) 101 throws IOException 102 { 103 return write(fd, bufs, 0, bufs.length, nd); 104 } 105 106 static long write(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length, 107 NativeDispatcher nd) 108 throws IOException 109 { 110 IOVecWrapper vec = IOVecWrapper.get(length); 111 112 boolean completed = false; 113 int iov_len = 0; 114 try { 115 116 // Iterate over buffers to populate native iovec array. 117 int count = offset + length; 118 int i = offset; 119 while (i < count && iov_len < IOV_MAX) { 120 ByteBuffer buf = bufs[i]; 121 int pos = buf.position(); 122 int lim = buf.limit(); 123 assert (pos <= lim); 124 int rem = (pos <= lim ? lim - pos : 0); 125 if (rem > 0) { 126 vec.setBuffer(iov_len, buf, pos, rem); 127 128 // allocate shadow buffer to ensure I/O is done with direct buffer 129 if (!(buf instanceof DirectBuffer)) { 130 ByteBuffer shadow = Util.getTemporaryDirectBuffer(rem); 131 shadow.put(buf); 132 shadow.flip(); 133 vec.setShadow(iov_len, shadow); 134 buf.position(pos); // temporarily restore position in user buffer 135 buf = shadow; 136 pos = shadow.position(); 137 } 138 139 vec.putBase(iov_len, ((DirectBuffer)buf).address() + pos); 140 vec.putLen(iov_len, rem); 141 iov_len++; 142 } 143 i++; 144 } 145 if (iov_len == 0) 146 return 0L; 147 148 long bytesWritten = nd.writev(fd, vec.address, iov_len); 149 150 // Notify the buffers how many bytes were taken 151 long left = bytesWritten; 152 for (int j=0; j<iov_len; j++) { 153 if (left > 0) { 154 ByteBuffer buf = vec.getBuffer(j); 155 int pos = vec.getPosition(j); 156 int rem = vec.getRemaining(j); 157 int n = (left > rem) ? rem : (int)left; 158 buf.position(pos + n); 159 left -= n; 160 } 161 // return shadow buffers to buffer pool 162 ByteBuffer shadow = vec.getShadow(j); 163 if (shadow != null) 164 Util.offerLastTemporaryDirectBuffer(shadow); 165 vec.clearRefs(j); 166 } 167 168 completed = true; 169 return bytesWritten; 170 171 } finally { 172 // if an error occurred then clear refs to buffers and return any shadow 173 // buffers to cache 174 if (!completed) { 175 for (int j=0; j<iov_len; j++) { 176 ByteBuffer shadow = vec.getShadow(j); 177 if (shadow != null) 178 Util.offerLastTemporaryDirectBuffer(shadow); 179 vec.clearRefs(j); 180 } 181 } 182 } 183 } 184 185 static int read(FileDescriptor fd, ByteBuffer dst, long position, 186 NativeDispatcher nd) 187 throws IOException 188 { 189 if (dst.isReadOnly()) 190 throw new IllegalArgumentException("Read-only buffer"); 191 if (dst instanceof DirectBuffer) 192 return readIntoNativeBuffer(fd, dst, position, nd); 193 194 // Substitute a native buffer 195 ByteBuffer bb = Util.getTemporaryDirectBuffer(dst.remaining()); 196 try { 197 int n = readIntoNativeBuffer(fd, bb, position, nd); 198 bb.flip(); 199 if (n > 0) 200 dst.put(bb); 201 return n; 202 } finally { 203 Util.offerFirstTemporaryDirectBuffer(bb); 204 } 205 } 206 207 private static int readIntoNativeBuffer(FileDescriptor fd, ByteBuffer bb, 208 long position, NativeDispatcher nd) 209 throws IOException 210 { 211 int pos = bb.position(); 212 int lim = bb.limit(); 213 assert (pos <= lim); 214 int rem = (pos <= lim ? lim - pos : 0); 215 216 if (rem == 0) 217 return 0; 218 int n = 0; 219 if (position != -1) { 220 n = nd.pread(fd, ((DirectBuffer)bb).address() + pos, 221 rem, position); 222 } else { 223 n = nd.read(fd, ((DirectBuffer)bb).address() + pos, rem); 224 } 225 if (n > 0) 226 bb.position(pos + n); 227 return n; 228 } 229 230 static long read(FileDescriptor fd, ByteBuffer[] bufs, NativeDispatcher nd) 231 throws IOException 232 { 233 return read(fd, bufs, 0, bufs.length, nd); 234 } 235 236 static long read(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length, 237 NativeDispatcher nd) 238 throws IOException 239 { 240 IOVecWrapper vec = IOVecWrapper.get(length); 241 242 boolean completed = false; 243 int iov_len = 0; 244 try { 245 246 // Iterate over buffers to populate native iovec array. 247 int count = offset + length; 248 int i = offset; 249 while (i < count && iov_len < IOV_MAX) { 250 ByteBuffer buf = bufs[i]; 251 if (buf.isReadOnly()) 252 throw new IllegalArgumentException("Read-only buffer"); 253 int pos = buf.position(); 254 int lim = buf.limit(); 255 assert (pos <= lim); 256 int rem = (pos <= lim ? lim - pos : 0); 257 258 if (rem > 0) { 259 vec.setBuffer(iov_len, buf, pos, rem); 260 261 // allocate shadow buffer to ensure I/O is done with direct buffer 262 if (!(buf instanceof DirectBuffer)) { 263 ByteBuffer shadow = Util.getTemporaryDirectBuffer(rem); 264 vec.setShadow(iov_len, shadow); 265 buf = shadow; 266 pos = shadow.position(); 267 } 268 269 vec.putBase(iov_len, ((DirectBuffer)buf).address() + pos); 270 vec.putLen(iov_len, rem); 271 iov_len++; 272 } 273 i++; 274 } 275 if (iov_len == 0) 276 return 0L; 277 278 long bytesRead = nd.readv(fd, vec.address, iov_len); 279 280 // Notify the buffers how many bytes were read 281 long left = bytesRead; 282 for (int j=0; j<iov_len; j++) { 283 ByteBuffer shadow = vec.getShadow(j); 284 if (left > 0) { 285 ByteBuffer buf = vec.getBuffer(j); 286 int rem = vec.getRemaining(j); 287 int n = (left > rem) ? rem : (int)left; 288 if (shadow == null) { 289 int pos = vec.getPosition(j); 290 buf.position(pos + n); 291 } else { 292 shadow.limit(shadow.position() + n); 293 buf.put(shadow); 294 } 295 left -= n; 296 } 297 if (shadow != null) 298 Util.offerLastTemporaryDirectBuffer(shadow); 299 vec.clearRefs(j); 300 } 301 302 completed = true; 303 return bytesRead; 304 305 } finally { 306 // if an error occurred then clear refs to buffers and return any shadow 307 // buffers to cache 308 if (!completed) { 309 for (int j=0; j<iov_len; j++) { 310 ByteBuffer shadow = vec.getShadow(j); 311 if (shadow != null) 312 Util.offerLastTemporaryDirectBuffer(shadow); 313 vec.clearRefs(j); 314 } 315 } 316 } 317 } 318 319 public static FileDescriptor newFD(int i) { 320 FileDescriptor fd = new FileDescriptor(); 321 setfdVal(fd, i); 322 return fd; 323 } 324 325 static native boolean randomBytes(byte[] someBytes); 326 327 /** 328 * Returns two file descriptors for a pipe encoded in a long. 329 * The read end of the pipe is returned in the high 32 bits, 330 * while the write end is returned in the low 32 bits. 331 */ 332 static native long makePipe(boolean blocking); 333 334 static native boolean drain(int fd) throws IOException; 335 336 public static native void configureBlocking(FileDescriptor fd, 337 boolean blocking) 338 throws IOException; 339 340 public static native int fdVal(FileDescriptor fd); 341 342 static native void setfdVal(FileDescriptor fd, int value); 343 344 static native int fdLimit(); 345 346 static native int iovMax(); 347 348 static native void initIDs(); 349 350 /** 351 * Used to trigger loading of native libraries 352 */ 353 public static void load() { } 354 355 static { 356 java.security.AccessController.doPrivileged( 357 new java.security.PrivilegedAction<Void>() { 358 public Void run() { 359 System.loadLibrary("net"); 360 System.loadLibrary("nio"); 361 return null; 362 } 363 }); 364 365 initIDs(); 366 367 IOV_MAX = iovMax(); 368 } 369 370 }