[prev in list] [next in list] [prev in thread] [next in thread] 

List:       opensolaris-code
Subject:    Re: [osol-code] |poll()| on multiple FIFOs vs. partial reads
From:       Roland Mainz <roland.mainz () nrubsig ! org>
Date:       2007-10-18 7:12:18
Message-ID: 47170752.A4BE0E81 () nrubsig ! org
[Download RAW message or body]


Hi!

----

[CC:'ing Andreas Borchert since he did a quick look at the problem]

Garrett D'Amore wrote:
> Roland Mainz wrote:
> > I'm currently writing a small application which should use |poll()| on
> > multiple FIFOs (created via /usr/bin/mkfifo) - after some testing I hit
> > a weired behaviour: The FIFOs are fed from other processes (one FIFO per
> > process) which never terminate (e.g. |POLLHUP| not involved) and only
> > write data from time to time into the FIFOs and the consumer application
> > uses |poll()| to wait for incoming data. It seems that if the consumer
> > only reads some data from a FIFO file descriptor and not all queued data
> > then the |revent| field for this pollfd entry will return |0| on the
> > following |poll()| call (even if there are still data queued).
> > Is this the correct behaviour ?
> 
> That certainly doesn't *sound* correct.  It *sounds* like a bug to me.
> 
>      POLLIN      Data other than high priority data may  be  read
>                  without  blocking. For STREAMS, this flag is set
>                  in revents  even  if  the  message  is  of  zero
>                  length.
> 
> The description above doesn't indicate anything about whether the data
> had previously been signaled or not.
> 
> That said, it does seem strange that you would read less than the full
> amount of data available in the FIFO at any given time.

The idea is to have a script which executes something like "tail -f" on
_multiple_ files and read one line per watched file in a round-robin
fashion if multiple files provide data.
For example the follwing script:
-- snip --
function fatal_error
{
    print -u 2 "${progname}: $@"
    exit 1
}


function usage
{
    OPTIND=0
    getopts -a "${progname}" "${USAGE}" OPT '-?'
    exit 2
}

# program start
builtin basename
builtin cat

typeset progname="$(basename "${0}")"

USAGE=$'
[-?\n@(#)\$Id: multifollow (Roland Mainz) 2007-10-09 \$\n]
[-author?Roland Mainz <roland.mainz@nrubsig.org]
[+NAME?multifollow - use tail -f on multiple files]
[+DESCRIPTION?\bmultifollow\b is a small utilty which can "follow"
multiple
	files similar to tail -f.]

[ file ... ]

[+SEE ALSO?\bksh93\b(1), \btail\b(1)]
'

while getopts -a "${progname}" "${USAGE}" OPT ; do 
#    printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|"
    case ${OPT} in
        *)    usage ;;
    esac
done
shift $((OPTIND-1))

# expecting at least one more arguments
(($# >= 1)) || usage

builtin -f libshell.so.1 poll || fatal_error "poll builtin not found."

typeset -a files
integer numfiles=0
integer i

# register trap to cleanup child processes
trap 'for ((i=0 ; i < numfiles ; i++ )) ; do kill -TERM
${files[i].childpid} ; done' EXIT

while (($# > 0)) ; do
    typeset files[${numfiles}]=(
        typeset name="$1"
        typeset pipename="/tmp/multifollow_pipe_${PPID}_$$_${numfiles}"
        integer childpid=-1

        # poll(1) information
        integer fd="-1"
	typeset events="POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI"
	typeset revents=""
    )

    mkfifo "${files[${numfiles}].pipename}"
    exec {files[numfiles].fd}<>"${files[numfiles].pipename}"

    tail -f "${files[${numfiles}].name}"
>"${files[${numfiles}].pipename}" &
    files[${numfiles}].childpid=$!

    rm "${files[${numfiles}].pipename}"
    
    shift
    (( numfiles++ ))
done

typeset do_poll=true

while true ; do
    if ${do_poll} ; then
        for ((i=0 ; i < numfiles ; i++ )) ; do
	    files[i].revents=""
	done
        poll files
    fi
    do_poll=true
    
    for ((i=0 ; i < numfiles ; i++ )) ; do
        if [[ "${files[i].revents}" != "" ]] ; then
	    # todo: investigate why we have to use "do_poll" at all - AFAIK it
	    # should be sufficient to call "poll" and get "revents" set if
there
	    # are any remaining data...
	    if read -t0 -u${files[i].fd} line ; then
	        print -- "#${i}: ${line}"
		do_poll=false        
	    fi
	fi
    done
done

fatal_error "not reached."
# EOF.
-- snip --
... uses "poll" to watch multiple FIFOs... but strangely I have to use
the "do_poll"-hack (see comment in the code) ... and even stranger
(OkOk, not exactly a suprise): Commenting the "do_poll=false"-line out
results in something like this:
-- snip --
$ ksh93 multifollow.ksh /var/adm/messages /var/log/syslog
#0: Oct 18 07:53:43 sxb72x86 genunix: [ID 936769 kern.info] dtrace0 is
/pseudo/dtrace@0
#1: Oct 13 04:03:27 sxb72x86 sendmail[391]: [ID 702911 mail.info]
starting daemon (8.14.1+Sun): queueing@00:15:00
poll: poll: failure [Interrupted system call]
-- snip --

----

Bye,
Roland

-- 
  __ .  . __
 (o.\ \/ /.o) roland.mainz@nrubsig.org
  \__\/\/__/  MPEG specialist, C&&JAVA&&Sun&&Unix programmer
  /O /==\ O\  TEL +49 641 7950090
 (;O/ \/ \O;)
_______________________________________________
opensolaris-code mailing list
opensolaris-code@opensolaris.org
http://mail.opensolaris.org/mailman/listinfo/opensolaris-code
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic