1 /* 2 * Copyright (c) 2000, 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.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 return write(fd, src, position, false, -1, nd); 51 } 52 53 static int write(FileDescriptor fd, ByteBuffer src, long position, 54 boolean directIO, int alignment, NativeDispatcher nd) 55 throws IOException 56 { 57 if (src instanceof DirectBuffer) { 58 return writeFromNativeBuffer(fd, src, position, directIO, alignment, nd); 59 } 60 61 // Substitute a native buffer 62 int pos = src.position(); 63 int lim = src.limit(); 64 assert (pos <= lim); 65 int rem = (pos <= lim ? lim - pos : 0); 66 ByteBuffer bb; 67 if (directIO) { 68 Util.checkRemainingBufferSizeAligned(rem, alignment); 69 bb = Util.getTemporaryAlignedDirectBuffer(rem, alignment); 70 } else { 71 bb = Util.getTemporaryDirectBuffer(rem); 72 } 73 try { 74 bb.put(src); 75 bb.flip(); 76 // Do not update src until we see how many bytes were written 77 src.position(pos); 78 79 int n = writeFromNativeBuffer(fd, bb, position, directIO, alignment, nd); 80 if (n > 0) { 81 // now update src 82 src.position(pos + n); 83 } 84 return n; 85 } finally { 86 Util.offerFirstTemporaryDirectBuffer(bb); 87 } 88 } 89 90 private static int writeFromNativeBuffer(FileDescriptor fd, ByteBuffer bb, 91 long position, boolean directIO, 92 int alignment, NativeDispatcher nd) 93 throws IOException 94 { 95 int pos = bb.position(); 96 int lim = bb.limit(); 97 assert (pos <= lim); 98 int rem = (pos <= lim ? lim - pos : 0); 99 100 if (directIO) { 101 Util.checkBufferPositionAligned(bb, pos, alignment); 102 Util.checkRemainingBufferSizeAligned(rem, alignment); 103 } 104 105 int written = 0; 106 if (rem == 0) 107 return 0; 108 if (position != -1) { 109 written = nd.pwrite(fd, 110 ((DirectBuffer)bb).address() + pos, 111 rem, position); 112 } else { 113 written = nd.write(fd, ((DirectBuffer)bb).address() + pos, rem); 114 } 115 if (written > 0) 116 bb.position(pos + written); 117 return written; 118 } 119 120 static long write(FileDescriptor fd, ByteBuffer[] bufs, NativeDispatcher nd) 121 throws IOException 122 { 123 return write(fd, bufs, 0, bufs.length, false, -1, nd); 124 } 125 126 static long write(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length, 127 NativeDispatcher nd) 128 throws IOException 129 { 130 return write(fd, bufs, offset, length, false, -1, nd); 131 } 132 133 static long write(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length, 134 boolean directIO, int alignment, NativeDispatcher nd) 135 throws IOException 136 { 137 IOVecWrapper vec = IOVecWrapper.get(length); 138 139 boolean completed = false; 140 int iov_len = 0; 141 try { 142 143 // Iterate over buffers to populate native iovec array. 144 int count = offset + length; 145 int i = offset; 146 while (i < count && iov_len < IOV_MAX) { 147 ByteBuffer buf = bufs[i]; 148 int pos = buf.position(); 149 int lim = buf.limit(); 150 assert (pos <= lim); 151 int rem = (pos <= lim ? lim - pos : 0); 152 if (directIO) 153 Util.checkRemainingBufferSizeAligned(rem, alignment); 154 155 if (rem > 0) { 156 vec.setBuffer(iov_len, buf, pos, rem); 157 158 // allocate shadow buffer to ensure I/O is done with direct buffer 159 if (!(buf instanceof DirectBuffer)) { 160 ByteBuffer shadow; 161 if (directIO) 162 shadow = Util.getTemporaryAlignedDirectBuffer(rem, alignment); 163 else 164 shadow = Util.getTemporaryDirectBuffer(rem); 165 shadow.put(buf); 166 shadow.flip(); 167 vec.setShadow(iov_len, shadow); 168 buf.position(pos); // temporarily restore position in user buffer 169 buf = shadow; 170 pos = shadow.position(); 171 } 172 173 vec.putBase(iov_len, ((DirectBuffer)buf).address() + pos); 174 vec.putLen(iov_len, rem); 175 iov_len++; 176 } 177 i++; 178 } 179 if (iov_len == 0) 180 return 0L; 181 182 long bytesWritten = nd.writev(fd, vec.address, iov_len); 183 184 // Notify the buffers how many bytes were taken 185 long left = bytesWritten; 186 for (int j=0; j<iov_len; j++) { 187 if (left > 0) { 188 ByteBuffer buf = vec.getBuffer(j); 189 int pos = vec.getPosition(j); 190 int rem = vec.getRemaining(j); 191 int n = (left > rem) ? rem : (int)left; 192 buf.position(pos + n); 193 left -= n; 194 } 195 // return shadow buffers to buffer pool 196 ByteBuffer shadow = vec.getShadow(j); 197 if (shadow != null) 198 Util.offerLastTemporaryDirectBuffer(shadow); 199 vec.clearRefs(j); 200 } 201 202 completed = true; 203 return bytesWritten; 204 205 } finally { 206 // if an error occurred then clear refs to buffers and return any shadow 207 // buffers to cache 208 if (!completed) { 209 for (int j=0; j<iov_len; j++) { 210 ByteBuffer shadow = vec.getShadow(j); 211 if (shadow != null) 212 Util.offerLastTemporaryDirectBuffer(shadow); 213 vec.clearRefs(j); 214 } 215 } 216 } 217 } 218 219 static int read(FileDescriptor fd, ByteBuffer dst, long position, 220 NativeDispatcher nd) 221 throws IOException 222 { 223 return read(fd, dst, position, false, -1, nd); 224 } 225 226 static int read(FileDescriptor fd, ByteBuffer dst, long position, 227 boolean directIO, int alignment, NativeDispatcher nd) 228 throws IOException 229 { 230 if (dst.isReadOnly()) 231 throw new IllegalArgumentException("Read-only buffer"); 232 if (dst instanceof DirectBuffer) 233 return readIntoNativeBuffer(fd, dst, position, directIO, alignment, nd); 234 235 // Substitute a native buffer 236 ByteBuffer bb; 237 int rem = dst.remaining(); 238 if (directIO) { 239 Util.checkRemainingBufferSizeAligned(rem, alignment); 240 bb = Util.getTemporaryAlignedDirectBuffer(rem, alignment); 241 } else { 242 bb = Util.getTemporaryDirectBuffer(rem); 243 } 244 try { 245 int n = readIntoNativeBuffer(fd, bb, position, directIO, alignment,nd); 246 bb.flip(); 247 if (n > 0) 248 dst.put(bb); 249 return n; 250 } finally { 251 Util.offerFirstTemporaryDirectBuffer(bb); 252 } 253 } 254 255 private static int readIntoNativeBuffer(FileDescriptor fd, ByteBuffer bb, 256 long position, boolean directIO, 257 int alignment, NativeDispatcher nd) 258 throws IOException 259 { 260 int pos = bb.position(); 261 int lim = bb.limit(); 262 assert (pos <= lim); 263 int rem = (pos <= lim ? lim - pos : 0); 264 265 if (directIO) { 266 Util.checkBufferPositionAligned(bb, pos, alignment); 267 Util.checkRemainingBufferSizeAligned(rem, alignment); 268 } 269 270 if (rem == 0) 271 return 0; 272 int n = 0; 273 if (position != -1) { 274 n = nd.pread(fd, ((DirectBuffer)bb).address() + pos, rem, position); 275 } else { 276 n = nd.read(fd, ((DirectBuffer)bb).address() + pos, rem); 277 } 278 if (n > 0) 279 bb.position(pos + n); 280 return n; 281 } 282 283 static long read(FileDescriptor fd, ByteBuffer[] bufs, NativeDispatcher nd) 284 throws IOException 285 { 286 return read(fd, bufs, 0, bufs.length, false, -1, nd); 287 } 288 289 static long read(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length, 290 NativeDispatcher nd) 291 throws IOException 292 { 293 return read(fd, bufs, offset, length, false, -1, nd); 294 } 295 296 static long read(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length, 297 boolean directIO, int alignment, NativeDispatcher nd) 298 throws IOException 299 { 300 IOVecWrapper vec = IOVecWrapper.get(length); 301 302 boolean completed = false; 303 int iov_len = 0; 304 try { 305 306 // Iterate over buffers to populate native iovec array. 307 int count = offset + length; 308 int i = offset; 309 while (i < count && iov_len < IOV_MAX) { 310 ByteBuffer buf = bufs[i]; 311 if (buf.isReadOnly()) 312 throw new IllegalArgumentException("Read-only buffer"); 313 int pos = buf.position(); 314 int lim = buf.limit(); 315 assert (pos <= lim); 316 int rem = (pos <= lim ? lim - pos : 0); 317 318 if (directIO) 319 Util.checkRemainingBufferSizeAligned(rem, alignment); 320 321 if (rem > 0) { 322 vec.setBuffer(iov_len, buf, pos, rem); 323 324 // allocate shadow buffer to ensure I/O is done with direct buffer 325 if (!(buf instanceof DirectBuffer)) { 326 ByteBuffer shadow; 327 if (directIO) { 328 shadow = Util.getTemporaryAlignedDirectBuffer(rem, alignment); 329 } else { 330 shadow = Util.getTemporaryDirectBuffer(rem); 331 } 332 vec.setShadow(iov_len, shadow); 333 buf = shadow; 334 pos = shadow.position(); 335 } 336 337 vec.putBase(iov_len, ((DirectBuffer)buf).address() + pos); 338 vec.putLen(iov_len, rem); 339 iov_len++; 340 } 341 i++; 342 } 343 if (iov_len == 0) 344 return 0L; 345 346 long bytesRead = nd.readv(fd, vec.address, iov_len); 347 348 // Notify the buffers how many bytes were read 349 long left = bytesRead; 350 for (int j=0; j<iov_len; j++) { 351 ByteBuffer shadow = vec.getShadow(j); 352 if (left > 0) { 353 ByteBuffer buf = vec.getBuffer(j); 354 int rem = vec.getRemaining(j); 355 int n = (left > rem) ? rem : (int)left; 356 if (shadow == null) { 357 int pos = vec.getPosition(j); 358 buf.position(pos + n); 359 } else { 360 shadow.limit(shadow.position() + n); 361 buf.put(shadow); 362 } 363 left -= n; 364 } 365 if (shadow != null) 366 Util.offerLastTemporaryDirectBuffer(shadow); 367 vec.clearRefs(j); 368 } 369 370 completed = true; 371 return bytesRead; 372 373 } finally { 374 // if an error occurred then clear refs to buffers and return any shadow 375 // buffers to cache 376 if (!completed) { 377 for (int j=0; j<iov_len; j++) { 378 ByteBuffer shadow = vec.getShadow(j); 379 if (shadow != null) 380 Util.offerLastTemporaryDirectBuffer(shadow); 381 vec.clearRefs(j); 382 } 383 } 384 } 385 } 386 387 public static FileDescriptor newFD(int i) { 388 FileDescriptor fd = new FileDescriptor(); 389 setfdVal(fd, i); 390 return fd; 391 } 392 393 static native boolean randomBytes(byte[] someBytes); 394 395 /** 396 * Returns two file descriptors for a pipe encoded in a long. 397 * The read end of the pipe is returned in the high 32 bits, 398 * while the write end is returned in the low 32 bits. 399 */ 400 static native long makePipe(boolean blocking) throws IOException; 401 402 static native int write1(int fd, byte b) throws IOException; 403 404 /** 405 * Read and discard all bytes. 406 */ 407 static native boolean drain(int fd) throws IOException; 408 409 /** 410 * Read and discard at most one byte 411 * @return the number of bytes read or IOS_INTERRUPTED 412 */ 413 static native int drain1(int fd) throws IOException; 414 415 public static native void configureBlocking(FileDescriptor fd, 416 boolean blocking) 417 throws IOException; 418 419 public static native int fdVal(FileDescriptor fd); 420 421 static native void setfdVal(FileDescriptor fd, int value); 422 423 static native int fdLimit(); 424 425 static native int iovMax(); 426 427 static native void initIDs(); 428 429 /** 430 * Used to trigger loading of native libraries 431 */ 432 public static void load() { } 433 434 static { 435 java.security.AccessController.doPrivileged( 436 new java.security.PrivilegedAction<Void>() { 437 public Void run() { 438 System.loadLibrary("net"); 439 System.loadLibrary("nio"); 440 return null; 441 } 442 }); 443 444 initIDs(); 445 446 IOV_MAX = iovMax(); 447 } 448 449 }