PPP Exercises: External Code and Data


Exercise: Binding to external code

Assume there is this module written in C that you want to use from Tycoon. You can bind TL functions to C functions using the builtin-function 'bind', e.g.
Let T(E <:Ok) <:Ok = word.Handle(E)
let lib = runtimeCore.auxiliaryLibraryName("test")
let list_new = bind(:Fun(E <:Ok) :T(E)  lib "list_new" "w")                      
Create a new subdirectory 'src/test' and use this library definition:
library test
with
  library machineenv stdenv bulkenv
  interface
    CList
  module
    cList :CList
end;
Write an implementation 'cList.tm' for this interface 'CList.ti' using the C functions from the C module 'test.c':
interface CList
(* System:  test
   File:    CList.ti
   Author:  Gerald Schr"oder
   Date:    24-jun-1996
   Purpose: Lists using C functions
*)
export

  T(E <:Ok) <:Ok
  (* Type of polymorphic lists. *)

  error :Exception end
  (* Raised when trying to access freed list. *)

  new(E <:Ok) :T(E)
  (* Create a new (empty) list. *)

  insert(E <:Ok  :T(E)  :E) :Ok
  (* Insert an element into the list. Raise error if list has been freed. *)

  iterate(E <:Ok  :T(E)  :Fun(:E) :Ok) :Ok
  (* Call iteration function for each element of the list. 
     Raise error if list has been freed. *)

  free(E <:Ok  :T(E)) :Ok
  (* Free list. Do not call 'insert', 'iterate' or 'free' on this list again! 
     Raise error if list has been freed. *)

end;
Test your implementation with:
do makeLibraries test;
import print cList;

Let Person = Tuple name :String  age :Int end;
let peter = tuple "Peter" 22 end;
let paul = tuple "Paul" 32 end;
let mary = tuple "Mary" 28 end;

let printPerson(p :Person) :Ok =
begin
  print.string(p.name)
  print.string(" (")
  print.int(p.age)
  print.string(")\n")
end;

let myList = cList.new(:Person);
cList.insert(myList peter);
cList.insert(myList paul);
cList.insert(myList mary);
cList.iterate(myList printPerson);
cList.free(myList);
Hints: Take the definitions of 'T' and 'list_new' given above as a starting point. Use (only) the modules 'runtimeCore', 'word' and 'cCallback' from 'machineenv'. Note the parameter descriptions 'w' for C values and '=' for TL values. Refer to other module implementations using the 'bind' construct.

Exercise: Persistence of transient (volatile) data

Try this example with your implementation written in the previous exercise:
tycoon -create -store test.ts
do makeLibraries test;
import print cList;
Let Person = Tuple name :String  age :Int end;
let peter = tuple "Peter" 22 end;
let paul = tuple "Paul" 32 end;
let mary = tuple "Mary" 28 end;

let printPerson(p :Person) :Ok =
begin
  print.string(p.name)
  print.string(" (")
  print.int(p.age)
  print.string(")\n")
end;

let myList = cList.new(:Person);
cList.insert(myList peter);
cList.insert(myList paul);
cList.insert(myList mary);
cList.iterate(myList printPerson);
do saveSystem;
cList.free(myList);
do exit;
tycoon -restart -store test.ts
cList.iterate(myList printPerson);
This may lead to bus errors or other unpredictable behaviour. Why? Think about the two storage areas: the persistent Tycoon store and the transient C heap. Try to paint a map with references between these stores, i.e. where are pointers from the Tycoon to store to the C heap and vice versa? What happens if the Tycoon store is stabilized? Where does this leave the transient data, the pointers to transient data and the references from the external data to the Tycoon store objects? When should the transient C heap objects be deallocated? (Note that this cannot be done automatically in Tycoon yet. Refer to Deallocating transient data structures.) When should the transient C heap objects be allocated again?

Taking this into account, rewrite the implementation of 'cList' using tge module 'volatile' from 'machineenv' to reconstruct the transient data on restart. Test with the script above, but insert the statements

import volatile;
volatile.recreateAll();
after restart before calling 'cList.iterate'.
Gerald Schröder, 1996