diff options
Diffstat (limited to 'arch/um/os-Linux/sigio.c')
-rw-r--r-- | arch/um/os-Linux/sigio.c | 164 |
1 files changed, 155 insertions, 9 deletions
diff --git a/arch/um/os-Linux/sigio.c b/arch/um/os-Linux/sigio.c index 3fc43b33db66..8d4e0c6b8c92 100644 --- a/arch/um/os-Linux/sigio.c +++ b/arch/um/os-Linux/sigio.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <termios.h> | 8 | #include <termios.h> |
9 | #include <pty.h> | 9 | #include <pty.h> |
10 | #include <signal.h> | 10 | #include <signal.h> |
11 | #include <fcntl.h> | ||
11 | #include <errno.h> | 12 | #include <errno.h> |
12 | #include <string.h> | 13 | #include <string.h> |
13 | #include <sched.h> | 14 | #include <sched.h> |
@@ -16,10 +17,10 @@ | |||
16 | #include "init.h" | 17 | #include "init.h" |
17 | #include "user.h" | 18 | #include "user.h" |
18 | #include "kern_util.h" | 19 | #include "kern_util.h" |
19 | #include "user_util.h" | ||
20 | #include "sigio.h" | 20 | #include "sigio.h" |
21 | #include "os.h" | 21 | #include "os.h" |
22 | #include "um_malloc.h" | 22 | #include "um_malloc.h" |
23 | #include "init.h" | ||
23 | 24 | ||
24 | /* Protected by sigio_lock(), also used by sigio_cleanup, which is an | 25 | /* Protected by sigio_lock(), also used by sigio_cleanup, which is an |
25 | * exitcall. | 26 | * exitcall. |
@@ -68,11 +69,12 @@ static int write_sigio_thread(void *unused) | |||
68 | p = &fds->poll[i]; | 69 | p = &fds->poll[i]; |
69 | if(p->revents == 0) continue; | 70 | if(p->revents == 0) continue; |
70 | if(p->fd == sigio_private[1]){ | 71 | if(p->fd == sigio_private[1]){ |
71 | n = os_read_file(sigio_private[1], &c, sizeof(c)); | 72 | CATCH_EINTR(n = read(sigio_private[1], &c, |
73 | sizeof(c))); | ||
72 | if(n != sizeof(c)) | 74 | if(n != sizeof(c)) |
73 | printk("write_sigio_thread : " | 75 | printk("write_sigio_thread : " |
74 | "read on socket failed, " | 76 | "read on socket failed, " |
75 | "err = %d\n", -n); | 77 | "err = %d\n", errno); |
76 | tmp = current_poll; | 78 | tmp = current_poll; |
77 | current_poll = next_poll; | 79 | current_poll = next_poll; |
78 | next_poll = tmp; | 80 | next_poll = tmp; |
@@ -85,10 +87,10 @@ static int write_sigio_thread(void *unused) | |||
85 | (fds->used - i) * sizeof(*fds->poll)); | 87 | (fds->used - i) * sizeof(*fds->poll)); |
86 | } | 88 | } |
87 | 89 | ||
88 | n = os_write_file(respond_fd, &c, sizeof(c)); | 90 | CATCH_EINTR(n = write(respond_fd, &c, sizeof(c))); |
89 | if(n != sizeof(c)) | 91 | if(n != sizeof(c)) |
90 | printk("write_sigio_thread : write on socket " | 92 | printk("write_sigio_thread : write on socket " |
91 | "failed, err = %d\n", -n); | 93 | "failed, err = %d\n", errno); |
92 | } | 94 | } |
93 | } | 95 | } |
94 | 96 | ||
@@ -126,15 +128,15 @@ static void update_thread(void) | |||
126 | char c; | 128 | char c; |
127 | 129 | ||
128 | flags = set_signals(0); | 130 | flags = set_signals(0); |
129 | n = os_write_file(sigio_private[0], &c, sizeof(c)); | 131 | n = write(sigio_private[0], &c, sizeof(c)); |
130 | if(n != sizeof(c)){ | 132 | if(n != sizeof(c)){ |
131 | printk("update_thread : write failed, err = %d\n", -n); | 133 | printk("update_thread : write failed, err = %d\n", errno); |
132 | goto fail; | 134 | goto fail; |
133 | } | 135 | } |
134 | 136 | ||
135 | n = os_read_file(sigio_private[0], &c, sizeof(c)); | 137 | CATCH_EINTR(n = read(sigio_private[0], &c, sizeof(c))); |
136 | if(n != sizeof(c)){ | 138 | if(n != sizeof(c)){ |
137 | printk("update_thread : read failed, err = %d\n", -n); | 139 | printk("update_thread : read failed, err = %d\n", errno); |
138 | goto fail; | 140 | goto fail; |
139 | } | 141 | } |
140 | 142 | ||
@@ -320,6 +322,10 @@ out_close1: | |||
320 | close(l_write_sigio_fds[1]); | 322 | close(l_write_sigio_fds[1]); |
321 | } | 323 | } |
322 | 324 | ||
325 | /* Changed during early boot */ | ||
326 | static int pty_output_sigio = 0; | ||
327 | static int pty_close_sigio = 0; | ||
328 | |||
323 | void maybe_sigio_broken(int fd, int read) | 329 | void maybe_sigio_broken(int fd, int read) |
324 | { | 330 | { |
325 | int err; | 331 | int err; |
@@ -357,3 +363,143 @@ static void sigio_cleanup(void) | |||
357 | } | 363 | } |
358 | 364 | ||
359 | __uml_exitcall(sigio_cleanup); | 365 | __uml_exitcall(sigio_cleanup); |
366 | |||
367 | /* Used as a flag during SIGIO testing early in boot */ | ||
368 | static volatile int got_sigio = 0; | ||
369 | |||
370 | static void __init handler(int sig) | ||
371 | { | ||
372 | got_sigio = 1; | ||
373 | } | ||
374 | |||
375 | struct openpty_arg { | ||
376 | int master; | ||
377 | int slave; | ||
378 | int err; | ||
379 | }; | ||
380 | |||
381 | static void openpty_cb(void *arg) | ||
382 | { | ||
383 | struct openpty_arg *info = arg; | ||
384 | |||
385 | info->err = 0; | ||
386 | if(openpty(&info->master, &info->slave, NULL, NULL, NULL)) | ||
387 | info->err = -errno; | ||
388 | } | ||
389 | |||
390 | static int async_pty(int master, int slave) | ||
391 | { | ||
392 | int flags; | ||
393 | |||
394 | flags = fcntl(master, F_GETFL); | ||
395 | if(flags < 0) | ||
396 | return -errno; | ||
397 | |||
398 | if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) || | ||
399 | (fcntl(master, F_SETOWN, os_getpid()) < 0)) | ||
400 | return -errno; | ||
401 | |||
402 | if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)) | ||
403 | return -errno; | ||
404 | |||
405 | return(0); | ||
406 | } | ||
407 | |||
408 | static void __init check_one_sigio(void (*proc)(int, int)) | ||
409 | { | ||
410 | struct sigaction old, new; | ||
411 | struct openpty_arg pty = { .master = -1, .slave = -1 }; | ||
412 | int master, slave, err; | ||
413 | |||
414 | initial_thread_cb(openpty_cb, &pty); | ||
415 | if(pty.err){ | ||
416 | printk("openpty failed, errno = %d\n", -pty.err); | ||
417 | return; | ||
418 | } | ||
419 | |||
420 | master = pty.master; | ||
421 | slave = pty.slave; | ||
422 | |||
423 | if((master == -1) || (slave == -1)){ | ||
424 | printk("openpty failed to allocate a pty\n"); | ||
425 | return; | ||
426 | } | ||
427 | |||
428 | /* Not now, but complain so we now where we failed. */ | ||
429 | err = raw(master); | ||
430 | if (err < 0) | ||
431 | panic("check_sigio : __raw failed, errno = %d\n", -err); | ||
432 | |||
433 | err = async_pty(master, slave); | ||
434 | if(err < 0) | ||
435 | panic("tty_fds : sigio_async failed, err = %d\n", -err); | ||
436 | |||
437 | if(sigaction(SIGIO, NULL, &old) < 0) | ||
438 | panic("check_sigio : sigaction 1 failed, errno = %d\n", errno); | ||
439 | new = old; | ||
440 | new.sa_handler = handler; | ||
441 | if(sigaction(SIGIO, &new, NULL) < 0) | ||
442 | panic("check_sigio : sigaction 2 failed, errno = %d\n", errno); | ||
443 | |||
444 | got_sigio = 0; | ||
445 | (*proc)(master, slave); | ||
446 | |||
447 | close(master); | ||
448 | close(slave); | ||
449 | |||
450 | if(sigaction(SIGIO, &old, NULL) < 0) | ||
451 | panic("check_sigio : sigaction 3 failed, errno = %d\n", errno); | ||
452 | } | ||
453 | |||
454 | static void tty_output(int master, int slave) | ||
455 | { | ||
456 | int n; | ||
457 | char buf[512]; | ||
458 | |||
459 | printk("Checking that host ptys support output SIGIO..."); | ||
460 | |||
461 | memset(buf, 0, sizeof(buf)); | ||
462 | |||
463 | while(write(master, buf, sizeof(buf)) > 0) ; | ||
464 | if(errno != EAGAIN) | ||
465 | panic("tty_output : write failed, errno = %d\n", errno); | ||
466 | while(((n = read(slave, buf, sizeof(buf))) > 0) && !got_sigio) ; | ||
467 | |||
468 | if(got_sigio){ | ||
469 | printk("Yes\n"); | ||
470 | pty_output_sigio = 1; | ||
471 | } | ||
472 | else if(n == -EAGAIN) | ||
473 | printk("No, enabling workaround\n"); | ||
474 | else panic("tty_output : read failed, err = %d\n", n); | ||
475 | } | ||
476 | |||
477 | static void tty_close(int master, int slave) | ||
478 | { | ||
479 | printk("Checking that host ptys support SIGIO on close..."); | ||
480 | |||
481 | close(slave); | ||
482 | if(got_sigio){ | ||
483 | printk("Yes\n"); | ||
484 | pty_close_sigio = 1; | ||
485 | } | ||
486 | else printk("No, enabling workaround\n"); | ||
487 | } | ||
488 | |||
489 | void __init check_sigio(void) | ||
490 | { | ||
491 | if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) && | ||
492 | (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){ | ||
493 | printk("No pseudo-terminals available - skipping pty SIGIO " | ||
494 | "check\n"); | ||
495 | return; | ||
496 | } | ||
497 | check_one_sigio(tty_output); | ||
498 | check_one_sigio(tty_close); | ||
499 | } | ||
500 | |||
501 | /* Here because it only does the SIGIO testing for now */ | ||
502 | void __init os_check_bugs(void) | ||
503 | { | ||
504 | check_sigio(); | ||
505 | } | ||