|
|
1.1 root 1: /*
2: * Code for various kinds of delays. Most of this is nonportable and
3: * requires various enhancements to the operating system, so it won't
4: * work on all systems. It is included in curses to provide a portable
5: * interface, and so curses itself can use it for function keys.
6: */
7:
8: /* @(#) naps.c: 1.1 10/15/83 (1.10 3/6/83) */
9:
10: #include "curses.ext"
11: #include <signal.h>
12:
13: #define NAPINTERVAL 100
14: #define HZ 60
15:
16: /* From early specs - this may change by 4.2BSD */
17: struct _timeval {
18: long tv_sec;
19: long tv_usec;
20: };
21:
22: /*
23: * Delay the output for ms milliseconds.
24: * Note that this is NOT the same as a high resolution sleep. It will
25: * cause a delay in the output but will not necessarily suspend the
26: * processor. For applications needing to sleep for 1/10th second,
27: * this is not a usable substitute. It causes a pause in the displayed
28: * output, for example, for the eye wink in snake. It is disrecommended
29: * for "delay" to be much more than 1/2 second, especially at high
30: * baud rates, because of all the characters it will output. Note
31: * that due to system delays, the actual pause could be even more.
32: * Some games won't work decently with this routine.
33: */
34: delay_output(ms)
35: int ms;
36: {
37: extern int _outchar(); /* it's in putp.c */
38:
39: return _delay(ms*10, _outchar);
40: }
41:
42: /*
43: * napms. Sleep for ms milliseconds. We don't expect a particularly good
44: * resolution - 60ths of a second is normal, 10ths might even be good enough,
45: * but the rest of the program thinks in ms because the unit of resolution
46: * varies from system to system. (In some countries, it's 50ths, for example.)
47: *
48: * Here are some reasonable ways to get a good nap.
49: *
50: * (1) Use the select system call in Berkeley 4.2BSD.
51: *
52: * (2) Use the 1/10th second resolution wait in the UNIX 3.0 tty driver.
53: * It turns out this is hard to do - you need a tty line that is
54: * always unused that you have read permission on to sleep on.
55: *
56: * (3) Install the ft (fast timer) device in your kernel.
57: * This is a psuedo-device to which an ioctl will wait n ticks
58: * and then send you an alarm.
59: *
60: * (4) Install the nap system call in your kernel.
61: * This system call does a timeout for the requested number of ticks.
62: *
63: * (5) Write a routine that busy waits checking the time with ftime.
64: * Ftime is not present on USG systems, and since this busy waits,
65: * it will drag down response on your system. But it works.
66: */
67: #ifdef TIOCREMOTE
68: /* on 4.2BSD, use select */
69: napms(ms)
70: int ms;
71: {
72: struct _timeval t;
73:
74: /*
75: * If your 4.2BSD select still rounds up to the next higher second,
76: * you should remove this code and install the ft driver.
77: * This routine was written under the assumption that the problem
78: * would be corrected by 4.2BSD.
79: */
80: t.sec = ms/1000;
81: t.usec = 1000 * (ms % 1000);
82: select(0, 0, 0, 0, &t);
83: return OK;
84: }
85: #else
86: /*
87: * Pause for ms milliseconds. Convert to ticks and wait that long.
88: * Call nap, which is either defined below or a system call.
89: */
90: napms(ms)
91: int ms;
92: {
93: int ticks;
94: int rv;
95:
96: ticks = ms / (1000 / HZ);
97: if (ticks <= 0)
98: ticks = 1;
99: rv = nap(ticks); /* call either the code below or nap system call */
100: return rv;
101: }
102: #endif
103:
104: #ifdef FTIOCSET
105: #define HASNAP
106: /*
107: * The following code is adapted from the sleep code in libc.
108: * It uses the "fast timer" device posted to USENET in Feb 1982.
109: * nap is like sleep but the units are ticks (e.g. 1/60ths of
110: * seconds in the USA).
111: */
112: #include <setjmp.h>
113: static jmp_buf jmp;
114: static int ftfd;
115:
116: /* don't call nap directly, you should call napms instead */
117: static int
118: nap(n)
119: unsigned n;
120: {
121: int napx();
122: unsigned altime;
123: int (*alsig)() = SIG_DFL;
124: char *ftname;
125: struct requestbuf {
126: short time;
127: short signo;
128: } rb;
129:
130: if (n==0)
131: return OK;
132: if (ftfd <= 0) {
133: ftname = "/dev/ft0";
134: while (ftfd <= 0 && ftname[7] <= '~') {
135: ftfd = open(ftname, 0);
136: if (ftfd <= 0)
137: ftname[7] ++;
138: }
139: }
140: if (ftfd <= 0) { /* Couldn't open a /dev/ft? */
141: sleepnap(n);
142: return ERR;
143: }
144: altime = alarm(1000); /* time to maneuver */
145: if (setjmp(jmp)) {
146: signal(SIGALRM, alsig);
147: alarm(altime);
148: return OK;
149: }
150: if (altime) {
151: if (altime > n)
152: altime -= n;
153: else {
154: n = altime;
155: altime = 1;
156: }
157: }
158: alsig = signal(SIGALRM, napx);
159: rb.time = n;
160: rb.signo = SIGALRM;
161: ioctl(ftfd, FTIOCSET, &rb);
162: for(;;)
163: pause();
164: /*NOTREACHED*/
165: }
166:
167: static
168: napx()
169: {
170: longjmp(jmp, 1);
171: }
172: #endif
173:
174: #ifdef USG
175: #ifndef HASNAP
176: #define HASNAP
177: #define IDLETTY "/dev/idletty"
178: /*
179: * Do it with the timer in the tty driver. Resolution is only 1/10th
180: * of a second. Problem is, if the user types something while we're
181: * sleeping, we wake up immediately, and have no way to tell how long
182: * we should sleep again. So we're sneaky and use a tty which we are
183: * pretty sure nobody is using.
184: *
185: * Note that we should be able to do this by setting VMIN to 100 and VTIME
186: * to the proper number of ticks. But due to a bug in the USG tty driver
187: * (this bug was still there in 5.0) this hangs until VMIN chars are typed
188: * no matter how much time elapses.
189: *
190: * This requires some care. If you choose a tty that is a dialup or
191: * which otherwise can show carrier, it will hang and you won't get
192: * any response from the keyboard. You can use /dev/tty if you have
193: * no such tty, but response will feel funny as described above.
194: * To find a suitable tty, try "stty > /dev/ttyxx" for various ttyxx's
195: * that look unused. If it hangs, you can't use it. You might try
196: * connecting a cable to your port that raises carrier to keep it from hanging.
197: *
198: * To use this feature on USG, you must
199: * ln /dev/ttyxx /dev/idletty,
200: * where /dev/ttyxx is one of your tty lines that is never used but
201: * won't hang on open. Otherwise we always return ERR.
202: *
203: * THIS USG CODE IS UNSUPPORTED AND ON A USE-AT-YOUR-OWN-RISK BASIS.
204: */
205: static int
206: nap(ticks)
207: int ticks;
208: {
209: struct termio t, ot;
210: static int ttyfd;
211: int n, tenths;
212: char c;
213:
214: if (ttyfd == 0)
215: ttyfd = open(IDLETTY, 2);
216: if (ttyfd < 0) {
217: sleepnap(ticks);
218: return ERR;
219: }
220: tenths = (ticks+(HZ/10)/2) / (HZ/10); /* Round to nearest 10th second */
221: ioctl(ttyfd, TCGETA, &t);
222: ot = t;
223: t.c_lflag &= ~ICANON;
224: t.c_cc[VMIN] = 0;
225: t.c_cc[VTIME] = tenths;
226: ioctl(ttyfd, TCSETAW, &t);
227: n = read(ttyfd, &c, 1);
228: ioctl(ttyfd, TCSETAW, &ot);
229: /*
230: * Now we potentially have a character in c that somebody's going
231: * to want. We just hope and pray they use getch, because there
232: * is no reasonable way to push it back onto the tty.
233: */
234: if (n > 0) {
235: for (n=0; SP->input_queue[n] >= 0; n++)
236: ;
237: SP->input_queue[n++] = c;
238: SP->input_queue[n++] = -1;
239: }
240: return OK;
241: }
242: #endif
243: #endif
244:
245: /* If you have some other externally supplied nap(), add -DHASNAP to cflags */
246: #ifndef HASNAP
247: static int
248: nap(ms)
249: int ms;
250: {
251: sleep((ms+999)/1000);
252: return ERR;
253: }
254: #endif
255:
256: /*
257: * Nothing better around, so we have to simulate nap with sleep.
258: */
259: static
260: sleepnap(ticks)
261: {
262: sleep((ticks+(HZ-1))/HZ);
263: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.