PageRenderTime 69ms CodeModel.GetById 13ms app.highlight 52ms RepoModel.GetById 1ms app.codeStats 0ms

/arch/um/kernel/sigio_user.c

https://bitbucket.org/evzijst/gittest
C | 431 lines | 347 code | 63 blank | 21 comment | 79 complexity | f5c7caed4fbe3dad93d491731b41c7e3 MD5 | raw file
  1/* 
  2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
  3 * Licensed under the GPL
  4 */
  5
  6#include <unistd.h>
  7#include <stdlib.h>
  8#include <termios.h>
  9#include <pty.h>
 10#include <signal.h>
 11#include <errno.h>
 12#include <string.h>
 13#include <sched.h>
 14#include <sys/socket.h>
 15#include <sys/poll.h>
 16#include "init.h"
 17#include "user.h"
 18#include "kern_util.h"
 19#include "user_util.h"
 20#include "sigio.h"
 21#include "helper.h"
 22#include "os.h"
 23
 24/* Changed during early boot */
 25int pty_output_sigio = 0;
 26int pty_close_sigio = 0;
 27
 28/* Used as a flag during SIGIO testing early in boot */
 29static volatile int got_sigio = 0;
 30
 31void __init handler(int sig)
 32{
 33	got_sigio = 1;
 34}
 35
 36struct openpty_arg {
 37	int master;
 38	int slave;
 39	int err;
 40};
 41
 42static void openpty_cb(void *arg)
 43{
 44	struct openpty_arg *info = arg;
 45
 46	info->err = 0;
 47	if(openpty(&info->master, &info->slave, NULL, NULL, NULL))
 48		info->err = -errno;
 49}
 50
 51void __init check_one_sigio(void (*proc)(int, int))
 52{
 53	struct sigaction old, new;
 54	struct openpty_arg pty = { .master = -1, .slave = -1 };
 55	int master, slave, err;
 56
 57	initial_thread_cb(openpty_cb, &pty);
 58	if(pty.err){
 59		printk("openpty failed, errno = %d\n", -pty.err);
 60		return;
 61	}
 62
 63	master = pty.master;
 64	slave = pty.slave;
 65
 66	if((master == -1) || (slave == -1)){
 67		printk("openpty failed to allocate a pty\n");
 68		return;
 69	}
 70
 71	/* Not now, but complain so we now where we failed. */
 72	err = raw(master);
 73	if (err < 0)
 74		panic("check_sigio : __raw failed, errno = %d\n", -err);
 75
 76	err = os_sigio_async(master, slave);
 77	if(err < 0)
 78		panic("tty_fds : sigio_async failed, err = %d\n", -err);
 79
 80	if(sigaction(SIGIO, NULL, &old) < 0)
 81		panic("check_sigio : sigaction 1 failed, errno = %d\n", errno);
 82	new = old;
 83	new.sa_handler = handler;
 84	if(sigaction(SIGIO, &new, NULL) < 0)
 85		panic("check_sigio : sigaction 2 failed, errno = %d\n", errno);
 86
 87	got_sigio = 0;
 88	(*proc)(master, slave);
 89		
 90	os_close_file(master);
 91	os_close_file(slave);
 92
 93	if(sigaction(SIGIO, &old, NULL) < 0)
 94		panic("check_sigio : sigaction 3 failed, errno = %d\n", errno);
 95}
 96
 97static void tty_output(int master, int slave)
 98{
 99	int n;
100	char buf[512];
101
102	printk("Checking that host ptys support output SIGIO...");
103
104	memset(buf, 0, sizeof(buf));
105
106	while(os_write_file(master, buf, sizeof(buf)) > 0) ;
107	if(errno != EAGAIN)
108		panic("check_sigio : write failed, errno = %d\n", errno);
109	while(((n = os_read_file(slave, buf, sizeof(buf))) > 0) && !got_sigio) ;
110
111	if (got_sigio) {
112		printk("Yes\n");
113		pty_output_sigio = 1;
114	} else if (n == -EAGAIN) {
115		printk("No, enabling workaround\n");
116	} else {
117		panic("check_sigio : read failed, err = %d\n", n);
118	}
119}
120
121static void tty_close(int master, int slave)
122{
123	printk("Checking that host ptys support SIGIO on close...");
124
125	os_close_file(slave);
126	if(got_sigio){
127		printk("Yes\n");
128		pty_close_sigio = 1;
129	}
130	else printk("No, enabling workaround\n");
131}
132
133void __init check_sigio(void)
134{
135	if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) &&
136	   (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){
137		printk("No pseudo-terminals available - skipping pty SIGIO "
138		       "check\n");
139		return;
140	}
141	check_one_sigio(tty_output);
142	check_one_sigio(tty_close);
143}
144
145/* Protected by sigio_lock(), also used by sigio_cleanup, which is an 
146 * exitcall.
147 */
148static int write_sigio_pid = -1;
149
150/* These arrays are initialized before the sigio thread is started, and
151 * the descriptors closed after it is killed.  So, it can't see them change.
152 * On the UML side, they are changed under the sigio_lock.
153 */
154static int write_sigio_fds[2] = { -1, -1 };
155static int sigio_private[2] = { -1, -1 };
156
157struct pollfds {
158	struct pollfd *poll;
159	int size;
160	int used;
161};
162
163/* Protected by sigio_lock().  Used by the sigio thread, but the UML thread
164 * synchronizes with it.
165 */
166struct pollfds current_poll = {
167	.poll  		= NULL,
168	.size 		= 0,
169	.used 		= 0
170};
171
172struct pollfds next_poll = {
173	.poll  		= NULL,
174	.size 		= 0,
175	.used 		= 0
176};
177
178static int write_sigio_thread(void *unused)
179{
180	struct pollfds *fds, tmp;
181	struct pollfd *p;
182	int i, n, respond_fd;
183	char c;
184
185	fds = &current_poll;
186	while(1){
187		n = poll(fds->poll, fds->used, -1);
188		if(n < 0){
189			if(errno == EINTR) continue;
190			printk("write_sigio_thread : poll returned %d, "
191			       "errno = %d\n", n, errno);
192		}
193		for(i = 0; i < fds->used; i++){
194			p = &fds->poll[i];
195			if(p->revents == 0) continue;
196			if(p->fd == sigio_private[1]){
197				n = os_read_file(sigio_private[1], &c, sizeof(c));
198				if(n != sizeof(c))
199					printk("write_sigio_thread : "
200					       "read failed, err = %d\n", -n);
201				tmp = current_poll;
202				current_poll = next_poll;
203				next_poll = tmp;
204				respond_fd = sigio_private[1];
205			}
206			else {
207				respond_fd = write_sigio_fds[1];
208				fds->used--;
209				memmove(&fds->poll[i], &fds->poll[i + 1],
210					(fds->used - i) * sizeof(*fds->poll));
211			}
212
213			n = os_write_file(respond_fd, &c, sizeof(c));
214			if(n != sizeof(c))
215				printk("write_sigio_thread : write failed, "
216				       "err = %d\n", -n);
217		}
218	}
219}
220
221static int need_poll(int n)
222{
223	if(n <= next_poll.size){
224		next_poll.used = n;
225		return(0);
226	}
227	if(next_poll.poll != NULL) kfree(next_poll.poll);
228	next_poll.poll = um_kmalloc_atomic(n * sizeof(struct pollfd));
229	if(next_poll.poll == NULL){
230		printk("need_poll : failed to allocate new pollfds\n");
231		next_poll.size = 0;
232		next_poll.used = 0;
233		return(-1);
234	}
235	next_poll.size = n;
236	next_poll.used = n;
237	return(0);
238}
239
240/* Must be called with sigio_lock held, because it's needed by the marked
241 * critical section. */
242static void update_thread(void)
243{
244	unsigned long flags;
245	int n;
246	char c;
247
248	flags = set_signals(0);
249	n = os_write_file(sigio_private[0], &c, sizeof(c));
250	if(n != sizeof(c)){
251		printk("update_thread : write failed, err = %d\n", -n);
252		goto fail;
253	}
254
255	n = os_read_file(sigio_private[0], &c, sizeof(c));
256	if(n != sizeof(c)){
257		printk("update_thread : read failed, err = %d\n", -n);
258		goto fail;
259	}
260
261	set_signals(flags);
262	return;
263 fail:
264	/* Critical section start */
265	if(write_sigio_pid != -1) 
266		os_kill_process(write_sigio_pid, 1);
267	write_sigio_pid = -1;
268	os_close_file(sigio_private[0]);
269	os_close_file(sigio_private[1]);
270	os_close_file(write_sigio_fds[0]);
271	os_close_file(write_sigio_fds[1]);
272	/* Critical section end */
273	set_signals(flags);
274}
275
276int add_sigio_fd(int fd, int read)
277{
278	int err = 0, i, n, events;
279
280	sigio_lock();
281	for(i = 0; i < current_poll.used; i++){
282		if(current_poll.poll[i].fd == fd) 
283			goto out;
284	}
285
286	n = current_poll.used + 1;
287	err = need_poll(n);
288	if(err) 
289		goto out;
290
291	for(i = 0; i < current_poll.used; i++)
292		next_poll.poll[i] = current_poll.poll[i];
293
294	if(read) events = POLLIN;
295	else events = POLLOUT;
296
297	next_poll.poll[n - 1] = ((struct pollfd) { .fd  	= fd,
298						   .events 	= events,
299						   .revents 	= 0 });
300	update_thread();
301 out:
302	sigio_unlock();
303	return(err);
304}
305
306int ignore_sigio_fd(int fd)
307{
308	struct pollfd *p;
309	int err = 0, i, n = 0;
310
311	sigio_lock();
312	for(i = 0; i < current_poll.used; i++){
313		if(current_poll.poll[i].fd == fd) break;
314	}
315	if(i == current_poll.used)
316		goto out;
317	
318	err = need_poll(current_poll.used - 1);
319	if(err)
320		goto out;
321
322	for(i = 0; i < current_poll.used; i++){
323		p = &current_poll.poll[i];
324		if(p->fd != fd) next_poll.poll[n++] = current_poll.poll[i];
325	}
326	if(n == i){
327		printk("ignore_sigio_fd : fd %d not found\n", fd);
328		err = -1;
329		goto out;
330	}
331
332	update_thread();
333 out:
334	sigio_unlock();
335	return(err);
336}
337
338static int setup_initial_poll(int fd)
339{
340	struct pollfd *p;
341
342	p = um_kmalloc(sizeof(struct pollfd));
343	if(p == NULL){
344		printk("setup_initial_poll : failed to allocate poll\n");
345		return(-1);
346	}
347	*p = ((struct pollfd) { .fd  	= fd,
348				.events 	= POLLIN,
349				.revents 	= 0 });
350	current_poll = ((struct pollfds) { .poll 	= p,
351					   .used 	= 1,
352					   .size 	= 1 });
353	return(0);
354}
355
356void write_sigio_workaround(void)
357{
358	unsigned long stack;
359	int err;
360
361	sigio_lock();
362	if(write_sigio_pid != -1)
363		goto out;
364
365	err = os_pipe(write_sigio_fds, 1, 1);
366	if(err < 0){
367		printk("write_sigio_workaround - os_pipe 1 failed, "
368		       "err = %d\n", -err);
369		goto out;
370	}
371	err = os_pipe(sigio_private, 1, 1);
372	if(err < 0){
373		printk("write_sigio_workaround - os_pipe 2 failed, "
374		       "err = %d\n", -err);
375		goto out_close1;
376	}
377	if(setup_initial_poll(sigio_private[1]))
378		goto out_close2;
379
380	write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, 
381					    CLONE_FILES | CLONE_VM, &stack, 0);
382
383	if(write_sigio_pid < 0) goto out_close2;
384
385	if(write_sigio_irq(write_sigio_fds[0])) 
386		goto out_kill;
387
388 out:
389	sigio_unlock();
390	return;
391
392 out_kill:
393	os_kill_process(write_sigio_pid, 1);
394	write_sigio_pid = -1;
395 out_close2:
396	os_close_file(sigio_private[0]);
397	os_close_file(sigio_private[1]);
398 out_close1:
399	os_close_file(write_sigio_fds[0]);
400	os_close_file(write_sigio_fds[1]);
401	sigio_unlock();
402}
403
404int read_sigio_fd(int fd)
405{
406	int n;
407	char c;
408
409	n = os_read_file(fd, &c, sizeof(c));
410	if(n != sizeof(c)){
411		if(n < 0) {
412			printk("read_sigio_fd - read failed, err = %d\n", -n);
413			return(n);
414		}
415		else {
416			printk("read_sigio_fd - short read, bytes = %d\n", n);
417			return(-EIO);
418		}
419	}
420	return(n);
421}
422
423static void sigio_cleanup(void)
424{
425	if (write_sigio_pid != -1) {
426		os_kill_process(write_sigio_pid, 1);
427		write_sigio_pid = -1;
428	}
429}
430
431__uml_exitcall(sigio_cleanup);