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