sigio.c revision a61f334fd2864b9b040f7e882726426ed7e8a317
18e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Licensed under the GPL
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <unistd.h>
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <stdlib.h>
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <termios.h>
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pty.h>
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <signal.h>
11c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike#include <fcntl.h>
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <errno.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <string.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <sched.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <sys/socket.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <sys/poll.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "init.h"
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "user.h"
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "kern_util.h"
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "sigio.h"
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "os.h"
22c13e569073b89eb75216a2551e89ae93ad1f9951Paolo 'Blaisorblade' Giarrusso#include "um_malloc.h"
23c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike#include "init.h"
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25f206aabb035318ac4bafbf0b87798335de3634dfJeff Dike/* Protected by sigio_lock(), also used by sigio_cleanup, which is an
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * exitcall.
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int write_sigio_pid = -1;
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* These arrays are initialized before the sigio thread is started, and
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the descriptors closed after it is killed.  So, it can't see them change.
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * On the UML side, they are changed under the sigio_lock.
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
345f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike#define SIGIO_FDS_INIT {-1, -1}
355f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike
365f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dikestatic int write_sigio_fds[2] = SIGIO_FDS_INIT;
375f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dikestatic int sigio_private[2] = SIGIO_FDS_INIT;
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pollfds {
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pollfd *poll;
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int size;
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int used;
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Protected by sigio_lock().  Used by the sigio thread, but the UML thread
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * synchronizes with it.
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4819bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dikestatic struct pollfds current_poll;
4919bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dikestatic struct pollfds next_poll;
5019bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dikestatic struct pollfds all_sigio_fds;
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int write_sigio_thread(void *unused)
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pollfds *fds, tmp;
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pollfd *p;
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, n, respond_fd;
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char c;
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
59cd2ee4a30cc0775d8b54e5b958613361a7cacfecJeff Dike        signal(SIGWINCH, SIG_IGN);
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fds = &current_poll;
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while(1){
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		n = poll(fds->poll, fds->used, -1);
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(n < 0){
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if(errno == EINTR) continue;
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("write_sigio_thread : poll returned %d, "
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "errno = %d\n", n, errno);
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for(i = 0; i < fds->used; i++){
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			p = &fds->poll[i];
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if(p->revents == 0) continue;
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if(p->fd == sigio_private[1]){
72a61f334fd2864b9b040f7e882726426ed7e8a317Jeff Dike				CATCH_EINTR(n = read(sigio_private[1], &c,
73a61f334fd2864b9b040f7e882726426ed7e8a317Jeff Dike						     sizeof(c)));
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if(n != sizeof(c))
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printk("write_sigio_thread : "
7619bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike					       "read on socket failed, "
77a61f334fd2864b9b040f7e882726426ed7e8a317Jeff Dike					       "err = %d\n", errno);
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				tmp = current_poll;
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				current_poll = next_poll;
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				next_poll = tmp;
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				respond_fd = sigio_private[1];
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else {
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				respond_fd = write_sigio_fds[1];
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fds->used--;
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				memmove(&fds->poll[i], &fds->poll[i + 1],
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					(fds->used - i) * sizeof(*fds->poll));
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
90a61f334fd2864b9b040f7e882726426ed7e8a317Jeff Dike			CATCH_EINTR(n = write(respond_fd, &c, sizeof(c)));
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if(n != sizeof(c))
9219bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike				printk("write_sigio_thread : write on socket "
93a61f334fd2864b9b040f7e882726426ed7e8a317Jeff Dike				       "failed, err = %d\n", errno);
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
961b57e9c27882a908f180d4daf72ee12c6f137178Jeff Dike
971b57e9c27882a908f180d4daf72ee12c6f137178Jeff Dike	return 0;
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10019bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dikestatic int need_poll(struct pollfds *polls, int n)
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
102838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike	struct pollfd *new;
103838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike
104838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike	if(n <= polls->size)
10519bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike		return 0;
106838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike
107838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike	new = um_kmalloc_atomic(n * sizeof(struct pollfd));
108838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike	if(new == NULL){
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("need_poll : failed to allocate new pollfds\n");
11019bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike		return -ENOMEM;
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
112838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike
113838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike	memcpy(new, polls->poll, polls->used * sizeof(struct pollfd));
114838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike	kfree(polls->poll);
115838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike
116838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike	polls->poll = new;
11719bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike	polls->size = n;
11819bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike	return 0;
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Must be called with sigio_lock held, because it's needed by the marked
12219bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike * critical section.
12319bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike */
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void update_thread(void)
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int n;
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char c;
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	flags = set_signals(0);
131a61f334fd2864b9b040f7e882726426ed7e8a317Jeff Dike	n = write(sigio_private[0], &c, sizeof(c));
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(n != sizeof(c)){
133a61f334fd2864b9b040f7e882726426ed7e8a317Jeff Dike		printk("update_thread : write failed, err = %d\n", errno);
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto fail;
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
137a61f334fd2864b9b040f7e882726426ed7e8a317Jeff Dike	CATCH_EINTR(n = read(sigio_private[0], &c, sizeof(c)));
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(n != sizeof(c)){
139a61f334fd2864b9b040f7e882726426ed7e8a317Jeff Dike		printk("update_thread : read failed, err = %d\n", errno);
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto fail;
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_signals(flags);
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return;
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fail:
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Critical section start */
147f206aabb035318ac4bafbf0b87798335de3634dfJeff Dike	if(write_sigio_pid != -1)
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		os_kill_process(write_sigio_pid, 1);
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_sigio_pid = -1;
1508e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike	close(sigio_private[0]);
1518e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike	close(sigio_private[1]);
1528e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike	close(write_sigio_fds[0]);
1538e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike	close(write_sigio_fds[1]);
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Critical section end */
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_signals(flags);
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15819bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dikeint add_sigio_fd(int fd)
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16019bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike	struct pollfd *p;
16119bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike	int err = 0, i, n;
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sigio_lock();
16419bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike	for(i = 0; i < all_sigio_fds.used; i++){
16519bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike		if(all_sigio_fds.poll[i].fd == fd)
16619bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike			break;
16719bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike	}
16819bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike	if(i == all_sigio_fds.used)
16919bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike		goto out;
17019bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike
17119bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike	p = &all_sigio_fds.poll[i];
17219bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for(i = 0; i < current_poll.used; i++){
174f206aabb035318ac4bafbf0b87798335de3634dfJeff Dike		if(current_poll.poll[i].fd == fd)
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
178838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike	n = current_poll.used;
179838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike	err = need_poll(&next_poll, n + 1);
180f206aabb035318ac4bafbf0b87798335de3634dfJeff Dike	if(err)
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
183838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike	memcpy(next_poll.poll, current_poll.poll,
184838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike	       current_poll.used * sizeof(struct pollfd));
185838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike	next_poll.poll[n] = *p;
186838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike	next_poll.used = n + 1;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	update_thread();
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sigio_unlock();
19019bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike	return err;
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint ignore_sigio_fd(int fd)
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pollfd *p;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0, i, n = 0;
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19861232f2fe44f7ac12d7512d099a8f10923eff7eaJeff Dike	/* This is called from exitcalls elsewhere in UML - if
19961232f2fe44f7ac12d7512d099a8f10923eff7eaJeff Dike	 * sigio_cleanup has already run, then update_thread will hang
20061232f2fe44f7ac12d7512d099a8f10923eff7eaJeff Dike	 * or fail because the thread is no longer running.
20161232f2fe44f7ac12d7512d099a8f10923eff7eaJeff Dike	 */
20261232f2fe44f7ac12d7512d099a8f10923eff7eaJeff Dike	if(write_sigio_pid == -1)
20361232f2fe44f7ac12d7512d099a8f10923eff7eaJeff Dike		return -EIO;
20461232f2fe44f7ac12d7512d099a8f10923eff7eaJeff Dike
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sigio_lock();
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for(i = 0; i < current_poll.used; i++){
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(current_poll.poll[i].fd == fd) break;
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(i == current_poll.used)
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
211f206aabb035318ac4bafbf0b87798335de3634dfJeff Dike
21219bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike	err = need_poll(&next_poll, current_poll.used - 1);
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(err)
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for(i = 0; i < current_poll.used; i++){
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		p = &current_poll.poll[i];
21819bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike		if(p->fd != fd)
21919bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike			next_poll.poll[n++] = *p;
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
221838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike	next_poll.used = current_poll.used - 1;
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	update_thread();
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sigio_unlock();
22661232f2fe44f7ac12d7512d099a8f10923eff7eaJeff Dike	return err;
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
229f206aabb035318ac4bafbf0b87798335de3634dfJeff Dikestatic struct pollfd *setup_initial_poll(int fd)
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pollfd *p;
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
233b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	p = um_kmalloc(sizeof(struct pollfd));
234b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	if (p == NULL) {
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("setup_initial_poll : failed to allocate poll\n");
236b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso		return NULL;
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
23819bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike	*p = ((struct pollfd) { .fd		= fd,
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				.events 	= POLLIN,
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				.revents 	= 0 });
241b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	return p;
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2448e64d96aeb495709c13307e2d79f3ee37e96aa4eJeff Dikestatic void write_sigio_workaround(void)
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long stack;
247b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	struct pollfd *p;
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
249b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	int l_write_sigio_fds[2];
250b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	int l_sigio_private[2];
251b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	int l_write_sigio_pid;
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
253b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	/* We call this *tons* of times - and most ones we must just fail. */
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sigio_lock();
255b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	l_write_sigio_pid = write_sigio_pid;
256b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	sigio_unlock();
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
258b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	if (l_write_sigio_pid != -1)
259b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso		return;
260b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso
261b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	err = os_pipe(l_write_sigio_fds, 1, 1);
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(err < 0){
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("write_sigio_workaround - os_pipe 1 failed, "
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "err = %d\n", -err);
265b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso		return;
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
267b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	err = os_pipe(l_sigio_private, 1, 1);
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(err < 0){
269f206aabb035318ac4bafbf0b87798335de3634dfJeff Dike		printk("write_sigio_workaround - os_pipe 2 failed, "
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "err = %d\n", -err);
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out_close1;
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
273b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso
274b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	p = setup_initial_poll(l_sigio_private[1]);
275b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	if(!p)
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out_close2;
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
278b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	sigio_lock();
279b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso
280b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	/* Did we race? Don't try to optimize this, please, it's not so likely
281b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	 * to happen, and no more than once at the boot. */
282b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	if(write_sigio_pid != -1)
2835f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike		goto out_free;
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2855f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike	current_poll = ((struct pollfds) { .poll 	= p,
2865f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike					   .used 	= 1,
2875f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike					   .size 	= 1 });
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
289b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	if (write_sigio_irq(l_write_sigio_fds[0]))
2905f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike		goto out_clear_poll;
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
292b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	memcpy(write_sigio_fds, l_write_sigio_fds, sizeof(l_write_sigio_fds));
293b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	memcpy(sigio_private, l_sigio_private, sizeof(l_sigio_private));
294b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso
2955f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike	write_sigio_pid = run_helper_thread(write_sigio_thread, NULL,
2965f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike					    CLONE_FILES | CLONE_VM, &stack, 0);
297b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso
2985f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike	if (write_sigio_pid < 0)
2995f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike		goto out_clear;
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
301b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	sigio_unlock();
3025f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike	return;
303b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso
3045f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dikeout_clear:
305b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	write_sigio_pid = -1;
3065f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike	write_sigio_fds[0] = -1;
3075f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike	write_sigio_fds[1] = -1;
3085f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike	sigio_private[0] = -1;
3095f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike	sigio_private[1] = -1;
3105f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dikeout_clear_poll:
3115f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike	current_poll = ((struct pollfds) { .poll	= NULL,
3125f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike					   .size	= 0,
3135f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike					   .used	= 0 });
3145f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dikeout_free:
3155f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike	sigio_unlock();
316e6fb54abb8a36703f54b7e27a756a3df6667c37bPaolo 'Blaisorblade' Giarrusso	kfree(p);
3175f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dikeout_close2:
3188e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike	close(l_sigio_private[0]);
3198e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike	close(l_sigio_private[1]);
3205f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dikeout_close1:
3218e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike	close(l_write_sigio_fds[0]);
3228e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike	close(l_write_sigio_fds[1]);
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
325c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike/* Changed during early boot */
326c65badbdf5dc117e45873e760f807063ad59a854Jeff Dikestatic int pty_output_sigio = 0;
327c65badbdf5dc117e45873e760f807063ad59a854Jeff Dikestatic int pty_close_sigio = 0;
328c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
3298e64d96aeb495709c13307e2d79f3ee37e96aa4eJeff Dikevoid maybe_sigio_broken(int fd, int read)
3308e64d96aeb495709c13307e2d79f3ee37e96aa4eJeff Dike{
33119bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike	int err;
33219bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike
3338e64d96aeb495709c13307e2d79f3ee37e96aa4eJeff Dike	if(!isatty(fd))
3348e64d96aeb495709c13307e2d79f3ee37e96aa4eJeff Dike		return;
3358e64d96aeb495709c13307e2d79f3ee37e96aa4eJeff Dike
3368e64d96aeb495709c13307e2d79f3ee37e96aa4eJeff Dike	if((read || pty_output_sigio) && (!read || pty_close_sigio))
3378e64d96aeb495709c13307e2d79f3ee37e96aa4eJeff Dike		return;
3388e64d96aeb495709c13307e2d79f3ee37e96aa4eJeff Dike
3398e64d96aeb495709c13307e2d79f3ee37e96aa4eJeff Dike	write_sigio_workaround();
34019bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike
34119bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike	sigio_lock();
34219bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike	err = need_poll(&all_sigio_fds, all_sigio_fds.used + 1);
34304a51e66adcdc0de6ffaa488934ce3ffb3818ecfJeff Dike	if(err){
34404a51e66adcdc0de6ffaa488934ce3ffb3818ecfJeff Dike		printk("maybe_sigio_broken - failed to add pollfd for "
34504a51e66adcdc0de6ffaa488934ce3ffb3818ecfJeff Dike		       "descriptor %d\n", fd);
34619bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike		goto out;
34704a51e66adcdc0de6ffaa488934ce3ffb3818ecfJeff Dike	}
348838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike
34919bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike	all_sigio_fds.poll[all_sigio_fds.used++] =
35019bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike		((struct pollfd) { .fd  	= fd,
35119bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike				   .events 	= read ? POLLIN : POLLOUT,
35219bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike				   .revents 	= 0 });
35319bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dikeout:
35419bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike	sigio_unlock();
3558e64d96aeb495709c13307e2d79f3ee37e96aa4eJeff Dike}
3568e64d96aeb495709c13307e2d79f3ee37e96aa4eJeff Dike
35729ac1c2142346e1e0e072f41df31688fc42ff540Jeff Dikestatic void sigio_cleanup(void)
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
359f206aabb035318ac4bafbf0b87798335de3634dfJeff Dike	if(write_sigio_pid != -1){
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		os_kill_process(write_sigio_pid, 1);
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_sigio_pid = -1;
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
36429ac1c2142346e1e0e072f41df31688fc42ff540Jeff Dike
36529ac1c2142346e1e0e072f41df31688fc42ff540Jeff Dike__uml_exitcall(sigio_cleanup);
366c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
367c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike/* Used as a flag during SIGIO testing early in boot */
368c65badbdf5dc117e45873e760f807063ad59a854Jeff Dikestatic volatile int got_sigio = 0;
369c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
370c65badbdf5dc117e45873e760f807063ad59a854Jeff Dikestatic void __init handler(int sig)
371c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike{
372c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	got_sigio = 1;
373c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike}
374c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
375c65badbdf5dc117e45873e760f807063ad59a854Jeff Dikestruct openpty_arg {
376c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	int master;
377c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	int slave;
378c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	int err;
379c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike};
380c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
381c65badbdf5dc117e45873e760f807063ad59a854Jeff Dikestatic void openpty_cb(void *arg)
382c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike{
383c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	struct openpty_arg *info = arg;
384c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
385c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	info->err = 0;
386c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	if(openpty(&info->master, &info->slave, NULL, NULL, NULL))
387c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike		info->err = -errno;
388c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike}
389c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
390c65badbdf5dc117e45873e760f807063ad59a854Jeff Dikestatic int async_pty(int master, int slave)
391c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike{
392c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	int flags;
393c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
394c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	flags = fcntl(master, F_GETFL);
395c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	if(flags < 0)
396c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike		return -errno;
397c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
398c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) ||
399c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	   (fcntl(master, F_SETOWN, os_getpid()) < 0))
400c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike		return -errno;
401c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
402c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0))
403c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike		return -errno;
404c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
405c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	return(0);
406c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike}
407c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
408c65badbdf5dc117e45873e760f807063ad59a854Jeff Dikestatic void __init check_one_sigio(void (*proc)(int, int))
409c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike{
410c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	struct sigaction old, new;
411c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	struct openpty_arg pty = { .master = -1, .slave = -1 };
412c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	int master, slave, err;
413c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
414c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	initial_thread_cb(openpty_cb, &pty);
415c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	if(pty.err){
416c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike		printk("openpty failed, errno = %d\n", -pty.err);
417c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike		return;
418c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	}
419c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
420c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	master = pty.master;
421c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	slave = pty.slave;
422c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
423c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	if((master == -1) || (slave == -1)){
424c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike		printk("openpty failed to allocate a pty\n");
425c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike		return;
426c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	}
427c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
428c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	/* Not now, but complain so we now where we failed. */
429c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	err = raw(master);
430c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	if (err < 0)
431c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike		panic("check_sigio : __raw failed, errno = %d\n", -err);
432c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
433c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	err = async_pty(master, slave);
434c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	if(err < 0)
435c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike		panic("tty_fds : sigio_async failed, err = %d\n", -err);
436c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
437c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	if(sigaction(SIGIO, NULL, &old) < 0)
438c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike		panic("check_sigio : sigaction 1 failed, errno = %d\n", errno);
439c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	new = old;
440c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	new.sa_handler = handler;
441c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	if(sigaction(SIGIO, &new, NULL) < 0)
442c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike		panic("check_sigio : sigaction 2 failed, errno = %d\n", errno);
443c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
444c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	got_sigio = 0;
445c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	(*proc)(master, slave);
446c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
447c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	close(master);
448c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	close(slave);
449c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
450c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	if(sigaction(SIGIO, &old, NULL) < 0)
451c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike		panic("check_sigio : sigaction 3 failed, errno = %d\n", errno);
452c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike}
453c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
454c65badbdf5dc117e45873e760f807063ad59a854Jeff Dikestatic void tty_output(int master, int slave)
455c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike{
456c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	int n;
457c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	char buf[512];
458c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
459c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	printk("Checking that host ptys support output SIGIO...");
460c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
461c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	memset(buf, 0, sizeof(buf));
462c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
463a61f334fd2864b9b040f7e882726426ed7e8a317Jeff Dike	while(write(master, buf, sizeof(buf)) > 0) ;
464c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	if(errno != EAGAIN)
465ef0470c053274c343b2be8737e0146d65e17f9beJeff Dike		panic("tty_output : write failed, errno = %d\n", errno);
466a61f334fd2864b9b040f7e882726426ed7e8a317Jeff Dike	while(((n = read(slave, buf, sizeof(buf))) > 0) && !got_sigio) ;
467c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
468c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	if(got_sigio){
469c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike		printk("Yes\n");
470c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike		pty_output_sigio = 1;
471c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	}
472ef0470c053274c343b2be8737e0146d65e17f9beJeff Dike	else if(n == -EAGAIN)
473ef0470c053274c343b2be8737e0146d65e17f9beJeff Dike		printk("No, enabling workaround\n");
474ef0470c053274c343b2be8737e0146d65e17f9beJeff Dike	else panic("tty_output : read failed, err = %d\n", n);
475c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike}
476c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
477c65badbdf5dc117e45873e760f807063ad59a854Jeff Dikestatic void tty_close(int master, int slave)
478c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike{
479c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	printk("Checking that host ptys support SIGIO on close...");
480c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
481c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	close(slave);
482c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	if(got_sigio){
483c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike		printk("Yes\n");
484c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike		pty_close_sigio = 1;
485c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	}
486c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	else printk("No, enabling workaround\n");
487c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike}
488c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
489c65badbdf5dc117e45873e760f807063ad59a854Jeff Dikevoid __init check_sigio(void)
490c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike{
491c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) &&
492c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	   (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){
493c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike		printk("No pseudo-terminals available - skipping pty SIGIO "
494c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike		       "check\n");
495c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike		return;
496c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	}
497c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	check_one_sigio(tty_output);
498c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	check_one_sigio(tty_close);
499c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike}
500c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
501c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike/* Here because it only does the SIGIO testing for now */
502c65badbdf5dc117e45873e760f807063ad59a854Jeff Dikevoid __init os_check_bugs(void)
503c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike{
504c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	check_sigio();
505c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike}
506