]> code.delx.au - pulseaudio/blob - src/iochannel.c
f0c4c4998b7fb1420bfd183b869cf90b9554da67
[pulseaudio] / src / iochannel.c
1 #include <assert.h>
2 #include <fcntl.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5
6 #include "iochannel.h"
7
8 struct iochannel {
9 int ifd, ofd;
10 struct mainloop* mainloop;
11
12 void (*callback)(struct iochannel*io, void *userdata);
13 void*userdata;
14
15 int readable;
16 int writable;
17
18 int no_close;
19
20 struct mainloop_source* input_source, *output_source;
21 };
22
23 static void enable_mainloop_sources(struct iochannel *io) {
24 assert(io);
25
26 if (io->input_source == io->output_source) {
27 enum mainloop_io_event e = MAINLOOP_IO_EVENT_NULL;
28 assert(io->input_source);
29
30 if (!io->readable)
31 e |= MAINLOOP_IO_EVENT_IN;
32 if (!io->writable)
33 e |= MAINLOOP_IO_EVENT_OUT;
34
35 mainloop_source_io_set_events(io->input_source, e);
36 } else {
37 if (io->input_source)
38 mainloop_source_io_set_events(io->input_source, io->readable ? MAINLOOP_IO_EVENT_NULL : MAINLOOP_IO_EVENT_IN);
39 if (io->output_source)
40 mainloop_source_io_set_events(io->output_source, io->writable ? MAINLOOP_IO_EVENT_NULL : MAINLOOP_IO_EVENT_OUT);
41 }
42 }
43
44 static void callback(struct mainloop_source*s, int fd, enum mainloop_io_event events, void *userdata) {
45 struct iochannel *io = userdata;
46 int changed = 0;
47 assert(s && fd >= 0 && userdata);
48
49 if ((events & MAINLOOP_IO_EVENT_IN) && !io->readable) {
50 io->readable = 1;
51 changed = 1;
52 }
53
54 if ((events & MAINLOOP_IO_EVENT_OUT) && !io->writable) {
55 io->writable = 1;
56 changed = 1;
57 }
58
59 if (changed) {
60 enable_mainloop_sources(io);
61
62 if (io->callback)
63 io->callback(io, io->userdata);
64 }
65 }
66
67 static void make_nonblock_fd(int fd) {
68 int v;
69
70 if ((v = fcntl(fd, F_GETFL)) >= 0)
71 if (!(v & O_NONBLOCK))
72 fcntl(fd, F_SETFL, v|O_NONBLOCK);
73 }
74
75 struct iochannel* iochannel_new(struct mainloop*m, int ifd, int ofd) {
76 struct iochannel *io;
77 assert(m && (ifd >= 0 || ofd >= 0));
78
79 io = malloc(sizeof(struct iochannel));
80 io->ifd = ifd;
81 io->ofd = ofd;
82 io->mainloop = m;
83
84 io->userdata = NULL;
85 io->callback = NULL;
86 io->readable = 0;
87 io->writable = 0;
88 io->no_close = 0;
89
90 if (ifd == ofd) {
91 assert(ifd >= 0);
92 make_nonblock_fd(io->ifd);
93 io->input_source = io->output_source = mainloop_source_new_io(m, ifd, MAINLOOP_IO_EVENT_IN|MAINLOOP_IO_EVENT_OUT, callback, io);
94 } else {
95
96 if (ifd >= 0) {
97 make_nonblock_fd(io->ifd);
98 io->input_source = mainloop_source_new_io(m, ifd, MAINLOOP_IO_EVENT_IN, callback, io);
99 } else
100 io->input_source = NULL;
101
102 if (ofd >= 0) {
103 make_nonblock_fd(io->ofd);
104 io->output_source = mainloop_source_new_io(m, ofd, MAINLOOP_IO_EVENT_OUT, callback, io);
105 } else
106 io->output_source = NULL;
107 }
108
109 return io;
110 }
111
112 void iochannel_free(struct iochannel*io) {
113 assert(io);
114
115 if (!io->no_close) {
116 if (io->ifd >= 0)
117 close(io->ifd);
118 if (io->ofd >= 0 && io->ofd != io->ifd)
119 close(io->ofd);
120 }
121
122 if (io->input_source)
123 mainloop_source_free(io->input_source);
124 if (io->output_source && io->output_source != io->input_source)
125 mainloop_source_free(io->output_source);
126
127 free(io);
128 }
129
130 int iochannel_is_readable(struct iochannel*io) {
131 assert(io);
132 return io->readable;
133 }
134
135 int iochannel_is_writable(struct iochannel*io) {
136 assert(io);
137 return io->writable;
138 }
139
140 ssize_t iochannel_write(struct iochannel*io, const void*data, size_t l) {
141 ssize_t r;
142 assert(io && data && l && io->ofd >= 0);
143
144 if ((r = write(io->ofd, data, l)) >= 0) {
145 io->writable = 0;
146 enable_mainloop_sources(io);
147 }
148
149 return r;
150 }
151
152 ssize_t iochannel_read(struct iochannel*io, void*data, size_t l) {
153 ssize_t r;
154
155 assert(io && data && l && io->ifd >= 0);
156
157 if ((r = read(io->ifd, data, l)) >= 0) {
158 io->readable = 0;
159 enable_mainloop_sources(io);
160 }
161
162 return r;
163 }
164
165 void iochannel_set_callback(struct iochannel*io, void (*callback)(struct iochannel*io, void *userdata), void *userdata) {
166 assert(io);
167 io->callback = callback;
168 io->userdata = userdata;
169 }
170
171 void iochannel_set_noclose(struct iochannel*io, int b) {
172 assert(io);
173 io->no_close = b;
174 }