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