Serialport problems in multi-threaded application

C

Caleb Tennis

(I posted this a little earlier, but apparently it got sent with no
subject and was hidden within another thread - mail reader mishap I
suppose - my apologies for posting again):

A small testcase program has unexpected results:

-------

require 'thread'
$serport = "/dev/tts/5"

class SerialPort
def write(port, arry)
puts "WRITING: #{arry.inspect}"
file = File.new(port, File::RDWR | File::NOCTTY )
puts "WRITE"
file.write(arry.pack("C*"))
puts "READ"
str = file.read(50).to_s.unpack("C*")
puts "CLOSE"
file.close
puts "READ: #{str.inspect}"
str
end
end

a = Thread.new do
SerialPort.new.write($serport, [ 4, 4, 0, 16, 0, 1, 48, 90]);
end

a.join

------

The program hangs on the read() call - if I run the same program above and
perform the "SerialPort.new.write()" call without making a new thread, the
code works fine. I performed an strace, with some interesting results -
namely, that for the multithreaded application I don't ever see a call to
the system's read/write, just select. The above code works fine for
regular files - it just seems to have trouble with device files.

Is this a bug or am I just missing something?



As a single thread:
-------
open("/dev/tts/5", O_RDWR|O_NOCTTY|O_LARGEFILE) = 3
fcntl64(3, F_GETFL) = 0x8002 (flags O_RDWR|O_LARGEFILE)
fstat64(3, {st_mode=S_IFCHR|0666, st_rdev=makedev(4, 69), ...}) = 0
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {B19200 -opost -isig -icanon -echo
...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)
= 0x40014000
_llseek(3, 0, 0xbfffd580, SEEK_CUR) = -1 ESPIPE (Illegal seek)
write(1, "WRITE\n", 6WRITE
) = 6
write(1, "READ\n", 5READ
) = 5
write(3, "\4\4\0\20\0\0010Z", 8) = 8
read(3, "\4\4\2\0\0u0", 1024) = 7
read(3, "", 1024) = 0
write(1, "CLOSE\n", 6CLOSE
) = 6
close(3) = 0
munmap(0x40014000, 4096) = 0
write(1, "READ: [4, 4, 2, 0, 0, 117, 48]\n", 31READ: [4, 4, 2, 0, 0, 117, 48]
) = 31
munmap(0x40013000, 4096) = 0
_exit(0) = ?
-------------

As two threads:
------------------
open("/dev/tts/5", O_RDWR|O_NOCTTY|O_LARGEFILE) = 3
fcntl64(3, F_GETFL) = 0x8002 (flags O_RDWR|O_LARGEFILE)
fstat64(3, {st_mode=S_IFCHR|0666, st_rdev=makedev(4, 69), ...}) = 0
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {B19200 -opost -isig -icanon -echo
...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)
= 0x40014000
_llseek(3, 0, 0xbfffba40, SEEK_CUR) = -1 ESPIPE (Illegal seek)
write(1, "WRITE\n", 6WRITE
) = 6
write(1, "READ\n", 5READ
) = 5
select(4, [3], [], [], {0, 0}) = 0 (Timeout)
brk(0) = 0x808d000
brk(0x8091000) = 0x8091000
gettimeofday({1107792091, 536853}, NULL) = 0
select(4, [3], [], [], NULL <unfinished ...>
--------------
 
T

Tanaka Akira

Caleb Tennis said:
The program hangs on the read() call - if I run the same program above and
perform the "SerialPort.new.write()" call without making a new thread, the
code works fine. I performed an strace, with some interesting results -
namely, that for the multithreaded application I don't ever see a call to
the system's read/write, just select. The above code works fine for
regular files - it just seems to have trouble with device files.

Is this a bug or am I just missing something?

It seems that write buffer should be flushed before select for reading.

Index: io.c
===================================================================
RCS file: /src/ruby/io.c,v
retrieving revision 1.246.2.71
diff -u -p -r1.246.2.71 io.c
--- io.c 25 Jan 2005 04:02:27 -0000 1.246.2.71
+++ io.c 8 Feb 2005 12:46:54 -0000
@@ -236,14 +236,12 @@ rb_io_check_readable(fptr)
if (!(fptr->mode & FMODE_READABLE)) {
rb_raise(rb_eIOError, "not opened for reading");
}
-#if NEED_IO_SEEK_BETWEEN_RW
if (((fptr->mode & FMODE_WBUF) ||
(fptr->mode & (FMODE_SYNCWRITE|FMODE_RBUF)) == FMODE_SYNCWRITE) &&
!feof(fptr->f) &&
!fptr->f2) {
io_seek(fptr, 0, SEEK_CUR);
}
-#endif
fptr->mode |= FMODE_RBUF;
}
 
C

Caleb Tennis

It seems that write buffer should be flushed before select for reading.

I tried flushing with File.flush, but it didn't help. Or should I be using
File.fsync ?

Caleb
 
T

Tanaka Akira

Caleb Tennis said:
I tried flushing with File.flush, but it didn't help. Or should I be using
File.fsync ?

It's strange. file.flush should call write system call. sample
script which contains file.flush and strace result?

File.fsync is not related.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,045
Latest member
DRCM

Latest Threads

Top