sigio.c revision 8e367065eea04a6fde5cb8f3854164af99c45693
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>
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <errno.h>
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <string.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <sched.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <sys/socket.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <sys/poll.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "init.h"
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "user.h"
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "kern_util.h"
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "user_util.h"
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "sigio.h"
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "os.h"
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Protected by sigio_lock(), also used by sigio_cleanup, which is an
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * exitcall.
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int write_sigio_pid = -1;
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 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 */
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int write_sigio_fds[2] = { -1, -1 };
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int sigio_private[2] = { -1, -1 };
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pollfds {
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pollfd *poll;
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int size;
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int used;
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Protected by sigio_lock().  Used by the sigio thread, but the UML thread
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * synchronizes with it.
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pollfds current_poll = {
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.poll  		= NULL,
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.size 		= 0,
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.used 		= 0
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pollfds next_poll = {
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.poll  		= NULL,
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.size 		= 0,
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.used 		= 0
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int write_sigio_thread(void *unused)
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pollfds *fds, tmp;
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pollfd *p;
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, n, respond_fd;
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char c;
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
63cd2ee4a30cc0775d8b54e5b958613361a7cacfecJeff Dike        signal(SIGWINCH, SIG_IGN);
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fds = &current_poll;
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while(1){
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		n = poll(fds->poll, fds->used, -1);
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(n < 0){
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if(errno == EINTR) continue;
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("write_sigio_thread : poll returned %d, "
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "errno = %d\n", n, errno);
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for(i = 0; i < fds->used; i++){
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			p = &fds->poll[i];
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if(p->revents == 0) continue;
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if(p->fd == sigio_private[1]){
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				n = os_read_file(sigio_private[1], &c, sizeof(c));
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if(n != sizeof(c))
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printk("write_sigio_thread : "
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       "read failed, err = %d\n", -n);
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
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			n = os_write_file(respond_fd, &c, sizeof(c));
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if(n != sizeof(c))
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk("write_sigio_thread : write failed, "
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       "err = %d\n", -n);
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
981b57e9c27882a908f180d4daf72ee12c6f137178Jeff Dike
991b57e9c27882a908f180d4daf72ee12c6f137178Jeff Dike	return 0;
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int need_poll(int n)
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(n <= next_poll.size){
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		next_poll.used = n;
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return(0);
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
108b2325fe1b7e5654fac9e9419423aa2c58a3dbd83Jesper Juhl	kfree(next_poll.poll);
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	next_poll.poll = um_kmalloc_atomic(n * sizeof(struct pollfd));
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(next_poll.poll == NULL){
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("need_poll : failed to allocate new pollfds\n");
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		next_poll.size = 0;
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		next_poll.used = 0;
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return(-1);
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	next_poll.size = n;
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	next_poll.used = n;
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return(0);
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Must be called with sigio_lock held, because it's needed by the marked
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * critical section. */
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void update_thread(void)
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int n;
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char c;
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	flags = set_signals(0);
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	n = os_write_file(sigio_private[0], &c, sizeof(c));
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(n != sizeof(c)){
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("update_thread : write failed, err = %d\n", -n);
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto fail;
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	n = os_read_file(sigio_private[0], &c, sizeof(c));
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(n != sizeof(c)){
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("update_thread : read failed, err = %d\n", -n);
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto fail;
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_signals(flags);
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return;
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fail:
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Critical section start */
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(write_sigio_pid != -1)
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		os_kill_process(write_sigio_pid, 1);
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_sigio_pid = -1;
1498e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike	close(sigio_private[0]);
1508e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike	close(sigio_private[1]);
1518e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike	close(write_sigio_fds[0]);
1528e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike	close(write_sigio_fds[1]);
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Critical section end */
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_signals(flags);
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint add_sigio_fd(int fd, int read)
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0, i, n, events;
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sigio_lock();
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for(i = 0; i < current_poll.used; i++){
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(current_poll.poll[i].fd == fd)
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out;
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	n = current_poll.used + 1;
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = need_poll(n);
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(err)
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for(i = 0; i < current_poll.used; i++)
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		next_poll.poll[i] = current_poll.poll[i];
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(read) events = POLLIN;
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else events = POLLOUT;
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	next_poll.poll[n - 1] = ((struct pollfd) { .fd  	= fd,
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						   .events 	= events,
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						   .revents 	= 0 });
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	update_thread();
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sigio_unlock();
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return(err);
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint ignore_sigio_fd(int fd)
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pollfd *p;
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = 0, i, n = 0;
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sigio_lock();
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for(i = 0; i < current_poll.used; i++){
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(current_poll.poll[i].fd == fd) break;
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(i == current_poll.used)
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = need_poll(current_poll.used - 1);
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(err)
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for(i = 0; i < current_poll.used; i++){
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		p = &current_poll.poll[i];
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(p->fd != fd) next_poll.poll[n++] = current_poll.poll[i];
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(n == i){
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("ignore_sigio_fd : fd %d not found\n", fd);
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -1;
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	update_thread();
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sigio_unlock();
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return(err);
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
219b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrussostatic struct pollfd* setup_initial_poll(int fd)
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pollfd *p;
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
223b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	p = um_kmalloc(sizeof(struct pollfd));
224b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	if (p == NULL) {
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("setup_initial_poll : failed to allocate poll\n");
226b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso		return NULL;
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*p = ((struct pollfd) { .fd  	= fd,
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				.events 	= POLLIN,
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				.revents 	= 0 });
231b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	return p;
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid write_sigio_workaround(void)
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long stack;
237b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	struct pollfd *p;
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
239b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	int l_write_sigio_fds[2];
240b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	int l_sigio_private[2];
241b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	int l_write_sigio_pid;
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
243b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	/* We call this *tons* of times - and most ones we must just fail. */
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sigio_lock();
245b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	l_write_sigio_pid = write_sigio_pid;
246b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	sigio_unlock();
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
248b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	if (l_write_sigio_pid != -1)
249b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso		return;
250b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso
251b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	err = os_pipe(l_write_sigio_fds, 1, 1);
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(err < 0){
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("write_sigio_workaround - os_pipe 1 failed, "
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "err = %d\n", -err);
255b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso		return;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
257b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	err = os_pipe(l_sigio_private, 1, 1);
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(err < 0){
259b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso		printk("write_sigio_workaround - os_pipe 1 failed, "
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "err = %d\n", -err);
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out_close1;
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
263b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso
264b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	p = setup_initial_poll(l_sigio_private[1]);
265b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	if(!p)
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out_close2;
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
268b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	sigio_lock();
269b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso
270b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	/* Did we race? Don't try to optimize this, please, it's not so likely
271b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	 * to happen, and no more than once at the boot. */
272b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	if(write_sigio_pid != -1)
273b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso		goto out_unlock;
274b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso
275b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	write_sigio_pid = run_helper_thread(write_sigio_thread, NULL,
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    CLONE_FILES | CLONE_VM, &stack, 0);
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
278b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	if (write_sigio_pid < 0)
279b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso		goto out_clear;
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
281b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	if (write_sigio_irq(l_write_sigio_fds[0]))
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out_kill;
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
284b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	/* Success, finally. */
285b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	memcpy(write_sigio_fds, l_write_sigio_fds, sizeof(l_write_sigio_fds));
286b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	memcpy(sigio_private, l_sigio_private, sizeof(l_sigio_private));
287b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso
288b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	current_poll = ((struct pollfds) { .poll 	= p,
289b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso					   .used 	= 1,
290b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso					   .size 	= 1 });
291b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sigio_unlock();
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return;
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out_kill:
296b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	l_write_sigio_pid = write_sigio_pid;
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	write_sigio_pid = -1;
298b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	sigio_unlock();
299b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	/* Going to call waitpid, avoid holding the lock. */
300b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	os_kill_process(l_write_sigio_pid, 1);
301b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	goto out_free;
302b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso
303b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso out_clear:
304b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	write_sigio_pid = -1;
305b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso out_unlock:
306b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	sigio_unlock();
307b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso out_free:
308b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	kfree(p);
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out_close2:
3108e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike	close(l_sigio_private[0]);
3118e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike	close(l_sigio_private[1]);
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out_close1:
3138e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike	close(l_write_sigio_fds[0]);
3148e367065eea04a6fde5cb8f3854164af99c45693Jeff Dike	close(l_write_sigio_fds[1]);
315b6a2b13778873bd9edd0b4a7d24a7bd730369021Paolo 'Blaisorblade' Giarrusso	return;
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3188e367065eea04a6fde5cb8f3854164af99c45693Jeff Dikevoid sigio_cleanup(void)
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (write_sigio_pid != -1) {
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		os_kill_process(write_sigio_pid, 1);
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		write_sigio_pid = -1;
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
325