/src/pango/subprojects/glib/gio/gpollableutils.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* GIO - GLib Input, Output and Streaming Library |
2 | | * |
3 | | * Copyright (C) 2010 Red Hat, Inc. |
4 | | * |
5 | | * SPDX-License-Identifier: LGPL-2.1-or-later |
6 | | * |
7 | | * This library is free software; you can redistribute it and/or |
8 | | * modify it under the terms of the GNU Lesser General Public |
9 | | * License as published by the Free Software Foundation; either |
10 | | * version 2.1 of the License, or (at your option) any later version. |
11 | | * |
12 | | * This library is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | | * Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General |
18 | | * Public License along with this library; if not, see <http://www.gnu.org/licenses/>. |
19 | | */ |
20 | | |
21 | | #include "config.h" |
22 | | |
23 | | #include <errno.h> |
24 | | |
25 | | #include "gpollableinputstream.h" |
26 | | #include "gasynchelper.h" |
27 | | #include "glibintl.h" |
28 | | |
29 | | typedef struct { |
30 | | GSource source; |
31 | | |
32 | | GObject *stream; |
33 | | } GPollableSource; |
34 | | |
35 | | static gboolean |
36 | | pollable_source_dispatch (GSource *source, |
37 | | GSourceFunc callback, |
38 | | gpointer user_data) |
39 | 0 | { |
40 | 0 | GPollableSourceFunc func = (GPollableSourceFunc)callback; |
41 | 0 | GPollableSource *pollable_source = (GPollableSource *)source; |
42 | |
|
43 | 0 | return (*func) (pollable_source->stream, user_data); |
44 | 0 | } |
45 | | |
46 | | static void |
47 | | pollable_source_finalize (GSource *source) |
48 | 0 | { |
49 | 0 | GPollableSource *pollable_source = (GPollableSource *)source; |
50 | |
|
51 | 0 | g_object_unref (pollable_source->stream); |
52 | 0 | } |
53 | | |
54 | | static gboolean |
55 | | pollable_source_closure_callback (GObject *stream, |
56 | | gpointer data) |
57 | 0 | { |
58 | 0 | GClosure *closure = data; |
59 | |
|
60 | 0 | GValue param = G_VALUE_INIT; |
61 | 0 | GValue result_value = G_VALUE_INIT; |
62 | 0 | gboolean result; |
63 | |
|
64 | 0 | g_value_init (&result_value, G_TYPE_BOOLEAN); |
65 | |
|
66 | 0 | g_value_init (¶m, G_TYPE_OBJECT); |
67 | 0 | g_value_set_object (¶m, stream); |
68 | |
|
69 | 0 | g_closure_invoke (closure, &result_value, 1, ¶m, NULL); |
70 | |
|
71 | 0 | result = g_value_get_boolean (&result_value); |
72 | 0 | g_value_unset (&result_value); |
73 | 0 | g_value_unset (¶m); |
74 | |
|
75 | 0 | return result; |
76 | 0 | } |
77 | | |
78 | | static GSourceFuncs pollable_source_funcs = |
79 | | { |
80 | | NULL, |
81 | | NULL, |
82 | | pollable_source_dispatch, |
83 | | pollable_source_finalize, |
84 | | (GSourceFunc)pollable_source_closure_callback, |
85 | | NULL, |
86 | | }; |
87 | | |
88 | | /** |
89 | | * g_pollable_source_new: |
90 | | * @pollable_stream: the stream associated with the new source |
91 | | * |
92 | | * Utility method for #GPollableInputStream and #GPollableOutputStream |
93 | | * implementations. Creates a new #GSource that expects a callback of |
94 | | * type #GPollableSourceFunc. The new source does not actually do |
95 | | * anything on its own; use g_source_add_child_source() to add other |
96 | | * sources to it to cause it to trigger. |
97 | | * |
98 | | * Returns: (transfer full): the new #GSource. |
99 | | * |
100 | | * Since: 2.28 |
101 | | */ |
102 | | GSource * |
103 | | g_pollable_source_new (GObject *pollable_stream) |
104 | 0 | { |
105 | 0 | GSource *source; |
106 | 0 | GPollableSource *pollable_source; |
107 | |
|
108 | 0 | g_return_val_if_fail (G_IS_POLLABLE_INPUT_STREAM (pollable_stream) || |
109 | 0 | G_IS_POLLABLE_OUTPUT_STREAM (pollable_stream), NULL); |
110 | | |
111 | 0 | source = g_source_new (&pollable_source_funcs, sizeof (GPollableSource)); |
112 | 0 | g_source_set_static_name (source, "GPollableSource"); |
113 | 0 | pollable_source = (GPollableSource *)source; |
114 | 0 | pollable_source->stream = g_object_ref (pollable_stream); |
115 | |
|
116 | 0 | return source; |
117 | 0 | } |
118 | | |
119 | | /** |
120 | | * g_pollable_source_new_full: |
121 | | * @pollable_stream: (type GObject): the stream associated with the |
122 | | * new source |
123 | | * @child_source: (nullable): optional child source to attach |
124 | | * @cancellable: (nullable): optional #GCancellable to attach |
125 | | * |
126 | | * Utility method for #GPollableInputStream and #GPollableOutputStream |
127 | | * implementations. Creates a new #GSource, as with |
128 | | * g_pollable_source_new(), but also attaching @child_source (with a |
129 | | * dummy callback), and @cancellable, if they are non-%NULL. |
130 | | * |
131 | | * Returns: (transfer full): the new #GSource. |
132 | | * |
133 | | * Since: 2.34 |
134 | | */ |
135 | | GSource * |
136 | | g_pollable_source_new_full (gpointer pollable_stream, |
137 | | GSource *child_source, |
138 | | GCancellable *cancellable) |
139 | 0 | { |
140 | 0 | GSource *source; |
141 | |
|
142 | 0 | g_return_val_if_fail (G_IS_POLLABLE_INPUT_STREAM (pollable_stream) || |
143 | 0 | G_IS_POLLABLE_OUTPUT_STREAM (pollable_stream), NULL); |
144 | | |
145 | 0 | source = g_pollable_source_new (pollable_stream); |
146 | 0 | if (child_source) |
147 | 0 | { |
148 | 0 | g_source_set_dummy_callback (child_source); |
149 | 0 | g_source_add_child_source (source, child_source); |
150 | 0 | } |
151 | 0 | if (cancellable) |
152 | 0 | { |
153 | 0 | GSource *cancellable_source = g_cancellable_source_new (cancellable); |
154 | |
|
155 | 0 | g_source_set_dummy_callback (cancellable_source); |
156 | 0 | g_source_add_child_source (source, cancellable_source); |
157 | 0 | g_source_unref (cancellable_source); |
158 | 0 | } |
159 | |
|
160 | 0 | return source; |
161 | 0 | } |
162 | | |
163 | | /** |
164 | | * g_pollable_stream_read: |
165 | | * @stream: a #GInputStream |
166 | | * @buffer: (array length=count) (element-type guint8): a buffer to |
167 | | * read data into |
168 | | * @count: the number of bytes to read |
169 | | * @blocking: whether to do blocking I/O |
170 | | * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore. |
171 | | * @error: location to store the error occurring, or %NULL to ignore |
172 | | * |
173 | | * Tries to read from @stream, as with g_input_stream_read() (if |
174 | | * @blocking is %TRUE) or g_pollable_input_stream_read_nonblocking() |
175 | | * (if @blocking is %FALSE). This can be used to more easily share |
176 | | * code between blocking and non-blocking implementations of a method. |
177 | | * |
178 | | * If @blocking is %FALSE, then @stream must be a |
179 | | * #GPollableInputStream for which g_pollable_input_stream_can_poll() |
180 | | * returns %TRUE, or else the behavior is undefined. If @blocking is |
181 | | * %TRUE, then @stream does not need to be a #GPollableInputStream. |
182 | | * |
183 | | * Returns: the number of bytes read, or -1 on error. |
184 | | * |
185 | | * Since: 2.34 |
186 | | */ |
187 | | gssize |
188 | | g_pollable_stream_read (GInputStream *stream, |
189 | | void *buffer, |
190 | | gsize count, |
191 | | gboolean blocking, |
192 | | GCancellable *cancellable, |
193 | | GError **error) |
194 | 0 | { |
195 | 0 | if (blocking) |
196 | 0 | { |
197 | 0 | return g_input_stream_read (stream, |
198 | 0 | buffer, count, |
199 | 0 | cancellable, error); |
200 | 0 | } |
201 | 0 | else |
202 | 0 | { |
203 | 0 | return g_pollable_input_stream_read_nonblocking (G_POLLABLE_INPUT_STREAM (stream), |
204 | 0 | buffer, count, |
205 | 0 | cancellable, error); |
206 | 0 | } |
207 | 0 | } |
208 | | |
209 | | /** |
210 | | * g_pollable_stream_write: |
211 | | * @stream: a #GOutputStream. |
212 | | * @buffer: (array length=count) (element-type guint8): the buffer |
213 | | * containing the data to write. |
214 | | * @count: the number of bytes to write |
215 | | * @blocking: whether to do blocking I/O |
216 | | * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore. |
217 | | * @error: location to store the error occurring, or %NULL to ignore |
218 | | * |
219 | | * Tries to write to @stream, as with g_output_stream_write() (if |
220 | | * @blocking is %TRUE) or g_pollable_output_stream_write_nonblocking() |
221 | | * (if @blocking is %FALSE). This can be used to more easily share |
222 | | * code between blocking and non-blocking implementations of a method. |
223 | | * |
224 | | * If @blocking is %FALSE, then @stream must be a |
225 | | * #GPollableOutputStream for which |
226 | | * g_pollable_output_stream_can_poll() returns %TRUE or else the |
227 | | * behavior is undefined. If @blocking is %TRUE, then @stream does not |
228 | | * need to be a #GPollableOutputStream. |
229 | | * |
230 | | * Returns: the number of bytes written, or -1 on error. |
231 | | * |
232 | | * Since: 2.34 |
233 | | */ |
234 | | gssize |
235 | | g_pollable_stream_write (GOutputStream *stream, |
236 | | const void *buffer, |
237 | | gsize count, |
238 | | gboolean blocking, |
239 | | GCancellable *cancellable, |
240 | | GError **error) |
241 | 0 | { |
242 | 0 | if (blocking) |
243 | 0 | { |
244 | 0 | return g_output_stream_write (stream, |
245 | 0 | buffer, count, |
246 | 0 | cancellable, error); |
247 | 0 | } |
248 | 0 | else |
249 | 0 | { |
250 | 0 | return g_pollable_output_stream_write_nonblocking (G_POLLABLE_OUTPUT_STREAM (stream), |
251 | 0 | buffer, count, |
252 | 0 | cancellable, error); |
253 | 0 | } |
254 | 0 | } |
255 | | |
256 | | /** |
257 | | * g_pollable_stream_write_all: |
258 | | * @stream: a #GOutputStream. |
259 | | * @buffer: (array length=count) (element-type guint8): the buffer |
260 | | * containing the data to write. |
261 | | * @count: the number of bytes to write |
262 | | * @blocking: whether to do blocking I/O |
263 | | * @bytes_written: (out): location to store the number of bytes that was |
264 | | * written to the stream |
265 | | * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore. |
266 | | * @error: location to store the error occurring, or %NULL to ignore |
267 | | * |
268 | | * Tries to write @count bytes to @stream, as with |
269 | | * g_output_stream_write_all(), but using g_pollable_stream_write() |
270 | | * rather than g_output_stream_write(). |
271 | | * |
272 | | * On a successful write of @count bytes, %TRUE is returned, and |
273 | | * @bytes_written is set to @count. |
274 | | * |
275 | | * If there is an error during the operation (including |
276 | | * %G_IO_ERROR_WOULD_BLOCK in the non-blocking case), %FALSE is |
277 | | * returned and @error is set to indicate the error status, |
278 | | * @bytes_written is updated to contain the number of bytes written |
279 | | * into the stream before the error occurred. |
280 | | * |
281 | | * As with g_pollable_stream_write(), if @blocking is %FALSE, then |
282 | | * @stream must be a #GPollableOutputStream for which |
283 | | * g_pollable_output_stream_can_poll() returns %TRUE or else the |
284 | | * behavior is undefined. If @blocking is %TRUE, then @stream does not |
285 | | * need to be a #GPollableOutputStream. |
286 | | * |
287 | | * Returns: %TRUE on success, %FALSE if there was an error |
288 | | * |
289 | | * Since: 2.34 |
290 | | */ |
291 | | gboolean |
292 | | g_pollable_stream_write_all (GOutputStream *stream, |
293 | | const void *buffer, |
294 | | gsize count, |
295 | | gboolean blocking, |
296 | | gsize *bytes_written, |
297 | | GCancellable *cancellable, |
298 | | GError **error) |
299 | 0 | { |
300 | 0 | gsize _bytes_written; |
301 | 0 | gssize res; |
302 | |
|
303 | 0 | _bytes_written = 0; |
304 | 0 | while (_bytes_written < count) |
305 | 0 | { |
306 | 0 | res = g_pollable_stream_write (stream, |
307 | 0 | (char *)buffer + _bytes_written, |
308 | 0 | count - _bytes_written, |
309 | 0 | blocking, |
310 | 0 | cancellable, error); |
311 | 0 | if (res == -1) |
312 | 0 | { |
313 | 0 | if (bytes_written) |
314 | 0 | *bytes_written = _bytes_written; |
315 | 0 | return FALSE; |
316 | 0 | } |
317 | | |
318 | 0 | if (res == 0) |
319 | 0 | g_warning ("Write returned zero without error"); |
320 | |
|
321 | 0 | _bytes_written += res; |
322 | 0 | } |
323 | | |
324 | 0 | if (bytes_written) |
325 | 0 | *bytes_written = _bytes_written; |
326 | |
|
327 | 0 | return TRUE; |
328 | 0 | } |