lkml.org 
[lkml]   [1999]   [Mar]   [18]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
From
Subjectbug(?) in block_til_ready serial.c - open() blocking, 2.0 & 2.2
Abstract:

After running the attached program and breaking it with ^C open calls on
/dev/ttyS0 are blocking forever. No way to return to original state of ttyS0
exept reboot was found. Both 2.0.37pre8 and 2.2.3 kernels are affected. In
2.0.37pre8 the wchan points around serial.c:2487.

Experiment and results:

gcc -o demo demo.c

[root@crds pcontrol-parport]# strace ./demo
execve("./demo", ["./demo"], [/* 33 vars */]) = 0
[...]
open("/dev/ttyS0", O_RDWR|O_NOCTTY) = 3
gettimeofday({921790934, 786136}, NULL) = 0
ioctl(3, TCFLSH, TCIFLUSH) = 0
ioctl(3, SNDCTL_TMR_START, {B19200 -opost -isig icanon -echo ...}) = 0
write(3, "PR13", 4) = 4
read(3, <unfinished ...> /* Ctrl-C pressed*/

running it (or any other program opening /dev/ttyS0) again:

[root@crds pcontrol-parport]# strace ./demo
execve("./demo", ["./demo"], [/* 33 vars */]) = 0
[...]
open("/dev/ttyS0", O_RDWR|O_NOCTTY <unfinished ...> /* Ctrl-C pressed*/

strace cat /dev/ttyS0
[...]
open(ptrace: umoven: I/O error
0xbffffc50, O_RDONLY <unfinished ...> /* Ctrl-C pressed here */

strace cat /dev/ttyS1 before running demo was looking like:

open(ptrace: umoven: I/O error
0xbffffc50, O_RDONLY) = 3
fstat(3, {st_mode=S_IFCHR|0666, st_rdev=makedev(4, 65), ...}) = 0
brk(0x8051000) = 0x8051000
read(3, <unfinished ...> /* Ctrl-C pressed*/


where is it waiting:

ps axlwwwww | grep cat
100000 0 930 784 3 0 936 284 block_til_r S p3 0:00 cat /dev/ttyS0

ps axlwwwwwn | grep cat
100000 0 930 784 1 0 936 284 18a791 S 0303 0:00 cat /dev/ttyS0

System.map :
0018a500 T rs_hangup
0018a5a8 t block_til_ready
0018a808 T rs_open

18A791-18A5A8 == 1E9

if (current->signal & ~current->blocked) {
000033c8 <block_til_ready+1d4> movl 0x0,%edx
000033ce <block_til_ready+1da> movl 0x10(%edx),%eax
000033d1 <block_til_ready+1dd> notl %eax
000033d3 <block_til_ready+1df> testl %eax,0xc(%edx)
000033d6 <block_til_ready+1e2> jne 000033e0 <block_til_ready+1ec>
/mnt/motyl/usr/src/20/linux/drivers/char/serial.c:2486
retval = -ERESTARTSYS;
break;
}
#ifdef SERIAL_DEBUG_OPEN
printk("block_til_ready blocking: ttys%d, count = %d\n",
info->line, info->count);
#endif
schedule(); /* HERE ??????? <<<<<<<<------------------- */
000033d8 <block_til_ready+1e4> call 000033d9 <block_til_ready+1e5>
/mnt/motyl/usr/src/20/linux/drivers/char/serial.c:2487
}
000033dd <block_til_ready+1e9> jmp 00003364 <block_til_ready+170>
000033df <block_til_ready+1eb> nop

Discussion:

My program is partially based on serial-programmming-howto. May still contain
some bugs. But it should not result in such a state of /dev/ttyS0. In my
opinion serial.c uses too much undocumented features of Linux scheduler.

More details available on request.

Please reply to motyl@tichy.ch.uj.edu.pl, since switch.ch may have some
problems with intercontinental connectivity.

--
Tomasz Motylewski
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sys/types.h>
#include <fcntl.h>
#include <limits.h>
#include <termios.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <sched.h>

//#include "crds-shm.h"

char *devname = "/dev/ttyS0";
#define ACK_CHAR '\006' /* ACKnowledge */

int shminit() {
volatile char grow_stack[64*1024];
volatile int tmp;
int i,j;
seteuid(getuid());
return(0);
}

int fdadc; /* serial port file descriptor (fd) */
struct termios serial_param; /* serial port settings */

int adc_init() {
int i;

if( (fdadc=open(devname,O_RDWR | O_NOCTTY)) < 0) {
perror(devname);
exit(2);
}
adc_set();
return(0);
}
int adc_set() {
int i;
static double lasttime=0.0;
struct timeval tv;

gettimeofday( &tv, NULL);
if(tv.tv_sec+tv.tv_usec/1000000.0<lasttime+2.0)
return(0);
lasttime=tv.tv_sec+tv.tv_usec/1000000.0;
bzero((char*)&serial_param,sizeof(serial_param));
cfmakeraw(&serial_param);
cfsetospeed(&serial_param,B19200);
serial_param.c_iflag = IGNCR | IGNPAR; /*ignore CR on input */
serial_param.c_oflag = CLOCAL; /*ignore modem control lines */
serial_param.c_lflag = ICANON; /*canonical mode - buffer by lines */
// serial_param.c_cc[VEOL] = LF_CHAR; /* LF is the default EOL */
serial_param.c_cc[VMIN] = 1;
tcflush(fdadc, TCIFLUSH);
tcsetattr(fdadc, TCSANOW, &serial_param);
return(0);
}
#define B_BUFS 256
double balzers_get_p(int chn) {
char outbuf[B_BUFS], inbuf[B_BUFS];
int in;

snprintf(outbuf,B_BUFS-1,"PR%d\n",chn);
write(fdadc,outbuf,4);
in=0;
in=read(fdadc,inbuf,10);
if(inbuf[0] != ACK_CHAR) {
printf("comm. error, received :%s:\n",inbuf);
sleep (1);
return -1.0; /* warning: the caller may accept only return values >= 0 */
}
write(fdadc,"\005\n",2);
in=read(fdadc,inbuf,B_BUFS-1);
if(in>=0) {
inbuf[in]='\0';
printf("got %d:%s:\n",chn,inbuf);
} else {
perror("read:");
}
return 0.000001;
}


#undef DEBUG
/* DMA has been set to deliver data to dmabuf, we just process it, sleeping
for 2 ms when all data is processed. Other processes read sorted samples
or averages from shared memory buffer shd */
int get_data_loop() {
int nread;
static int cnt=0, i=0;
int chn, chsn, val;
double p1,p2;

while (1) {
val=balzers_get_p(chn);
}
return(0);
}
#define TRUE 1
#define FALSE 0

int main(int argc, char *argv[]) {
int i;

shminit();
adc_init();
get_data_loop(); /* should loop forever */
return(0);
}
\
 
 \ /
  Last update: 2005-03-22 13:50    [W:0.048 / U:0.356 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site