From: "Ara.T.Howard" Date: 2003-10-05T01:54:58+09:00 Subject: Re: webrick, threads, and i/o On Sat, 4 Oct 2003, NAKAMURA, Hiroshi wrote: > You open fifo with blocking mode and read here. Blocking entire process > here is expected behavior if I understand correctly. o.k. - that is what i was trying to confirm: that one must be careful using webrick when doing something in a servlet that could block a process in the kernel... good (and not unexpected) to know. > I think the process is blocked at the second access. Does third > access works? no!? i think it's a case of thread starvation here. one servlet is blocked opening the fifo for reading, but the other cannot open it for writing since the entire process has halting on the first open... > You can open fifo with File::RDONLY|File::NONBLOCK for read side and > File::WRONLY|File::NONBLOCK for write side. I think it should work. strangley, this does not work: ----CUT---- #!/usr/local/ruby-1.8.0/bin/ruby require 'webrick' include WEBrick # or set this up by hand before! system 'mkfifo fifo && chmod 777 fifo' rescue nil port = (ARGV[0] or 2003).to_i s = HTTPServer.new( :Port => port ) class TimeServlet < HTTPServlet::AbstractServlet def do_GET(req, res) res['Content-Type'] = "text/plain" res.body = Time.now.to_s end end class ReadServlet < HTTPServlet::AbstractServlet def do_GET(req, res) res['Content-Type'] = "text/plain" res.body = begin fifo = open 'fifo', File::RDWR|File::NONBLOCK begin fifo.read rescue Errno::EWOULDBLOCK 'NO DATA' end rescue Exception => e e.to_s << "\n" << e.backtrace.join("\n") end end end class WriteServlet < HTTPServlet::AbstractServlet def do_GET(req, res) res['Content-Type'] = "text/plain" res.body = begin fifo = open 'fifo', File::RDWR|File::NONBLOCK begin msg = "%s:%s" % [self.class, Time.now.to_s] fifo.puts msg fifo.flush "WROTE <%s>" % [msg] rescue Errno::EWOULDBLOCK 'COULD NOT WRITE' end rescue Exception => e e.to_s << "\n" << e.backtrace.join("\n") end end end s.mount("/write", WriteServlet) s.mount("/read", ReadServlet) s.mount("/time", TimeServlet) trap("INT"){ s.shutdown } s.start ----CUT---- while this does: ----CUT---- #!/usr/local/ruby-1.8.0/bin/ruby system 'mkfifo fifo && chmod 777 fifo' rescue nil r = open 'fifo', File::RDWR|File::NONBLOCK w = open 'fifo', File::RDWR|File::NONBLOCK w.puts 'hi' w.flush puts r.gets ----CUT---- so i think the logic in my servlets is correct. this is very strange?! what's really strange about the above is that the WriteServlet DOES work, only the ReadServlet hangs in the browser. however, even when it hanging the other servlets (Write, Time) continue to work, so it is not as if the _process_ is blocked, only the ReadServlet request thread!? > In other words, if you want the server never blocks no matter what servlets > do, you should use other process forking WWW server application, or should > make your server using WEBrick as a toolkit. well - the first would require NOT using ruby so that's NOT an option! ;-) as for the second, i'm unsure as to the best way to accomplish blocking tasking from servlets: a) have a dedicated worker thread so all, IO for example, is done carefully there... b) fire up a Drb object (in another process) and use it to perform, for example, io. (does Drb work on windows?) ?? any other ideas? thanks very much. -a ==================================== | Ara Howard | NOAA Forecast Systems Laboratory | Information and Technology Services | Data Systems Group | R/FST 325 Broadway | Boulder, CO 80305-3328 | Email: ara.t.howard@noaa.gov | Phone: 303-497-7238 | Fax: 303-497-7259 | The difference between art and science is that science is what we understand | well enough to explain to a computer. Art is everything else. | -- Donald Knuth, "Discover" | ~ > /bin/sh -c 'for lang in ruby perl; do $lang -e "print \"\x3a\x2d\x29\x0a\""; done' ====================================