[net.sources] OSSI: SIBlockIO

biagioni@unc.UUCP (Edoardo Biagioni) (11/06/86)

(***************************************************************************)
(***                                                                     ***)
(***                                                                     ***)
(***                        O  S  S  I                                   ***)
(***                        ==========                                   ***)
(***                                                                     ***)
(**)               DEFINITION MODULE SIBlockIO;                          (**)
(***               ===========================                           ***)
(***                                                                     ***)
(***   This module allows block access to mass storage devices,          ***)
(***   thus enabling the user to implement his/her own input/output.     ***)
(***   The module only provides primitive, unsafe low level              ***)
(***   I/O operations.                                                   ***)
(***                                                                     ***)
(***---------------------------------------------------------------------***)
(***                                                                     ***)
(***   Hardware:             VAX-11                                      ***)
(***   Operating System:     UNIX BSD 4.2                                ***)
(***   Compiler:             independent                                 ***)
(***                                                                     ***)
(***   Version:      3.0                                                 ***)
(***   Implemented:  see copyright                                       ***)
(***   Date:         1986-03-11                                          ***)
(***                                                                     ***)
(***---------------------------------------------------------------------***)
(***                                                                     ***)
(***   Copyright 1984, 1985, 1986 by                                     ***)
(***      E. S. Biagioni                                                 ***)
(***      G. Heiser                                                      ***)
(***      K. Hinrichs                                                    ***)
(***      C. Muller                                                      ***)
(***                                                                     ***)
(***   Institut fuer Informatik                                          ***)
(***   ETH Zuerich                                                       ***)
(***   CH 8092 Zuerich                                                   ***)
(***   Switzerland                                                       ***)
(***                                                                     ***)
(***   Department of Computer Science                                    ***)
(***   University of North Carolina                                      ***)
(***   Chapel Hill, North Carolina 27514                                 ***)
(***   U.S.A.                                                            ***)
(***                                                                     ***)
(*** Permission to copy without fee all of this material is granted      ***)
(*** provided that the copies are not made or distributed for direct     ***)
(*** commercial advantage, that this OSSI copyright notice is            ***)
(*** included in the copy, that the module is not modified in any way    ***)
(*** except where necessary for compilation on a particular system,      ***)
(*** and that the module is always distributed in its original form.     ***)
(*** Distribution of this module in a modified form without including    ***)
(*** the original version is a violation of this copyright notice.       ***)
(***                                                                     ***)
(***---------------------------------------------------------------------***)
(***                                                                     ***)
(***   Updates:                                                          ***)
(***                                                                     ***)
(***                                                                     ***)
(***************************************************************************)

