don't drop spl during selwakeup
[unix-history] / usr / src / sys / kern / sys_generic.c
CommitLineData
c4e1f1e5 1/* sys_generic.c 6.7 85/02/08 */
ffe28cfe 2
94368568
JB
3#include "param.h"
4#include "systm.h"
5#include "dir.h"
6#include "user.h"
7#include "ioctl.h"
8#include "file.h"
9#include "proc.h"
10#include "uio.h"
11#include "kernel.h"
12#include "stat.h"
ffe28cfe
BJ
13
14/*
15 * Read system call.
16 */
17read()
18{
ffe28cfe
BJ
19 register struct a {
20 int fdes;
21 char *cbuf;
22 unsigned count;
b9429893 23 } *uap = (struct a *)u.u_ap;
32a43ee2
BJ
24 struct uio auio;
25 struct iovec aiov;
ffe28cfe 26
32a43ee2
BJ
27 aiov.iov_base = (caddr_t)uap->cbuf;
28 aiov.iov_len = uap->count;
29 auio.uio_iov = &aiov;
30 auio.uio_iovcnt = 1;
b9429893
BJ
31 rwuio(&auio, UIO_READ);
32}
33
34readv()
35{
36 register struct a {
37 int fdes;
38 struct iovec *iovp;
39 int iovcnt;
40 } *uap = (struct a *)u.u_ap;
41 struct uio auio;
42 struct iovec aiov[16]; /* XXX */
43
44 if (uap->iovcnt <= 0 || uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) {
45 u.u_error = EINVAL;
46 return;
47 }
48 auio.uio_iov = aiov;
49 auio.uio_iovcnt = uap->iovcnt;
127f7d76
SL
50 u.u_error = copyin((caddr_t)uap->iovp, (caddr_t)aiov,
51 (unsigned)(uap->iovcnt * sizeof (struct iovec)));
52 if (u.u_error)
b9429893 53 return;
b9429893 54 rwuio(&auio, UIO_READ);
ffe28cfe
BJ
55}
56
57/*
58 * Write system call
59 */
60write()
61{
ffe28cfe
BJ
62 register struct a {
63 int fdes;
64 char *cbuf;
b9429893
BJ
65 int count;
66 } *uap = (struct a *)u.u_ap;
67 struct uio auio;
68 struct iovec aiov;
ffe28cfe 69
b9429893
BJ
70 auio.uio_iov = &aiov;
71 auio.uio_iovcnt = 1;
72 aiov.iov_base = uap->cbuf;
73 aiov.iov_len = uap->count;
74 rwuio(&auio, UIO_WRITE);
75}
76
77writev()
78{
79 register struct a {
80 int fdes;
81 struct iovec *iovp;
82 int iovcnt;
83 } *uap = (struct a *)u.u_ap;
84 struct uio auio;
85 struct iovec aiov[16]; /* XXX */
86
87 if (uap->iovcnt <= 0 || uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) {
ffe28cfe
BJ
88 u.u_error = EINVAL;
89 return;
90 }
b9429893
BJ
91 auio.uio_iov = aiov;
92 auio.uio_iovcnt = uap->iovcnt;
127f7d76
SL
93 u.u_error = copyin((caddr_t)uap->iovp, (caddr_t)aiov,
94 (unsigned)(uap->iovcnt * sizeof (struct iovec)));
95 if (u.u_error)
b9429893 96 return;
b9429893
BJ
97 rwuio(&auio, UIO_WRITE);
98}
99
100rwuio(uio, rw)
101 register struct uio *uio;
102 enum uio_rw rw;
103{
104 struct a {
105 int fdes;
106 };
107 register struct file *fp;
108 register struct iovec *iov;
b9429893
BJ
109 int i, count;
110
111 GETF(fp, ((struct a *)u.u_ap)->fdes);
112 if ((fp->f_flag&(rw==UIO_READ ? FREAD : FWRITE)) == 0) {
ffe28cfe
BJ
113 u.u_error = EBADF;
114 return;
115 }
b9429893 116 uio->uio_resid = 0;
c41770c0 117 uio->uio_segflg = UIO_USERSPACE;
b9429893
BJ
118 iov = uio->uio_iov;
119 for (i = 0; i < uio->uio_iovcnt; i++) {
120 if (iov->iov_len < 0) {
121 u.u_error = EINVAL;
122 return;
123 }
124 uio->uio_resid += iov->iov_len;
125 if (uio->uio_resid < 0) {
126 u.u_error = EINVAL;
127 return;
128 }
2a0114a8 129 iov++;
b9429893
BJ
130 }
131 count = uio->uio_resid;
88a7a62a 132 uio->uio_offset = fp->f_offset;
dd012d1e 133 if ((u.u_procp->p_flag&SOUSIG) == 0 && setjmp(&u.u_qsave)) {
b9429893 134 if (uio->uio_resid == count)
ffe28cfe 135 u.u_eosys = RESTARTSYS;
b9429893 136 } else
88a7a62a
SL
137 u.u_error = (*fp->f_ops->fo_rw)(fp, rw, uio);
138 u.u_r.r_val1 = count - uio->uio_resid;
139 fp->f_offset += u.u_r.r_val1;
4147b3f6 140}
ffe28cfe
BJ
141
142/*
143 * Ioctl system call
ffe28cfe
BJ
144 */
145ioctl()
146{
147 register struct file *fp;
4b72e2f9 148 struct a {
ffe28cfe
BJ
149 int fdes;
150 int cmd;
151 caddr_t cmarg;
152 } *uap;
b9429893
BJ
153 register int com;
154 register u_int size;
4b72e2f9 155 char data[IOCPARM_MASK+1];
ffe28cfe
BJ
156
157 uap = (struct a *)u.u_ap;
21e0a474 158 GETF(fp, uap->fdes);
ffe28cfe
BJ
159 if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
160 u.u_error = EBADF;
161 return;
162 }
4b72e2f9
SL
163 com = uap->cmd;
164
75a02b8d 165#if defined(vax) && defined(COMPAT)
4b72e2f9
SL
166 /*
167 * Map old style ioctl's into new for the
168 * sake of backwards compatibility (sigh).
169 */
170 if ((com&~0xffff) == 0) {
171 com = mapioctl(com);
172 if (com == 0) {
173 u.u_error = EINVAL;
174 return;
175 }
176 }
177#endif
178 if (com == FIOCLEX) {
3650c37d 179 u.u_pofile[uap->fdes] |= UF_EXCLOSE;
ffe28cfe
BJ
180 return;
181 }
4b72e2f9 182 if (com == FIONCLEX) {
3650c37d 183 u.u_pofile[uap->fdes] &= ~UF_EXCLOSE;
ffe28cfe
BJ
184 return;
185 }
4b72e2f9
SL
186
187 /*
188 * Interpret high order word to find
189 * amount of data to be copied to/from the
190 * user's address space.
4b72e2f9
SL
191 */
192 size = (com &~ (IOC_INOUT|IOC_VOID)) >> 16;
193 if (size > sizeof (data)) {
194 u.u_error = EFAULT;
ffe28cfe
BJ
195 return;
196 }
471f17ed
SL
197 if (com&IOC_IN) {
198 if (size) {
199 u.u_error =
200 copyin(uap->cmarg, (caddr_t)data, (u_int)size);
201 if (u.u_error)
202 return;
203 } else
204 *(caddr_t *)data = uap->cmarg;
205 } else if ((com&IOC_OUT) && size)
206 /*
207 * Zero the buffer on the stack so the user
208 * always gets back something deterministic.
209 */
4b72e2f9 210 bzero((caddr_t)data, size);
a76b60f6
SL
211 else if (com&IOC_VOID)
212 *(caddr_t *)data = uap->cmarg;
4b72e2f9 213
88a7a62a
SL
214 switch (com) {
215
216 case FIONBIO:
217 u.u_error = fset(fp, FNDELAY, *(int *)data);
218 return;
219
220 case FIOASYNC:
221 u.u_error = fset(fp, FASYNC, *(int *)data);
222 return;
223
224 case FIOSETOWN:
225 u.u_error = fsetown(fp, *(int *)data);
226 return;
4b72e2f9 227
88a7a62a
SL
228 case FIOGETOWN:
229 u.u_error = fgetown(fp, (int *)data);
230 return;
231 }
232 u.u_error = (*fp->f_ops->fo_ioctl)(fp, com, data);
4b72e2f9
SL
233 /*
234 * Copy any data to user, size was
235 * already set and checked above.
236 */
127f7d76
SL
237 if (u.u_error == 0 && (com&IOC_OUT) && size)
238 u.u_error = copyout(data, uap->cmarg, (u_int)size);
ffe28cfe
BJ
239}
240
88a7a62a
SL
241int unselect();
242int nselcoll;
d441e5bc
MK
243
244/*
245 * Select uses bit masks of file descriptors in ints.
246 * These macros manipulate such bit fields (the filesystem macros use chars).
247 */
248#define NBI (sizeof(int) * NBBY) /* bits per int */
249#define NI howmany(NOFILE, NBI)
250#define tbit(p, n) ((p)[(n)/NBI] & (1 << ((n) % NBI)))
251#define sbit(p, n) ((p)[(n)/NBI] |= (1 << ((n) % NBI)))
252#define cbit(p, n) ((p)[(n)/NBI] &= ~(1 << ((n) % NBI)))
253
ffe28cfe 254/*
88a7a62a 255 * Select system call.
ffe28cfe 256 */
88a7a62a
SL
257select()
258{
259 register struct uap {
260 int nd;
d441e5bc 261 int *in, *ou, *ex;
88a7a62a
SL
262 struct timeval *tv;
263 } *uap = (struct uap *)u.u_ap;
d441e5bc 264 int ibits[3][NI], obits[3][NI];
88a7a62a 265 struct timeval atv;
d441e5bc 266 int s, ncoll, ni;
88a7a62a
SL
267 label_t lqsave;
268
d441e5bc
MK
269 bzero(ibits, sizeof(ibits));
270 bzero(obits, sizeof(obits));
88a7a62a
SL
271 if (uap->nd > NOFILE)
272 uap->nd = NOFILE; /* forgiving, if slightly wrong */
d441e5bc 273 ni = howmany(uap->nd, NBI);
88a7a62a
SL
274
275#define getbits(name, x) \
276 if (uap->name) { \
d441e5bc
MK
277 u.u_error = copyin((caddr_t)uap->name, (caddr_t)ibits[x], \
278 ni * sizeof(int)); \
88a7a62a
SL
279 if (u.u_error) \
280 goto done; \
d441e5bc 281 }
88a7a62a
SL
282 getbits(in, 0);
283 getbits(ou, 1);
284 getbits(ex, 2);
285#undef getbits
286
287 if (uap->tv) {
288 u.u_error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
289 sizeof (atv));
290 if (u.u_error)
291 goto done;
292 if (itimerfix(&atv)) {
293 u.u_error = EINVAL;
294 goto done;
295 }
c4e1f1e5 296 s = splhigh(); timevaladd(&atv, &time); splx(s);
88a7a62a
SL
297 }
298retry:
299 ncoll = nselcoll;
300 u.u_procp->p_flag |= SSEL;
d441e5bc 301 u.u_r.r_val1 = selscan(ibits, obits, uap->nd);
88a7a62a
SL
302 if (u.u_error || u.u_r.r_val1)
303 goto done;
c4e1f1e5 304 s = splhigh();
e394e134
SL
305 /* this should be timercmp(&time, &atv, >=) */
306 if (uap->tv && (time.tv_sec > atv.tv_sec ||
307 time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) {
88a7a62a
SL
308 splx(s);
309 goto done;
310 }
311 if ((u.u_procp->p_flag & SSEL) == 0 || nselcoll != ncoll) {
312 u.u_procp->p_flag &= ~SSEL;
313 splx(s);
314 goto retry;
315 }
316 u.u_procp->p_flag &= ~SSEL;
317 if (uap->tv) {
318 lqsave = u.u_qsave;
319 if (setjmp(&u.u_qsave)) {
320 untimeout(unselect, (caddr_t)u.u_procp);
321 u.u_error = EINTR;
322 splx(s);
323 goto done;
324 }
325 timeout(unselect, (caddr_t)u.u_procp, hzto(&atv));
326 }
327 sleep((caddr_t)&selwait, PZERO+1);
328 if (uap->tv) {
329 u.u_qsave = lqsave;
330 untimeout(unselect, (caddr_t)u.u_procp);
331 }
332 splx(s);
333 goto retry;
334done:
335#define putbits(name, x) \
336 if (uap->name) { \
d441e5bc
MK
337 int error = copyout((caddr_t)obits[x], (caddr_t)uap->name, \
338 ni * sizeof(int)); \
88a7a62a
SL
339 if (error) \
340 u.u_error = error; \
341 }
342 putbits(in, 0);
343 putbits(ou, 1);
344 putbits(ex, 2);
345#undef putbits
346}
347
348unselect(p)
349 register struct proc *p;
350{
c4e1f1e5 351 register int s = splhigh();
88a7a62a
SL
352
353 switch (p->p_stat) {
354
355 case SSLEEP:
356 setrun(p);
357 break;
358
359 case SSTOP:
360 unsleep(p);
361 break;
362 }
363 splx(s);
364}
365
d441e5bc
MK
366selscan(ibits, obits, nfd)
367 int (*ibits)[NI], (*obits)[NI];
88a7a62a 368{
d441e5bc 369 register int which, bits, i, j;
88a7a62a
SL
370 int flag;
371 struct file *fp;
372 int n = 0;
373
374 for (which = 0; which < 3; which++) {
88a7a62a
SL
375 switch (which) {
376
377 case 0:
378 flag = FREAD; break;
379
380 case 1:
381 flag = FWRITE; break;
382
383 case 2:
384 flag = 0; break;
385 }
d441e5bc
MK
386 for (i = 0; i < nfd; i += NBI) {
387 bits = ibits[which][i/NBI];
388 while ((j = ffs(bits)) && i + --j < nfd) {
389 bits &= ~(1 << j);
390 fp = u.u_ofile[i + j];
391 if (fp == NULL) {
392 u.u_error = EBADF;
393 break;
394 }
395 if ((*fp->f_ops->fo_select)(fp, flag)) {
396 sbit(obits[which], i + j);
397 n++;
398 }
88a7a62a
SL
399 }
400 }
401 }
402 return (n);
403}
404
ffe28cfe 405/*ARGSUSED*/
88a7a62a
SL
406seltrue(dev, flag)
407 dev_t dev;
408 int flag;
ffe28cfe
BJ
409{
410
88a7a62a 411 return (1);
ffe28cfe 412}
1edb1cf8 413
88a7a62a
SL
414selwakeup(p, coll)
415 register struct proc *p;
416 int coll;
1edb1cf8
BJ
417{
418
88a7a62a
SL
419 if (coll) {
420 nselcoll++;
421 wakeup((caddr_t)&selwait);
422 }
423 if (p) {
c4e1f1e5 424 int s = splhigh();
6bc3aba9
MK
425 if (p->p_wchan == (caddr_t)&selwait) {
426 if (p->p_stat == SSLEEP)
427 setrun(p);
428 else
429 unsleep(p);
430 } else if (p->p_flag & SSEL)
88a7a62a
SL
431 p->p_flag &= ~SSEL;
432 splx(s);
433 }
1edb1cf8 434}