4 * Copyright (c) 2003-2008 Fabrice Bellard
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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
24 #include "qemu/osdep.h"
27 typedef struct IOWatchPoll
{
33 IOCanReadHandler
*fd_can_read
;
36 GMainContext
*context
;
39 static IOWatchPoll
*io_watch_poll_from_source(GSource
*source
)
41 return container_of(source
, IOWatchPoll
, parent
);
44 static gboolean
io_watch_poll_prepare(GSource
*source
,
47 IOWatchPoll
*iwp
= io_watch_poll_from_source(source
);
48 bool now_active
= iwp
->fd_can_read(iwp
->opaque
) > 0;
49 bool was_active
= iwp
->src
!= NULL
;
50 if (was_active
== now_active
) {
55 iwp
->src
= qio_channel_create_watch(
56 iwp
->ioc
, G_IO_IN
| G_IO_ERR
| G_IO_HUP
| G_IO_NVAL
);
57 g_source_set_callback(iwp
->src
, iwp
->fd_read
, iwp
->opaque
, NULL
);
58 g_source_attach(iwp
->src
, iwp
->context
);
60 g_source_destroy(iwp
->src
);
61 g_source_unref(iwp
->src
);
67 static gboolean
io_watch_poll_check(GSource
*source
)
72 static gboolean
io_watch_poll_dispatch(GSource
*source
, GSourceFunc callback
,
78 static void io_watch_poll_finalize(GSource
*source
)
80 /* Due to a glib bug, removing the last reference to a source
81 * inside a finalize callback causes recursive locking (and a
82 * deadlock). This is not a problem inside other callbacks,
83 * including dispatch callbacks, so we call io_remove_watch_poll
84 * to remove this source. At this point, iwp->src must
85 * be NULL, or we would leak it.
87 * This would be solved much more elegantly by child sources,
88 * but we support older glib versions that do not have them.
90 IOWatchPoll
*iwp
= io_watch_poll_from_source(source
);
91 assert(iwp
->src
== NULL
);
94 static GSourceFuncs io_watch_poll_funcs
= {
95 .prepare
= io_watch_poll_prepare
,
96 .check
= io_watch_poll_check
,
97 .dispatch
= io_watch_poll_dispatch
,
98 .finalize
= io_watch_poll_finalize
,
101 guint
io_add_watch_poll(Chardev
*chr
,
103 IOCanReadHandler
*fd_can_read
,
104 QIOChannelFunc fd_read
,
106 GMainContext
*context
)
112 iwp
= (IOWatchPoll
*) g_source_new(&io_watch_poll_funcs
,
113 sizeof(IOWatchPoll
));
114 iwp
->fd_can_read
= fd_can_read
;
115 iwp
->opaque
= user_data
;
117 iwp
->fd_read
= (GSourceFunc
) fd_read
;
119 iwp
->context
= context
;
121 name
= g_strdup_printf("chardev-iowatch-%s", chr
->label
);
122 g_source_set_name((GSource
*)iwp
, name
);
125 tag
= g_source_attach(&iwp
->parent
, context
);
126 g_source_unref(&iwp
->parent
);
130 static void io_remove_watch_poll(guint tag
, GMainContext
*context
)
135 g_return_if_fail(tag
> 0);
137 source
= g_main_context_find_source_by_id(context
, tag
);
138 g_return_if_fail(source
!= NULL
);
140 iwp
= io_watch_poll_from_source(source
);
142 g_source_destroy(iwp
->src
);
143 g_source_unref(iwp
->src
);
146 g_source_destroy(&iwp
->parent
);
149 void remove_fd_in_watch(Chardev
*chr
, GMainContext
*context
)
151 if (chr
->fd_in_tag
) {
152 io_remove_watch_poll(chr
->fd_in_tag
, context
);
157 int io_channel_send_full(QIOChannel
*ioc
,
158 const void *buf
, size_t len
,
159 int *fds
, size_t nfds
)
163 while (offset
< len
) {
165 struct iovec iov
= { .iov_base
= (char *)buf
+ offset
,
166 .iov_len
= len
- offset
};
168 ret
= qio_channel_writev_full(
171 if (ret
== QIO_CHANNEL_ERR_BLOCK
) {
178 } else if (ret
< 0) {
189 int io_channel_send(QIOChannel
*ioc
, const void *buf
, size_t len
)
191 return io_channel_send_full(ioc
, buf
, len
, NULL
, 0);