(* Storage is allocated in pieces called "segments", each segment
   consisting of an integral number of blocks.
   Blocks are of a fixed size, namely "BlockLength" bytes.
   The implementation of the module should attempt to allocate a contiguous
   section of memory for each segment; in any case it must give the user
   the illusion of contiguous segments.

   Segments are located on devices. The meaning of "device", and the syntax
   of a DeviceName is system dependent and will in general conform with
   system conventions.

   A device is made accessible by a call to OpenDevice. This procedure
   accepts a string containing the device name and, if successful,
   returns a DeviceId. The DeviceId is used in all further SIBlockIO
   operations on that particular device and the segments on the device.

   A particular device can be opened more than once at the same time,
   a different DeviceId will be returned by each open operation.

   If a device is no longer needed, it must be closed by a call to
   CloseDevice. This call dissasociates the DeviceId from the DeviceName
   (and the physical device) and guarantees a consistent state of the data
   stored on the device. After closing a device, the DeviceId must not
   be used again.

   W a r n i n g: Devices left open at program termination time are in an
   undefined state. Some of their data may be corrupted or unaccessible.

   Each segment on a particular device is uniquely identified by a
   "SegmentId" which serves as the user's address of the segment.

   It is the user's sole responsibility to manage his/her segments, that is
   to remember and properly use their respective ids and sizes.
   To this purpose the system provides for the usage of "NamedBlocks" in
   which the user can implement his/her directories.
   A NamedBlock is a segment with some special properties:
      1) a NamedBlock has a name in addition to its id,
      2) a NamedBlock is always a segment of length 1 (blocks),
      3) a NamedBlock must never be allocated/deallocated using the regular
         allocation/deallocation procedures CreateSegment/DeleteSegment.
         An actual implementation may or may not detect violations of this
         rule.

   A block name is a character string. It is the user's identification of
   the NamedBlock (and all the segments managed by means of this block).
   For a given physical device (characterized by the deviceName), block names
   must be unique.

   In order to perform any I/O operation on the NamedBlock, a SegmentId
   must be attached to the block. This is done by a call to the procedure
   GetId, after the NamedBlock has been introduced by a call to
   CreateNamedBlock. The SegmentId is the user's address of the block,
   used to perform I/O operations by means of the procedures ReadSegment
   and WriteSegment.

   "Normal" segments are de/allocated using CreateSegment/DeleteSegment
   and I/O operations are performed on them using ReadSegment/WriteSegment.
   As mentioned before, it is the user's responsibility, using a NamedBlock
   or other means, to manage the ids and sizes of his/her segments.

   SIBlockIO input/output operations may be implemented asynchronously,
   provided the underlying system supports asynchronous I/O.
   That requires some care on the user's side: A call to ReadSegment will
   only initiate the physical I/O operation. Before accessing the data
   read into the user-supplied buffer, the user must await completion
   of the physical read operation. This is done by a call to the
   Synchronize procedure. Similarly a call to Synchronize must be performed
   after calling WriteSegment if the user-supplied buffer is to be
   modified afterwards. Of course, the call to Synchronize does not have to
   be performed immediately afterwards, the user can do other processing
   in between, thus possibly avoiding any delays due to waiting for I/O
   completion.

   There is an implicit synchronization done by the system before any further
   I/O operations are performed on the respective device. Hence an explicit
   call to Synchronize is not required, if a ReadSegment operation follows
   a WriteSegment call or vice versa, or between successive calls to
   ReadSegment or WriteSegment using different buffers.

   The main requirement to any implementation is to minimize the number of
   physical I/O operations for the procedures ReadSegment and WriteSegment.
   The procedures CreateSegment, DeleteSegment, CreateNamedBlock and
   DeleteNamedBlock may be much more expensive in terms of physical I/O
   operations. *)

FROM SISystem IMPORT
  SIResult,
  BYTE;

EXPORT QUALIFIED
  DeviceNameLength,
  BlockNameLength,
  DeviceIdLength,
  SegmentIdLength,
  BlockLength,
  DefaultDeviceName,
  DeviceName,
  DeviceId,
  BlockName,
  SegmentId,
  Block,
  ConsistencyCheck,
  OpenDevice,
  CloseDevice,
  CreateNamedBlock,
  DeleteNamedBlock,
  GetId,
  CreateSegment,
  DeleteSegment,
  ReadSegment,
  WriteSegment,
  Synchronize,
  GetIOCounts;

CONST DeviceNameLength  = 255;   (* VAX *)
      BlockNameLength   =  24;
      DeviceIdLength    =   1;
      SegmentIdLength   =   2;
      BlockLength       = 512;   (* VAX *)

TYPE DeviceName        = ARRAY [0 .. DeviceNameLength - 1] OF CHAR;
     BlockName         = ARRAY [0 .. BlockNameLength - 1]  OF CHAR;
     DeviceId          = ARRAY [0 .. DeviceIdLength - 1]   OF BYTE;
     SegmentId         = ARRAY [0 .. SegmentIdLength - 1]  OF BYTE;
     Block             = ARRAY [0 .. BlockLength - 1]      OF BYTE;

CONST DefaultDeviceName = "~/.BlockIO";   (* Unix *)

(* The meaning of 'result' in the following procedures is machine-dependent,
   but a successfull operation always returns result=SIDone . *)

PROCEDURE ConsistencyCheck (VAR result: SIResult);
(* checks the external directory structure for consistency and for
   agreement with the internal data structure.
   If an inconsistency is found, result<>SIDone on return *)

