lkml.org 
[lkml]   [1998]   [Dec]   [10]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
From
SubjectRe: A question on PTY
Date
> 
> From: hjl@lucon.org (H.J. Lu)
> Date: Wed, 9 Dec 1998 08:09:12 -0800 (PST)
>
> I got 2 failures in the POSIX test on PTY. One is the STOP char
> is not sent when the PTY is full. Although write blocks, read on
> the blocked PTY doesn't return the STOP char. The other one is
> when the PTY is put in back ground, output doesn't generate
> SIGTTOU. I can provide testcases if necessary.
>
> HJ,
>
> Can you provide test cases? Both of these cases are
> handled by the high-level tty code, and the last time I checked using
> the serial driver (which granted was a while ago), neither of these
> cases were a problem. So test cases would be most helpful. Thanks!!
>
> - Ted
>

Here is a testcase.

# gcc loop.c test19.c
# a.out
Wrote 8190 bytes
read 4222 bytes
after input queue filled to 4222 bytes, attempt, to read() STOP character(s) returned 0, expected >= 1


--
H.J. Lu (hjl@gnu.org)
----
#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.2).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `!/bin/sh' line above, then type `sh FILE'.
#
# Made on 1998-12-09 21:12 PST by <hjl@ocean.lucon.org>.
# Source directory was `/home/hjl/bugs/glibc/termios'.
#
# Existing files will *not* be overwritten unless `-c' is specified.
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 12926 -rw-r--r-- loop.c
# 4666 -rw-r--r-- test19.c
#
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=FAILED
locale_dir=FAILED
first_param="$1"
for dir in $PATH
do
if test "$gettext_dir" = FAILED && test -f $dir/gettext \
&& ($dir/gettext --version >/dev/null 2>&1)
then
set `$dir/gettext --version 2>&1`
if test "$3" = GNU
then
gettext_dir=$dir
fi
fi
if test "$locale_dir" = FAILED && test -f $dir/shar \
&& ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
then
locale_dir=`$dir/shar --print-text-domain-dir`
fi
done
IFS="$save_IFS"
if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
then
echo=echo
else
TEXTDOMAINDIR=$locale_dir
export TEXTDOMAINDIR
TEXTDOMAIN=sharutils
export TEXTDOMAIN
echo="$gettext_dir/gettext -s"
fi
touch -am 1231235999 $$.touch >/dev/null 2>&1
if test ! -f 1231235999 && test -f $$.touch; then
shar_touch=touch
else
shar_touch=:
echo
$echo 'WARNING: not restoring timestamps. Consider getting and'
$echo "installing GNU \`touch', distributed in GNU File Utilities..."
echo
fi
rm -f 1231235999 $$.touch
#
if mkdir _sh10858; then
$echo 'x -' 'creating lock directory'
else
$echo 'failed to create lock directory'
exit 1
fi
# ============= loop.c ==============
if test -f 'loop.c' && test "$first_param" != -c; then
$echo 'x -' SKIPPING 'loop.c' '(file already exists)'
else
$echo 'x -' extracting 'loop.c' '(text)'
sed 's/^X//' << 'SHAR_EOF' > 'loop.c' &&
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <limits.h>
#include <termios.h>
#include <string.h>
X
#define WAITTIME (5 * SPEEDFACTOR)
#define COMBITS 11
#define TTY_SIDE 1
#define LOOP_SIDE 2
X
extern void setsigs (void (*func)());
X
int sig_recvd;
int sig_cont;
int sig_errno;
int sig_ret;
X
pid_t child1;
pid_t child2;
X
int data_rate = 9600 / COMBITS;
X
cc_t PERASE = 0x7f;
cc_t PKILL = 0x15;
cc_t PINTR = 0x03;
cc_t PQUIT = 0x1c;
cc_t PSTART = 0x11;
cc_t PSTOP = 0x13;
cc_t PEOF = 0x04;
cc_t PEOL = 0x0b;
cc_t PSUSP = 0x1a;
cc_t PMIN = 0;
cc_t PTIME = 10;
X
static int tty_done = 0;
static struct termios tty_termios;
static int loop_done = 0;
static struct termios loop_termios;
static int tty_master_fd = -1;
static int loop_master_fd = -1;
X
int
openctl(spec, oflag)
char *spec;
int oflag;
{
X /* Note: setsid() will have been called before this routine */
X
X int fd;
X
X /* allow for modem line delay if there has just been a close() */
X (void) sleep(1);
X
X fd = open(spec, oflag, 0);
X
X /* Make sure failure is not just because the device cannot
X become the controlling terminal */
X
X if (fd < 0 && errno != EINTR)
X fd = open(spec, oflag|O_NOCTTY, 0);
X
X return fd;
}
X
int
openpty(master, slave, mfdp, sfdp, cntrl)
char *master;
char *slave;
int *mfdp;
int *sfdp;
int cntrl;
{
X *mfdp = open(master, O_RDWR|O_NOCTTY);
X if (*mfdp < 0 && errno != EBUSY)
X return -1;
X
X if (*mfdp >= 0)
X {
X char *newslave;
X size_t len;
X static struct { char *ptr; size_t len; } slavelen[2];
X extern char *ptsname();
X
X (void) grantpt(*mfdp); /* change permission of slave */
X (void) unlockpt(*mfdp); /* unlock slave */
X newslave=ptsname(*mfdp); /* get a slave */
X if (slavelen[0].ptr == NULL)
X {
X /* remember length of original dummy name
X to be used if called again */
X slavelen[0].ptr = slave;
X slavelen[0].len = strlen(slave);
X }
X else if (slave != slavelen[0].ptr && slavelen[1].ptr == NULL)
X {
X /* remember length of original dummy name
X to be used if called again */
X slavelen[1].ptr = slave;
X slavelen[1].len = strlen(slave);
X }
X if (slave == slavelen[0].ptr)
X len = slavelen[0].len;
X else
X len = slavelen[1].len;
X if (strlen(newslave) > len)
X {
X (void) fprintf(stderr,
X "dummy slave name too short to take \"%s\" in openpty()\n",
X newslave);
X return -1;
X }
X (void) strcpy(slave, newslave);
X }
X
X if (cntrl)
X *sfdp = openctl(slave, O_RDWR);
X else
X *sfdp = open(slave, O_RDWR|O_NOCTTY);
X
X if (*sfdp < 0)
X return -1;
X
X return 0;
}
X
int
ptygetattr(mfd, termios_p)
int mfd;
struct termios *termios_p;
{
X return tcgetattr(mfd, termios_p);
}
X
static void
rdwr(fdin, fdout)
int fdin;
int fdout;
{
X /* read from fdin and write to fdout - called in child process */
X
X int n;
X char buf[_POSIX_MAX_INPUT/2];
X
X while ((n = read(fdin, buf, sizeof(buf))) >= 0)
X {
X /* On EOF write EOF character */
X if (n == 0)
X {
X if (ptygetattr(fdout, &tty_termios) == 0)
X buf[n++] = tty_termios.c_cc[VEOF];
X else
X buf[n++] = PEOF;
X }
X
X errno = 0;
X if (write(fdout, buf, (unsigned int)n) != n)
X {
X /* die quietly on EIO */
X if (errno != EIO)
X perror ("write");
X _exit(1);
X }
X }
X /* die quietly on EIO */
X if (errno != EIO)
X perror ("read");
X _exit(1);
}
X
static int
ptycon(tty_fildes, loop_fildes)
int tty_fildes;
int loop_fildes;
{
X /* connect two master pty's so slaves can be used as loopback */
X
X pid_t ppid;
X
X switch (child1 = fork())
X {
X case -1:
X perror ("fork");
X exit (1);
X
X case 0:
X setsigs(SIG_IGN);
X (void) close(tty_fildes);
X (void) close(loop_fildes);
X rdwr(tty_master_fd, loop_master_fd);
X _exit(0);
X }
X
X switch (child2 = fork())
X {
X case -1:
X perror ("fork");
X exit (1);
X
X case 0:
X setsigs(SIG_IGN);
X (void) close(tty_fildes);
X (void) close(loop_fildes);
X rdwr(loop_master_fd, tty_master_fd);
X _exit(0);
X }
X
X /* rdwr processes may not be killed by tests, so this process
X checks for when the parent dies, and kills the rdwr's */
X
X ppid = getpid();
X switch (fork())
X {
X
X case -1:
X perror ("fork");
X exit (1);
X
X case 0:
X setsigs(SIG_IGN);
X (void) close(tty_fildes);
X (void) close(loop_fildes);
X
X /* When parent PID changes, parent has died */
X while (ppid == getppid())
X (void) sleep(2);
X
X (void) kill(child1, SIGKILL);
X (void) kill(child2, SIGKILL);
X
X _exit(0);
X }
X
X return 0;
}
X
char *
xstrdup (const char *s)
{
X char *p = malloc (strlen (s) + 1);
X strcpy (p, s);
X return p;
}
X
static int
do_prep(side, oflags, fildes_p, termios_p)
int side;
int oflags;
int *fildes_p;
struct termios *termios_p;
{
X /* common function called by tty_prep() and loop_prep() */
X
X char *termios_tty, *master_tty;
X int flags, cntrl, *master_fdp;
X
X *fildes_p = -1;
X
X if (side == TTY_SIDE)
X termios_tty = xstrdup ("/dev/pts/xxxxxxx");
X else
X termios_tty = xstrdup ("/dev/pts/xxxxxxx");
X
X if (side == TTY_SIDE)
X {
X master_tty = "/dev/ptmx";
X master_fdp = &tty_master_fd;
X }
X else
X {
X master_tty = "/dev/ptmx";
X master_fdp = &loop_master_fd;
X }
X
X if (master_tty == NULL || *master_tty == '\0')
X {
X if (side == TTY_SIDE)
X *fildes_p = openctl(termios_tty, oflags | O_NONBLOCK);
X else
X *fildes_p = open(termios_tty,
X oflags | O_NONBLOCK | O_NOCTTY);
X if(*fildes_p < 0)
X return -1;
X }
X else
X {
X /* allow previous rdwr() processes to finish */
X (void) sleep(3);
X
X if (side == TTY_SIDE)
X cntrl = (oflags & O_NOCTTY) == 0;
X else
X cntrl = 0;
X
X /* Implementation-supplied pseudo-terminal opener */
X if (openpty(master_tty, termios_tty,
X master_fdp, fildes_p, cntrl) != 0)
X {
X fprintf (stderr, "openpty(\"%s\", \"%s\", mfdp, sfdp, %d) failed\n",
X master_tty, termios_tty, cntrl);
X if (*master_fdp >= 0)
X {
X (void) close(*master_fdp);
X *master_fdp = -1;
X }
X return -1;
X }
X }
X
X /* Initialize fields */
X if (side == TTY_SIDE)
X {
X if (tty_init(*fildes_p, termios_p) != 0)
X return -1;
X }
X else
X {
X if (loop_init(*fildes_p, termios_p) != 0)
X return -1;
X }
X if (tcsetattr(*fildes_p, TCSANOW, termios_p) != 0)
X return -1;
X
X if ((oflags & O_NONBLOCK) == 0)
X {
X /* Clear O_NONBLOCK flag after opening */
X if ((flags = fcntl (*fildes_p, F_GETFL)) == -1)
X return -1;
X if (fcntl (*fildes_p, F_SETFL, flags & ~O_NONBLOCK) == -1)
X return -1;
X }
X
X return 0;
}
X
/*******************************
* Prepare tty's
********************************/
int
terms_prep(tty_flags, tty_fildes_p, tty_termios_p,
X loop_flags, loop_fildes_p, loop_termios_p)
int tty_flags;
int *tty_fildes_p;
struct termios *tty_termios_p;
int loop_flags;
int *loop_fildes_p;
struct termios *loop_termios_p;
{
X int ret;
X
X *tty_fildes_p = *loop_fildes_p = -1;
X
X /*
X * TERMIOS_TTY must be the next tty opened so that if the process
X * is a session leader it will become the controlling terminal
X */
X
X ret = do_prep(TTY_SIDE, tty_flags, tty_fildes_p, tty_termios_p);
X if (ret != 0)
X return ret;
X
X ret = do_prep(LOOP_SIDE, loop_flags, loop_fildes_p, loop_termios_p);
X if (ret != 0)
X return ret;
X
X /* If pseudo-terminal looback required, connect master sides */
X if (tty_master_fd >= 0 && loop_master_fd >= 0)
X ret = ptycon(*tty_fildes_p, *loop_fildes_p);
X
X if (tty_master_fd >= 0)
X {
X (void) close(tty_master_fd);
X tty_master_fd = -1;
X }
X if (loop_master_fd >= 0)
X {
X (void) close(loop_master_fd);
X loop_master_fd = -1;
X }
X
X return ret;
}
X
int
termios_prep (tty_fildes_p, tty_termios_p, loop_fildes_p, loop_termios_p)
int *tty_fildes_p; /* TERMIOS_TTY file descriptor */
struct termios *tty_termios_p; /* terminal attributes */
int *loop_fildes_p; /* TERMIOS_LOOP file descriptor */
struct termios *loop_termios_p; /* terminal attributes */
{
X (void) setsid();
X
X return terms_prep(O_RDWR, tty_fildes_p, tty_termios_p,
X O_RDWR, loop_fildes_p, loop_termios_p);
}
X
/*************************
* TERMIOS_TTY
*************************/
int
tty_prep (tty_fildes_p, tty_termios_p)
int *tty_fildes_p; /* TERMIOS_TTY file descriptor */
struct termios *tty_termios_p; /* terminal attributes */
{
X return do_prep(TTY_SIDE, O_RDWR, tty_fildes_p, tty_termios_p);
}
X
/*************************
* TERMIOS_LOOP
*************************/
int
loop_prep (loop_fildes_p, loop_termios_p)
int *loop_fildes_p; /* TERMIOS_LOOP file descriptor */
struct termios *loop_termios_p; /* terminal attributes */
{
X return do_prep(LOOP_SIDE, O_RDWR, loop_fildes_p, loop_termios_p);
}
X
/**********************************************
* Save the initial termios state
* Modify struct termios to VSX values
* Modify struct termios for test values
**********************************************/
int
tty_init(fildes, termios_p)
int fildes;
struct termios *termios_p;
{
X /*************************
X * save initial state
X **************************/
X if (!tty_done)
X {
X if (tcgetattr(fildes, &tty_termios) != 0)
X return -1;
X }
X tty_done = 1;
X
X *termios_p = tty_termios; /* ANSI C structure assignment */
X
X /*************************
X * set to VSX values
X **************************/
X (termios_p)->c_iflag &= ~(PARMRK|INLCR|INPCK|IGNCR|IXOFF|BRKINT|IXON);
X (termios_p)->c_iflag |= (IGNPAR|IGNBRK|ICRNL);
X if ((termios_p->c_cflag & CSIZE) == CS8)
X (termios_p)->c_iflag &= ~ISTRIP;
#ifdef _XOPEN_SOURCE
X (termios_p)->c_iflag &= ~(IUCLC|IXANY);
#endif
X (termios_p)->c_oflag &= ~OPOST;
X
X (termios_p)->c_cflag |= (CLOCAL|CREAD);
X
X (termios_p)->c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP|IEXTEN);
X (termios_p)->c_lflag |= (ISIG|ICANON|NOFLSH);
#ifdef _XOPEN_SOURCE
X (termios_p)->c_lflag &= ~XCASE;
#endif
X (termios_p)->c_cc[VMIN] = PMIN;
X (termios_p)->c_cc[VTIME] = PTIME;
X (termios_p)->c_cc[VINTR] = PINTR;
X (termios_p)->c_cc[VQUIT] = PQUIT;
X (termios_p)->c_cc[VERASE] = PERASE;
X (termios_p)->c_cc[VKILL] = PKILL;
X (termios_p)->c_cc[VEOF] = PEOF;
X (termios_p)->c_cc[VEOL] = PEOL;
X (termios_p)->c_cc[VSUSP] = PSUSP;
X (termios_p)->c_cc[VSTART] = PSTART;
X (termios_p)->c_cc[VSTOP] = PSTOP;
X
X if (cfsetispeed(termios_p,B9600) != 0 ||
X cfsetospeed(termios_p,B9600) != 0)
X return -1;
X
X return 0;
}
X
/**********************************
* Initialize LOOP to noncanonical
***********************************/
int
loop_init(fildes, termios_p)
X
int fildes;
struct termios *termios_p;
{
X static long NOTHING; /* "disable" character */
X
X /*************************
X * save initial state
X **************************/
X if (!loop_done)
X {
X if (tcgetattr(fildes, &loop_termios) != 0)
X return -1;
X NOTHING = fpathconf(fildes, _PC_VDISABLE);
X if (NOTHING == -1)
X NOTHING = 0;
X }
X loop_done = 1;
X
X *termios_p = loop_termios; /* ANSI C structure assignment */
X
X /*************************
X * set VSX values
X **************************/
X (termios_p)->c_iflag &= ~(PARMRK|ICRNL|INLCR|INPCK|IGNCR|IXOFF|BRKINT|IXON);
X (termios_p)->c_iflag |= (IGNPAR|IGNBRK);
#ifdef _XOPEN_SOURCE
X (termios_p)->c_iflag &= ~(IUCLC|IXANY);
#endif
X (termios_p)->c_oflag &= ~OPOST;
X
X (termios_p)->c_cflag |= (CLOCAL|CREAD);
X /* make sure LOOP has similar enough c_cflag values to TTY
X so they can talk to each other */
X if (tty_done)
X {
X termios_p->c_cflag &= ~(CSIZE|CSTOPB|PARENB|PARODD);
X termios_p->c_cflag |=
X (tty_termios.c_cflag & (CSIZE|CSTOPB|PARENB|PARODD));
X }
X
X if ((termios_p->c_cflag & CSIZE) == CS8)
X (termios_p)->c_iflag &= ~ISTRIP;
X
X (termios_p)->c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|ISIG|ICANON|TOSTOP|IEXTEN);
X (termios_p)->c_lflag |= (NOFLSH);
#ifdef _XOPEN_SOURCE
X (termios_p)->c_lflag &= ~XCASE;
#endif
X (termios_p)->c_cc[VINTR] = NOTHING;
X (termios_p)->c_cc[VQUIT] = NOTHING;
X (termios_p)->c_cc[VERASE] = NOTHING;
X (termios_p)->c_cc[VKILL] = NOTHING;
X (termios_p)->c_cc[VEOF] = NOTHING;
X (termios_p)->c_cc[VEOL] = NOTHING;
X (termios_p)->c_cc[VSUSP] = NOTHING;
X (termios_p)->c_cc[VMIN] = PMIN;
X (termios_p)->c_cc[VTIME] = PTIME;
X (termios_p)->c_cc[VSTART] = PSTART;
X (termios_p)->c_cc[VSTOP] = PSTOP;
X
X if (cfsetispeed((termios_p),B9600) != 0 ||
X cfsetospeed((termios_p),B9600) != 0)
X return -1;
X
X return 0;
}
X
#ifdef __hpux
#undef NSIG
#define NSIG 31
#endif
X
int
sig_init (int signum, sigset_t *sigmask, void (*sigfunc)(),
X int sigflags)
{
X struct sigaction act;
X act.sa_flags = sigflags;
X act.sa_mask = *sigmask;
X act.sa_handler = sigfunc;
X return(sigaction(signum, &act, (struct sigaction *)NULL));
}
X
static sigset_t sig_empty;
X
void
do_signal (signum, sigfunc)
X int signum;
X void (*sigfunc)();
{
X struct sigaction act;
X
X act.sa_flags = 0;
X act.sa_handler = sigfunc;
X sigemptyset(&act.sa_mask);
X if (sigaction(signum, &act, (struct sigaction *)NULL) < 0)
X {
X perror ("sigaction");
X abort ();
X }
}
X
void
sig_catch (sig)
X int sig;
{
X sig_recvd = sig;
}
X
void
sig_resume (sig)
X int sig;
{
X sig_cont = sig;
}
X
void
setsigs (func)
X void (*func)();
{
X int i;
X for (i = 1; i < NSIG; i++)
X {
X if (i == SIGKILL || i == SIGSTOP || i == SIGCHLD)
X continue;
X
X do_signal (i, func);
X }
}
X
int alrm_flag;
X
void
alrm (int sig)
{
X alrm_flag = 1;
}
SHAR_EOF
$shar_touch -am 1207115798 'loop.c' &&
chmod 0644 'loop.c' ||
$echo 'restore of' 'loop.c' 'failed'
if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
&& ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
md5sum -c << SHAR_EOF >/dev/null 2>&1 \
|| $echo 'loop.c:' 'MD5 check failed'
9a85b08a341019e2ab49c64fad7f8d80 loop.c
SHAR_EOF
else
shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'loop.c'`"
test 12926 -eq "$shar_count" ||
$echo 'loop.c:' 'original size' '12926,' 'current size' "$shar_count!"
fi
fi
# ============= test19.c ==============
if test -f 'test19.c' && test "$first_param" != -c; then
$echo 'x -' SKIPPING 'test19.c' '(file already exists)'
else
$echo 'x -' extracting 'test19.c' '(text)'
sed 's/^X//' << 'SHAR_EOF' > 'test19.c' &&
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <limits.h>
#include <termios.h>
#include <string.h>
X
extern void alrm (int);
X
extern int data_rate;
X
#define Strlen (sizeof(string)-1)
#define NAP 2
X
static long max_input;
static int tty_fildes, loop_fildes;
static struct termios tty_termios, loop_termios,
X *loop_termios_p = &loop_termios,
X *tty_termios_p = &tty_termios;
static char string[] = "And they thwam and they thwam all over the dam!";
static char inbuf[512];
static char Stop = '\023'; /* ASCII DC3 */
static char Start = '\021'; /* ASCII DC1 */
extern int alrm_flag;
X
void
test19()
{
X int ret, err;
X unsigned capacity, total, nbytes, wrote;
X
X errno = 0;
X max_input = fpathconf(tty_fildes, _PC_MAX_INPUT);
X if (max_input < 0)
X {
X perror ("fpathconf");
X return;
X }
X
X if (loop_init(loop_fildes, loop_termios_p) != 0)
X {
X return;
X }
X
X loop_termios_p->c_lflag &= ~ICANON;
X loop_termios_p->c_iflag |= IXON;
X loop_termios_p->c_cc[VMIN] = 0;
X loop_termios_p->c_cc[VTIME] = 10;
X if (tcsetattr(loop_fildes, TCSANOW, loop_termios_p) != 0)
X {
X perror ("tcsetattr");
X return;
X }
X
X if (tty_init(tty_fildes, tty_termios_p) != 0)
X {
X return;
X }
X
X tty_termios_p->c_lflag &= ~ICANON;
X tty_termios_p->c_cc[VMIN] = 0;
X tty_termios_p->c_cc[VTIME] = 10;
X tty_termios_p->c_iflag |= IXOFF;
X if (tcsetattr(tty_fildes, TCSANOW, tty_termios_p) != 0)
X {
X perror ("tcsetattr");
X return;
X }
X
X alrm_flag = 0;
X wrote = 0;
X while (alrm_flag == 0)
X {
X do_signal (SIGALRM, alrm);
X alarm (10);
X ret = write(loop_fildes, string, Strlen);
X alarm (0);
X err = errno;
X
X if (ret < 0)
X break;
X wrote += ret;
X }
X
X if (alrm_flag == 0)
X {
X fprintf (stderr, "no alarm\n");
X perror ("write");
X return;
X }
X
X fprintf (stderr, "Wrote %d bytes\n", wrote);
X
X if (tcflush(loop_fildes, TCOFLUSH) != 0)
X {
X perror ("tcflush");
X return;
X }
X
X capacity = 0;
X while ((ret = read(tty_fildes, inbuf, sizeof(inbuf))) > 0)
X capacity += ret;
X if (ret < 0)
X {
X perror ("read");
X return;
X }
X
X fprintf (stderr, "read %d bytes\n", capacity);
X
X /*
X * Now switch off flow control and fill the input queue
X */
X
X loop_termios_p->c_iflag &= ~IXON;
X if (tcsetattr(loop_fildes, TCSANOW, loop_termios_p) != 0)
X {
X perror ("tcsetattr");
X return;
X }
X
X if (capacity < max_input)
X capacity = max_input;
X
X total = 0;
X do {
X nbytes = capacity - total;
X if (nbytes > Strlen)
X nbytes = Strlen;
X
X errno = 0;
X ret = write(loop_fildes, string, nbytes);
X
X if (ret != nbytes)
X {
X perror ("write");
X return;
X } else {
X total += ret;
X }
X
X } while (total < capacity);
X
X (void) sleep((unsigned)(capacity/data_rate)+NAP);
X
X /* Read STOP character(s) */
X
X ret = read(loop_fildes, inbuf, sizeof(inbuf));
X if (ret < 1)
X {
X err = errno;
X fprintf (stderr, "after input queue filled to %u bytes, attempt, to read() STOP character(s) returned %d, expected >= 1\n",
X capacity, ret);
X if (ret < 0)
X fprintf (stderr, "errno was set to %d\n", err);
X return;
X }
X else if (memchr((void *)inbuf, Stop, (size_t)ret) == 0)
X {
X fprintf (stderr, "system did not transmit STOP when input queue filled to %u bytes\n",
X capacity);
X return;
X }
X
X /* read input to cause START to be sent, and check no data was lost */
X
X total = 0;
X do {
X ret = read(tty_fildes, inbuf, sizeof(inbuf));
X
X } while (ret > 0 && (total += ret) < capacity);
X
X if (total != capacity)
X {
X err = errno;
X fprintf (stderr, "second read() loop gave %u bytes, expected %u\n",
X total, capacity);
X if (ret < 0)
X fprintf (stderr, "errno was set to %d\n", err);
X }
X
X (void) sleep(NAP);
X
X ret = read(loop_fildes, inbuf, sizeof(inbuf));
X if (ret < 1)
X {
X err = errno;
X fprintf (stderr, "attempt to read() START character returned %d, expected >= 1\n", ret);
X if (ret < 0)
X fprintf (stderr, "errno was set to %d\n", err);
X }
X else if (memchr((void *)inbuf, Start, (size_t)ret) == 0)
X {
X fprintf (stderr, "system did not transmit START after input queue emptied\n");
X }
}
X
void
prepare_tests()
{
X switch (termios_prep (&tty_fildes, tty_termios_p,
X &loop_fildes, loop_termios_p) )
X {
X case 0:
X break;
X case 1:
X fprintf (stderr, "Unsupported\n");
X return;
X break;
X default:
X fprintf (stderr, "Unsupported\n");
X return;
X break;
X }
X
X tty_termios_p->c_lflag &= ~ICANON;
X tty_termios_p->c_cc[VMIN] = 0;
X tty_termios_p->c_cc[VTIME] = 30;
X
X if (tcsetattr(tty_fildes, TCSANOW, tty_termios_p) != 0)
X {
X perror ("tcsetattr");
X return;
X }
}
X
void
clean_tests()
{
X
X (void) close(tty_fildes);
X (void) close(loop_fildes);
}
main ()
{
X prepare_tests();
X test19 ();
X clean_tests ();
}
SHAR_EOF
$shar_touch -am 1209211198 'test19.c' &&
chmod 0644 'test19.c' ||
$echo 'restore of' 'test19.c' 'failed'
if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
&& ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
md5sum -c << SHAR_EOF >/dev/null 2>&1 \
|| $echo 'test19.c:' 'MD5 check failed'
2e7db6dd2d7cd45a268dd40afad60486 test19.c
SHAR_EOF
else
shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'test19.c'`"
test 4666 -eq "$shar_count" ||
$echo 'test19.c:' 'original size' '4666,' 'current size' "$shar_count!"
fi
fi
rm -fr _sh10858
exit 0

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2005-03-22 13:46    [W:0.045 / U:0.572 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site