FILE
sigio.c
File preview with syntax highlighting.
linux-6.19.14/arch/um/os-Linux/sigio.c
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2002 - 2008 Jeff Dike (jdike@{addtoit,linux.intel}.com) 4 */ 5 6#include <unistd.h> 7#include <errno.h> 8#include <fcntl.h> 9#include <poll.h> 10#include <pty.h> 11#include <sched.h> 12#include <signal.h> 13#include <string.h> 14#include <sys/epoll.h> 15#include <asm/unistd.h> 16#include <kern_util.h> 17#include <init.h> 18#include <os.h> 19#include <sigio.h> 20#include <um_malloc.h> 21 22/* 23 * Protected by sigio_lock(), also used by sigio_cleanup, which is an 24 * exitcall. 25 */ 26static struct os_helper_thread *write_sigio_td; 27 28static int epollfd = -1; 29 30#define MAX_EPOLL_EVENTS 64 31 32static struct epoll_event epoll_events[MAX_EPOLL_EVENTS]; 33 34static void *write_sigio_thread(void *unused) 35{ 36 int pid = getpid(); 37 int r; 38 39 os_fix_helper_thread_signals(); 40 41 while (1) { 42 r = epoll_wait(epollfd, epoll_events, MAX_EPOLL_EVENTS, -1); 43 if (r < 0) { 44 if (errno == EINTR) 45 continue; 46 printk(UM_KERN_ERR "%s: epoll_wait failed, errno = %d\n", 47 __func__, errno); 48 } 49 50 CATCH_EINTR(r = syscall(__NR_tgkill, pid, pid, SIGIO)); 51 if (r < 0) 52 printk(UM_KERN_ERR "%s: tgkill failed, errno = %d\n", 53 __func__, errno); 54 } 55 56 return NULL; 57} 58 59int __add_sigio_fd(int fd) 60{ 61 struct epoll_event event = { 62 .data.fd = fd, 63 .events = EPOLLIN | EPOLLET, 64 }; 65 int r; 66 67 CATCH_EINTR(r = epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event)); 68 return r < 0 ? -errno : 0; 69} 70 71int add_sigio_fd(int fd) 72{ 73 int err; 74 75 sigio_lock(); 76 err = __add_sigio_fd(fd); 77 sigio_unlock(); 78 79 return err; 80} 81 82int __ignore_sigio_fd(int fd) 83{ 84 struct epoll_event event; 85 int r; 86 87 CATCH_EINTR(r = epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, &event)); 88 return r < 0 ? -errno : 0; 89} 90 91int ignore_sigio_fd(int fd) 92{ 93 int err; 94 95 sigio_lock(); 96 err = __ignore_sigio_fd(fd); 97 sigio_unlock(); 98 99 return err; 100} 101 102static void write_sigio_workaround(void) 103{ 104 int err; 105 106 sigio_lock(); 107 if (write_sigio_td) 108 goto out; 109 110 epollfd = epoll_create(MAX_EPOLL_EVENTS); 111 if (epollfd < 0) { 112 printk(UM_KERN_ERR "%s: epoll_create failed, errno = %d\n", 113 __func__, errno); 114 goto out; 115 } 116 117 err = os_run_helper_thread(&write_sigio_td, write_sigio_thread, NULL); 118 if (err < 0) { 119 printk(UM_KERN_ERR "%s: os_run_helper_thread failed, errno = %d\n", 120 __func__, -err); 121 close(epollfd); 122 epollfd = -1; 123 goto out; 124 } 125 126out: 127 sigio_unlock(); 128} 129 130void sigio_broken(void) 131{ 132 write_sigio_workaround(); 133} 134 135/* Changed during early boot */ 136static int pty_output_sigio; 137 138void maybe_sigio_broken(int fd) 139{ 140 if (!isatty(fd)) 141 return; 142 143 if (pty_output_sigio) 144 return; 145 146 sigio_broken(); 147} 148 149static void sigio_cleanup(void) 150{ 151 if (!write_sigio_td) 152 return; 153 154 os_kill_helper_thread(write_sigio_td); 155 write_sigio_td = NULL; 156} 157 158__uml_exitcall(sigio_cleanup); 159 160/* Used as a flag during SIGIO testing early in boot */ 161static int got_sigio; 162 163static void __init handler(int sig) 164{ 165 got_sigio = 1; 166} 167 168struct openpty_arg { 169 int master; 170 int slave; 171 int err; 172}; 173 174static void openpty_cb(void *arg) 175{ 176 struct openpty_arg *info = arg; 177 178 info->err = 0; 179 if (openpty(&info->master, &info->slave, NULL, NULL, NULL)) 180 info->err = -errno; 181} 182 183static int async_pty(int master, int slave) 184{ 185 int flags; 186 187 flags = fcntl(master, F_GETFL); 188 if (flags < 0) 189 return -errno; 190 191 if ((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) || 192 (fcntl(master, F_SETOWN, os_getpid()) < 0)) 193 return -errno; 194 195 if ((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)) 196 return -errno; 197 198 return 0; 199} 200 201static void __init check_one_sigio(void (*proc)(int, int)) 202{ 203 struct sigaction old, new; 204 struct openpty_arg pty = { .master = -1, .slave = -1 }; 205 int master, slave, err; 206 207 initial_thread_cb(openpty_cb, &pty); 208 if (pty.err) { 209 printk(UM_KERN_ERR "check_one_sigio failed, errno = %d\n", 210 -pty.err); 211 return; 212 } 213 214 master = pty.master; 215 slave = pty.slave; 216 217 if ((master == -1) || (slave == -1)) { 218 printk(UM_KERN_ERR "check_one_sigio failed to allocate a " 219 "pty\n"); 220 return; 221 } 222 223 /* Not now, but complain so we now where we failed. */ 224 err = raw(master); 225 if (err < 0) { 226 printk(UM_KERN_ERR "check_one_sigio : raw failed, errno = %d\n", 227 -err); 228 return; 229 } 230 231 err = async_pty(master, slave); 232 if (err < 0) { 233 printk(UM_KERN_ERR "check_one_sigio : sigio_async failed, " 234 "err = %d\n", -err); 235 return; 236 } 237 238 if (sigaction(SIGIO, NULL, &old) < 0) { 239 printk(UM_KERN_ERR "check_one_sigio : sigaction 1 failed, " 240 "errno = %d\n", errno); 241 return; 242 } 243 244 new = old; 245 new.sa_handler = handler; 246 if (sigaction(SIGIO, &new, NULL) < 0) { 247 printk(UM_KERN_ERR "check_one_sigio : sigaction 2 failed, " 248 "errno = %d\n", errno); 249 return; 250 } 251 252 got_sigio = 0; 253 (*proc)(master, slave); 254 255 close(master); 256 close(slave); 257 258 if (sigaction(SIGIO, &old, NULL) < 0) 259 printk(UM_KERN_ERR "check_one_sigio : sigaction 3 failed, " 260 "errno = %d\n", errno); 261} 262 263static void tty_output(int master, int slave) 264{ 265 int n; 266 char buf[512]; 267 268 printk(UM_KERN_INFO "Checking that host ptys support output SIGIO..."); 269 270 memset(buf, 0, sizeof(buf)); 271 272 while (write(master, buf, sizeof(buf)) > 0) ; 273 if (errno != EAGAIN) 274 printk(UM_KERN_ERR "tty_output : write failed, errno = %d\n", 275 errno); 276 while (((n = read(slave, buf, sizeof(buf))) > 0) && 277 !({ barrier(); got_sigio; })) 278 ; 279 280 if (got_sigio) { 281 printk(UM_KERN_CONT "Yes\n"); 282 pty_output_sigio = 1; 283 } else if (n == -EAGAIN) 284 printk(UM_KERN_CONT "No, enabling workaround\n"); 285 else 286 printk(UM_KERN_CONT "tty_output : read failed, err = %d\n", n); 287} 288 289static void __init check_sigio(void) 290{ 291 if ((access("/dev/ptmx", R_OK) < 0) && 292 (access("/dev/ptyp0", R_OK) < 0)) { 293 printk(UM_KERN_WARNING "No pseudo-terminals available - " 294 "skipping pty SIGIO check\n"); 295 return; 296 } 297 check_one_sigio(tty_output); 298} 299 300/* Here because it only does the SIGIO testing for now */ 301void __init os_check_bugs(void) 302{ 303 check_sigio(); 304}
~/
Read-only file preview.