PROCEDURE OpenDevice (devicename: DeviceName; VAR device: DeviceId;
                      VAR result: SIResult);
(* opens the designated device for usage by SIBlockIO and associates it with
   the DeviceId returned. If the device does not exist or is not (currently)
   accessible, result<>SIDone on return *)

PROCEDURE CloseDevice (device: DeviceId; VAR result: SIResult);
(* dissociates the DeviceId from the corresponding device, making it
   unaccessible by SIBlockIO. If the DeviceId does not designate an
   opened device, result<>SIDone on return *)

PROCEDURE CreateNamedBlock (device: DeviceId; blockname: BlockName;
                            VAR result: SIResult);
(* associates a block on device with the given blockname, for later opening
   by GetId or deleting by DeleteNamedBlock, or both. If a block with this
   name exists already, result<>SIDone *)

PROCEDURE DeleteNamedBlock (device: DeviceId; blockname: BlockName;
                            VAR result: SIResult);
(* deletes the block name so that no block is associated with the name.
   If no such name was found, result <> SIDone *)

PROCEDURE GetId (device: DeviceId; blockname: BlockName;
		 VAR segmentid: SegmentId;
                 VAR result: SIResult);
(* returns the id associated with the given block name. If no such name
   was found, result <> BlockIODone. The segmentid returned should not
   be used in a call to DeleteSegment *)


(* a segment is a set of contiguously allocated blocks. The user is
   responsible for remembering the size of a segment and for using
   the same size in each procedure call. Failure to observe this rule
   may result in serious disk and system errors *)

PROCEDURE CreateSegment (device: DeviceId; numberofblocks: CARDINAL;
                         VAR segmentid: SegmentId; VAR result: SIResult);
(* Returns an identifier for numberofblocks contiguous free (not allocated)
   blocks. If no space is available for such a segment, result <> SIDone *)

PROCEDURE DeleteSegment (device: DeviceId; numberofblocks: CARDINAL;
                         segmentid: SegmentId; VAR result: SIResult);
(* Deletes the block set identified by segmentid. numberofblocks must be
   the same as was used for the corresponding call to CreateSegment *)

PROCEDURE ReadSegment (device: DeviceId; numberofblocks: CARDINAL;
                       segmentid: SegmentId; VAR blocks: ARRAY OF Block;
                       VAR result: SIResult);
(* initiates reading numberofblocks blocks identified by segmentid.
   For correct operation, the following conditions must be satisfied:
    - numberofblocks <= <numberofblocks declared in CreateSegment>
    - numberofblocks <= HIGH (blocks) + 1
    - the segment to be read must have been written before. *)

PROCEDURE WriteSegment (device: DeviceId; numberofblocks: CARDINAL;
                        segmentid: SegmentId; VAR blocks: ARRAY OF Block;
                        VAR result: SIResult);
(* initiates writing numberofblocks blocks identified by segmentid.
   For correct operation, the following conditions must be satisfied:
    - numberofblocks <= <numberofblocks declared in CreateSegment>
    - numberofblocks <= HIGH (blocks) + 1 *)

PROCEDURE Synchronize (device: DeviceId; VAR result: SIResult);
(* awaits completion of any previously initiated I/O operation on
   the specified device.
   Returns  result = SIDone  if the previously initiated I/O operation
   is completed sucessfully or if there was no I/O operation initiated.
   Otherwise  result # SIDone  on return.
   Note that in this case result will indicate an error occured during the
   execution of the previously initiated I/O operation. *)

PROCEDURE GetIOCounts (device: DeviceId;
                       VAR userReadCount,   userWriteCount,
                           systemReadCount, systemWriteCount: CARDINAL;
                       VAR result: SIResult);
(* returns the number of physical I/O operations performed on the device.
   userReadCount,   userWriteCount:   number of user I/O operations
                                      (calls to ReadSegment/WriteSegment)
   systemReadCount, systemWriteCount: number of I/O operations due to
                                      system overhead *)

END SIBlockIO.