qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

char-fd.c (7016B)


      1 /*
      2  * QEMU System Emulator
      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 "qemu/osdep.h"
     26 #include "qemu/module.h"
     27 #include "qemu/sockets.h"
     28 #include "qapi/error.h"
     29 #include "chardev/char.h"
     30 #include "chardev/char-fe.h"
     31 #include "io/channel-file.h"
     32 
     33 #include "chardev/char-fd.h"
     34 #include "chardev/char-io.h"
     35 
     36 /* Called with chr_write_lock held.  */
     37 static int fd_chr_write(Chardev *chr, const uint8_t *buf, int len)
     38 {
     39     FDChardev *s = FD_CHARDEV(chr);
     40 
     41     if (!s->ioc_out) {
     42         return -1;
     43     }
     44 
     45     return io_channel_send(s->ioc_out, buf, len);
     46 }
     47 
     48 static gboolean fd_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
     49 {
     50     Chardev *chr = CHARDEV(opaque);
     51     FDChardev *s = FD_CHARDEV(opaque);
     52     int len;
     53     uint8_t buf[CHR_READ_BUF_LEN];
     54     ssize_t ret;
     55 
     56     len = sizeof(buf);
     57     if (len > s->max_size) {
     58         len = s->max_size;
     59     }
     60     if (len == 0) {
     61         return TRUE;
     62     }
     63 
     64     ret = qio_channel_read(
     65         chan, (gchar *)buf, len, NULL);
     66     if (ret == 0) {
     67         remove_fd_in_watch(chr);
     68         qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
     69         return FALSE;
     70     }
     71     if (ret > 0) {
     72         qemu_chr_be_write(chr, buf, ret);
     73     }
     74 
     75     return TRUE;
     76 }
     77 
     78 static int fd_chr_read_poll(void *opaque)
     79 {
     80     Chardev *chr = CHARDEV(opaque);
     81     FDChardev *s = FD_CHARDEV(opaque);
     82 
     83     s->max_size = qemu_chr_be_can_write(chr);
     84     return s->max_size;
     85 }
     86 
     87 typedef struct FDSource {
     88     GSource parent;
     89 
     90     GIOCondition cond;
     91 } FDSource;
     92 
     93 static gboolean
     94 fd_source_prepare(GSource *source,
     95                   gint *timeout_)
     96 {
     97     FDSource *src = (FDSource *)source;
     98 
     99     return src->cond != 0;
    100 }
    101 
    102 static gboolean
    103 fd_source_check(GSource *source)
    104 {
    105     FDSource *src = (FDSource *)source;
    106 
    107     return src->cond != 0;
    108 }
    109 
    110 static gboolean
    111 fd_source_dispatch(GSource *source, GSourceFunc callback,
    112                    gpointer user_data)
    113 {
    114     FDSource *src = (FDSource *)source;
    115     FEWatchFunc func = (FEWatchFunc)callback;
    116     gboolean ret = G_SOURCE_CONTINUE;
    117 
    118     if (src->cond) {
    119         ret = func(NULL, src->cond, user_data);
    120         src->cond = 0;
    121     }
    122 
    123     return ret;
    124 }
    125 
    126 static GSourceFuncs fd_source_funcs = {
    127   fd_source_prepare,
    128   fd_source_check,
    129   fd_source_dispatch,
    130   NULL, NULL, NULL
    131 };
    132 
    133 static GSource *fd_source_new(FDChardev *chr)
    134 {
    135     return g_source_new(&fd_source_funcs, sizeof(FDSource));
    136 }
    137 
    138 static gboolean child_func(GIOChannel *source,
    139                            GIOCondition condition,
    140                            gpointer data)
    141 {
    142     FDSource *parent = data;
    143 
    144     parent->cond |= condition;
    145 
    146     return G_SOURCE_CONTINUE;
    147 }
    148 
    149 static GSource *fd_chr_add_watch(Chardev *chr, GIOCondition cond)
    150 {
    151     FDChardev *s = FD_CHARDEV(chr);
    152     g_autoptr(GSource) source = fd_source_new(s);
    153 
    154     if (s->ioc_out) {
    155         g_autoptr(GSource) child = qio_channel_create_watch(s->ioc_out, cond & ~G_IO_IN);
    156         g_source_set_callback(child, (GSourceFunc)child_func, source, NULL);
    157         g_source_add_child_source(source, child);
    158     }
    159     if (s->ioc_in) {
    160         g_autoptr(GSource) child = qio_channel_create_watch(s->ioc_in, cond & ~G_IO_OUT);
    161         g_source_set_callback(child, (GSourceFunc)child_func, source, NULL);
    162         g_source_add_child_source(source, child);
    163     }
    164 
    165     return g_steal_pointer(&source);
    166 }
    167 
    168 static void fd_chr_update_read_handler(Chardev *chr)
    169 {
    170     FDChardev *s = FD_CHARDEV(chr);
    171 
    172     remove_fd_in_watch(chr);
    173     if (s->ioc_in) {
    174         chr->gsource = io_add_watch_poll(chr, s->ioc_in,
    175                                            fd_chr_read_poll,
    176                                            fd_chr_read, chr,
    177                                            chr->gcontext);
    178     }
    179 }
    180 
    181 static void char_fd_finalize(Object *obj)
    182 {
    183     Chardev *chr = CHARDEV(obj);
    184     FDChardev *s = FD_CHARDEV(obj);
    185 
    186     remove_fd_in_watch(chr);
    187     if (s->ioc_in) {
    188         object_unref(OBJECT(s->ioc_in));
    189     }
    190     if (s->ioc_out) {
    191         object_unref(OBJECT(s->ioc_out));
    192     }
    193 
    194     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
    195 }
    196 
    197 int qmp_chardev_open_file_source(char *src, int flags, Error **errp)
    198 {
    199     int fd = -1;
    200 
    201     TFR(fd = qemu_open_old(src, flags, 0666));
    202     if (fd == -1) {
    203         error_setg_file_open(errp, errno, src);
    204     }
    205     return fd;
    206 }
    207 
    208 /* open a character device to a unix fd */
    209 void qemu_chr_open_fd(Chardev *chr,
    210                       int fd_in, int fd_out)
    211 {
    212     FDChardev *s = FD_CHARDEV(chr);
    213     g_autofree char *name = NULL;
    214 
    215     if (fd_out >= 0 && !g_unix_set_fd_nonblocking(fd_out, true, NULL)) {
    216         assert(!"Failed to set FD nonblocking");
    217     }
    218 
    219     if (fd_out == fd_in && fd_in >= 0) {
    220         s->ioc_in = QIO_CHANNEL(qio_channel_file_new_fd(fd_in));
    221         name = g_strdup_printf("chardev-file-%s", chr->label);
    222         qio_channel_set_name(QIO_CHANNEL(s->ioc_in), name);
    223         s->ioc_out = QIO_CHANNEL(object_ref(s->ioc_in));
    224         return;
    225     }
    226 
    227     if (fd_in >= 0) {
    228         s->ioc_in = QIO_CHANNEL(qio_channel_file_new_fd(fd_in));
    229         name = g_strdup_printf("chardev-file-in-%s", chr->label);
    230         qio_channel_set_name(QIO_CHANNEL(s->ioc_in), name);
    231     }
    232 
    233     if (fd_out >= 0) {
    234         s->ioc_out = QIO_CHANNEL(qio_channel_file_new_fd(fd_out));
    235         g_free(name);
    236         name = g_strdup_printf("chardev-file-out-%s", chr->label);
    237         qio_channel_set_name(QIO_CHANNEL(s->ioc_out), name);
    238     }
    239 }
    240 
    241 static void char_fd_class_init(ObjectClass *oc, void *data)
    242 {
    243     ChardevClass *cc = CHARDEV_CLASS(oc);
    244 
    245     cc->chr_add_watch = fd_chr_add_watch;
    246     cc->chr_write = fd_chr_write;
    247     cc->chr_update_read_handler = fd_chr_update_read_handler;
    248 }
    249 
    250 static const TypeInfo char_fd_type_info = {
    251     .name = TYPE_CHARDEV_FD,
    252     .parent = TYPE_CHARDEV,
    253     .instance_size = sizeof(FDChardev),
    254     .instance_finalize = char_fd_finalize,
    255     .class_init = char_fd_class_init,
    256     .abstract = true,
    257 };
    258 
    259 static void register_types(void)
    260 {
    261     type_register_static(&char_fd_type_info);
    262 }
    263 
    264 type_init(register_types);