Don't understand cause of `sysread': Bad file descriptor (Errno::EBADF)

Was writting a script to poll an audiotron (www.audiotron.net) and
record a list of the music that has been played.

The audiotron has an internal webserver so I used the net/http package.
The script runs fine for a while, but after about the 11th pass it falls
over with the following error:

I:/development/ruby/lib/ruby/1.7/net/protocol.rb:501:in sysread': Bad file descriptor (Errno::EBADF) from I:/development/ruby/lib/ruby/1.7/net/protocol.rb:501:inrbuf_fill’
from I:/development/ruby/lib/ruby/1.7/net/protocol.rb:443:in read' from I:/development/ruby/lib/ruby/1.7/net/http.rb:1520:inread_chunked’
from I:/development/ruby/lib/ruby/1.7/net/http.rb:1494:in read_body_0' from I:/development/ruby/lib/ruby/1.7/net/http.rb:1477:inread_body’
from I:/development/ruby/lib/ruby/1.7/net/http.rb:1463:in reading_body' from I:/development/ruby/lib/ruby/1.7/net/http.rb:780:inrequest’
from I:\ruby stuff\audiotron-play-watcher.rb:37
from I:\ruby stuff\audiotron-play-watcher.rb:36:in `start’
from I:\ruby stuff\audiotron-play-watcher.rb:36

I’m puzzeled as to what the problem is. The page is always there, if
will update if continually refreshed in a browser without a problem.

What file descriptor is being referred to here?

Anyone have any thoughts or comments?

TIA

Rob

<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>

require 'english’
require 'net/http’
require 'log4r’
include Log4r

set up logger

atlog = Logger.new 'atlog’
outputter = FileOutputter.new( atlog, { ‘filename’, ‘./at.log’, ‘trunc’,
false } )
outputter.formatter = PatternFormatter.new :pattern => "[%l] %d :: %m"
atlog.outputters = outputter

set up connection details for audiotron

req = Net::HTTP::Get.new(‘apigetstatus.asp’)
address = Net::HTTP.new(‘atron00427c’, 80)
req.basic_auth ‘admin’,‘admin’

response = nil

previousFile = nil
currentFile = nil
currentArtist = nil
currentAlbum = nil
currentTrack = nil
currentGenre = nil
currentPlayStyle = nil
currentTrackLength = 0

queueLength = 0
currentIndex = 0

passes = 0

while true
atlog.debug(“Pass #{passes}”)
passes += 1
address.start { |http|
response = http.request(req) # <<<---- problem line
}

response.body.each { | line |
	if line =~ /TotalTime=/
		currentTrackLength = $POSTMATCH
	elsif line =~ /RANDOM_LED=/
		if $POSTMATCH
			currentPlayStyle = "random"
		else
			currentPlayStyle = "ordered"
		end
	elsif line =~ /^Title=/
		currentTrack = $POSTMATCH.chomp
	elsif line =~ /^Artist=/
		currentArtist = $POSTMATCH.chomp
	elsif line =~ /^Album=/
		currentAlbum = $POSTMATCH.chomp
	elsif line =~ /^Genre=/
		currentGenre = $POSTMATCH.chomp
	elsif line =~ /^SourceID=/
		currentFile = $POSTMATCH.chomp
	elsif line =~ /^QueueLen=/
		queueLength = $POSTMATCH.chomp
	elsif line =~ /^CurrIndex=/
		currentIndex = $POSTMATCH.chomp
	end
}

if currentFile != previousFile
	atlog.info("Playing track #{currentIndex} of #{queueLength} in a 

#{currentPlayStyle} way\n" +
"#{currentTrack} by #{currentArtist} on #{currentAlbum} is
#{currentTrackLength} seconds long\n" +
“File is :- #{currentFile}\n”)

	previousFile = currentFile
end

currentFile = nil
currentTrack = nil
currentArtist = nil
currentAlbum = nil
currentGenre = nil
currentPlayStyle = nil
currentTrackLength = nil
queueLength = 0
currentIndex = 0

response = nil

sleep 5

end

Okay looking at this futher, I stripped out all the superflous stuff
(apologies for not doing that first) and ran the code again. This time
it managed 18 iterations before it bombed out.

When I remove the req.basic_auth line, the code iterates 77 times before
it dies.

As an experiment, I checked the latest source out of CVS and compiled it
under Cygwin. At the time of writting, the script below has iterated 250
times without a problem.

Going to leave it running and see if it simply keeps on going.

Rob, puzzeled!

<<<<< code >>>>>

require ‘net/http’

set up connection details for audiotron

req = Net::HTTP::Get.new(‘apigetstatus.asp’)
address = Net::HTTP.new(‘atron00427c’, 80)
req.basic_auth ‘admin’,‘admin’

response = nil

passes = 0

while true
puts passes
passes += 1
address.start { |http|
response = http.request(req)
}
response = nil

sleep 5

end

As an experiment, I checked the latest source out of CVS and compiled it
under Cygwin. At the time of writting, the script below has iterated 250
times without a problem.

Going to leave it running and see if it simply keeps on going.

Rob, puzzeled!

Just wanted to do a final follow up, I have been running the code under
cygwin all weekend now and it hasn’t crashed. (a marked improvement over
the 50 odd seconds I was previously getting).

I can’t see anything in the changelog to suggest that there was
something fixed between when 1.7.2-4 for windows was released and the
cvs code I checked out on the 20th september.

Which, I think, suggests there is something wrong in the underlying
nature of the VisiC++ build. Unfortuantly I am not capable of digging
deep enough to find out what.

Rob

Hi,

···

At Tue, 24 Sep 2002 02:39:57 +0900, Robert McGovern wrote:

Which, I think, suggests there is something wrong in the underlying
nature of the VisiC++ build. Unfortuantly I am not capable of digging
deep enough to find out what.

mingw32 version is almost equal to mswin32. Could you test
with it?


Nobu Nakada

Hi Nobu, I am building the mingw32 version right now. Will let you know
how it goes

Rob

ps cygwin version still running :slight_smile:

···

nobu.nokada@softhome.net wrote:

mingw32 version is almost equal to mswin32. Could you test
with it?

mingw32 version is almost equal to mswin32. Could you test
with it?

Hi again Nobu,

Here is the trace from running under mingw32:

I:\mingw-ruby\bin>ruby audiotron-play-watcher.rb
0
Playing track 0 of 21119 in a random way
(05) Wherever I May Roam.Mp3 by on is 391 seconds long
File is :- \CLEMFAR\bigmusic (Z)\collections\from someone at work(05)
Wherever
I May Roam.Mp3
1
2
3
4
5
6
7
I:/mingw-ruby/lib/ruby/1.7/net/protocol.rb:501:in sysread': Bad file descriptor (Errno::EBADF) from I:/mingw-ruby/lib/ruby/1.7/net/protocol.rb:501:in rbuf_fill’
from I:/mingw-ruby/lib/ruby/1.7/net/protocol.rb:443:in read' from I:/mingw-ruby/lib/ruby/1.7/net/http.rb:1552:in read_chunked’
from I:/mingw-ruby/lib/ruby/1.7/net/http.rb:1525:in read_body_0' from I:/mingw-ruby/lib/ruby/1.7/net/http.rb:1508:in body’
from I:/mingw-ruby/lib/ruby/1.7/net/http.rb:1494:in reading_body' from I:/mingw-ruby/lib/ruby/1.7/net/http.rb:811:in request’
from audiotron-play-watcher.rb:37
from audiotron-play-watcher.rb:36:in `start’
from audiotron-play-watcher.rb:36

