Chapter 6 
=========

  The Runtime System 


  
6.1 Introduction 
================

  The Eiffel/S runtime  system has manifold  responsibilities such as 
  memory  management,  garbage collection,  exception  handling, etc. 
  Most of the functions  of the runtime system  are not accessible to 
  the  programmer.  However,  as we  explained  in  the  previous two 
  chapters, you can use some of the services of the runtime system in 
  C routines. 


  With some of the functions you are  likely to ask why they are made 
  available since  there are  analogous functions  in the  standard C 
  library. The most important reason is that the functions offered by 
  the     Eiffel/S    runtime   system    are   guaranteed    to   be 
  platform--independent.  Another reason  is  that later  releases of 
  Eiffel/S  will  gather  statistics  and  make  profiles  of  Eiffel 
  programs that will for  example help you get  a precise idea of the 
  memory demands of  your programs. For  this to work  you should not 
  circumvent  the  runtime  system  by  calling  external  C  library 
  functions. 


 
6.2 Presentation
================ 

  To keep the  presentation compact the  function prototypes given in 
  the following sections will use  the Eiffel conventions even though 
  we are talking about C routines. 


  Unless  the contrary  is explicitly  stated  a precondition  of all 
  functions described is that their arguments are not void. 


  
6.3 Treatment of errors 
=======================

  All  runtime functions  test their  arguments for  correctness (for 
  example    void  tests).   If  a   precondition  is   violated  the 
  corresponding exception is raised.  A runtime function thus returns 
  to  its caller  only  if it  could  carry out  its  task correctly. 
  Otherwise control is returned to the last routine that had a rescue 
  clause. You  can also  include rescue  clauses in  your C functions 
  (see the section on exceptions) in order to handle errors. 


  The list of  the exception codes  can be found  in the Eiffel class 
  EXCEPTION and in the include file eiffel.h. 


  
6.4 Strings 
===========

  Strings are special objects in  Eiffel. The runtime system provides 
  the following functions for manipulating strings: 

  CHARACTER *RSTR_seq (string : OBJREF) 

  Returns a pointer to the C string that is stored in string. 

Remark 

  If the string is empty (i.e. count  = 0) the result will be a null 
  pointer. See also Chapter 4. 


  INTEGER RSTR_count (string : OBJREF) 

  Returns the length in characters of the string. 

  OBJREF RSTR_create (c_string : CHARACTER *) 

  Converts the C  string into an  Eiffel object of  type STRING. The 
  Eiffel object gets a private copy of the string. 


  
6.5 Arrays
========== 

  You will find a more detailed  discussion of the array functions in 
  Chapter 4. 

  CHARACTER *RARR_seq (array : OBJREF) 

  Returns a pointer to the data area of the array. 

Remark 

  If the  array has  size 0  (i.e. size  = 0)  the result  is a null 
  pointer. 

  The pointer always points to the first element in the array (index
  lower). SO on the C side of the world, indexing is 0 .. RARR_size - 1.

  INTEGER RARR_size (array : OBJREF) 

  Size of the array. The available indices are 0 .. RARR_size -1. 

  CHARACTER RARR_type (array : OBJREF) 

  Returns a character specifying the actual generic parameter. Please 
  see Chapter 4 for more details. 


  
6.6 Bits 
========

  Here too we  refer the reader to  Chapter 4 where  the type BITS is 
  discussed more thoroughly. 

  CHARACTER *RBIT_seq (bits : OBJREF) 

  Returns a C array containing the actual bit sequence --- 8 bits per 
  CHARACTER. 

  INTEGER RBIT_count (bits : OBJREF) 

  Returns the number of bits stored in the object. 


Remark 

  If you  create an instance  of BITS  n then the  result returned by 
  RBIT_count is exactly n. 

  OBJREF RBIT_make (string : CHARACTER *) 

  Converts  the  bit constant  string,  which may  only  contain the 
  characters 0 and 1, into an object of type BITS n, where n is the 
  length of the string. 


  
6.7 Files 
=========

  The  Eiffel/S  runtime  system provides  you  with  the  usual file 
  functions of the C library in a form that is platform--independent. 
  A  further  advantage  of  these functions  is  that  they  use the 
  internal   runtime  file   manager,  which  permits   you  to  keep 
  arbitrarily many files ``open''  --- independent of any limitations 
  imposed by the  operating system. Moreover the  file manager uses a 
  buffer cache which accelerates the file operations. 


  The reader is also referred to  the chapter on the class FILE_SYS 
  in the library  manual. There one finds  a more detailed discussion 
  of these functions. 

  INTEGER RFM_open (path, mode : CHARACTER *, truncate : BOOLEAN) 

  Opens the file path in the mode mode. If truncate is true then the 
  file is truncated  to length 0  upon opening. If  the file does not 
  yet exist it will be automaticallly created. 


  The  result  of the  function  is  an integer,  the  ``hook''. This 
  integer will  be needed for  the other file  functions; it uniquely 
  identifies the file.  If the same file  is ``opened'' several times 
  you will always get the same hook! 


