Previous section   Next section

Practical Programming in Tcl & Tk, Third Edition
By Brent B. Welch

Table of Contents
Chapter 19.  Multiple Interpreters and Safe-Tcl

I/O from Safe Interpreters

A safe child interpreter cannot open files or network sockets directly. An alias can create an I/O channel (i.e., open a file or socket) and give the child access to it. The parent can share the I/O channel with the child, or it can transfer the I/O channel to the child. If the channel is shared, both the parent and the child can use it. If the channel is transferred, the parent no longer has access to the channel. In general, transferring an I/O channel is simpler, but sharing an I/O channel gives the parent more control over an unsafe child. The differences are illustrated in Example 19-7 and Example 19-9.

There are three properties of I/O channels that are important to consider when choosing between sharing and transferring: the name, the seek offset, and the reference count.

  • The name of the I/O channel (e.g., file4) is the same in all interpreters. If a parent transfers a channel to a child, it can close the channel by evaluating a close command in the child. Although names are shared, an interpreter cannot attempt I/O on a channel to which it has not been given access.

  • The seek offset of the I/O channel is shared by all interpreters that share the I/O channel. An I/O operation on the channel updates the seek offset for all interpreters that share the channel. This means that if two interpreters share an I/O channel, their output will be cleanly interleaved in the channel. If they both read from the I/O channel, they will get different data. Seek offsets are explained in more detail on page 114.

  • A channel has a reference count of all interpreters that share the I/O channel. The channel remains open until all references are closed. When a parent transfers an I/O channel, the reference count stays the same. When a parent shares an I/O channel, the reference count increments by one. When an interpreter closes a channel with close, the reference count is decremented by one. When an interpreter is deleted, all of its references to I/O channels are removed.

    The syntax of commands to share or transfer an I/O channel is:

    interp share interp1 chanName interp2
    interp transfer interp1 chanName interp2

In these commands, chanName exists in interp1 and is being shared or transferred to interp2. As with command aliases, if interp1 is the current interpreter, name it with {}.

The following example creates a temporary file for an unsafe interpreter. The file is opened for reading and writing, and the slave can use it to store data temporarily.

Example 19-7 Opening a file for an unsafe interpreter.
proc TempfileAlias {slave} {
   set i 0
   while {[file exists Temp$slave$i]} {
      incr i
   set out [open Temp$slave$i w+]
   interp transfer {}$out $slave
   return $out
proc TempfileExitAlias {slave} {
   foreach file [glob -nocomplain Temp$slave*] {
      file delete -force $file
   interp delete $slave
interp create -safe foo
interp alias foo Tempfile {}TempfileAlias foo
interp alias foo exit {}TempfileExitAlias foo

The TempfileAlias procedure is invoked in the parent when the child interpreter invokes Tempfile. TempfileAlias returns the name of the open channel, which becomes the return value from Tempfile, so the child knows the name of the I/O channel. TempfileAlias uses interp transfer to pass the I/O channel to the child, so the child has permission to access the I/O channel. In this example, it would also work to invoke the hidden open command to create the I/O channel directly in the slave.

Example 19-7 is not fully safe because the unsafe interpreter can still overflow the disk or create a million files. Because the parent has transferred the I/O channel to the child, it cannot easily monitor the I/O activity by the child. Example 19-9 addresses these issues.

      Previous section   Next section