[comp.unix.microport] Fast timer driver source

plocher%sally@Sun.COM (John Plocher) (06/07/89)

:
#!/bin/sh
#    This is a shell archive created by yasa (1.74jmp).
#    Run the following text with /bin/sh to extract.
#
#    Archive: /usr/src2/public/drivers/ft/ft.shar        
#
#    This archive is a complete distribution by itself.
#
#    Packed under unix by plocher@lessa (John Plocher)
#    Date: Wed Jun  7 00:00:49 1989
#
#    This archive will not overwrite existing files
#    inless invoked with the -c flag: sh SHARNAME -c
#
PATH=/bin:/usr/bin ; export PATH

YASASTART=`pwd`

echo x - ft.n
if [ -f ft.n -a "${1}" != "-c" ] ;then
    echo "shar: will not overwrite 'ft.n'"
else
    sed "s/^X//" << \!End-Of-ft.n! > ft.n
X
X
X
X     FT(4)                     UNIX System V                     FT(4)
X
X
X
X     NAME
X          ft - fast interval timer
X
X     DESCRIPTION
X          ft is a pseudo-device that makes it possible to simulate a
X          sleep(2) call or an alarm(2) with the same resolution as the
X          system clock (usually in 100th's of a second).
X
X          To use the interval timer, open one of the files /dev/ft?.
X          This opens the interval timer for exclusive use; an attempt
X          by another process to open the timer will fail with error
X          indication ENXIO in errno - see intro(2).  The resulting
X          file descriptor can be the argument of an ioctl(2) call:
X
X            #include <sys/ft.h>
X            unsigned long request;
X            ioctl(fildes, FTIOCSET, request);
X
X          The high order word of request is the duration of the delay
X          and the low order word of request is the signal to be sent
X          to the process.  After delay ticks of the system clock, the
X          desired signal will be sent to the process.  The requested
X          delay may not exceed about 655 seconds.
X
X          The ioctl(2) call :
X
X            #include <sys/ft.h>
X            unsigned long request = 0;
X            ioctl(fildes, FTIOCANCEL, request);
X
X          will cancel the pending signal to the process if the signal
X          has not yet occurred.
X
X          The ioctl(2) call :
X
X            #include <sys/ft.h>
X            unsigned long delay;
X            ioctl(fildes, FTIOCSLEEP, &delay);
X
X          will cause the calling process to sleep for delay ticks of
X          the system clock. The delay may not be greater than about
X          497 days long. Note, the number of ticks delay is (2^
X          sizeof(long) -1).
X
X          The ioctl(2) call :
X
X            #include <sys/ft.h>
X            #include <sys/types.h>
X            time_t interval;
X            ioctl(fildes, FTIOCLBOLT, &interval);
X
X          will copy the current value of lbolt from kernel space to
X
X
X
X     Page 1                                          (printed 3/17/89)
X
X
X
X
X
X
X     FT(4)                     UNIX System V                     FT(4)
X
X
X
X          user space.
X
X     FILES
X          /dev/ft?
X
X     SEE ALSO
X          ioctl(2), alarm(2)
X
X     CAVEATS
X          Since the ioctl system call takes some finite amount of time
X          to be performed, on slower machines the resolution of 1/HZ
X          of a second might not be a fine enough granularity for very
X          accurate timing of events.
X
X     BUGS
X          An FTIOCCANCEL request prevents the signal from being sent
X          when the interval has expired, but does not actually cancel
X          the timeout request.  It cannot be followed by a new
X          FTIOCSET request until the original delay has expired.
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X     Page 2                                          (printed 3/17/89)
X
X
X
!End-Of-ft.n!
if [ "`wc -c ft.n`" != "   2897 ft.n" ]
then
echo '   ft.n may be bad'
fi
fi
echo x - ft.c
if [ -f ft.c -a "${1}" != "-c" ] ;then
    echo "shar: will not overwrite 'ft.c'"
else
    sed "s/^X//" << \!End-Of-ft.c! > ft.c
X/*
X *  "ft.c"
X *
X *	Copyright (c) 1989 Ken Chapin
X *	  All Rights Reserved
X *
X *	THIS IS PUBLISHABLE PROPRIETARY SOURCE CODE OF Ken Chapin
X *	The copyright notice above does not evidence any
X *	actual or intended publication of such source code.
X *
X *	Usenet Distribution Allowed
X *
X *ident	"@(#)ft.c	1.0 - 89/03/17"
X */
X
X#include <sys/param.h>
X#include <sys/types.h>
X#include <sys/dir.h>
X#include <sys/sysi86.h>
X#include <sys/dirent.h>
X#include <sys/signal.h>
X#include <sys/errno.h>
X#include <sys/systm.h>
X#include <sys/user.h>
X#include <sys/ioctl.h>
X#include <sys/sysmacros.h>
X#include "ft.h"
X
X#define AVAILABLE   (0)
X#define CANCEL	(0)
X#define INUSE  (-1)
X#define NOTOWNED (-1)
X#define DELAYMIN 0
X#define DELAYMAX 65535
X#define NUMDEV 8
X#define NULLPROC	((struct proc *) 0)
X
Xchar num_devices;
Xstruct ft_tab {
X	int owner;
X	char state;
X	struct proc *pproc;
X	unsigned int request;
X} ft_tab[NUMDEV];
X
X/*
X *	Initialize all device states to available.
X *	This is only done once at boot time
X */
X
Xftinit()
X{
X	register char i;
X
X	num_devices = 0;
X	for (i=0; i<NUMDEV; i++) {
X		ft_tab[i].owner = NOTOWNED;
X		ft_tab[i].state = AVAILABLE;
X		ft_tab[i].pproc = NULLPROC;
X		ft_tab[i].request = CANCEL;
X	}
X}
X
X/*
X *	Mark a device busy if opened and make sure that not too many are opened
X *	at one time. Also record who the owner of the process is.
X */
X
Xftopen(dev)
Xdev_t dev;
X{
X
X	if (num_devices >= NUMDEV) {
X		u.u_error = EAGAIN;
X		return;
X	}
X	if (minor(dev) >= NUMDEV) {
X		u.u_error = ENXIO;
X		return;
X	}
X    if (ft_tab[minor(dev)].state == INUSE) {
X        u.u_error = EBUSY;
X        return;
X    }
X    if (ft_tab[minor(dev)].owner != NOTOWNED) {
X        u.u_error = EBUSY;
X        return;
X    }
X	ft_tab[minor(dev)].state = INUSE;
X	ft_tab[minor(dev)].owner = u.u_uid;
X	ft_tab[minor(dev)].pproc = u.u_procp;
X	++num_devices;
X}
X
X
X/*
X *	Mark a device unused if closed & make sure that no one tries to close a
X *	device that is not in use. Also make sure that the person closing the
X *	device is either the owner or root.
X */
X
Xftclose(dev)
Xdev_t dev;
X{
X	if (ft_tab[minor(dev)].state == AVAILABLE) {
X		u.u_error = ENODEV;
X		return;
X	}
X	if (ft_tab[minor(dev)].owner != u.u_uid
X	 && ft_tab[minor(dev)].owner != 0) {
X		u.u_error = EACCES;
X		return;
X	}
X    ft_tab[minor(dev)].state = AVAILABLE;
X	ft_tab[minor(dev)].owner = NOTOWNED;
X	ft_tab[minor(dev)].pproc = NULLPROC;
X	ft_tab[minor(dev)].request = CANCEL;
X	--num_devices;
X}
X
X
X/*
X * ioctl
X *
X * This is where stuff happens.
X *
X *  FTIOCSLEEP	request the calling process to sleep for the specified number
X *              of clock ticks.
X *  FTIOCLBOLT	requests the value of lbolt be copied into user space.
X *  FTIOCSET	requests that the calling process be sent a signal after some
X *		elapsed time where the time is in the upper eight bits of the
X *		argument sent and the signal to send is in the lower eight
X *		bits.
X *  FTIOCANCEL	requests that the signal that is pending be cancelled if it has
X *		not been sent yet.
X */
X
Xftioctl(dev, cmd, arg, flag)
Xunion ioctl_arg arg;
Xdev_t dev;
Xint cmd, flag;
X{
X	unsigned char dvice;
X	void ftcancel();
X
X	dvice = minor(dev);
X	if (ft_tab[dvice].state != INUSE) {
X			u.u_error = EBUSY;
X			return;
X	}
X	if ((ft_tab[dvice].owner != u.u_uid) && (ft_tab[dvice].owner != 0)) {
X		u.u_error = EACCES;
X		return;
X	}
X    switch(cmd) {
X
X    case FTIOCSLEEP: {
X		if (arg.iarg <= DELAYMIN || arg.iarg >= DELAYMAX) {
X			u.u_error = EINVAL;
X			return;
X		}
X		delay(arg.iarg);
X		return;
X	}
X
X    case FTIOCLBOLT:
X		copyout(lbolt, arg.iparg, sizeof(long));
X		return;
X
X	case FTIOCSET: {
X		register unsigned short timer, sig;
X
X		timer = HIWORD(arg.iarg);
X		sig = LOWORD(arg.iarg);
X		if (sig < 1 || sig >= NSIG) {
X			u.u_error = EINVAL;
X#ifdef DEBUG
X		printf("SIGNAL = %u\n", sig);
X#endif
X			return;
X		}
X		if (timer < 2 || timer > 65535) {
X			u.u_error = EINVAL;
X#ifdef DEBUG
X		printf("TIME = %u\n", timer);
X#endif
X			return;
X		}
X		ft_tab[dvice].request = arg.iarg;
X		timeout(ftcancel, (caddr_t) &ft_tab[dvice], timer);
X		return;
X	}
X
X	case FTIOCANCEL:
X		ft_tab[dvice].request = CANCEL;
X		return;
X
X	default:
X		u.u_error = ENOTTY;
X		return;
X        }
X}
X
X
Xvoid ftcancel(f)
Xcaddr_t f;
X{
X
X	struct ft_tab *temp;
X
X	temp = (struct ft_tab *) f;
X	if (temp->request != CANCEL) {
X		psignal(temp->pproc, LOWORD(temp->request));
X#ifdef DEBUG
X		printf("signal = %u\n", LOWORD(temp->request));
X#endif
X		temp->request = CANCEL;
X	}
X}
X
!End-Of-ft.c!
if [ "`wc -c ft.c`" != "   4365 ft.c" ]
then
echo '   ft.c may be bad'
fi
fi
echo x - ft.h
if [ -f ft.h -a "${1}" != "-c" ] ;then
    echo "shar: will not overwrite 'ft.h'"
else
    sed "s/^X//" << \!End-Of-ft.h! > ft.h
X#define FTIOCSLEEP	(('F'<<8)|0)
X#define FTIOCLBOLT	(('F'<<8)|1)
X#define FTIOCSET	(('F'<<8)|2)
X#define FTIOCANCEL	(('F'<<8)|3)
X
X#define HIWORD(x)	(((x) >> 16) & 0xffff)		
X#define LOWORD(x)	((x) & 0xffff)
X#define MAKEVAL(x,y)	((x) << 16 | (y))
!End-Of-ft.h!
if [ "`wc -c ft.h`" != "    242 ft.h" ]
then
echo '   ft.h may be bad'
fi
fi
echo x - chk.c
if [ -f chk.c -a "${1}" != "-c" ] ;then
    echo "shar: will not overwrite 'chk.c'"
else
    sed "s/^X//" << \!End-Of-chk.c! > chk.c
X#include <fcntl.h>
X#include <stdio.h>
X#include <sys/signal.h>
X#include "ft.h"
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	int fd, open();
X	unsigned int val=MAKEVAL(255,14);	/* 60 (tics) | 14 (SIGALARM) */
X	void sigcatch();
X	register char i;
X	unsigned short sleep;
X
X	sleep = (HIWORD(val) + 10);
X	for (i=1; i<20; ++i)
X		signal(i, sigcatch);
X	if ((fd = open("/dev/ft0", O_RDWR)) == -1) {
X		perror("/dev/ft");
X		exit(1);
X	}
X	fprintf(stderr, "Sending sig %u in %u tics\n", LOWORD(val), HIWORD(val));
X	if (ioctl(fd, FTIOCSET, val) == -1) {
X		perror("ioctl: FTIOCSET");
X		exit(1);
X	}
X	if (ioctl(fd, FTIOCSLEEP, sleep) == -1) {
X		perror("ioctl: FTIOCSET");
X		exit(1);
X	}
X}
X
X
Xvoid sigcatch(sig)
Xint sig;
X{
X	fprintf(stderr, "Got signal %d\n\n", sig);
X	return;
X}
!End-Of-chk.c!
if [ "`wc -c chk.c`" != "    753 chk.c" ]
then
echo '   chk.c may be bad'
fi
fi
echo x - config
if [ -f config -a "${1}" != "-c" ] ;then
    echo "shar: will not overwrite 'config'"
