1(* $Id: IO.Mod,v 1.15 2004/11/21 20:31:50 mva Exp $ *) 2MODULE IO; 3(* Defines common behaviour of I/O channel and selector. 4 Copyright (C) 2003, 2004 Michael van Acken 5 6 This module is free software; you can redistribute it and/or 7 modify it under the terms of the GNU Lesser General Public License 8 as published by the Free Software Foundation; either version 2 of 9 the License, or (at your option) any later version. 10 11 This module is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 Lesser General Public License for more details. 15 16 You should have received a copy of the GNU Lesser General Public 17 License along with OOC. If not, write to the Free Software Foundation, 18 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19*) 20 21(** 22 23 This set of modules defines a set of input/output abstractions for files, 24 sockets, pipes, and so on. The modules are not related to the library 25 modules @omodule{*Channel}, @omodule{*Files}, and derivates. Their goals 26 are quite different: 27 28 @itemize @bullet 29 @item 30 Provide an thin and efficient layer on top of the operation system's I/O 31 features. 32 @item 33 Use exceptions to propagate errors to the application that are reported by 34 the C library. 35 @item 36 Provide an abstraction for I/O multiplexing that allows to use different 37 mechanisms besides @code{select()}. 38 @item 39 The level of abstraction should be high-level enough to care for slighty 40 different I/O primitives, most notably under Windows. 41 @end itemize 42 43 The roots of the interface are partially the Java IO package, Python, and 44 the Oberon-2 standard I/O modules. Eventually, the modules will replace the 45 @samp{IO:*} inherited from the old @samp{libxml} package. *) 46 47IMPORT 48 SYSTEM, Object, Exception, C; 49 50TYPE 51 Channel* = POINTER TO ChannelDesc; 52 SelectionKey* = POINTER TO SelectionKeyDesc; 53 SelectionKeyList = POINTER TO ARRAY OF SelectionKey; 54 ChannelDesc* = RECORD [ABSTRACT] 55 (**A channel is a means by which a program can perform I/O operations. 56 Examples for channels are @otype{*IO:FileChannel.Channel}, 57 @otype{*IO:SocketChannel.Channel}, and 58 @otype{*IO:SocketChannel.ServerChannel}. *) 59 readyOps*: SET; 60 (* Set of operations that can be performed on the channel without blocking. 61 Valid elements are @oconst{opRead}, @oconst{opWrite}, @oconst{opAccept}, 62 and @oconst{opConnect}. 63 64 This field is used in conjunction with a @oproc{Selector}. It should 65 only be modified by I/O operations of extensions of @otype{Channel}. *) 66 67 keys: SelectionKeyList; 68 (* List of selection keys for each selector for which this channel has 69 been registered. The last entry is followed by NIL. *) 70 END; 71 72TYPE 73 ByteChannel* = POINTER TO ByteChannelDesc; 74 ByteChannelDesc* = RECORD [ABSTRACT] 75 (ChannelDesc) 76 (**Common base type of channels supporting the @oproc{ByteChannel.Read} and 77 @oproc{ByteChannel.Write} methods. *) 78 END; 79 80TYPE 81 Selector* = POINTER TO SelectorDesc; 82 SelectorDesc* = RECORD [ABSTRACT] 83 (**A mechanism to discover channels that are ready for I/O operations. For 84 example, a selector can be used to find out for which channels input 85 data is available. 86 87 Note: The definition of this class covers both selectors that report the 88 current state of a channel, and those that only report an event if a 89 channel becomes ready. @oproc{Selector.Select} only adds new ready flags, 90 but never clears them. I/O operations like @oproc{ByteChannel.Read}, 91 @oproc{ByteChannel.Write}, @oproc{*SocketChannel.Channel.Connect}, and 92 @oproc{*SocketChannel.ServerChannel.Accept} clear the corresponding flag 93 if the channel is in non-blocking mode and they get an @samp{EWOULDBLOCK} 94 error from the libc function. *) 95 (Object.ObjectDesc) 96 keys-: SelectionKey; 97 (**A list of selection keys registered for this selector. The keys are 98 linked via @ofield{SelectionKey.nextKey}. *) 99 cancel: BOOLEAN; 100 END; 101 102TYPE 103 FileDescriptor* = C.int; 104 SelectionKeyDesc* = RECORD 105 (**Association between a @otype{Channel} and @otype{Selector}. *) 106 (Object.ObjectDesc) 107 fd-: FileDescriptor; 108 interestOps-: SET; 109 attachment-: Object.Object; 110 selector-: Selector; 111 channel-: Channel; 112 113 nextKey-: SelectionKey; 114 cancel: BOOLEAN; 115 END; 116 117CONST 118 opRead* = 0; 119 (**Used to signal interest in new input data, or to indicate that some 120 input data has become available for processing. *) 121 opWrite* = 1; 122 (**Used to signal interest to produce output on a channel, or to indicate 123 that there is room for more data to be passed to the operating system. *) 124 opAccept* = 2; 125 (**Used to signal interest in connection requests, or to indicate that there 126 are pending requests. *) 127 opConnect* = 3; 128 (**Used to signal interest in completion of a currently pending connection 129 attempt, or to indicate that a pending connect has been completed. *) 130 131TYPE 132 Error* = POINTER TO ErrorDesc; 133 ErrorDesc* = RECORD 134 (**Base class of all I/O exceptions raised by channel implementations. *) 135 (Exception.CheckedDesc) 136 END; 137 FileNotFound* = POINTER TO FileNotFoundDesc; 138 FileNotFoundDesc = RECORD 139 (**This exception is raised if a C function returns a @samp{ENOENT} error. *) 140 (ErrorDesc) 141 END; 142 AccessDenied* = POINTER TO AccessDeniedDesc; 143 AccessDeniedDesc = RECORD 144 (**This exception is raised if a C function returns a @samp{EACCES} error. *) 145 (ErrorDesc) 146 END; 147 FileExists* = POINTER TO FileExistsDesc; 148 FileExistsDesc = RECORD 149 (**This exception is raised if a C function returns a @samp{EEXIST} error. *) 150 (ErrorDesc) 151 END; 152 FileBusy* = POINTER TO FileBusyDesc; 153 FileBusyDesc = RECORD 154 (**This exception is raised if a C function returns a @samp{EBUSY} error. *) 155 (ErrorDesc) 156 END; 157 InvalidArgument* = POINTER TO InvalidArgumentDesc; 158 InvalidArgumentDesc = RECORD 159 (**This exception is raised if a C function returns a @samp{EINVAL} error. *) 160 (ErrorDesc) 161 END; 162 OutOfRange* = POINTER TO OutOfRangeDesc; 163 OutOfRangeDesc = RECORD 164 (**This exception is raised if a C function returns a @samp{ERANGE} error. *) 165 (ErrorDesc) 166 END; 167 168TYPE 169 NotImplemented* = POINTER TO NotImplementedDesc; 170 NotImplementedDesc = RECORD 171 (**Raised when a method is called that is not implemented for a particular 172 channel. Note: This should be moved into module @omodule{Exception} and 173 marked as an unchecked exception. *) 174 (ErrorDesc) 175 END; 176 FormatError* = POINTER TO FormatErrorDesc; 177 FormatErrorDesc = RECORD 178 (**Raised if input data does not satisfy the expected format. For example, 179 because the required number of bytes cannot be read from the channel, 180 or because the data is syntactically wrong. *) 181 (ErrorDesc) 182 END; 183 ProtocolError* = POINTER TO ProtocolErrorDesc; 184 ProtocolErrorDesc* = RECORD 185 (**Raised if malformed data is received from the remote side of a 186 conversation. This is @emph{not} used for responses that indicate failure 187 to process a request. An example for a protocol error is an NNTP response 188 message that does not begin with a three digit status code. After such an 189 error, the connection should be closed immediately. *) 190 (ErrorDesc) 191 END; 192 ErrorResponse* = POINTER TO ErrorResponseDesc; 193 ErrorResponseDesc* = RECORD 194 (**Raised if the remote side of a conversation sends a reply with an error 195 status code. *) 196 (ErrorDesc) 197 END; 198 199 200PROCEDURE (e: Error) INIT*(msg: STRING); 201 BEGIN 202 e.INIT^(msg); 203 END INIT; 204 205PROCEDURE NewFormatError*(msg: STRING): FormatError; 206 BEGIN 207 RETURN NEW(FormatError, msg); 208 END NewFormatError; 209 210PROCEDURE RaiseFormatError*(msg: STRING) 211RAISES FormatError; 212 BEGIN 213 RAISE(NewFormatError(msg)); 214 END RaiseFormatError; 215 216PROCEDURE RaiseNotImplemented*() 217RAISES NotImplemented; 218 BEGIN 219 RAISE(NEW(NotImplemented, NIL)); 220 END RaiseNotImplemented; 221 222PROCEDURE (k: SelectionKey) INIT*(fd: FileDescriptor; 223 selector: Selector; channel: Channel; 224 ops: SET; attachment: Object.Object); 225 BEGIN 226 k.fd := fd; 227 k.interestOps := ops; 228 k.attachment := attachment; 229 k.selector := selector; 230 k.channel := channel; 231 k.cancel := FALSE; 232 END INIT; 233 234PROCEDURE (k: SelectionKey) Attach*(obj: Object.Object); 235(**Set @ofield{k.attachment} to @oparam{obj}. *) 236 BEGIN 237 k.attachment := obj; 238 END Attach; 239 240PROCEDURE (k: SelectionKey) Cancel*; 241(**Mark key @oparam{k} as canceled. The key is immediately eliminated from the 242 channels's list of keys. It is removed from the selector's key list with 243 the next call to @oproc{Selector.Select}. Closing a channel cancels all its 244 selection keys. *) 245 BEGIN 246 IF ~k.cancel THEN 247 k.cancel := TRUE; 248 k.selector.cancel := TRUE; 249 END; 250 END Cancel; 251 252PROCEDURE (k: SelectionKey) SetInterestOps*(ops: SET); 253(**Set @ofield{k.interestOps} to @oparam{ops}. *) 254 BEGIN 255 k.interestOps := ops; 256 END SetInterestOps; 257 258 259PROCEDURE (s: Selector) INIT*(); 260 BEGIN 261 s.keys := NIL; 262 s.cancel := FALSE; 263 END INIT; 264 265PROCEDURE (s: Selector) Close*(); 266(**Cancel all selection keys registered for the selector @oparam{s} and close 267 the selector. *) 268 VAR 269 k: SelectionKey; 270 BEGIN 271 k := s.keys; 272 WHILE (k # NIL) DO 273 k.Cancel(); 274 k := k.nextKey; 275 END; 276 s.keys := NIL; 277 END Close; 278 279PROCEDURE (s: Selector) [ABSTRACT] Select*(sec, usec: LONGINT): LONGINT 280RAISES Error; 281(**Determine if operations on registered channels are ready. The function 282 returns the number of channels with a non-empty ready set. Result is 283 @samp{0} if no channels are ready or have become ready until the time the 284 specified timeout expires. If this function is called with a channel 285 already being ready, then it behaves as if a timeout of zero had been 286 requested. 287 288 After a call to @oproc{Selector.Select}, the method @oproc{Selector.NextKey} 289 iterates over all ready channels. *) 290 END Select; 291 292PROCEDURE (s: Selector) [ABSTRACT] NextKey*(): SelectionKey; 293(**Return the next selection key of selector @oparam{s} with a non-empty 294 intersection of @ofield{SelectionKey.interestOps} and 295 @ofield{Channel.readyOps}. Result is @code{NIL} if no such channel exists. *) 296 END NextKey; 297 298PROCEDURE (s: Selector) [ABSTRACT] AddSelectionKey*(fd: FileDescriptor; 299 channel: Channel; 300 ops: SET; 301 attachment: Object.Object): SelectionKey; 302(**Private method of the selector. Create and initialize a selection key. 303 The caller is responsible for adding the key to the selector. *) 304 END AddSelectionKey; 305 306PROCEDURE (s: Selector) [ABSTRACT] RemoveSelectionKey*(k: SelectionKey); 307(**Private method of the selector. Do any bookkeeping require to eliminate the 308 selection key. The caller is responsible for removing the key from the 309 selector's list of keys. *) 310 END RemoveSelectionKey; 311 312PROCEDURE (s: Selector) RemoveCanceled*(); 313(**Removes all keys that have been marked as ``canceled'' from the selector. 314 This is a private method, and should only be called from 315 @oproc{Selector.Select}. *) 316 VAR 317 prev, k: SelectionKey; 318 BEGIN 319 IF s.cancel THEN 320 prev := NIL; 321 k := s.keys; 322 WHILE (k # NIL) DO 323 IF k.cancel THEN 324 s.RemoveSelectionKey(k); 325 IF (prev = NIL) THEN 326 s.keys := k.nextKey; 327 ELSE 328 prev.nextKey := k.nextKey; 329 END; 330 ELSE 331 prev := k; 332 END; 333 k := k.nextKey; 334 END; 335 END; 336 END RemoveCanceled; 337 338 339PROCEDURE (ch: Channel) INIT*(); 340 BEGIN 341 ch.readyOps := {}; 342 NEW(ch.keys, 2); 343 ch.keys[0] := NIL; 344 END INIT; 345 346PROCEDURE (ch: Channel) [ABSTRACT] FileDescriptor*(): FileDescriptor; 347(**Return the file descriptor of the channel. This is the integer number 348 that is used to identify the channel on the level of the C library. 349 If the channel is not associated with a file descriptor, result is 350 @samp{-1}. *) 351 END FileDescriptor; 352 353PROCEDURE (ch: Channel) RegisterWithSelector*(sel: Selector; 354 ops: SET; 355 attachment: Object.Object): SelectionKey; 356(**Register the channel @oparam{ch} with the selector @oparam{sel}. If such a 357 registration already exists, then return the old selection key. Otherwise, 358 create a new key with an interest set @oparam{ops} and attachment 359 @oparam{attachment} and return it. *) 360 VAR 361 k: SelectionKey; 362 n: SelectionKeyList; 363 i, j: LONGINT; 364 BEGIN 365 i := 0; 366 WHILE (ch.keys[i] # NIL) DO 367 IF (ch.keys[i].selector = sel) THEN (* key already exists: return it *) 368 RETURN ch.keys[i]; 369 END; 370 INC(i); 371 END; 372 IF (i+1 = LEN(ch.keys^)) THEN 373 NEW(n, LEN(ch.keys^)*2); 374 FOR j := 0 TO i DO 375 n[i] := ch.keys[i]; 376 END; 377 ch.keys := n; 378 END; 379 ch.keys[i+1] := NIL; 380 k := sel.AddSelectionKey(ch.FileDescriptor(), ch, ops, attachment); 381 ch.keys[i] := k; 382 RETURN k; 383 END RegisterWithSelector; 384 385PROCEDURE (ch: Channel) KeyForSelector*(sel: Selector): SelectionKey; 386(**Return selection key of @oparam{ch} for selector @oparam{sel}. Result is 387 @code{NIL} if the channel is not registered with the selector. *) 388 389 VAR 390 i: LONGINT; 391 BEGIN 392 i := 0; 393 WHILE (ch.keys[i] # NIL) & (ch.keys[i].selector # sel) DO 394 INC(i); 395 END; 396 RETURN ch.keys[i]; 397 END KeyForSelector; 398 399PROCEDURE (ch: Channel) [ABSTRACT] SetBlocking*(block: BOOLEAN) 400RAISES Error; 401(**Change the channel's blocking mode. Channels typically default to 402 blocking mode on creation. 403 404 If a channel does not support non-blocking operation, then any call to this 405 method is ignored. Rider implementations from @omodule{*IO:BinaryRider} and 406 @omodule{*IO:TextRider} only work with blocking channels. *) 407 END SetBlocking; 408 409PROCEDURE (ch: Channel) Close*() 410RAISES Error; 411(**Cancel all selection keys registered for the channel @oparam{ch} and close 412 the channel. *) 413 VAR 414 i: LONGINT; 415 BEGIN 416 i := 0; 417 WHILE (ch.keys[i] # NIL) DO 418 ch.keys[i].Cancel(); 419 INC(i); 420 END; 421 END Close; 422 423PROCEDURE (ch: Channel) CloseAndRegister*() 424RAISES Error; 425(**Like @oproc{Channel.Close}, but register the channel's target with its 426 naming service once done. Right now, only @omodule{*IO:FileChannel} 427 supports this feature; see @oconst{*IO:FileChannel.tmpFile} for details. 428 By default, this method simply calls @oproc{Channel.Close}. *) 429 BEGIN 430 ch.Close(); 431 END CloseAndRegister; 432 433PROCEDURE (ch: ByteChannel) INIT*(); 434 BEGIN 435 ch.INIT^(); 436 END INIT; 437 438PROCEDURE (ch: Channel) SetPos*(pos: LONGINT) 439RAISES Error; 440(**Change the channels position to @oparam{pos}. *) 441 BEGIN 442 RaiseNotImplemented(); 443 END SetPos; 444 445PROCEDURE (ch: ByteChannel) [ABSTRACT] Read*(VAR buffer: ARRAY OF SYSTEM.BYTE; 446 start, length: LONGINT): LONGINT 447RAISES Error; 448(**Read a sequence of bytes from the channel into the buffer. 449 450 An attempt is made to read up to @oparam{length} bytes from the channel. 451 The bytes are written to @oparam{buffer}, starting at position 452 @oparam{start}. Result is the number of bytes actually read, or @samp{-1} 453 if the read position is at the end of the channel, and @oparam{length} 454 is not zero. 455 456 A read operation might not read @oparam{length} bytes, and in fact it might 457 not read any bytes at all. Whether or not it does so depends upon the 458 nature and state of the channel. A socket channel in non-blocking mode, for 459 example, cannot read any more bytes than are immediately available from the 460 socket's input buffer; similarly, a file channel cannot read any more bytes 461 than remain in the file. It is guaranteed, however, that if a channel is in 462 blocking mode and there is at least one byte remaining in the buffer then 463 this method will block until at least one byte is read. 464 465 @precond 466 @samp{0 <= @oparam{start} <= @oparam{start}+@oparam{length} <= 467 LEN(@oparam{buffer})} and @samp{@oparam{length} >= 0}. 468 @end precond *) 469 END Read; 470 471PROCEDURE (ch: ByteChannel) [ABSTRACT] Write*(buffer[NO_COPY]: ARRAY OF SYSTEM.BYTE; 472 start, length: LONGINT): LONGINT 473RAISES Error; 474(**Write a sequence of bytes to this channel from the buffer. 475 476 An attempt is made to write up to @oparam{length} bytes to the channel. The 477 bytes are taken from @oparam{buffer}, beginning at position @oparam{start}. 478 479 A write operation can return after writing less than @oparam{length} bytes. 480 That is, some types of channels, depending upon their state, may write only 481 some of the bytes or possibly none at all. A socket channel in non-blocking 482 mode, for example, cannot write any more bytes than are free in the socket's 483 output buffer. Result is the number of bytes actually written. 484 485 @precond 486 @samp{0 <= @oparam{start} <= @oparam{start}+@oparam{length} <= 487 LEN(@oparam{buffer})} and @samp{@oparam{length} >= 0}. 488 @end precond *) 489 END Write; 490 491PROCEDURE (ch: ByteChannel) Flush*() 492RAISES Error; 493(**Flush all buffers associated with channel @oparam{ch}. *) 494 END Flush; 495 496PROCEDURE (ch: ByteChannel) TransferTo*(length: LONGINT; 497 target: ByteChannel): LONGINT 498RAISES Error; 499(**Transfer upto @oparam{length} bytes from channel @oparam{ch} to 500 @oparam{target}. Result is the number of bytes actually copied. *) 501 CONST 502 sizeBuffer = 8*1024; 503 VAR 504 buffer: ARRAY sizeBuffer OF SYSTEM.BYTE; 505 i, j, rd, wd: LONGINT; 506 BEGIN 507 i := 0; 508 WHILE (i # length) DO 509 rd := ch.Read(buffer, 0, sizeBuffer); 510 IF (rd = -1) THEN (* end of channel *) 511 RETURN i; 512 ELSE 513 j := 0; 514 WHILE (j # rd) DO 515 wd := target.Write(buffer, j, rd-j); 516 IF (wd = -1) THEN 517 RETURN i+j; 518 ELSE 519 INC(j, wd); 520 END; 521 END; 522 INC(i, rd); 523 END; 524 END; 525 RETURN i; 526 END TransferTo; 527 528END IO. 529