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 "os.h" 22 23 /* Protected by sigio_lock(), also used by sigio_cleanup, which is an 24 * exitcall. 25 */ 26 static int write_sigio_pid = -1; 27 28 /* These arrays are initialized before the sigio thread is started, and 29 * the descriptors closed after it is killed. So, it can't see them change. 30 * On the UML side, they are changed under the sigio_lock. 31 */ 32 #define SIGIO_FDS_INIT {-1, -1} 33 34 static int write_sigio_fds[2] = SIGIO_FDS_INIT; 35 static int sigio_private[2] = SIGIO_FDS_INIT; 36 37 struct pollfds { 38 struct pollfd *poll; 39 int size; 40 int used; 41 }; 42 43 /* Protected by sigio_lock(). Used by the sigio thread, but the UML thread 44 * synchronizes with it. 45 */ 46 static struct pollfds current_poll; 47 static struct pollfds next_poll; 48 static struct pollfds all_sigio_fds; 49 50 static int write_sigio_thread(void *unused) 51 { 52 struct pollfds *fds, tmp; 53 struct pollfd *p; 54 int i, n, respond_fd; 55 char c; 56 57 signal(SIGWINCH, SIG_IGN); 58 fds = ¤t_poll; 59 while(1){ 60 n = poll(fds->poll, fds->used, -1); 61 if(n < 0){ 62 if(errno == EINTR) continue; 63 printk("write_sigio_thread : poll returned %d, " 64 "errno = %d\n", n, errno); 65 } 66 for(i = 0; i < fds->used; i++){ 67 p = &fds->poll[i]; 68 if(p->revents == 0) continue; 69 if(p->fd == sigio_private[1]){ 70 n = os_read_file(sigio_private[1], &c, sizeof(c)); 71 if(n != sizeof(c)) 72 printk("write_sigio_thread : " 73 "read on socket failed, " 74 "err = %d\n", -n); 75 tmp = current_poll; 76 current_poll = next_poll; 77 next_poll = tmp; 78 respond_fd = sigio_private[1]; 79 } 80 else { 81 respond_fd = write_sigio_fds[1]; 82 fds->used--; 83 memmove(&fds->poll[i], &fds->poll[i + 1], 84 (fds->used - i) * sizeof(*fds->poll)); 85 } 86 87 n = os_write_file(respond_fd, &c, sizeof(c)); 88 if(n != sizeof(c)) 89 printk("write_sigio_thread : write on socket " 90 "failed, err = %d\n", -n); 91 } 92 } 93 94 return 0; 95 } 96 97 static int need_poll(struct pollfds *polls, int n) 98 { 99 if(n <= polls->size){ 100 polls->used = n; 101 return 0; 102 } 103 kfree(polls->poll); 104 polls->poll = um_kmalloc_atomic(n * sizeof(struct pollfd)); 105 if(polls->poll == NULL){ 106 printk("need_poll : failed to allocate new pollfds\n"); 107 polls->size = 0; 108 polls->used = 0; 109 return -ENOMEM; 110 } 111 polls->size = n; 112 polls->used = n; 113 return 0; 114 } 115 116 /* Must be called with sigio_lock held, because it's needed by the marked 117 * critical section. 118 */ 119 static void update_thread(void) 120 { 121 unsigned long flags; 122 int n; 123 char c; 124 125 flags = set_signals(0); 126 n = os_write_file(sigio_private[0], &c, sizeof(c)); 127 if(n != sizeof(c)){ 128 printk("update_thread : write failed, err = %d\n", -n); 129 goto fail; 130 } 131 132 n = os_read_file(sigio_private[0], &c, sizeof(c)); 133 if(n != sizeof(c)){ 134 printk("update_thread : read failed, err = %d\n", -n); 135 goto fail; 136 } 137 138 set_signals(flags); 139 return; 140 fail: 141 /* Critical section start */ 142 if(write_sigio_pid != -1) 143 os_kill_process(write_sigio_pid, 1); 144 write_sigio_pid = -1; 145 close(sigio_private[0]); 146 close(sigio_private[1]); 147 close(write_sigio_fds[0]); 148 close(write_sigio_fds[1]); 149 /* Critical section end */ 150 set_signals(flags); 151 } 152 153 int add_sigio_fd(int fd) 154 { 155 struct pollfd *p; 156 int err = 0, i, n; 157 158 sigio_lock(); 159 for(i = 0; i < all_sigio_fds.used; i++){ 160 if(all_sigio_fds.poll[i].fd == fd) 161 break; 162 } 163 if(i == all_sigio_fds.used) 164 goto out; 165 166 p = &all_sigio_fds.poll[i]; 167 168 for(i = 0; i < current_poll.used; i++){ 169 if(current_poll.poll[i].fd == fd) 170 goto out; 171 } 172 173 n = current_poll.used + 1; 174 err = need_poll(&next_poll, n); 175 if(err) 176 goto out; 177 178 for(i = 0; i < current_poll.used; i++) 179 next_poll.poll[i] = current_poll.poll[i]; 180 181 next_poll.poll[n - 1] = *p; 182 update_thread(); 183 out: 184 sigio_unlock(); 185 return err; 186 } 187 188 int ignore_sigio_fd(int fd) 189 { 190 struct pollfd *p; 191 int err = 0, i, n = 0; 192 193 /* This is called from exitcalls elsewhere in UML - if 194 * sigio_cleanup has already run, then update_thread will hang 195 * or fail because the thread is no longer running. 196 */ 197 if(write_sigio_pid == -1) 198 return -EIO; 199 200 sigio_lock(); 201 for(i = 0; i < current_poll.used; i++){ 202 if(current_poll.poll[i].fd == fd) break; 203 } 204 if(i == current_poll.used) 205 goto out; 206 207 err = need_poll(&next_poll, current_poll.used - 1); 208 if(err) 209 goto out; 210 211 for(i = 0; i < current_poll.used; i++){ 212 p = ¤t_poll.poll[i]; 213 if(p->fd != fd) 214 next_poll.poll[n++] = *p; 215 } 216 217 update_thread(); 218 out: 219 sigio_unlock(); 220 return err; 221 } 222 223 static struct pollfd *setup_initial_poll(int fd) 224 { 225 struct pollfd *p; 226 227 p = um_kmalloc(sizeof(struct pollfd)); 228 if (p == NULL) { 229 printk("setup_initial_poll : failed to allocate poll\n"); 230 return NULL; 231 } 232 *p = ((struct pollfd) { .fd = fd, 233 .events = POLLIN, 234 .revents = 0 }); 235 return p; 236 } 237 238 static void write_sigio_workaround(void) 239 { 240 unsigned long stack; 241 struct pollfd *p; 242 int err; 243 int l_write_sigio_fds[2]; 244 int l_sigio_private[2]; 245 int l_write_sigio_pid; 246 247 /* We call this *tons* of times - and most ones we must just fail. */ 248 sigio_lock(); 249 l_write_sigio_pid = write_sigio_pid; 250 sigio_unlock(); 251 252 if (l_write_sigio_pid != -1) 253 return; 254 255 err = os_pipe(l_write_sigio_fds, 1, 1); 256 if(err < 0){ 257 printk("write_sigio_workaround - os_pipe 1 failed, " 258 "err = %d\n", -err); 259 return; 260 } 261 err = os_pipe(l_sigio_private, 1, 1); 262 if(err < 0){ 263 printk("write_sigio_workaround - os_pipe 2 failed, " 264 "err = %d\n", -err); 265 goto out_close1; 266 } 267 268 p = setup_initial_poll(l_sigio_private[1]); 269 if(!p) 270 goto out_close2; 271 272 sigio_lock(); 273 274 /* Did we race? Don't try to optimize this, please, it's not so likely 275 * to happen, and no more than once at the boot. */ 276 if(write_sigio_pid != -1) 277 goto out_free; 278 279 current_poll = ((struct pollfds) { .poll = p, 280 .used = 1, 281 .size = 1 }); 282 283 if (write_sigio_irq(l_write_sigio_fds[0])) 284 goto out_clear_poll; 285 286 memcpy(write_sigio_fds, l_write_sigio_fds, sizeof(l_write_sigio_fds)); 287 memcpy(sigio_private, l_sigio_private, sizeof(l_sigio_private)); 288 289 write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, 290 CLONE_FILES | CLONE_VM, &stack, 0); 291 292 if (write_sigio_pid < 0) 293 goto out_clear; 294 295 sigio_unlock(); 296 return; 297 298 out_clear: 299 write_sigio_pid = -1; 300 write_sigio_fds[0] = -1; 301 write_sigio_fds[1] = -1; 302 sigio_private[0] = -1; 303 sigio_private[1] = -1; 304 out_clear_poll: 305 current_poll = ((struct pollfds) { .poll = NULL, 306 .size = 0, 307 .used = 0 }); 308 out_free: 309 sigio_unlock(); 310 kfree(p); 311 out_close2: 312 close(l_sigio_private[0]); 313 close(l_sigio_private[1]); 314 out_close1: 315 close(l_write_sigio_fds[0]); 316 close(l_write_sigio_fds[1]); 317 } 318 319 void maybe_sigio_broken(int fd, int read) 320 { 321 int err; 322 323 if(!isatty(fd)) 324 return; 325 326 if((read || pty_output_sigio) && (!read || pty_close_sigio)) 327 return; 328 329 write_sigio_workaround(); 330 331 sigio_lock(); 332 err = need_poll(&all_sigio_fds, all_sigio_fds.used + 1); 333 if(err){ 334 printk("maybe_sigio_broken - failed to add pollfd\n"); 335 goto out; 336 } 337 all_sigio_fds.poll[all_sigio_fds.used++] = 338 ((struct pollfd) { .fd = fd, 339 .events = read ? POLLIN : POLLOUT, 340 .revents = 0 }); 341 out: 342 sigio_unlock(); 343 } 344 345 static void sigio_cleanup(void) 346 { 347 if(write_sigio_pid != -1){ 348 os_kill_process(write_sigio_pid, 1); 349 write_sigio_pid = -1; 350 } 351 } 352 353 __uml_exitcall(sigio_cleanup); 354