Remark 


  Please read  the section on  access_file in Section  3.5.2 of the 
  library manual. There  you will find among  other things a complete 
  description of the structure of the string mode. 

  void RFM_close (hook : INTEGER) 

  Closes the file  that belongs to  hook. If the  same file has been 
  opened several times it must be closed correspondingly often. It is 
  not an error never to close a file; this will be done automatically 
  when  the  program  terminates.  However  it  is  good  programming 
  practice  to close  all  files not  needed  any longer;  this saves 
  memory and lightens the burden of the file manager. 

  INTEGER  RFM_read (hook  :  INTEGER, 
                     buf   :  CHARACTER *,  
                     nbytes:  INTEGER ) 

  Reads nbytes  bytes from  the file  that belongs  to hook  into the 
  buffer buf. The result is the  number of bytes actually read. If a 
  read error occurs an exception will be raised. 



  Important Remark 
  ================

  Never use this function with  Eiffel/S files --- with the exception 
  of the types FILE [ BOOLEAN ], FILE [ CHARACTER ], FILE [ INTEGER 
  ] and  FILE [ REAL  ], which are  in fact flat  files of CHARACTER 
  resp. INTEGER  resp. REAL. The  function is intended  for use with 
  ``external'' files. 

  void RFM_write (hook  : INTEGER, 
                  buf   : CHARACTER *, 
                  nbytes: INTEGER) 

  Writes nbytes bytes from the buffer buf to the file that belongs to 
  hook. If  fewer than  nbytes bytes  could be  written an exception 
  will be raised. 


  Important Remark 
  ================
 
  Never use this function with  Eiffel/S files --- with the exception 
  of the types FILE [ CHARACTER ],  FILE [ INTEGER ] and FILE [ REAL 
  ], which are in  fact flat files of  CHARACTER resp. INTEGER resp. 
  REAL. The function is intended for use with ``external'' files. 

  void RFM_seek (hook, position : INTEGER) 

  Positions the  internal file  pointer of  the file  that belongs to 
  hook to  position. These are  absolute positions  beginning at the 
  beginning of the file (pos = 0). 


  In addition we have the following functions of the file system that 
  are  implemented in  the Eiffel  class  FILE_SYS. We  omit their 
  description here. Please read the corresponding sections in Chapter 
  3 of the Eiffel/S library manual. 


  Important Remark 
  ================
  The runtime file system uses  a static buffer for various purposes. 
  Each of  the following  functions that  returns a  CHARACTER * uses 
  this buffer  and the pointer  returned points to  it. Therefore you 
  should always  copy the  result of such  a function  into a private 
  buffer immediately! 

  void RFS_add_cluster (cluster, permissions : CHARACTER *) 

  void RFS_remove_cluster (cluster : CHARACTER *) 

  BOOLEAN RFS_cluster_exists (cluster : CHARACTER *) 

  void RFS_change_cluster (cluster : CHARACTER *) 

  CHARACTER *RFS_cluster_perm (cluster : CHARACTER *) 
  
  CHARACTER *RFS_my_cluster_perm (cluster : CHARACTER *) 
  
  REAL RFS_cluster_time (cluster : CHARACTER *) 
  
  INTEGER RFS_cluster_count (cluster : CHARACTER *) 
  
  INTEGER RFS_subcluster_count (cluster : CHARACTER *) 
  
  void RFS_change_cluster_perm (cluster, new_permissions : CHARACTER *) 

  CHARACTER *RFS_current_cluster () 
  
  void RFS_add_file (filename, permissions : CHARACTER *) 
  
  void RFS_remove_file (filename : CHARACTER *) 
  
  BOOLEAN RFS_file_exists (filename : CHARACTER *) 
  
  INTEGER RFS_file_count (filename : CHARACTER *) 
  
  REAL RFS_file_time (filename : CHARACTER *) 
  
  CHARACTER *RFS_file_perm (filename : CHARACTER *) 
  
  CHARACTER *RFS_my_file_perm (filename : CHARACTER *) 
  
  void RFS_change_file_perm (filename,  new_permissions : CHARACTER *) 
  
  CHARACTER *RFS_path_prefix (path : CHARACTER *) 
  
  CHARACTER *RFS_path_suffix (path : CHARACTER *) 
  
  CHARACTER *RFS_concat_paths (path1, path2 : CHARACTER *) 
  
  CHARACTER *RFS_absolute_path (path : CHARACTER *) 
  
  BOOLEAN RFS_same_path (path1, path2 : CHARACTER *) 



  