else
    sed "s/^X//" << \!End-Of-config! > config
X* 1 "ft/config"
X
X*	Copyright (c) 1989 Ken Chapin
X*	  All Rights Reserved
X
X*	THIS IS PUBLISHABLE PROPRIETARY SOURCE CODE OF Ken Chapin
X*	The copyright notice above does not evidence any
X*	actual or intended publication of such source code.
X
X*ident	"@(#)config	1.0 - 89/03/14"
X
Xcharacter(9)
X
Xprefix = ft
X
Xfunctions = init, open, close, ioctl
!End-Of-config!
if [ "`wc -c config`" != "    340 config" ]
then
echo '   config may be bad'
fi
fi
echo x - ft.4
if [ -f ft.4 -a "${1}" != "-c" ] ;then
    echo "shar: will not overwrite 'ft.4'"
else
    sed "s/^X//" << \!End-Of-ft.4! > ft.4
X.TH FT 4 
X.UC 4
X.SH NAME
Xft \- fast interval timer
X.SH DESCRIPTION
X.I ft
Xis a pseudo-device that makes it possible to simulate a
X.IR sleep (2)
Xcall or an
X.IR alarm (2)
Xwith the same resolution as the system clock (usually in 100th's of a second).
X.PP
XTo use the interval timer, open one of the files
X.I /dev/ft?.
XThis opens the interval timer for exclusive use;
Xan attempt by another process to open the timer will fail
Xwith error indication ENXIO in 
X.I errno
X\- see
X.IR intro (2).
XThe resulting file descriptor can be the argument of an
X.IR ioctl (2)
Xcall:
X.RS 1
X
X #include <sys/ft.h>
X unsigned long request;
X ioctl(fildes, FTIOCSET, request);
X
X.RE
XThe high order word of request is the duration of the delay and the low order 
Xword of request is the signal to be sent to the process.  After
X.I delay
Xticks of the system clock, the desired signal will be sent to the process.
XThe requested
X.I delay
Xmay not exceed about 655 seconds.
X.br
X
XThe 
X.IR ioctl (2)
Xcall :
X.RS 1
X
X #include <sys/ft.h>
X ioctl(fildes, FTIOCANCEL, (long) 0);
X
X.RE
Xwill cancel the pending signal to the process if the signal has not yet
Xoccurred.
X.br
X
XThe 
X.IR ioctl (2)
Xcall :
X.RS 1
X
X #include <sys/ft.h>
X unsigned long delay;
X ioctl(fildes, FTIOCSLEEP, &delay);
X
X.RE
Xwill cause the calling process to sleep for 
X.I delay
Xticks of the system clock. The delay may not be greater than about 497 days
Xlong. Note, the number of ticks delay is (2^ sizeof(long) -1).
X.br 
X
XThe
X.IR ioctl (2)
Xcall :
X.RS 1
X
X #include <sys/ft.h>
X #include <sys/types.h>
X time_t interval;
X ioctl(fildes, FTIOCLBOLT, &interval);
X
X.RE
Xwill copy the current value of
X.IR lbolt
Xfrom kernel space to user space.
X.SH FILES
X/dev/ft?
X.SH "SEE ALSO"
Xioctl(2), alarm(2)
X.SH CAVEATS
XSince the ioctl system call takes some finite amount of time to be performed,
Xon slower machines the resolution of 1/HZ of a second might not be a fine
Xenough granularity for very accurate timing of events.
X.SH BUGS
XAn FTIOCCANCEL request prevents the signal from being sent
Xwhen the interval has expired, but does not actually cancel
Xthe timeout request.
XIt cannot be followed by a new FTIOCSET request
Xuntil the original delay has expired.
!End-Of-ft.4!
if [ "`wc -c ft.4`" != "   2160 ft.4" ]
then
echo '   ft.4 may be bad'
fi
fi