EG: Simple implementation of 'fifo2' channel driver in pure Tcl. See also memchan.
package require Tcl 8.5 namespace eval memchan { variable id 0 # fifo2 handler. This is the body of a namespace ensemble. # Could be a tcloo class, but I want this code to run in 8.5 without extras too variable f2h { variable events "" variable data "" variable peerinfo "" proc initialize {chan mode} { return [list initialize finalize watch read write cget cgetall] } proc finalize {chan} { variable peerinfo set peerchan [dict get $peerinfo chan] if {$peerchan in [chan names]} { # close the peer channel chan close $peerchan } destroy } proc watch {chan evs} { variable events variable data set events $evs if {[string length $data] > 0 && "read" in $events} { chan postevent $chan read } } proc write {chan str} { variable peerinfo set peercmd [dict get $peerinfo cmd] set peerchan [dict get $peerinfo chan] $peercmd add $peerchan $str return [string length $str] } proc read {chan count} { variable data variable events set result [string range $data 0 [expr {$count - 1}]] set data [string range $data $count end] if {[string length $data] > 0 && "read" in $events} { chan postevent $chan read } return $result } proc cget {chan opt} { variable data variable peerinfo switch -exact -- $opt { -rlength { set result [string length $data] } -wlength { set peercmd [dict get $peerinfo cmd] set result [$peercmd getsize] } default { return -code error "bad option \"$opt\"" } } return $result } proc cgetall {chan} { foreach opt {-rlength -wlength} { lappend result $opt [cget $chan $opt] } return $result } proc add {chan str} { variable events variable data append data $str if {[string length $data] > 0 && "read" in $events} { chan postevent $chan read } } proc setpeerinfo {peerchan peercmd} { variable peerinfo dict set peerinfo chan $peerchan dict set peerinfo cmd $peercmd } proc getsize {} { variable data return [string length $data] } proc destroy {} { namespace delete [namespace current] } # we rely on these two lines being the last ones on the handler body namespace export -clear * namespace ensemble create } } proc memchan::fifo2 {} { variable f2h variable id set hd1 [namespace eval fifo2#[incr id] $f2h] set hd2 [namespace eval fifo2#[incr id] $f2h] set fd1 [chan create {read write} $hd1] set fd2 [chan create {read write} $hd2] $hd1 setpeerinfo $fd2 $hd2 $hd2 setpeerinfo $fd1 $hd1 # we want immediate delivery by default chan configure $fd1 -buffering none chan configure $fd2 -buffering none return [list $fd1 $fd2] } ############################################################################ # testing if {$argv0 eq [info script]} { proc eventHandler {fd} { chan puts "Reading data from $fd" chan puts **[chan gets $fd]** } lassign [memchan::fifo2] fd1 fd2 chan event $fd1 readable [list eventHandler $fd1] chan event $fd2 readable [list eventHandler $fd2] after 1000 { chan puts "Writing data into $fd1" chan puts -nonewline $fd1 "Hello World" } after 2000 { chan puts "Writing data into $fd2" chan puts -nonewline $fd2 "Hello There !!" } after 4000 { chan puts "\nDisabling $fd2 events\nWriting five lines into $fd1" chan event $fd2 readable {} chan puts $fd1 "line 1\nline 2\nline 3\nline 4\nline5" } after 5000 { chan puts "Enabling $fd2 events" chan event $fd2 readable [list eventHandler $fd2] } after 8000 exit if {[info commands tk] eq ""} { vwait forever } }