6.8 Environment 
===============

  Here  we only  give  the prototypes  of  the functions.  A detailed 
  discussion  can be  found in  Section 2.3  of the  Eiffel/S library 
  manual (class ENVIRON). 


  Important Remark 
  ================

  The runtime  system environment functions  use a  static buffer for 
  various purposes.  Each of the  following functions  that returns a 
  CHARACTER * uses this buffer and the pointer returned points to it. 
  Therefore you should always copy the result of such a function into 
  a private buffer immediately! 

  CHARACTER *RENV_program_name () 
  
  CHARACTER *RENV_arg_item (index : INTEGER) 
  
  INTEGER RENV_arg_count () 
  
  CHARACTER *RENV_env_item (env_var : CHARACTER *) 
  
  void RENV_env_put (env_var, new_text : CHARACTER *) 


  

6.9 Memory management 
=====================

  The  memory  management functions  are  to  be used  just  like the 
  familiar functions of the C library. 

  In  the event  that  an attempt  to fetch  memory  with one  of the 
  following  functions should  fail,  the garbage  collector  will be 
  activated. Should the  garbage collector not  succeed in collecting 
  enough memory  to fill  the request  an exception OUT_OF_MEMORY 
  will  be raised.  One can  intercept this  exception in  a suitable 
  rescue clause in order to  terminate the program gracefully. It may 
  be useful  to know  that the  system lays  aside a  small amount of 
  memory for  emergencies at program  startup. This  allows a minimal 
  functionality  to  be maintained  even  after  an OUT_OF_MEMORY 
  exception.  Do not  try to  go  very far  on this  reserved memory, 
  however! 


  Important Remark 
  ================

  * A pointer that was fetched  with the C library functions malloc, 
    realloc or calloc may only  be modified using these functions and 
    may only be freed using free. 


  * A pointer  that was fetched  with the  Eiffel/S runtime functions 
    RMM_alloc  or RMM_realloc  may only  be modified  using these 
    functions and may only be freed using RMM_free. 

    It is permissible to use the C library functions and the Eiffel/S 
  runtime functions in parallel but you should never mix them! 



  CHARACTER *RMM_alloc (size : INTEGER) 

  Precondition 

  positive_size : size > 0 

  Returns a block of  contiguous memory of size  bytes. The block has 
  been initialized with the character '\0'. 



  CHARACTER *RMM_realloc (old_ptr : CHARACTER *, new_size : INTEGER ) 

  Precondition 

  positive_size : new_size > 0 

  Returns a block of contiguous  memory of new_size bytes. If new_ 
  size is less than or equal to  the size of the block to which old_ 
  ptr points, then the  first new_size bytes of  the old block will 
  be copied into the new block (and any remainder is lost). Otherwise 
  the entire old block  is copied into the new  block and the rest is 
  filled with '\0'. 



  void RMM_free (ptr : CHARACTER *) 

  Returns the block pointed  to by ptr to  the memory pool. The value 
  of ptr may not be used after this call. 

  

6.10 Time 
=========


  The  time  unit of  the  Eiffel/S  runtime system  is  1  day. Time 
  calculations can be carried out for arbitrary times in the past and 
  the future (within the limits of precision of a REAL). 

  REAL RTM_now () 

  Returns the current Greenwich Mean Time. The unit is 1 day. 

  INTEGER RTM_clock () 

  Returns the time that has elapsed since the start of the program in 
  units of one millisecond (1/1000 sec). 


  
6.11 Exceptions 
===============

  Using the  following functions you  can raise  exceptions and build 
  rescue clauses into  your C routines  in order to  catch errors. Be 
  warned that you  must follow the rules  given exactly. Improper use 
  can lead to unpredictable behavior of your program. 

  void  RXM_raise (CHARACTER *routine_name,
                   CHARACTER *message,
                   INTEGER    code,
                   OBJREF     xobj)

  Raises  an  exception. message  is  an arbitrary  text  that should 
  describe the cause of  the exception. code is  a number that should 
  lie in the  range 1 ... 9999  . xobj is  an arbitrary Eiffel object 
  --- normally Current or VOIDREF. 

  CHARACTER *RXM_last_etext () 

  Returns  the  text  (called message  above)  of  the  last previous 
  exception. 

  INTEGER RXM_last_ecode () 

  Returns the  code of  the last  previous exception.  This code will 
  typically   be  used   in  a  rescue  clause   in  order  to  react 
  appropriately to each kind of exception. 

  OBJREF RXM_last_eobj () 

  Returns a  reference to  the object  attached to  the last previous 
  exception. This can be an arbitrary Eiffel object. 


  If  an  exception  is  not caught  by  any  rescue  clause, program 
  execution   is  terminated  with  the  message  ``System  execution 
  terminated abnormally''. In the ASCII file eiffel.err you will find 
  an exception history table. 



