Home | History | Annotate | Download | only in qemu
      1 /*
      2  * QEMU System Emulator - managing I/O handler
      3  *
      4  * Copyright (c) 2003-2008 Fabrice Bellard
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a copy
      7  * of this software and associated documentation files (the "Software"), to deal
      8  * in the Software without restriction, including without limitation the rights
      9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10  * copies of the Software, and to permit persons to whom the Software is
     11  * furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     22  * THE SOFTWARE.
     23  */
     24 
     25 #include "config-host.h"
     26 #include "qemu-common.h"
     27 #include "qemu-char.h"
     28 #include "qemu-queue.h"
     29 
     30 #ifndef _WIN32
     31 #include <sys/wait.h>
     32 #endif
     33 
     34 typedef struct IOHandlerRecord {
     35     int fd;
     36     IOCanReadHandler *fd_read_poll;
     37     IOHandler *fd_read;
     38     IOHandler *fd_write;
     39     int deleted;
     40     void *opaque;
     41     QLIST_ENTRY(IOHandlerRecord) next;
     42 } IOHandlerRecord;
     43 
     44 static QLIST_HEAD(, IOHandlerRecord) io_handlers =
     45     QLIST_HEAD_INITIALIZER(io_handlers);
     46 
     47 
     48 /* XXX: fd_read_poll should be suppressed, but an API change is
     49    necessary in the character devices to suppress fd_can_read(). */
     50 int qemu_set_fd_handler2(int fd,
     51                          IOCanReadHandler *fd_read_poll,
     52                          IOHandler *fd_read,
     53                          IOHandler *fd_write,
     54                          void *opaque)
     55 {
     56     IOHandlerRecord *ioh;
     57 
     58     if (!fd_read && !fd_write) {
     59         QLIST_FOREACH(ioh, &io_handlers, next) {
     60             if (ioh->fd == fd) {
     61                 ioh->deleted = 1;
     62                 break;
     63             }
     64         }
     65     } else {
     66         QLIST_FOREACH(ioh, &io_handlers, next) {
     67             if (ioh->fd == fd)
     68                 goto found;
     69         }
     70         ioh = qemu_mallocz(sizeof(IOHandlerRecord));
     71         QLIST_INSERT_HEAD(&io_handlers, ioh, next);
     72     found:
     73         ioh->fd = fd;
     74         ioh->fd_read_poll = fd_read_poll;
     75         ioh->fd_read = fd_read;
     76         ioh->fd_write = fd_write;
     77         ioh->opaque = opaque;
     78         ioh->deleted = 0;
     79     }
     80     return 0;
     81 }
     82 
     83 int qemu_set_fd_handler(int fd,
     84                         IOHandler *fd_read,
     85                         IOHandler *fd_write,
     86                         void *opaque)
     87 {
     88     return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque);
     89 }
     90 
     91 void qemu_iohandler_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds)
     92 {
     93     IOHandlerRecord *ioh;
     94 
     95     QLIST_FOREACH(ioh, &io_handlers, next) {
     96         if (ioh->deleted)
     97             continue;
     98         if (ioh->fd_read &&
     99             (!ioh->fd_read_poll ||
    100              ioh->fd_read_poll(ioh->opaque) != 0)) {
    101             FD_SET(ioh->fd, readfds);
    102             if (ioh->fd > *pnfds)
    103                 *pnfds = ioh->fd;
    104         }
    105         if (ioh->fd_write) {
    106             FD_SET(ioh->fd, writefds);
    107             if (ioh->fd > *pnfds)
    108                 *pnfds = ioh->fd;
    109         }
    110     }
    111 }
    112 
    113 void qemu_iohandler_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, int ret)
    114 {
    115     if (ret > 0) {
    116         IOHandlerRecord *pioh, *ioh;
    117 
    118         QLIST_FOREACH_SAFE(ioh, &io_handlers, next, pioh) {
    119             if (!ioh->deleted && ioh->fd_read && FD_ISSET(ioh->fd, readfds)) {
    120                 ioh->fd_read(ioh->opaque);
    121             }
    122             if (!ioh->deleted && ioh->fd_write && FD_ISSET(ioh->fd, writefds)) {
    123                 ioh->fd_write(ioh->opaque);
    124             }
    125 
    126             /* Do this last in case read/write handlers marked it for deletion */
    127             if (ioh->deleted) {
    128                 QLIST_REMOVE(ioh, next);
    129                 qemu_free(ioh);
    130             }
    131         }
    132     }
    133 }
    134 
    135 /* reaping of zombies.  right now we're not passing the status to
    136    anyone, but it would be possible to add a callback.  */
    137 #ifndef _WIN32
    138 typedef struct ChildProcessRecord {
    139     int pid;
    140     QLIST_ENTRY(ChildProcessRecord) next;
    141 } ChildProcessRecord;
    142 
    143 static QLIST_HEAD(, ChildProcessRecord) child_watches =
    144     QLIST_HEAD_INITIALIZER(child_watches);
    145 
    146 static QEMUBH *sigchld_bh;
    147 
    148 static void sigchld_handler(int signal)
    149 {
    150     qemu_bh_schedule(sigchld_bh);
    151 }
    152 
    153 static void sigchld_bh_handler(void *opaque)
    154 {
    155     ChildProcessRecord *rec, *next;
    156 
    157     QLIST_FOREACH_SAFE(rec, &child_watches, next, next) {
    158         if (waitpid(rec->pid, NULL, WNOHANG) == rec->pid) {
    159             QLIST_REMOVE(rec, next);
    160             qemu_free(rec);
    161         }
    162     }
    163 }
    164 
    165 static void qemu_init_child_watch(void)
    166 {
    167     struct sigaction act;
    168     sigchld_bh = qemu_bh_new(sigchld_bh_handler, NULL);
    169 
    170     act.sa_handler = sigchld_handler;
    171     act.sa_flags = SA_NOCLDSTOP;
    172     sigaction(SIGCHLD, &act, NULL);
    173 }
    174 
    175 int qemu_add_child_watch(pid_t pid)
    176 {
    177     ChildProcessRecord *rec;
    178 
    179     if (!sigchld_bh) {
    180         qemu_init_child_watch();
    181     }
    182 
    183     QLIST_FOREACH(rec, &child_watches, next) {
    184         if (rec->pid == pid) {
    185             return 1;
    186         }
    187     }
    188     rec = qemu_mallocz(sizeof(ChildProcessRecord));
    189     rec->pid = pid;
    190     QLIST_INSERT_HEAD(&child_watches, rec, next);
    191     return 0;
    192 }
    193 #endif
    194