#include <termios.h>
#include <pty.h>
#include <signal.h>
+#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sched.h>
#include "init.h"
#include "user.h"
#include "kern_util.h"
-#include "user_util.h"
#include "sigio.h"
#include "os.h"
#include "um_malloc.h"
+#include "init.h"
/* Protected by sigio_lock(), also used by sigio_cleanup, which is an
* exitcall.
*/
static int write_sigio_pid = -1;
+static unsigned long write_sigio_stack;
/* These arrays are initialized before the sigio thread is started, and
* the descriptors closed after it is killed. So, it can't see them change.
p = &fds->poll[i];
if(p->revents == 0) continue;
if(p->fd == sigio_private[1]){
- n = os_read_file(sigio_private[1], &c, sizeof(c));
+ CATCH_EINTR(n = read(sigio_private[1], &c,
+ sizeof(c)));
if(n != sizeof(c))
printk("write_sigio_thread : "
"read on socket failed, "
- "err = %d\n", -n);
+ "err = %d\n", errno);
tmp = current_poll;
current_poll = next_poll;
next_poll = tmp;
(fds->used - i) * sizeof(*fds->poll));
}
- n = os_write_file(respond_fd, &c, sizeof(c));
+ CATCH_EINTR(n = write(respond_fd, &c, sizeof(c)));
if(n != sizeof(c))
printk("write_sigio_thread : write on socket "
- "failed, err = %d\n", -n);
+ "failed, err = %d\n", errno);
}
}
if(n <= polls->size)
return 0;
- new = um_kmalloc_atomic(n * sizeof(struct pollfd));
+ new = kmalloc(n * sizeof(struct pollfd), UM_GFP_ATOMIC);
if(new == NULL){
printk("need_poll : failed to allocate new pollfds\n");
return -ENOMEM;
char c;
flags = set_signals(0);
- n = os_write_file(sigio_private[0], &c, sizeof(c));
+ n = write(sigio_private[0], &c, sizeof(c));
if(n != sizeof(c)){
- printk("update_thread : write failed, err = %d\n", -n);
+ printk("update_thread : write failed, err = %d\n", errno);
goto fail;
}
- n = os_read_file(sigio_private[0], &c, sizeof(c));
+ CATCH_EINTR(n = read(sigio_private[0], &c, sizeof(c)));
if(n != sizeof(c)){
- printk("update_thread : read failed, err = %d\n", -n);
+ printk("update_thread : read failed, err = %d\n", errno);
goto fail;
}
return;
fail:
/* Critical section start */
- if(write_sigio_pid != -1)
+ if (write_sigio_pid != -1) {
os_kill_process(write_sigio_pid, 1);
+ free_stack(write_sigio_stack, 0);
+ }
write_sigio_pid = -1;
close(sigio_private[0]);
close(sigio_private[1]);
{
struct pollfd *p;
- p = um_kmalloc(sizeof(struct pollfd));
+ p = kmalloc(sizeof(struct pollfd), UM_GFP_KERNEL);
if (p == NULL) {
printk("setup_initial_poll : failed to allocate poll\n");
return NULL;
static void write_sigio_workaround(void)
{
- unsigned long stack;
struct pollfd *p;
int err;
int l_write_sigio_fds[2];
memcpy(sigio_private, l_sigio_private, sizeof(l_sigio_private));
write_sigio_pid = run_helper_thread(write_sigio_thread, NULL,
- CLONE_FILES | CLONE_VM, &stack, 0);
+ CLONE_FILES | CLONE_VM,
+ &write_sigio_stack);
if (write_sigio_pid < 0)
goto out_clear;
close(l_write_sigio_fds[1]);
}
+/* Changed during early boot */
+static int pty_output_sigio = 0;
+static int pty_close_sigio = 0;
+
void maybe_sigio_broken(int fd, int read)
{
int err;
sigio_lock();
err = need_poll(&all_sigio_fds, all_sigio_fds.used + 1);
- if(err)
+ if(err){
+ printk("maybe_sigio_broken - failed to add pollfd for "
+ "descriptor %d\n", fd);
goto out;
+ }
all_sigio_fds.poll[all_sigio_fds.used++] =
((struct pollfd) { .fd = fd,
static void sigio_cleanup(void)
{
- if(write_sigio_pid != -1){
- os_kill_process(write_sigio_pid, 1);
- write_sigio_pid = -1;
- }
+ if (write_sigio_pid == -1)
+ return;
+
+ os_kill_process(write_sigio_pid, 1);
+ free_stack(write_sigio_stack, 0);
+ write_sigio_pid = -1;
}
__uml_exitcall(sigio_cleanup);
+
+/* Used as a flag during SIGIO testing early in boot */
+static volatile int got_sigio = 0;
+
+static void __init handler(int sig)
+{
+ got_sigio = 1;
+}
+
+struct openpty_arg {
+ int master;
+ int slave;
+ int err;
+};
+
+static void openpty_cb(void *arg)
+{
+ struct openpty_arg *info = arg;
+
+ info->err = 0;
+ if(openpty(&info->master, &info->slave, NULL, NULL, NULL))
+ info->err = -errno;
+}
+
+static int async_pty(int master, int slave)
+{
+ int flags;
+
+ flags = fcntl(master, F_GETFL);
+ if(flags < 0)
+ return -errno;
+
+ if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) ||
+ (fcntl(master, F_SETOWN, os_getpid()) < 0))
+ return -errno;
+
+ if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0))
+ return -errno;
+
+ return 0;
+}
+
+static void __init check_one_sigio(void (*proc)(int, int))
+{
+ struct sigaction old, new;
+ struct openpty_arg pty = { .master = -1, .slave = -1 };
+ int master, slave, err;
+
+ initial_thread_cb(openpty_cb, &pty);
+ if(pty.err){
+ printk("openpty failed, errno = %d\n", -pty.err);
+ return;
+ }
+
+ master = pty.master;
+ slave = pty.slave;
+
+ if((master == -1) || (slave == -1)){
+ printk("openpty failed to allocate a pty\n");
+ return;
+ }
+
+ /* Not now, but complain so we now where we failed. */
+ err = raw(master);
+ if (err < 0)
+ panic("check_sigio : __raw failed, errno = %d\n", -err);
+
+ err = async_pty(master, slave);
+ if(err < 0)
+ panic("tty_fds : sigio_async failed, err = %d\n", -err);
+
+ if(sigaction(SIGIO, NULL, &old) < 0)
+ panic("check_sigio : sigaction 1 failed, errno = %d\n", errno);
+ new = old;
+ new.sa_handler = handler;
+ if(sigaction(SIGIO, &new, NULL) < 0)
+ panic("check_sigio : sigaction 2 failed, errno = %d\n", errno);
+
+ got_sigio = 0;
+ (*proc)(master, slave);
+
+ close(master);
+ close(slave);
+
+ if(sigaction(SIGIO, &old, NULL) < 0)
+ panic("check_sigio : sigaction 3 failed, errno = %d\n", errno);
+}
+
+static void tty_output(int master, int slave)
+{
+ int n;
+ char buf[512];
+
+ printk("Checking that host ptys support output SIGIO...");
+
+ memset(buf, 0, sizeof(buf));
+
+ while(write(master, buf, sizeof(buf)) > 0) ;
+ if(errno != EAGAIN)
+ panic("tty_output : write failed, errno = %d\n", errno);
+ while(((n = read(slave, buf, sizeof(buf))) > 0) && !got_sigio) ;
+
+ if(got_sigio){
+ printk("Yes\n");
+ pty_output_sigio = 1;
+ }
+ else if(n == -EAGAIN)
+ printk("No, enabling workaround\n");
+ else panic("tty_output : read failed, err = %d\n", n);
+}
+
+static void tty_close(int master, int slave)
+{
+ printk("Checking that host ptys support SIGIO on close...");
+
+ close(slave);
+ if(got_sigio){
+ printk("Yes\n");
+ pty_close_sigio = 1;
+ }
+ else printk("No, enabling workaround\n");
+}
+
+void __init check_sigio(void)
+{
+ if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) &&
+ (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){
+ printk("No pseudo-terminals available - skipping pty SIGIO "
+ "check\n");
+ return;
+ }
+ check_one_sigio(tty_output);
+ check_one_sigio(tty_close);
+}
+
+/* Here because it only does the SIGIO testing for now */
+void __init os_check_bugs(void)
+{
+ check_sigio();
+}