6.12 Garbage collection 
=======================

  Eiffel/S has  an automatic  garbage collector  that returns  to the 
  object manager all  objects which are no  longer needed. The memory 
  thus freed can be used for new objects. 


  
6.12.1 The method 

  Eiffel/S uses a mark--and--sweep  algorithm for garbage collection. 
  It does not  seem appropriate to  give an exact  description of the 
  mechanism in this context. We do, however, feel the need to explain 
  why we do not employ a (quasi--) parallel garbage collector. 


* Eiffel/S is offered for a wide variety of platforms. Almost none of 
  them offer the  necessary support through  the operating system --- 
  and much less the hardware --- that is required to register mutator 
  operations (the mutator is the running program). 


* Without  such  support  (e.g.  through  page  write  protection)  a 
  quasi--parallel GC incurs exorbitant mutator costs. 

    A further argument against a  quasi--parallel GC when there is no 
  OS-- or hardware support is that  the code produced by the compiler 
  must depend  upon whether  the GC is  being used  or not.  If it is 
  being used  then special  instructions for  the mutator  have to be 
  inserted into the code.  The result is that  users will tend not to 
  use  the garbage  collector in  order to  get compacter  and faster 
  code.  It  is  our conviction,  however,  that  an object--oriented 
  program without garbage collector is roughly the same as a pressure 
  cooker without a safety valve; sooner or later the thing is sure to 
  blow up! 

  For this reason the Eiffel/S garbage collector is always there. You 
  can turn it off  or set its ``threshold'' as  high as you like (see 
  below). But  you can  never prevent it  from being  activated in an 
  emergency. 

  Those wishing to learn more about garbage collection algorithms are 
  referred to [dij78] , [hey91] and [boe91]. 

  void RGAC_set_threshold (threshold : INTEGER) 

  The GC does not become active as  long as the program has used less 
  than threshold bytes  of dynamic storage ---  unless this number is 
  bigger than the amount of  actually available memory. In the latter 
  case the GC will naturally be activated sooner. 


  The default  value of threshold  is platform--dependent.  As a rule 
  one should not use this function.  One can also set threshold using 
  the RCL file (see Section 3.8.12). 

  void RGAC_enable_collector () 

  Turns the GC on. This is the default state. 

  void RGAC_disable_collector () 

  Turns the GC  off (conditionally). As we  remarked above you cannot 
  really turn the GC  off forever. If the  available memory should be 
  exhausted it will be  automatically reactivated. After carrying out 
  a full cycle of garbage collection it is turned off again. 

  void RGAC_force_collection () 

  Carries out a full garbage  collection independently of whether the 
  garbage collector is turned on or off. 

  void RGAC_protect (vars : OBJREF *, no_vars : INTEGER) 

  Adds the array of object references vars to the the list of ``roots 
  of the GC (sometimes also called the ``immune set''). This array is 
  to be understood as C array --- i.e. indexing begins at 0. 


  The meaning of  this instruction for  the GC is  the following: the 
  objects to which 

  vars [ 0 ] , vars [ 1 ] , ..., vars [ no_vars - 1 ] 

  point and  (recursively) all  of their  subobjects are  regarded as 
  ``live'', i.e. they may not be collected. 


  Always be  sure that  the array vars  is filled  with valid values: 
  either with  VOIDREFs or with  object references.  In addition you 
  should never ``protect''  a local array ---  unless you retract the 
  protection using RGAC_unprotect before leaving the routine. 


Example 

  OBJREF precious [ 10 ] ;
  OBJREF single; 

  void _my_routine (...) 
    ... 
    {
    ... /* Initialize "precious" with  VOIDREF's or valid OBJREF's */ 
    ... /* Initialize "single" with VOIDREF or valid OBJREF */ 
    RGAC_protect (precious, 10); 
    RGAC_protect (&single,  1); /* Note the & */ ... 
    }

  If you should forget the  unprotect instruction before a return the 
  garbage collector will eventually carry  out some operation with an 
  invalid stack address; the program is almost sure to crash then. 

  void RGAC_unprotect (vars : OBJREF *) 

  Removes the array vars from the list of roots. 
