2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
15 #include <sys/socket.h>
19 #include "kern_util.h"
24 /* Changed during early boot */
25 int pty_output_sigio = 0;
26 int pty_close_sigio = 0;
28 /* Used as a flag during SIGIO testing early in boot */
29 static int got_sigio = 0;
31 void __init handler(int sig)
42 static void openpty_cb(void *arg)
44 struct openpty_arg *info = arg;
47 if(openpty(&info->master, &info->slave, NULL, NULL, NULL))
51 void __init check_one_sigio(void (*proc)(int, int))
53 struct sigaction old, new;
55 struct openpty_arg pty = { .master = -1, .slave = -1 };
56 int master, slave, flags;
58 initial_thread_cb(openpty_cb, &pty);
60 printk("openpty failed, errno = %d\n", pty.err);
67 if((master == -1) || (slave == -1)){
68 printk("openpty failed to allocate a pty\n");
72 if(tcgetattr(master, &tt) < 0)
73 panic("check_sigio : tcgetattr failed, errno = %d\n", errno);
75 if(tcsetattr(master, TCSADRAIN, &tt) < 0)
76 panic("check_sigio : tcsetattr failed, errno = %d\n", errno);
78 if((flags = fcntl(master, F_GETFL)) < 0)
79 panic("tty_fds : fcntl F_GETFL failed, errno = %d\n", errno);
81 if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) ||
82 (fcntl(master, F_SETOWN, os_getpid()) < 0))
83 panic("check_sigio : fcntl F_SETFL or F_SETOWN failed, "
84 "errno = %d\n", errno);
86 if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0))
87 panic("check_sigio : fcntl F_SETFL failed, errno = %d\n",
90 if(sigaction(SIGIO, NULL, &old) < 0)
91 panic("check_sigio : sigaction 1 failed, errno = %d\n", errno);
93 new.sa_handler = handler;
94 if(sigaction(SIGIO, &new, NULL) < 0)
95 panic("check_sigio : sigaction 2 failed, errno = %d\n", errno);
98 (*proc)(master, slave);
103 if(sigaction(SIGIO, &old, NULL) < 0)
104 panic("check_sigio : sigaction 3 failed, errno = %d\n", errno);
107 static void tty_output(int master, int slave)
112 printk("Checking that host ptys support output SIGIO...");
114 memset(buf, 0, sizeof(buf));
115 while(write(master, buf, sizeof(buf)) > 0) ;
117 panic("check_sigio : write failed, errno = %d\n", errno);
119 while(((n = read(slave, buf, sizeof(buf))) > 0) && !got_sigio) ;
123 pty_output_sigio = 1;
125 else if(errno == EAGAIN) printk("No, enabling workaround\n");
126 else panic("check_sigio : read failed, errno = %d\n", errno);
129 static void tty_close(int master, int slave)
131 printk("Checking that host ptys support SIGIO on close...");
138 else printk("No, enabling workaround\n");
141 void __init check_sigio(void)
143 if(access("/dev/ptmx", R_OK) && access("/dev/ptyp0", R_OK)){
144 printk("No pseudo-terminals available - skipping pty SIGIO "
148 check_one_sigio(tty_output);
149 check_one_sigio(tty_close);
152 /* Protected by sigio_lock(), also used by sigio_cleanup, which is an
155 static int write_sigio_pid = -1;
157 /* These arrays are initialized before the sigio thread is started, and
158 * the descriptors closed after it is killed. So, it can't see them change.
159 * On the UML side, they are changed under the sigio_lock.
161 static int write_sigio_fds[2] = { -1, -1 };
162 static int sigio_private[2] = { -1, -1 };
170 /* Protected by sigio_lock(). Used by the sigio thread, but the UML thread
171 * synchronizes with it.
173 struct pollfds current_poll = {
179 struct pollfds next_poll = {
185 static int write_sigio_thread(void *unused)
187 struct pollfds *fds, tmp;
189 int i, n, respond_fd;
194 n = poll(fds->poll, fds->used, -1);
196 if(errno == EINTR) continue;
197 printk("write_sigio_thread : poll returned %d, "
198 "errno = %d\n", n, errno);
200 for(i = 0; i < fds->used; i++){
202 if(p->revents == 0) continue;
203 if(p->fd == sigio_private[1]){
204 n = read(sigio_private[1], &c, sizeof(c));
206 printk("write_sigio_thread : "
207 "read failed, errno = %d\n",
210 current_poll = next_poll;
212 respond_fd = sigio_private[1];
215 respond_fd = write_sigio_fds[1];
217 memmove(&fds->poll[i], &fds->poll[i + 1],
218 (fds->used - i) * sizeof(*fds->poll));
221 n = write(respond_fd, &c, sizeof(c));
223 printk("write_sigio_thread : write failed, "
224 "errno = %d\n", errno);
229 static int need_poll(int n)
231 if(n <= next_poll.size){
235 if(next_poll.poll != NULL) kfree(next_poll.poll);
236 next_poll.poll = um_kmalloc_atomic(n * sizeof(struct pollfd));
237 if(next_poll.poll == NULL){
238 printk("need_poll : failed to allocate new pollfds\n");
248 static void update_thread(void)
254 flags = set_signals(0);
255 n = write(sigio_private[0], &c, sizeof(c));
257 printk("update_thread : write failed, errno = %d\n", errno);
261 n = read(sigio_private[0], &c, sizeof(c));
263 printk("update_thread : read failed, errno = %d\n", errno);
271 if(write_sigio_pid != -1)
272 os_kill_process(write_sigio_pid, 1);
273 write_sigio_pid = -1;
274 close(sigio_private[0]);
275 close(sigio_private[1]);
276 close(write_sigio_fds[0]);
277 close(write_sigio_fds[1]);
282 int add_sigio_fd(int fd, int read)
284 int err = 0, i, n, events;
287 for(i = 0; i < current_poll.used; i++){
288 if(current_poll.poll[i].fd == fd)
292 n = current_poll.used + 1;
297 for(i = 0; i < current_poll.used; i++)
298 next_poll.poll[i] = current_poll.poll[i];
300 if(read) events = POLLIN;
301 else events = POLLOUT;
303 next_poll.poll[n - 1] = ((struct pollfd) { .fd = fd,
312 int ignore_sigio_fd(int fd)
315 int err = 0, i, n = 0;
318 for(i = 0; i < current_poll.used; i++){
319 if(current_poll.poll[i].fd == fd) break;
321 if(i == current_poll.used)
324 err = need_poll(current_poll.used - 1);
328 for(i = 0; i < current_poll.used; i++){
329 p = ¤t_poll.poll[i];
330 if(p->fd != fd) next_poll.poll[n++] = current_poll.poll[i];
333 printk("ignore_sigio_fd : fd %d not found\n", fd);
344 static int setup_initial_poll(int fd)
348 p = um_kmalloc(sizeof(struct pollfd));
350 printk("setup_initial_poll : failed to allocate poll\n");
353 *p = ((struct pollfd) { .fd = fd,
356 current_poll = ((struct pollfds) { .poll = p,
362 void write_sigio_workaround(void)
368 if(write_sigio_pid != -1)
371 err = os_pipe(write_sigio_fds, 1, 1);
373 printk("write_sigio_workaround - os_pipe 1 failed, "
374 "errno = %d\n", -err);
377 err = os_pipe(sigio_private, 1, 1);
379 printk("write_sigio_workaround - os_pipe 2 failed, "
380 "errno = %d\n", -err);
383 if(setup_initial_poll(sigio_private[1]))
386 write_sigio_pid = run_helper_thread(write_sigio_thread, NULL,
387 CLONE_FILES | CLONE_VM, &stack, 0);
389 if(write_sigio_pid < 0) goto out_close2;
391 if(write_sigio_irq(write_sigio_fds[0]))
399 os_kill_process(write_sigio_pid, 1);
400 write_sigio_pid = -1;
402 close(sigio_private[0]);
403 close(sigio_private[1]);
405 close(write_sigio_fds[0]);
406 close(write_sigio_fds[1]);
410 int read_sigio_fd(int fd)
415 n = read(fd, &c, sizeof(c));
417 printk("read_sigio_fd - read failed, errno = %d\n", errno);
423 static void sigio_cleanup(void)
425 if(write_sigio_pid != -1)
426 os_kill_process(write_sigio_pid, 1);
429 __uml_exitcall(sigio_cleanup);
432 * Overrides for Emacs so that we follow Linus's tabbing style.
433 * Emacs will notice this stuff at the end of the file and automatically
434 * adjust the settings for this buffer only. This must remain at the end
436 * ---------------------------------------------------------------------------
438 * c-file-style: "linux"