I:\mingw-ruby\bin>

It appears to have the same problem as the mswin32 version a second run
also crashed out, but ran for 32 iterations. A third run also dropped
out quickly, this time with the error

I:/mingw-ruby/lib/ruby/1.7/net/protocol.rb:501:in sysread': Invalid argument (Errno::EINVAL) from I:/mingw-ruby/lib/ruby/1.7/net/protocol.rb:501:in rbuf_fill’
from I:/mingw-ruby/lib/ruby/1.7/net/protocol.rb:477:in readuntil' from I:/mingw-ruby/lib/ruby/1.7/net/protocol.rb:488:in readline’
from I:/mingw-ruby/lib/ruby/1.7/net/http.rb:1406:in read_status_line' from I:/mingw-ruby/lib/ruby/1.7/net/http.rb:1390:in read_new’
from I:/mingw-ruby/lib/ruby/1.7/net/http.rb:809:in request' from audiotron-play-watcher.rb:37 from audiotron-play-watcher.rb:36:in start’
from audiotron-play-watcher.rb:36

Rob

Hello,

I want to start a thread from within the initialize method. This thread
will sleep for a time and then run a method of the Class being
instantiated. How do I refer to the object from within the block being
passed to the Thread constructor?

Currently this is what I have but it would seem to me that ‘self’ will
refer to the thread object.

def initialize
@guard = Thread.new {
while 1 do
sleep(timout)
self.clean
end
}
end

