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