Coverage Report

Created: 2025-07-23 08:13

/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 (&param, G_TYPE_OBJECT);
67
0
  g_value_set_object (&param, stream);
68
69
0
  g_closure_invoke (closure, &result_value, 1, &param, NULL);
70
71
0
  result = g_value_get_boolean (&result_value);
72
0
  g_value_unset (&result_value);
73
0
  g_value_unset (&param);
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
}