I'm seeing an unusual hanging problem, and I don't know if I'm hitting some
sort of race condition or am just misunderstanding what I'm trying to do.
I'm seeing this on both Windows NT and Solaris 2.5.7.

What's happening is that when I access a particular URL, I have tcl-httpd
spawn off a new process. I then establish a fileevent to grab output so I
can keep track of when the spawned process exits.

The problem I'm seeing is that if that process produces output immediately
but does not exit, tcl-httpd hangs until the process exits. If no output is
produced or the process exits, everything is fine.

I've managed to hack up config file which duplicates the problem. If you
save the bottom of this email as bug.rc, and run

    wish httpd.tcl -config bug.rc

you can try accessing /nohang1, /nohang2, and /hang. The last one will
reproduce the problem. If you try this under NT, you'll need something like
MKS or the GNU utils to have a sleep and ls command available.

# bug.rc
#
# This is the default configuration file for TclHttpd, the Tcl Web Server

# The Config array is set from the command line options or
# from defaults defined in httpd
# You can set them here, but then they smash any command-line values

# Config Array
# Element   Default
# host      [info hostname]
# port      8015
# debug     0
# docRoot   [file join $home htdocs]
# ipaddr    {}
# webmaster webmaster@[info hostname]
# uid       50
# gid       100

# Force running with wish

if { ! [ info exists tk_version ] } {
    puts {Please run this with wish, not tclsh}
    exit
}

# Add a text widget so we can see some output

text .text -width 30 -height 10 \
    -yscrollcommand { .textvsb set }
scrollbar .textvsb -command { .text yview }
grid configure .text .textvsb -sticky news

# These packages are required for "normal" web servers

package require doc     ;# Basic file URLS
package require include     ;# Server side includes
package require cgi     ;# Standard CGI
package require dirlist     ;# Directory listings

# These packages are for special things built right into the server

package require direct      ;# Application Direct URLs
package require status      ;# Built in status counters
package require mail        ;# Crude email support
package require admin       ;# Url-based administration
package require session     ;# Session state module (better Safe-Tcl)
package require debug       ;# Debug utilites

# This is currently broken
if {0} {
    package require safetcl ;# External process running safetcl shells
}

# These packages are for the SNMP demo application

if {[catch {
    package require snmp       ;# SNMP form creation
    package require Tnm        ;# Low level network stuff
}]} {
    puts "No SNMP support"
}

# For information about these calls, see htdocs/reference.html

Doc_Root        $Config(docRoot)
Doc_IndexFile       index.{tml,html,shtml,thtml,htm,subst}
Doc_PublicHtml      public_html
Cgi_Directory       /cgi-bin
Status_Url      /status
Debug_Url       /debug
Mail_Url        /mail
Admin_Url       /admin
Doc_TemplateInterp  {}
Doc_CheckTemplates  1
Doc_TemplateLibrary [file join $Config(docRoot) libtml]
Doc_ErrorPage       /error.html
Doc_NotFoundPage    /notfound.html
Doc_Webmaster       $Config(webmaster)
if {[catch {
    Auth_AccessFile .htaccess       ;# Enable Basic Auth
} err]} {
    puts "No Basic Authentication support: $err"
}

Log_SetFile     C:/Temp/log$Config(port)_
Log_FlushMinutes    1

# Establish mapping for URLs to test

Direct_Url /hang hang
Direct_Url /nohang1 nohang1
Direct_Url /nohang2 nohang2

proc nohang1 {} {
    textout nohang1 entered
    if { 0 == [ catch { open "| sleep 5 " } spawned ] } {
        fileevent $spawned readable [ list output $spawned nohang1 ]
    }
    textout nohang1 leaving
    return nohang1
}

proc nohang2 {} {
    textout nohang2 entered
    if { 0 == [ catch { open "| ls " } spawned ] } {
        fileevent $spawned readable [ list output $spawned nohang2 ]
    }
    textout nohang2 leaving
    return nohang2
}

proc hang {} {
    textout hang entered
    if { 0 == [ catch { open "| sleep 5 | ls " } spawned ] } {
        textout About to hang -- you cannot depress
        textout the Quit button now.
        update
        fileevent $spawned readable [ list output $spawned hang]
    }
    textout hang leaving
    return hang
}

proc output { channel which } {
    if { [ eof $channel ] } {
        close $channel
        textout $which exited.
    } else {
        set out [ read $channel ]
        textout $which output: $out
    }
}

proc textout { args } {
    set time [ clock format [ clock seconds ] -format "%H:%M:%S " ]
    .text insert end $time$args
    .text insert end \n
}

Reply via email to