18e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike/*
25d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dike * Copyright (C) 2002 - 2008 Jeff Dike (jdike@{addtoit,linux.intel}.com)
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Licensed under the GPL
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <unistd.h>
7fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike#include <errno.h>
8fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike#include <fcntl.h>
9fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike#include <poll.h>
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pty.h>
11fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike#include <sched.h>
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <signal.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <string.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "kern_util.h"
15fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike#include "init.h"
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "os.h"
17fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike#include "sigio.h"
18c13e569073b89eb75216a2551e89ae93ad1f9951Paolo 'Blaisorblade' Giarrusso#include "um_malloc.h"
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike/*
21fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike * Protected by sigio_lock(), also used by sigio_cleanup, which is an
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * exitcall.
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int write_sigio_pid = -1;
25c43990162fc7f9d2f15a12797fdc6f9c0905f704Jeff Dikestatic unsigned long write_sigio_stack;
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike/*
28fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike * These arrays are initialized before the sigio thread is started, and
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the descriptors closed after it is killed.  So, it can't see them change.
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * On the UML side, they are changed under the sigio_lock.
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
325f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike#define SIGIO_FDS_INIT {-1, -1}
335f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike
345f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dikestatic int write_sigio_fds[2] = SIGIO_FDS_INIT;
355f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dikestatic int sigio_private[2] = SIGIO_FDS_INIT;
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pollfds {
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pollfd *poll;
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int size;
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int used;
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike/*
44fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike * Protected by sigio_lock().  Used by the sigio thread, but the UML thread
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * synchronizes with it.
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4719bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dikestatic struct pollfds current_poll;
4819bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dikestatic struct pollfds next_poll;
4919bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dikestatic struct pollfds all_sigio_fds;
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int write_sigio_thread(void *unused)
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pollfds *fds, tmp;
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pollfd *p;
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, n, respond_fd;
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char c;
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
58fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	signal(SIGWINCH, SIG_IGN);
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fds = &current_poll;
60fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	while (1) {
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		n = poll(fds->poll, fds->used, -1);
62fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		if (n < 0) {
63fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike			if (errno == EINTR)
64fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike				continue;
65fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike			printk(UM_KERN_ERR "write_sigio_thread : poll returned "
66fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike			       "%d, errno = %d\n", n, errno);
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
68fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		for (i = 0; i < fds->used; i++) {
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			p = &fds->poll[i];
70fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike			if (p->revents == 0)
71fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike				continue;
72fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike			if (p->fd == sigio_private[1]) {
73a61f334fd2864b9b040f7e882726426ed7e8a317Jeff Dike				CATCH_EINTR(n = read(sigio_private[1], &c,
74a61f334fd2864b9b040f7e882726426ed7e8a317Jeff Dike						     sizeof(c)));
75fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike				if (n != sizeof(c))
76fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike					printk(UM_KERN_ERR
77fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike					       "write_sigio_thread : "
7819bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike					       "read on socket failed, "
79a61f334fd2864b9b040f7e882726426ed7e8a317Jeff Dike					       "err = %d\n", errno);
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				tmp = current_poll;
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				current_poll = next_poll;
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				next_poll = tmp;
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				respond_fd = sigio_private[1];
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else {
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				respond_fd = write_sigio_fds[1];
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fds->used--;
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				memmove(&fds->poll[i], &fds->poll[i + 1],
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					(fds->used - i) * sizeof(*fds->poll));
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
92a61f334fd2864b9b040f7e882726426ed7e8a317Jeff Dike			CATCH_EINTR(n = write(respond_fd, &c, sizeof(c)));
93fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike			if (n != sizeof(c))
94fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike				printk(UM_KERN_ERR "write_sigio_thread : "
95fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike				       "write on socket failed, err = %d\n",
96fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike				       errno);
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
991b57e9c27882a908f180d4daf72ee12c6f137178Jeff Dike
1001b57e9c27882a908f180d4daf72ee12c6f137178Jeff Dike	return 0;
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10319bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dikestatic int need_poll(struct pollfds *polls, int n)
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
105838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike	struct pollfd *new;
106838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike
107fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	if (n <= polls->size)
10819bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike		return 0;
109838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike
11043f5b3085fdd27c4edf535d938b2cb0ccead4f75Jeff Dike	new = uml_kmalloc(n * sizeof(struct pollfd), UM_GFP_ATOMIC);
111fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	if (new == NULL) {
112fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		printk(UM_KERN_ERR "need_poll : failed to allocate new "
113fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		       "pollfds\n");
11419bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike		return -ENOMEM;
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
116838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike
117838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike	memcpy(new, polls->poll, polls->used * sizeof(struct pollfd));
118838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike	kfree(polls->poll);
119838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike
120838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike	polls->poll = new;
12119bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike	polls->size = n;
12219bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike	return 0;
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
125fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike/*
126fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike * Must be called with sigio_lock held, because it's needed by the marked
12719bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike * critical section.
12819bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike */
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void update_thread(void)
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int n;
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char c;
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	flags = set_signals(0);
136fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	CATCH_EINTR(n = write(sigio_private[0], &c, sizeof(c)));
137fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	if (n != sizeof(c)) {
138fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		printk(UM_KERN_ERR "update_thread : write failed, err = %d\n",
139fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		       errno);
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto fail;
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
143a61f334fd2864b9b040f7e882726426ed7e8a317Jeff Dike	CATCH_EINTR(n = read(sigio_private[0], &c, sizeof(c)));
144fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	if (n != sizeof(c)) {
145fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		printk(UM_KERN_ERR "update_thread : read failed, err = %d\n",
146fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		       errno);
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto fail;
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_signals(flags);
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fail:
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Critical section start */
154c43990162fc7f9d2f15a12797fdc6f9c0905f704Jeff Dike	if (write_sigio_pid != -1) {
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		os_kill_process(write_sigio_pid, 1);
156c43990162fc7f9d2f15a12797fdc6f9c0905f704Jeff Dike		free_stack(write_sigio_stack, 0);
157c43990162fc7f9d2f15a12797fdc6f9c0905f704Jeff Dike	}
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_sigio_pid = -1;
1598e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike	close(sigio_private[0]);
1608e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike	close(sigio_private[1]);
1618e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike	close(write_sigio_fds[0]);
1628e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike	close(write_sigio_fds[1]);
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Critical section end */
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_signals(flags);
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16719bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dikeint add_sigio_fd(int fd)
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16919bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike	struct pollfd *p;
17019bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike	int err = 0, i, n;
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sigio_lock();
173fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	for (i = 0; i < all_sigio_fds.used; i++) {
174fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		if (all_sigio_fds.poll[i].fd == fd)
17519bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike			break;
17619bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike	}
177fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	if (i == all_sigio_fds.used)
17819bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike		goto out;
17919bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike
18019bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike	p = &all_sigio_fds.poll[i];
18119bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike
182fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	for (i = 0; i < current_poll.used; i++) {
183fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		if (current_poll.poll[i].fd == fd)
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
187838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike	n = current_poll.used;
188838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike	err = need_poll(&next_poll, n + 1);
189fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	if (err)
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
192838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike	memcpy(next_poll.poll, current_poll.poll,
193838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike	       current_poll.used * sizeof(struct pollfd));
194838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike	next_poll.poll[n] = *p;
195838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike	next_poll.used = n + 1;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	update_thread();
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sigio_unlock();
19919bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike	return err;
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint ignore_sigio_fd(int fd)
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pollfd *p;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0, i, n = 0;
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
207fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	/*
208fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	 * This is called from exitcalls elsewhere in UML - if
20961232f2fe44f7ac12d7512d099a8f10923eff7eaJeff Dike	 * sigio_cleanup has already run, then update_thread will hang
21061232f2fe44f7ac12d7512d099a8f10923eff7eaJeff Dike	 * or fail because the thread is no longer running.
21161232f2fe44f7ac12d7512d099a8f10923eff7eaJeff Dike	 */
212fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	if (write_sigio_pid == -1)
21361232f2fe44f7ac12d7512d099a8f10923eff7eaJeff Dike		return -EIO;
21461232f2fe44f7ac12d7512d099a8f10923eff7eaJeff Dike
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sigio_lock();
216fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	for (i = 0; i < current_poll.used; i++) {
217fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		if (current_poll.poll[i].fd == fd)
218fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike			break;
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
220fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	if (i == current_poll.used)
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
222f206aabb035318ac4bafbf0b87798335de3634dfJeff Dike
22319bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike	err = need_poll(&next_poll, current_poll.used - 1);
224fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	if (err)
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
227fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	for (i = 0; i < current_poll.used; i++) {
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		p = &current_poll.poll[i];
229fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		if (p->fd != fd)
23019bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike			next_poll.poll[n++] = *p;
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
232838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike	next_poll.used = current_poll.used - 1;
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	update_thread();
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sigio_unlock();
23761232f2fe44f7ac12d7512d099a8f10923eff7eaJeff Dike	return err;
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
240f206aabb035318ac4bafbf0b87798335de3634dfJeff Dikestatic struct pollfd *setup_initial_poll(int fd)
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pollfd *p;
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24443f5b3085fdd27c4edf535d938b2cb0ccead4f75Jeff Dike	p = uml_kmalloc(sizeof(struct pollfd), UM_GFP_KERNEL);
245b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	if (p == NULL) {
246fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		printk(UM_KERN_ERR "setup_initial_poll : failed to allocate "
247fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		       "poll\n");
248b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso		return NULL;
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
25019bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike	*p = ((struct pollfd) { .fd		= fd,
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				.events 	= POLLIN,
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				.revents 	= 0 });
253b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	return p;
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2568e64d96aeb495709c13307e2d79f3ee37e96aa4eJeff Dikestatic void write_sigio_workaround(void)
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
258b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	struct pollfd *p;
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
260b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	int l_write_sigio_fds[2];
261b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	int l_sigio_private[2];
262b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	int l_write_sigio_pid;
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
264b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	/* We call this *tons* of times - and most ones we must just fail. */
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sigio_lock();
266b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	l_write_sigio_pid = write_sigio_pid;
267b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	sigio_unlock();
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
269b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	if (l_write_sigio_pid != -1)
270b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso		return;
271b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso
272b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	err = os_pipe(l_write_sigio_fds, 1, 1);
273fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	if (err < 0) {
274fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		printk(UM_KERN_ERR "write_sigio_workaround - os_pipe 1 failed, "
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "err = %d\n", -err);
276b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso		return;
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
278b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	err = os_pipe(l_sigio_private, 1, 1);
279fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	if (err < 0) {
280fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		printk(UM_KERN_ERR "write_sigio_workaround - os_pipe 2 failed, "
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "err = %d\n", -err);
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out_close1;
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
284b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso
285b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	p = setup_initial_poll(l_sigio_private[1]);
286fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	if (!p)
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out_close2;
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
289b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	sigio_lock();
290b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso
291fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	/*
292fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	 * Did we race? Don't try to optimize this, please, it's not so likely
293fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	 * to happen, and no more than once at the boot.
294fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	 */
295fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	if (write_sigio_pid != -1)
2965f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike		goto out_free;
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2985f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike	current_poll = ((struct pollfds) { .poll 	= p,
2995f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike					   .used 	= 1,
3005f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike					   .size 	= 1 });
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
302b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	if (write_sigio_irq(l_write_sigio_fds[0]))
3035f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike		goto out_clear_poll;
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
305b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	memcpy(write_sigio_fds, l_write_sigio_fds, sizeof(l_write_sigio_fds));
306b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	memcpy(sigio_private, l_sigio_private, sizeof(l_sigio_private));
307b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso
3085f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike	write_sigio_pid = run_helper_thread(write_sigio_thread, NULL,
309c43990162fc7f9d2f15a12797fdc6f9c0905f704Jeff Dike					    CLONE_FILES | CLONE_VM,
310c43990162fc7f9d2f15a12797fdc6f9c0905f704Jeff Dike					    &write_sigio_stack);
311b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso
3125f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike	if (write_sigio_pid < 0)
3135f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike		goto out_clear;
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
315b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	sigio_unlock();
3165f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike	return;
317b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso
3185f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dikeout_clear:
319b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	write_sigio_pid = -1;
3205f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike	write_sigio_fds[0] = -1;
3215f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike	write_sigio_fds[1] = -1;
3225f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike	sigio_private[0] = -1;
3235f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike	sigio_private[1] = -1;
3245f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dikeout_clear_poll:
3255f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike	current_poll = ((struct pollfds) { .poll	= NULL,
3265f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike					   .size	= 0,
3275f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike					   .used	= 0 });
3285f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dikeout_free:
3295f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dike	sigio_unlock();
330e6fb54abb8a36703f54b7e27a756a3df6667c37bPaolo 'Blaisorblade' Giarrusso	kfree(p);
3315f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dikeout_close2:
3328e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike	close(l_sigio_private[0]);
3338e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike	close(l_sigio_private[1]);
3345f4e8fd08f3993bc31a7dd91767fdb4da4fe6278Jeff Dikeout_close1:
3358e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike	close(l_write_sigio_fds[0]);
3368e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike	close(l_write_sigio_fds[1]);
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3395d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dikevoid sigio_broken(int fd, int read)
3408e64d96aeb495709c13307e2d79f3ee37e96aa4eJeff Dike{
34119bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike	int err;
34219bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike
3438e64d96aeb495709c13307e2d79f3ee37e96aa4eJeff Dike	write_sigio_workaround();
34419bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike
34519bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike	sigio_lock();
34619bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike	err = need_poll(&all_sigio_fds, all_sigio_fds.used + 1);
347fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	if (err) {
348fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		printk(UM_KERN_ERR "maybe_sigio_broken - failed to add pollfd "
349fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		       "for descriptor %d\n", fd);
35019bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike		goto out;
35104a51e66adcdc0de6ffaa488934ce3ffb3818ecfJeff Dike	}
352838e56a11cdb2abaf490eb7879ab021db938d47dJeff Dike
35319bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike	all_sigio_fds.poll[all_sigio_fds.used++] =
35419bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike		((struct pollfd) { .fd  	= fd,
35519bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike				   .events 	= read ? POLLIN : POLLOUT,
35619bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike				   .revents 	= 0 });
35719bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dikeout:
35819bdf0409f25a85a45874a5a8da6f3e4edcf4a49Jeff Dike	sigio_unlock();
3598e64d96aeb495709c13307e2d79f3ee37e96aa4eJeff Dike}
3608e64d96aeb495709c13307e2d79f3ee37e96aa4eJeff Dike
3615d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dike/* Changed during early boot */
3625d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dikestatic int pty_output_sigio;
3635d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dikestatic int pty_close_sigio;
3645d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dike
3655d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dikevoid maybe_sigio_broken(int fd, int read)
3665d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dike{
3675d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dike	if (!isatty(fd))
3685d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dike		return;
3695d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dike
3705d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dike	if ((read || pty_output_sigio) && (!read || pty_close_sigio))
3715d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dike		return;
3725d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dike
3735d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dike	sigio_broken(fd, read);
3745d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dike}
3755d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dike
37629ac1c2142346e1e0e072f41df31688fc42ff540Jeff Dikestatic void sigio_cleanup(void)
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
378c43990162fc7f9d2f15a12797fdc6f9c0905f704Jeff Dike	if (write_sigio_pid == -1)
379c43990162fc7f9d2f15a12797fdc6f9c0905f704Jeff Dike		return;
380c43990162fc7f9d2f15a12797fdc6f9c0905f704Jeff Dike
381c43990162fc7f9d2f15a12797fdc6f9c0905f704Jeff Dike	os_kill_process(write_sigio_pid, 1);
382c43990162fc7f9d2f15a12797fdc6f9c0905f704Jeff Dike	free_stack(write_sigio_stack, 0);
383c43990162fc7f9d2f15a12797fdc6f9c0905f704Jeff Dike	write_sigio_pid = -1;
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
38529ac1c2142346e1e0e072f41df31688fc42ff540Jeff Dike
38629ac1c2142346e1e0e072f41df31688fc42ff540Jeff Dike__uml_exitcall(sigio_cleanup);
387c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
388c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike/* Used as a flag during SIGIO testing early in boot */
3895d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dikestatic int got_sigio;
390c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
391c65badbdf5dc117e45873e760f807063ad59a854Jeff Dikestatic void __init handler(int sig)
392c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike{
393c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	got_sigio = 1;
394c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike}
395c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
396c65badbdf5dc117e45873e760f807063ad59a854Jeff Dikestruct openpty_arg {
397c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	int master;
398c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	int slave;
399c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	int err;
400c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike};
401c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
402c65badbdf5dc117e45873e760f807063ad59a854Jeff Dikestatic void openpty_cb(void *arg)
403c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike{
404c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	struct openpty_arg *info = arg;
405c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
406c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	info->err = 0;
407fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	if (openpty(&info->master, &info->slave, NULL, NULL, NULL))
408c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike		info->err = -errno;
409c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike}
410c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
411c65badbdf5dc117e45873e760f807063ad59a854Jeff Dikestatic int async_pty(int master, int slave)
412c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike{
413c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	int flags;
414c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
415c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	flags = fcntl(master, F_GETFL);
416fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	if (flags < 0)
417c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike		return -errno;
418c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
419fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	if ((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) ||
420fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	    (fcntl(master, F_SETOWN, os_getpid()) < 0))
421c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike		return -errno;
422c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
423fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	if ((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0))
424c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike		return -errno;
425c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
426c0a9290ecf0dbb89958cb3a3f78964015a7de402WANG Cong	return 0;
427c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike}
428c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
429c65badbdf5dc117e45873e760f807063ad59a854Jeff Dikestatic void __init check_one_sigio(void (*proc)(int, int))
430c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike{
431c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	struct sigaction old, new;
432c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	struct openpty_arg pty = { .master = -1, .slave = -1 };
433c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	int master, slave, err;
434c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
435c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	initial_thread_cb(openpty_cb, &pty);
436fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	if (pty.err) {
437fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		printk(UM_KERN_ERR "check_one_sigio failed, errno = %d\n",
438fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		       -pty.err);
439c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike		return;
440c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	}
441c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
442c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	master = pty.master;
443c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	slave = pty.slave;
444c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
445fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	if ((master == -1) || (slave == -1)) {
446fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		printk(UM_KERN_ERR "check_one_sigio failed to allocate a "
447fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		       "pty\n");
448c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike		return;
449c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	}
450c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
451c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	/* Not now, but complain so we now where we failed. */
452c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	err = raw(master);
453fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	if (err < 0) {
454fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		printk(UM_KERN_ERR "check_one_sigio : raw failed, errno = %d\n",
455fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		      -err);
456fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		return;
457fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	}
458c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
459c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	err = async_pty(master, slave);
460fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	if (err < 0) {
461fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		printk(UM_KERN_ERR "check_one_sigio : sigio_async failed, "
462fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		       "err = %d\n", -err);
463fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		return;
464fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	}
465fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike
466fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	if (sigaction(SIGIO, NULL, &old) < 0) {
467fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		printk(UM_KERN_ERR "check_one_sigio : sigaction 1 failed, "
468fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		       "errno = %d\n", errno);
469fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		return;
470fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	}
471c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
472c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	new = old;
473c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	new.sa_handler = handler;
474fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	if (sigaction(SIGIO, &new, NULL) < 0) {
475fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		printk(UM_KERN_ERR "check_one_sigio : sigaction 2 failed, "
476fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		       "errno = %d\n", errno);
477fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		return;
478fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	}
479c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
480c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	got_sigio = 0;
481c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	(*proc)(master, slave);
482c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
483c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	close(master);
484c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	close(slave);
485c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
486fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	if (sigaction(SIGIO, &old, NULL) < 0)
487fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		printk(UM_KERN_ERR "check_one_sigio : sigaction 3 failed, "
488fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		       "errno = %d\n", errno);
489c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike}
490c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
491c65badbdf5dc117e45873e760f807063ad59a854Jeff Dikestatic void tty_output(int master, int slave)
492c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike{
493c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	int n;
494c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	char buf[512];
495c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
496fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	printk(UM_KERN_INFO "Checking that host ptys support output SIGIO...");
497c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
498c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	memset(buf, 0, sizeof(buf));
499c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
500fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	while (write(master, buf, sizeof(buf)) > 0) ;
501fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	if (errno != EAGAIN)
502fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		printk(UM_KERN_ERR "tty_output : write failed, errno = %d\n",
503fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		       errno);
5045d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dike	while (((n = read(slave, buf, sizeof(buf))) > 0) &&
5055d33e4d7fd9a52d2673e5c730eab81856e100a74Jeff Dike	       !({ barrier(); got_sigio; }))
506fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		;
507c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
508fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	if (got_sigio) {
509fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		printk(UM_KERN_CONT "Yes\n");
510c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike		pty_output_sigio = 1;
511fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	} else if (n == -EAGAIN)
512fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		printk(UM_KERN_CONT "No, enabling workaround\n");
513fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	else
514fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		printk(UM_KERN_CONT "tty_output : read failed, err = %d\n", n);
515c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike}
516c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
517c65badbdf5dc117e45873e760f807063ad59a854Jeff Dikestatic void tty_close(int master, int slave)
518c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike{
519fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	printk(UM_KERN_INFO "Checking that host ptys support SIGIO on "
520fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	       "close...");
521c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
522c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	close(slave);
523fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	if (got_sigio) {
524fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		printk(UM_KERN_CONT "Yes\n");
525c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike		pty_close_sigio = 1;
526fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	} else
527fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		printk(UM_KERN_CONT "No, enabling workaround\n");
528c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike}
529c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
53099764fa4ceeecba8b9e0a8a5565b418a2e94f83bWANG Congstatic void __init check_sigio(void)
531c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike{
532fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	if ((access("/dev/ptmx", R_OK) < 0) &&
533fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike	    (access("/dev/ptyp0", R_OK) < 0)) {
534fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		printk(UM_KERN_WARNING "No pseudo-terminals available - "
535fee64d3c153f1d5c28f91214b4d0db54d3f1fe0aJeff Dike		       "skipping pty SIGIO check\n");
536c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike		return;
537c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	}
538c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	check_one_sigio(tty_output);
539c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	check_one_sigio(tty_close);
540c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike}
541c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike
542c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike/* Here because it only does the SIGIO testing for now */
543c65badbdf5dc117e45873e760f807063ad59a854Jeff Dikevoid __init os_check_bugs(void)
544c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike{
545c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike	check_sigio();
546c65badbdf5dc117e45873e760f807063ad59a854Jeff Dike}
547