Hi,

It appears to have the same problem as the mswin32 version a second
run also crashed out, but ran for 32 iterations. A third run also
dropped out quickly, this time with the error

Hmmm, I tried the code in [ruby-talk:50993] with a little
modification, and got similar error. I’ll examin it.

51
52
53
54
C:/USR/lib/ruby/1.7/net/protocol.rb:576:in write': Bad file descriptor (Errno::EBADF) from C:/USR/lib/ruby/1.7/net/protocol.rb:576:in do_write’
from C:/USR/lib/ruby/1.7/net/protocol.rb:559:in writeline' from C:/USR/lib/ruby/1.7/net/protocol.rb:559:in writing’
from C:/USR/lib/ruby/1.7/net/protocol.rb:560:in writeline' from C:/USR/lib/ruby/1.7/net/http.rb:1109:in request’
from C:/USR/lib/ruby/1.7/net/http.rb:1109:in canonical_each' from C:/USR/lib/ruby/1.7/net/http.rb:935:in each’
from C:/USR/lib/ruby/1.7/net/http.rb:935:in canonical_each' from C:/USR/lib/ruby/1.7/net/http.rb:1110:in request’
from C:/USR/lib/ruby/1.7/net/http.rb:1075:in exec' from C:/USR/lib/ruby/1.7/net/http.rb:807:in request’
from badf.rb:19
from badf.rb:18:in `start’
from badf.rb:18

badf.rb (400 Bytes)

···

At Thu, 26 Sep 2002 05:43:40 +0900, Robert McGovern wrote:

Stathy G. Touloumis wrote:

Hello,

I want to start a thread from within the initialize method. This thread
will sleep for a time and then run a method of the Class being
instantiated. How do I refer to the object from within the block being
passed to the Thread constructor?

Currently this is what I have but it would seem to me that ‘self’ will
refer to the thread object.

def initialize
@guard = Thread.new {
while 1 do
sleep(timout)
self.clean
end
}
end

The block is a closure, so self, local vars (like timout), and even
instance vars (like @guard), are in the scope of the initialize method.

···

class A
def initialize
timout = 1 ### added
@guard = Thread.new {
while 1 do
sleep(timout)
self.clean
end
}
end

def clean
puts “Cleaning…”
end
end

A.new

sleep(20)

Cleaning…
Cleaning…
Cleaning…

Excellent, thats good to hear :slight_smile: that you’ll look into it & can
reproduce it that is. I was beginning to think I was going mad! just
glad I kept persisting with it.

BTW The Cygwin run version is still running, thats nearly 5 days now!

Rob

···

nobu.nokada@softhome.net wrote:

Hmmm, I tried the code in [ruby-talk:50993] with a little
modification, and got similar error. I’ll examin it.

Hi,

···

At Fri, 27 Sep 2002 06:37:21 +0900, Robert McGovern wrote:

Hmmm, I tried the code in [ruby-talk:50993] with a little
modification, and got similar error. I’ll examin it.

Excellent, thats good to hear :slight_smile: that you’ll look into it & can
reproduce it that is. I was beginning to think I was going mad! just
glad I kept persisting with it.

Now I expect it’s fixed. On my box, at least, it worked over
15,000 times.

In mswin/mingw version, till 1.6, socket descriptor is
duplicated and special finalizer was used. In 1.7 it is no
longer done but the finalizer has been used.


Nobu Nakada

Now I expect it’s fixed. On my box, at least, it worked over
15,000 times.

Wonderful Nobu! I’m very pleased about that :slight_smile:

I’ll check out the latest tree and build a mingw32 version to check
here. I don’t have the tools to build a proper win32 (ie Visi C++)
version, so I’ll test when Andy / Dave next updates the “full” windows
release.

In mswin/mingw version, till 1.6, socket descriptor is
duplicated and special finalizer was used. In 1.7 it is no
longer done but the finalizer has been used.

Thanks for the explanation.

Rob

Hi,

···

At Wed, 2 Oct 2002 06:20:59 +0900, Robert McGovern wrote:

I’ll check out the latest tree and build a mingw32 version to check
here. I don’t have the tools to build a proper win32 (ie Visi C++)
version, so I’ll test when Andy / Dave next updates the “full” windows
release.

Mingw32 is almost same as mswin32. You need cygwin environment
(http://cygwin.com/) to compile, or possibly GnuWin32
(http://gnuwin32.sf.net). But I’m not sure about the latter.

And also, you can use Borland compiler.


Nobu Nakada