qemu

Форк
0
/
char-fd.c 
264 строки · 6.9 Кб
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
    fd = RETRY_ON_EINTR(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);
265

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.