1 //****************************************************************************** 2 // 3 // File: IORequest.java 4 // Package: edu.rit.mp 5 // Unit: Class edu.rit.mp.IORequest 6 // 7 // This Java source file is copyright (C) 2008 by Alan Kaminsky. All rights 8 // reserved. For further information, contact the author, Alan Kaminsky, at 9 // ark@cs.rit.edu. 10 // 11 // This Java source file is part of the Parallel Java Library ("PJ"). PJ is free 12 // software; you can redistribute it and/or modify it under the terms of the GNU 13 // General Public License as published by the Free Software Foundation; either 14 // version 3 of the License, or (at your option) any later version. 15 // 16 // PJ is distributed in the hope that it will be useful, but WITHOUT ANY 17 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 18 // A PARTICULAR PURPOSE. See the GNU General Public License for more details. 19 // 20 // Linking this library statically or dynamically with other modules is making a 21 // combined work based on this library. Thus, the terms and conditions of the GNU 22 // General Public License cover the whole combination. 23 // 24 // As a special exception, the copyright holders of this library give you 25 // permission to link this library with independent modules to produce an 26 // executable, regardless of the license terms of these independent modules, and 27 // to copy and distribute the resulting executable under terms of your choice, 28 // provided that you also meet, for each linked independent module, the terms 29 // and conditions of the license of that module. An independent module is a module 30 // which is not derived from or based on this library. If you modify this library, 31 // you may extend this exception to your version of the library, but you are not 32 // obligated to do so. If you do not wish to do so, delete this exception 33 // statement from your version. 34 // 35 // A copy of the GNU General Public License is provided in the file gpl.txt. You 36 // may also obtain a copy of the GNU General Public License on the World Wide 37 // Web at http://www.gnu.org/licenses/gpl.html. 38 // 39 //****************************************************************************** 40 package edu.rit.mp; 41 42 import java.io.IOException; 43 import java.io.InterruptedIOException; 44 import java.lang.reflect.Constructor; 45 46 /** 47 * Class IORequest encapsulates the state of a message being sent or received in 48 * the Message Protocol (MP). 49 * <P> 50 * Class {@linkplain ChannelGroup}'s non-blocking <code>sendNoWait()</code> method 51 * includes an IORequest argument. This allows the caller to initiate the send 52 * operation and continue processing while the channel group sends the message 53 * in a separate thread. To wait for the message to be sent, the caller must 54 * call the IORequest object's <code>waitForFinish()</code> method. 55 * <P> 56 * Class {@linkplain ChannelGroup}'s non-blocking <code>receiveNoWait()</code> 57 * method includes an IORequest argument. This allows the caller to initiate the 58 * receive operation and continue processing while the channel group receives 59 * the message in a separate thread. To wait for the message to be received, the 60 * caller must call the IORequest object's <code>waitForFinish()</code> method, 61 * which returns a {@linkplain Status} object giving the results of the receive 62 * operation. 63 * 64 * @author Alan Kaminsky 65 * @version 12-Oct-2008 66 */ 67 public class IORequest { 68 69 // Hidden data members. 70 /** 71 * Channel on which to send or receive message. Null means "any channel" 72 * (only valid for receiving). 73 */ 74 protected Channel myChannel; 75 76 /** 77 * Message tag range lower bound. For sending, myTagLb gives the outgoing 78 * message tag, and myTagUb is not used. For receiving, an incoming message 79 * tag in the range myTagLb..myTabUb inclusive will match this I/O request. 80 */ 81 protected int myTagLb; 82 83 /** 84 * Message tag range upper bound. 85 */ 86 protected int myTagUb; 87 88 /** 89 * Source or destination of message items. 90 */ 91 protected Buf myBuf; 92 93 /** 94 * Status of a received message. 95 */ 96 protected Status myStatus; 97 98 // Exception that occurred, or null if none. 99 IOException myIOException; 100 RuntimeException myRuntimeException; 101 Error myError; 102 103 // State: PENDING = request still in progress; SUCCEEDED = request finished 104 // successfully; FAILED = request finished unsuccessfully and myIOException, 105 // myRuntimeException, or myError contains the exception object to throw. 106 int myState = PENDING; 107 static final int PENDING = 0; 108 static final int SUCCEEDED = 1; 109 static final int FAILED = 2; 110 111 // Exported constructors. 112 /** 113 * Construct a new I/O request object. 114 */ 115 public IORequest() { 116 } 117 118 /** 119 * Initialize this I/O request object. 120 * 121 * @param theChannel Channel on which to send or receive message. Null 122 * denotes "any channel." 123 * @param theTagLb Message tag range lower bound. 124 * @param theTagUb Message tag range upper bound. 125 * @param theBuf Source or destination of message items. 126 */ 127 void initialize(Channel theChannel, 128 int theTagLb, 129 int theTagUb, 130 Buf theBuf) { 131 myChannel = theChannel; 132 myTagLb = theTagLb; 133 myTagUb = theTagUb; 134 myBuf = theBuf; 135 myStatus = null; 136 myIOException = null; 137 myRuntimeException = null; 138 myError = null; 139 myState = PENDING; 140 } 141 142 // Exported operations. 143 /** 144 * Determine if this I/O request has finished. 145 * 146 * @return False if this I/O request has not finished, true if this I/O 147 * request has finished successfully. 148 * @exception IOException Thrown if this I/O request has finished and an I/O 149 * error occurred. 150 * @throws java.io.IOException if any. 151 */ 152 public synchronized boolean isFinished() 153 throws IOException { 154 if (myState == PENDING) { 155 return false; 156 } 157 rethrow("IORequest: Exception during send or receive"); 158 return true; 159 } 160 161 /** 162 * Wait until the send or receive operation corresponding to this I/O 163 * request has finished. For a receive operation, a {@linkplain Status} 164 * object containing the results of the receive operation is returned; for a 165 * send operation, null is returned. 166 * 167 * @return Receive status for a receive operation, or null for a send 168 * operation. 169 * @exception IOException Thrown if an I/O error occurred. 170 * @throws java.io.IOException if any. 171 */ 172 public synchronized Status waitForFinish() 173 throws IOException { 174 try { 175 while (myState == PENDING) { 176 wait(); 177 } 178 rethrow("IORequest: Exception during send or receive"); 179 return myStatus; 180 } catch (InterruptedException exc) { 181 IOException exc2 182 = new InterruptedIOException("IORequest: waitForFinish() interrupted"); 183 exc2.initCause(exc); 184 throw exc2; 185 } 186 } 187 188 /** 189 * Returns a string version of this I/O request. 190 * 191 * @return String version. 192 */ 193 public String toString() { 194 StringBuilder b = new StringBuilder(); 195 b.append("IORequest(myChannel="); 196 b.append(myChannel); 197 b.append(",myTagLb="); 198 b.append(myTagLb); 199 b.append(",myTagUb="); 200 b.append(myTagUb); 201 b.append(",myBuf="); 202 b.append(myBuf); 203 b.append(",myState="); 204 b.append(myState); 205 b.append(")"); 206 return b.toString(); 207 } 208 209 // Hidden operations. 210 /** 211 * Determine if this I/O request matches the given IORequest. 212 * 213 * @param that I/O request to match. 214 * 215 * @return True if this I/O request matches <code>theIORequest</code>, false 216 * otherwise. 217 */ 218 boolean match(IORequest that) { 219 return (this.myChannel == null 220 || that.myChannel == null 221 || this.myChannel == that.myChannel) 222 && (this.myTagLb <= that.myTagLb) 223 && (that.myTagLb <= this.myTagUb) 224 && (this.myBuf.myMessageType == that.myBuf.myMessageType); 225 } 226 227 /** 228 * Determine if this I/O request matches the given channel, message tag, and 229 * message type. 230 * 231 * @param channel Channel. 232 * @param tag Message tag. 233 * @param type Message type. 234 * 235 * @return True if this I/O request matches the given information, false 236 * otherwise. 237 */ 238 boolean match(Channel channel, 239 int tag, 240 byte type) { 241 return (this.myChannel == null 242 || channel == null 243 || this.myChannel == channel) 244 && (this.myTagLb <= tag) 245 && (tag <= this.myTagUb) 246 && (this.myBuf.myMessageType == type); 247 } 248 249 /** 250 * Report that this I/O request succeeded. 251 */ 252 protected synchronized void reportSuccess() { 253 myState = SUCCEEDED; 254 notifyAll(); 255 } 256 257 /** 258 * Report that this I/O request failed with an I/O exception. 259 * 260 * @param theIOException I/O exception. 261 */ 262 protected synchronized void reportFailure(IOException theIOException) { 263 myIOException = theIOException; 264 myState = FAILED; 265 notifyAll(); 266 } 267 268 /** 269 * Report that this I/O request failed with a runtime exception. 270 * 271 * @param theRuntimeException Runtime exception. 272 */ 273 synchronized void reportFailure(RuntimeException theRuntimeException) { 274 myRuntimeException = theRuntimeException; 275 myState = FAILED; 276 notifyAll(); 277 } 278 279 /** 280 * Report that this I/O request failed with an error. 281 * 282 * @param theError Error. 283 */ 284 synchronized void reportFailure(Error theError) { 285 myError = theError; 286 myState = FAILED; 287 notifyAll(); 288 } 289 290 /** 291 * Rethrow the exception reported to this I/O request if any. 292 * 293 * @param msg Detail message for rethrown exception. 294 * 295 * @exception IOException Thrown if an I/O error occurred. 296 */ 297 private void rethrow(String msg) 298 throws IOException { 299 if (myIOException != null) { 300 rethrowIOException(msg); 301 } else if (myRuntimeException != null) { 302 rethrowRuntimeException(msg); 303 } else if (myError != null) { 304 rethrowError(msg); 305 } 306 } 307 308 /** 309 * Rethrow the I/O exception reported to this I/O request. 310 * 311 * @param msg Detail message for rethrown exception. 312 * 313 * @exception IOException Thrown if an I/O error occurred. 314 */ 315 private void rethrowIOException(String msg) 316 throws IOException { 317 IOException exc2 = null; 318 try { 319 Class<? extends IOException> excClass 320 = myIOException.getClass(); 321 Constructor<? extends IOException> excConstructor 322 = excClass.getConstructor(String.class); 323 exc2 = excConstructor.newInstance(msg); 324 } catch (Throwable exc) { 325 exc2 = new IOException(msg); 326 } 327 exc2.initCause(myIOException); 328 throw exc2; 329 } 330 331 /** 332 * Rethrow the runtime exception reported to this I/O request. 333 * 334 * @param msg Detail message for rethrown exception. 335 */ 336 private void rethrowRuntimeException(String msg) { 337 RuntimeException exc2 = null; 338 try { 339 Class<? extends RuntimeException> excClass 340 = myRuntimeException.getClass(); 341 Constructor<? extends RuntimeException> excConstructor 342 = excClass.getConstructor(String.class); 343 exc2 = excConstructor.newInstance(msg); 344 } catch (Throwable exc) { 345 exc2 = new RuntimeException(msg); 346 } 347 exc2.initCause(myRuntimeException); 348 throw exc2; 349 } 350 351 /** 352 * Rethrow the error reported to this I/O request. 353 * 354 * @param msg Detail message for rethrown exception. 355 */ 356 private void rethrowError(String msg) { 357 Error exc2 = null; 358 try { 359 Class<? extends Error> excClass 360 = myError.getClass(); 361 Constructor<? extends Error> excConstructor 362 = excClass.getConstructor(String.class); 363 exc2 = excConstructor.newInstance(msg); 364 } catch (Throwable exc) { 365 exc2 = new Error(msg); 366 } 367 exc2.initCause(myError); 368 throw exc2; 369 } 370 371 }