xref: /openbmc/linux/arch/um/os-Linux/sigio.c (revision f206aabb035318ac4bafbf0b87798335de3634df)
1*f206aabbSJeff Dike /*
2*f206aabbSJeff Dike  * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3*f206aabbSJeff Dike  * Licensed under the GPL
4*f206aabbSJeff Dike  */
5*f206aabbSJeff Dike 
6*f206aabbSJeff Dike #include <unistd.h>
7*f206aabbSJeff Dike #include <stdlib.h>
8*f206aabbSJeff Dike #include <termios.h>
9*f206aabbSJeff Dike #include <pty.h>
10*f206aabbSJeff Dike #include <signal.h>
11*f206aabbSJeff Dike #include <errno.h>
12*f206aabbSJeff Dike #include <string.h>
13*f206aabbSJeff Dike #include <sched.h>
14*f206aabbSJeff Dike #include <sys/socket.h>
15*f206aabbSJeff Dike #include <sys/poll.h>
16*f206aabbSJeff Dike #include "init.h"
17*f206aabbSJeff Dike #include "user.h"
18*f206aabbSJeff Dike #include "kern_util.h"
19*f206aabbSJeff Dike #include "user_util.h"
20*f206aabbSJeff Dike #include "sigio.h"
21*f206aabbSJeff Dike #include "os.h"
22*f206aabbSJeff Dike 
23*f206aabbSJeff Dike /* Protected by sigio_lock(), also used by sigio_cleanup, which is an
24*f206aabbSJeff Dike  * exitcall.
25*f206aabbSJeff Dike  */
26*f206aabbSJeff Dike static int write_sigio_pid = -1;
27*f206aabbSJeff Dike 
28*f206aabbSJeff Dike /* These arrays are initialized before the sigio thread is started, and
29*f206aabbSJeff Dike  * the descriptors closed after it is killed.  So, it can't see them change.
30*f206aabbSJeff Dike  * On the UML side, they are changed under the sigio_lock.
31*f206aabbSJeff Dike  */
32*f206aabbSJeff Dike static int write_sigio_fds[2] = { -1, -1 };
33*f206aabbSJeff Dike static int sigio_private[2] = { -1, -1 };
34*f206aabbSJeff Dike 
35*f206aabbSJeff Dike struct pollfds {
36*f206aabbSJeff Dike 	struct pollfd *poll;
37*f206aabbSJeff Dike 	int size;
38*f206aabbSJeff Dike 	int used;
39*f206aabbSJeff Dike };
40*f206aabbSJeff Dike 
41*f206aabbSJeff Dike /* Protected by sigio_lock().  Used by the sigio thread, but the UML thread
42*f206aabbSJeff Dike  * synchronizes with it.
43*f206aabbSJeff Dike  */
44*f206aabbSJeff Dike struct pollfds current_poll = {
45*f206aabbSJeff Dike 	.poll  		= NULL,
46*f206aabbSJeff Dike 	.size 		= 0,
47*f206aabbSJeff Dike 	.used 		= 0
48*f206aabbSJeff Dike };
49*f206aabbSJeff Dike 
50*f206aabbSJeff Dike struct pollfds next_poll = {
51*f206aabbSJeff Dike 	.poll  		= NULL,
52*f206aabbSJeff Dike 	.size 		= 0,
53*f206aabbSJeff Dike 	.used 		= 0
54*f206aabbSJeff Dike };
55*f206aabbSJeff Dike 
56*f206aabbSJeff Dike static int write_sigio_thread(void *unused)
57*f206aabbSJeff Dike {
58*f206aabbSJeff Dike 	struct pollfds *fds, tmp;
59*f206aabbSJeff Dike 	struct pollfd *p;
60*f206aabbSJeff Dike 	int i, n, respond_fd;
61*f206aabbSJeff Dike 	char c;
62*f206aabbSJeff Dike 
63*f206aabbSJeff Dike         signal(SIGWINCH, SIG_IGN);
64*f206aabbSJeff Dike 	fds = &current_poll;
65*f206aabbSJeff Dike 	while(1){
66*f206aabbSJeff Dike 		n = poll(fds->poll, fds->used, -1);
67*f206aabbSJeff Dike 		if(n < 0){
68*f206aabbSJeff Dike 			if(errno == EINTR) continue;
69*f206aabbSJeff Dike 			printk("write_sigio_thread : poll returned %d, "
70*f206aabbSJeff Dike 			       "errno = %d\n", n, errno);
71*f206aabbSJeff Dike 		}
72*f206aabbSJeff Dike 		for(i = 0; i < fds->used; i++){
73*f206aabbSJeff Dike 			p = &fds->poll[i];
74*f206aabbSJeff Dike 			if(p->revents == 0) continue;
75*f206aabbSJeff Dike 			if(p->fd == sigio_private[1]){
76*f206aabbSJeff Dike 				n = os_read_file(sigio_private[1], &c, sizeof(c));
77*f206aabbSJeff Dike 				if(n != sizeof(c))
78*f206aabbSJeff Dike 					printk("write_sigio_thread : "
79*f206aabbSJeff Dike 					       "read failed, err = %d\n", -n);
80*f206aabbSJeff Dike 				tmp = current_poll;
81*f206aabbSJeff Dike 				current_poll = next_poll;
82*f206aabbSJeff Dike 				next_poll = tmp;
83*f206aabbSJeff Dike 				respond_fd = sigio_private[1];
84*f206aabbSJeff Dike 			}
85*f206aabbSJeff Dike 			else {
86*f206aabbSJeff Dike 				respond_fd = write_sigio_fds[1];
87*f206aabbSJeff Dike 				fds->used--;
88*f206aabbSJeff Dike 				memmove(&fds->poll[i], &fds->poll[i + 1],
89*f206aabbSJeff Dike 					(fds->used - i) * sizeof(*fds->poll));
90*f206aabbSJeff Dike 			}
91*f206aabbSJeff Dike 
92*f206aabbSJeff Dike 			n = os_write_file(respond_fd, &c, sizeof(c));
93*f206aabbSJeff Dike 			if(n != sizeof(c))
94*f206aabbSJeff Dike 				printk("write_sigio_thread : write failed, "
95*f206aabbSJeff Dike 				       "err = %d\n", -n);
96*f206aabbSJeff Dike 		}
97*f206aabbSJeff Dike 	}
98*f206aabbSJeff Dike 
99*f206aabbSJeff Dike 	return 0;
100*f206aabbSJeff Dike }
101*f206aabbSJeff Dike 
102*f206aabbSJeff Dike static int need_poll(int n)
103*f206aabbSJeff Dike {
104*f206aabbSJeff Dike 	if(n <= next_poll.size){
105*f206aabbSJeff Dike 		next_poll.used = n;
106*f206aabbSJeff Dike 		return(0);
107*f206aabbSJeff Dike 	}
108*f206aabbSJeff Dike 	kfree(next_poll.poll);
109*f206aabbSJeff Dike 	next_poll.poll = um_kmalloc_atomic(n * sizeof(struct pollfd));
110*f206aabbSJeff Dike 	if(next_poll.poll == NULL){
111*f206aabbSJeff Dike 		printk("need_poll : failed to allocate new pollfds\n");
112*f206aabbSJeff Dike 		next_poll.size = 0;
113*f206aabbSJeff Dike 		next_poll.used = 0;
114*f206aabbSJeff Dike 		return(-1);
115*f206aabbSJeff Dike 	}
116*f206aabbSJeff Dike 	next_poll.size = n;
117*f206aabbSJeff Dike 	next_poll.used = n;
118*f206aabbSJeff Dike 	return(0);
119*f206aabbSJeff Dike }
120*f206aabbSJeff Dike 
121*f206aabbSJeff Dike /* Must be called with sigio_lock held, because it's needed by the marked
122*f206aabbSJeff Dike  * critical section. */
123*f206aabbSJeff Dike static void update_thread(void)
124*f206aabbSJeff Dike {
125*f206aabbSJeff Dike 	unsigned long flags;
126*f206aabbSJeff Dike 	int n;
127*f206aabbSJeff Dike 	char c;
128*f206aabbSJeff Dike 
129*f206aabbSJeff Dike 	flags = set_signals(0);
130*f206aabbSJeff Dike 	n = os_write_file(sigio_private[0], &c, sizeof(c));
131*f206aabbSJeff Dike 	if(n != sizeof(c)){
132*f206aabbSJeff Dike 		printk("update_thread : write failed, err = %d\n", -n);
133*f206aabbSJeff Dike 		goto fail;
134*f206aabbSJeff Dike 	}
135*f206aabbSJeff Dike 
136*f206aabbSJeff Dike 	n = os_read_file(sigio_private[0], &c, sizeof(c));
137*f206aabbSJeff Dike 	if(n != sizeof(c)){
138*f206aabbSJeff Dike 		printk("update_thread : read failed, err = %d\n", -n);
139*f206aabbSJeff Dike 		goto fail;
140*f206aabbSJeff Dike 	}
141*f206aabbSJeff Dike 
142*f206aabbSJeff Dike 	set_signals(flags);
143*f206aabbSJeff Dike 	return;
144*f206aabbSJeff Dike  fail:
145*f206aabbSJeff Dike 	/* Critical section start */
146*f206aabbSJeff Dike 	if(write_sigio_pid != -1)
147*f206aabbSJeff Dike 		os_kill_process(write_sigio_pid, 1);
148*f206aabbSJeff Dike 	write_sigio_pid = -1;
149*f206aabbSJeff Dike 	close(sigio_private[0]);
150*f206aabbSJeff Dike 	close(sigio_private[1]);
151*f206aabbSJeff Dike 	close(write_sigio_fds[0]);
152*f206aabbSJeff Dike 	close(write_sigio_fds[1]);
153*f206aabbSJeff Dike 	/* Critical section end */
154*f206aabbSJeff Dike 	set_signals(flags);
155*f206aabbSJeff Dike }
156*f206aabbSJeff Dike 
157*f206aabbSJeff Dike int add_sigio_fd(int fd, int read)
158*f206aabbSJeff Dike {
159*f206aabbSJeff Dike 	int err = 0, i, n, events;
160*f206aabbSJeff Dike 
161*f206aabbSJeff Dike 	sigio_lock();
162*f206aabbSJeff Dike 	for(i = 0; i < current_poll.used; i++){
163*f206aabbSJeff Dike 		if(current_poll.poll[i].fd == fd)
164*f206aabbSJeff Dike 			goto out;
165*f206aabbSJeff Dike 	}
166*f206aabbSJeff Dike 
167*f206aabbSJeff Dike 	n = current_poll.used + 1;
168*f206aabbSJeff Dike 	err = need_poll(n);
169*f206aabbSJeff Dike 	if(err)
170*f206aabbSJeff Dike 		goto out;
171*f206aabbSJeff Dike 
172*f206aabbSJeff Dike 	for(i = 0; i < current_poll.used; i++)
173*f206aabbSJeff Dike 		next_poll.poll[i] = current_poll.poll[i];
174*f206aabbSJeff Dike 
175*f206aabbSJeff Dike 	if(read) events = POLLIN;
176*f206aabbSJeff Dike 	else events = POLLOUT;
177*f206aabbSJeff Dike 
178*f206aabbSJeff Dike 	next_poll.poll[n - 1] = ((struct pollfd) { .fd  	= fd,
179*f206aabbSJeff Dike 						   .events 	= events,
180*f206aabbSJeff Dike 						   .revents 	= 0 });
181*f206aabbSJeff Dike 	update_thread();
182*f206aabbSJeff Dike  out:
183*f206aabbSJeff Dike 	sigio_unlock();
184*f206aabbSJeff Dike 	return(err);
185*f206aabbSJeff Dike }
186*f206aabbSJeff Dike 
187*f206aabbSJeff Dike int ignore_sigio_fd(int fd)
188*f206aabbSJeff Dike {
189*f206aabbSJeff Dike 	struct pollfd *p;
190*f206aabbSJeff Dike 	int err = 0, i, n = 0;
191*f206aabbSJeff Dike 
192*f206aabbSJeff Dike 	sigio_lock();
193*f206aabbSJeff Dike 	for(i = 0; i < current_poll.used; i++){
194*f206aabbSJeff Dike 		if(current_poll.poll[i].fd == fd) break;
195*f206aabbSJeff Dike 	}
196*f206aabbSJeff Dike 	if(i == current_poll.used)
197*f206aabbSJeff Dike 		goto out;
198*f206aabbSJeff Dike 
199*f206aabbSJeff Dike 	err = need_poll(current_poll.used - 1);
200*f206aabbSJeff Dike 	if(err)
201*f206aabbSJeff Dike 		goto out;
202*f206aabbSJeff Dike 
203*f206aabbSJeff Dike 	for(i = 0; i < current_poll.used; i++){
204*f206aabbSJeff Dike 		p = &current_poll.poll[i];
205*f206aabbSJeff Dike 		if(p->fd != fd) next_poll.poll[n++] = current_poll.poll[i];
206*f206aabbSJeff Dike 	}
207*f206aabbSJeff Dike 	if(n == i){
208*f206aabbSJeff Dike 		printk("ignore_sigio_fd : fd %d not found\n", fd);
209*f206aabbSJeff Dike 		err = -1;
210*f206aabbSJeff Dike 		goto out;
211*f206aabbSJeff Dike 	}
212*f206aabbSJeff Dike 
213*f206aabbSJeff Dike 	update_thread();
214*f206aabbSJeff Dike  out:
215*f206aabbSJeff Dike 	sigio_unlock();
216*f206aabbSJeff Dike 	return(err);
217*f206aabbSJeff Dike }
218*f206aabbSJeff Dike 
219*f206aabbSJeff Dike static struct pollfd *setup_initial_poll(int fd)
220*f206aabbSJeff Dike {
221*f206aabbSJeff Dike 	struct pollfd *p;
222*f206aabbSJeff Dike 
223*f206aabbSJeff Dike 	p = um_kmalloc(sizeof(struct pollfd));
224*f206aabbSJeff Dike 	if (p == NULL) {
225*f206aabbSJeff Dike 		printk("setup_initial_poll : failed to allocate poll\n");
226*f206aabbSJeff Dike 		return NULL;
227*f206aabbSJeff Dike 	}
228*f206aabbSJeff Dike 	*p = ((struct pollfd) { .fd  	= fd,
229*f206aabbSJeff Dike 				.events 	= POLLIN,
230*f206aabbSJeff Dike 				.revents 	= 0 });
231*f206aabbSJeff Dike 	return p;
232*f206aabbSJeff Dike }
233*f206aabbSJeff Dike 
234*f206aabbSJeff Dike void write_sigio_workaround(void)
235*f206aabbSJeff Dike {
236*f206aabbSJeff Dike 	unsigned long stack;
237*f206aabbSJeff Dike 	struct pollfd *p;
238*f206aabbSJeff Dike 	int err;
239*f206aabbSJeff Dike 	int l_write_sigio_fds[2];
240*f206aabbSJeff Dike 	int l_sigio_private[2];
241*f206aabbSJeff Dike 	int l_write_sigio_pid;
242*f206aabbSJeff Dike 
243*f206aabbSJeff Dike 	/* We call this *tons* of times - and most ones we must just fail. */
244*f206aabbSJeff Dike 	sigio_lock();
245*f206aabbSJeff Dike 	l_write_sigio_pid = write_sigio_pid;
246*f206aabbSJeff Dike 	sigio_unlock();
247*f206aabbSJeff Dike 
248*f206aabbSJeff Dike 	if (l_write_sigio_pid != -1)
249*f206aabbSJeff Dike 		return;
250*f206aabbSJeff Dike 
251*f206aabbSJeff Dike 	err = os_pipe(l_write_sigio_fds, 1, 1);
252*f206aabbSJeff Dike 	if(err < 0){
253*f206aabbSJeff Dike 		printk("write_sigio_workaround - os_pipe 1 failed, "
254*f206aabbSJeff Dike 		       "err = %d\n", -err);
255*f206aabbSJeff Dike 		return;
256*f206aabbSJeff Dike 	}
257*f206aabbSJeff Dike 	err = os_pipe(l_sigio_private, 1, 1);
258*f206aabbSJeff Dike 	if(err < 0){
259*f206aabbSJeff Dike 		printk("write_sigio_workaround - os_pipe 2 failed, "
260*f206aabbSJeff Dike 		       "err = %d\n", -err);
261*f206aabbSJeff Dike 		goto out_close1;
262*f206aabbSJeff Dike 	}
263*f206aabbSJeff Dike 
264*f206aabbSJeff Dike 	p = setup_initial_poll(l_sigio_private[1]);
265*f206aabbSJeff Dike 	if(!p)
266*f206aabbSJeff Dike 		goto out_close2;
267*f206aabbSJeff Dike 
268*f206aabbSJeff Dike 	sigio_lock();
269*f206aabbSJeff Dike 
270*f206aabbSJeff Dike 	/* Did we race? Don't try to optimize this, please, it's not so likely
271*f206aabbSJeff Dike 	 * to happen, and no more than once at the boot. */
272*f206aabbSJeff Dike 	if(write_sigio_pid != -1)
273*f206aabbSJeff Dike 		goto out_unlock;
274*f206aabbSJeff Dike 
275*f206aabbSJeff Dike 	write_sigio_pid = run_helper_thread(write_sigio_thread, NULL,
276*f206aabbSJeff Dike 					    CLONE_FILES | CLONE_VM, &stack, 0);
277*f206aabbSJeff Dike 
278*f206aabbSJeff Dike 	if (write_sigio_pid < 0)
279*f206aabbSJeff Dike 		goto out_clear;
280*f206aabbSJeff Dike 
281*f206aabbSJeff Dike 	if (write_sigio_irq(l_write_sigio_fds[0]))
282*f206aabbSJeff Dike 		goto out_kill;
283*f206aabbSJeff Dike 
284*f206aabbSJeff Dike 	/* Success, finally. */
285*f206aabbSJeff Dike 	memcpy(write_sigio_fds, l_write_sigio_fds, sizeof(l_write_sigio_fds));
286*f206aabbSJeff Dike 	memcpy(sigio_private, l_sigio_private, sizeof(l_sigio_private));
287*f206aabbSJeff Dike 
288*f206aabbSJeff Dike 	current_poll = ((struct pollfds) { .poll 	= p,
289*f206aabbSJeff Dike 					   .used 	= 1,
290*f206aabbSJeff Dike 					   .size 	= 1 });
291*f206aabbSJeff Dike 
292*f206aabbSJeff Dike 	sigio_unlock();
293*f206aabbSJeff Dike 	return;
294*f206aabbSJeff Dike 
295*f206aabbSJeff Dike  out_kill:
296*f206aabbSJeff Dike 	l_write_sigio_pid = write_sigio_pid;
297*f206aabbSJeff Dike 	write_sigio_pid = -1;
298*f206aabbSJeff Dike 	sigio_unlock();
299*f206aabbSJeff Dike 	/* Going to call waitpid, avoid holding the lock. */
300*f206aabbSJeff Dike 	os_kill_process(l_write_sigio_pid, 1);
301*f206aabbSJeff Dike 	goto out_free;
302*f206aabbSJeff Dike 
303*f206aabbSJeff Dike  out_clear:
304*f206aabbSJeff Dike 	write_sigio_pid = -1;
305*f206aabbSJeff Dike  out_unlock:
306*f206aabbSJeff Dike 	sigio_unlock();
307*f206aabbSJeff Dike  out_free:
308*f206aabbSJeff Dike 	kfree(p);
309*f206aabbSJeff Dike  out_close2:
310*f206aabbSJeff Dike 	close(l_sigio_private[0]);
311*f206aabbSJeff Dike 	close(l_sigio_private[1]);
312*f206aabbSJeff Dike  out_close1:
313*f206aabbSJeff Dike 	close(l_write_sigio_fds[0]);
314*f206aabbSJeff Dike 	close(l_write_sigio_fds[1]);
315*f206aabbSJeff Dike 	return;
316*f206aabbSJeff Dike }
317*f206aabbSJeff Dike 
318*f206aabbSJeff Dike void sigio_cleanup(void)
319*f206aabbSJeff Dike {
320*f206aabbSJeff Dike 	if(write_sigio_pid != -1){
321*f206aabbSJeff Dike 		os_kill_process(write_sigio_pid, 1);
322*f206aabbSJeff Dike 		write_sigio_pid = -1;
323*f206aabbSJeff Dike 	}
324*f206aabbSJeff Dike }
325