diff options
-rw-r--r-- | arch/um/kernel/sigio_user.c | 83 |
1 files changed, 58 insertions, 25 deletions
diff --git a/arch/um/kernel/sigio_user.c b/arch/um/kernel/sigio_user.c index 62e5cfdf2188..f7b18e157d35 100644 --- a/arch/um/kernel/sigio_user.c +++ b/arch/um/kernel/sigio_user.c | |||
@@ -337,70 +337,103 @@ int ignore_sigio_fd(int fd) | |||
337 | return(err); | 337 | return(err); |
338 | } | 338 | } |
339 | 339 | ||
340 | static int setup_initial_poll(int fd) | 340 | static struct pollfd* setup_initial_poll(int fd) |
341 | { | 341 | { |
342 | struct pollfd *p; | 342 | struct pollfd *p; |
343 | 343 | ||
344 | p = um_kmalloc_atomic(sizeof(struct pollfd)); | 344 | p = um_kmalloc(sizeof(struct pollfd)); |
345 | if(p == NULL){ | 345 | if (p == NULL) { |
346 | printk("setup_initial_poll : failed to allocate poll\n"); | 346 | printk("setup_initial_poll : failed to allocate poll\n"); |
347 | return(-1); | 347 | return NULL; |
348 | } | 348 | } |
349 | *p = ((struct pollfd) { .fd = fd, | 349 | *p = ((struct pollfd) { .fd = fd, |
350 | .events = POLLIN, | 350 | .events = POLLIN, |
351 | .revents = 0 }); | 351 | .revents = 0 }); |
352 | current_poll = ((struct pollfds) { .poll = p, | 352 | return p; |
353 | .used = 1, | ||
354 | .size = 1 }); | ||
355 | return(0); | ||
356 | } | 353 | } |
357 | 354 | ||
358 | void write_sigio_workaround(void) | 355 | void write_sigio_workaround(void) |
359 | { | 356 | { |
360 | unsigned long stack; | 357 | unsigned long stack; |
358 | struct pollfd *p; | ||
361 | int err; | 359 | int err; |
360 | int l_write_sigio_fds[2]; | ||
361 | int l_sigio_private[2]; | ||
362 | int l_write_sigio_pid; | ||
362 | 363 | ||
364 | /* We call this *tons* of times - and most ones we must just fail. */ | ||
363 | sigio_lock(); | 365 | sigio_lock(); |
364 | if(write_sigio_pid != -1) | 366 | l_write_sigio_pid = write_sigio_pid; |
365 | goto out; | 367 | sigio_unlock(); |
366 | 368 | ||
367 | err = os_pipe(write_sigio_fds, 1, 1); | 369 | if (l_write_sigio_pid != -1) |
370 | return; | ||
371 | |||
372 | err = os_pipe(l_write_sigio_fds, 1, 1); | ||
368 | if(err < 0){ | 373 | if(err < 0){ |
369 | printk("write_sigio_workaround - os_pipe 1 failed, " | 374 | printk("write_sigio_workaround - os_pipe 1 failed, " |
370 | "err = %d\n", -err); | 375 | "err = %d\n", -err); |
371 | goto out; | 376 | return; |
372 | } | 377 | } |
373 | err = os_pipe(sigio_private, 1, 1); | 378 | err = os_pipe(l_sigio_private, 1, 1); |
374 | if(err < 0){ | 379 | if(err < 0){ |
375 | printk("write_sigio_workaround - os_pipe 2 failed, " | 380 | printk("write_sigio_workaround - os_pipe 1 failed, " |
376 | "err = %d\n", -err); | 381 | "err = %d\n", -err); |
377 | goto out_close1; | 382 | goto out_close1; |
378 | } | 383 | } |
379 | if(setup_initial_poll(sigio_private[1])) | 384 | |
385 | p = setup_initial_poll(l_sigio_private[1]); | ||
386 | if(!p) | ||
380 | goto out_close2; | 387 | goto out_close2; |
381 | 388 | ||
382 | write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, | 389 | sigio_lock(); |
390 | |||
391 | /* Did we race? Don't try to optimize this, please, it's not so likely | ||
392 | * to happen, and no more than once at the boot. */ | ||
393 | if(write_sigio_pid != -1) | ||
394 | goto out_unlock; | ||
395 | |||
396 | write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, | ||
383 | CLONE_FILES | CLONE_VM, &stack, 0); | 397 | CLONE_FILES | CLONE_VM, &stack, 0); |
384 | 398 | ||
385 | if(write_sigio_pid < 0) goto out_close2; | 399 | if (write_sigio_pid < 0) |
400 | goto out_clear; | ||
386 | 401 | ||
387 | if(write_sigio_irq(write_sigio_fds[0])) | 402 | if (write_sigio_irq(l_write_sigio_fds[0])) |
388 | goto out_kill; | 403 | goto out_kill; |
389 | 404 | ||
390 | out: | 405 | /* Success, finally. */ |
406 | memcpy(write_sigio_fds, l_write_sigio_fds, sizeof(l_write_sigio_fds)); | ||
407 | memcpy(sigio_private, l_sigio_private, sizeof(l_sigio_private)); | ||
408 | |||
409 | current_poll = ((struct pollfds) { .poll = p, | ||
410 | .used = 1, | ||
411 | .size = 1 }); | ||
412 | |||
391 | sigio_unlock(); | 413 | sigio_unlock(); |
392 | return; | 414 | return; |
393 | 415 | ||
394 | out_kill: | 416 | out_kill: |
395 | os_kill_process(write_sigio_pid, 1); | 417 | l_write_sigio_pid = write_sigio_pid; |
396 | write_sigio_pid = -1; | 418 | write_sigio_pid = -1; |
419 | sigio_unlock(); | ||
420 | /* Going to call waitpid, avoid holding the lock. */ | ||
421 | os_kill_process(l_write_sigio_pid, 1); | ||
422 | goto out_free; | ||
423 | |||
424 | out_clear: | ||
425 | write_sigio_pid = -1; | ||
426 | out_unlock: | ||
427 | sigio_unlock(); | ||
428 | out_free: | ||
429 | kfree(p); | ||
397 | out_close2: | 430 | out_close2: |
398 | os_close_file(sigio_private[0]); | 431 | os_close_file(l_sigio_private[0]); |
399 | os_close_file(sigio_private[1]); | 432 | os_close_file(l_sigio_private[1]); |
400 | out_close1: | 433 | out_close1: |
401 | os_close_file(write_sigio_fds[0]); | 434 | os_close_file(l_write_sigio_fds[0]); |
402 | os_close_file(write_sigio_fds[1]); | 435 | os_close_file(l_write_sigio_fds[1]); |
403 | sigio_unlock(); | 436 | return; |
404 | } | 437 | } |
405 | 438 | ||
406 | int read_sigio_fd(int fd) | 439 | int read_sigio_fd(int fd) |