gio: use GPollable* to implement fallback read_async/write_async
[platform/upstream/glib.git] / gio / gunixoutputstream.c
1 /* GIO - GLib Input, Output and Streaming Library
2  * 
3  * Copyright (C) 2006-2007 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: Alexander Larsson <alexl@redhat.com>
21  */
22
23 #include "config.h"
24
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #include <errno.h>
29 #include <stdio.h>
30 #include <fcntl.h>
31
32 #include <glib.h>
33 #include <glib/gstdio.h>
34 #include "gioerror.h"
35 #include "gunixoutputstream.h"
36 #include "gcancellable.h"
37 #include "gsimpleasyncresult.h"
38 #include "gasynchelper.h"
39 #include "gfiledescriptorbased.h"
40 #include "glibintl.h"
41
42
43 /**
44  * SECTION:gunixoutputstream
45  * @short_description: Streaming output operations for UNIX file descriptors
46  * @include: gio/gunixoutputstream.h
47  * @see_also: #GOutputStream
48  *
49  * #GUnixOutputStream implements #GOutputStream for writing to a UNIX
50  * file descriptor, including asynchronous operations. (If the file
51  * descriptor refers to a socket or pipe, this will use poll() to do
52  * asynchronous I/O. If it refers to a regular file, it will fall back
53  * to doing asynchronous I/O in another thread.)
54  *
55  * Note that <filename>&lt;gio/gunixoutputstream.h&gt;</filename> belongs
56  * to the UNIX-specific GIO interfaces, thus you have to use the
57  * <filename>gio-unix-2.0.pc</filename> pkg-config file when using it.
58  */
59
60 enum {
61   PROP_0,
62   PROP_FD,
63   PROP_CLOSE_FD
64 };
65
66 static void g_unix_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface);
67 static void g_unix_output_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface);
68
69 G_DEFINE_TYPE_WITH_CODE (GUnixOutputStream, g_unix_output_stream, G_TYPE_OUTPUT_STREAM,
70                          G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_OUTPUT_STREAM,
71                                                 g_unix_output_stream_pollable_iface_init)
72                          G_IMPLEMENT_INTERFACE (G_TYPE_FILE_DESCRIPTOR_BASED,
73                                                 g_unix_output_stream_file_descriptor_based_iface_init)
74                          )
75
76 struct _GUnixOutputStreamPrivate {
77   int fd;
78   guint close_fd : 1;
79   guint is_pipe_or_socket : 1;
80 };
81
82 static void     g_unix_output_stream_set_property (GObject              *object,
83                                                    guint                 prop_id,
84                                                    const GValue         *value,
85                                                    GParamSpec           *pspec);
86 static void     g_unix_output_stream_get_property (GObject              *object,
87                                                    guint                 prop_id,
88                                                    GValue               *value,
89                                                    GParamSpec           *pspec);
90 static gssize   g_unix_output_stream_write        (GOutputStream        *stream,
91                                                    const void           *buffer,
92                                                    gsize                 count,
93                                                    GCancellable         *cancellable,
94                                                    GError              **error);
95 static gboolean g_unix_output_stream_close        (GOutputStream        *stream,
96                                                    GCancellable         *cancellable,
97                                                    GError              **error);
98 static void     g_unix_output_stream_close_async  (GOutputStream        *stream,
99                                                    int                   io_priority,
100                                                    GCancellable         *cancellable,
101                                                    GAsyncReadyCallback   callback,
102                                                    gpointer              data);
103 static gboolean g_unix_output_stream_close_finish (GOutputStream        *stream,
104                                                    GAsyncResult         *result,
105                                                    GError              **error);
106
107 static gboolean g_unix_output_stream_pollable_is_writable   (GPollableOutputStream *stream);
108 static GSource *g_unix_output_stream_pollable_create_source (GPollableOutputStream *stream,
109                                                              GCancellable         *cancellable);
110
111 static void
112 g_unix_output_stream_finalize (GObject *object)
113 {
114   G_OBJECT_CLASS (g_unix_output_stream_parent_class)->finalize (object);
115 }
116
117 static void
118 g_unix_output_stream_class_init (GUnixOutputStreamClass *klass)
119 {
120   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
121   GOutputStreamClass *stream_class = G_OUTPUT_STREAM_CLASS (klass);
122   
123   g_type_class_add_private (klass, sizeof (GUnixOutputStreamPrivate));
124
125   gobject_class->get_property = g_unix_output_stream_get_property;
126   gobject_class->set_property = g_unix_output_stream_set_property;
127   gobject_class->finalize = g_unix_output_stream_finalize;
128
129   stream_class->write_fn = g_unix_output_stream_write;
130   stream_class->close_fn = g_unix_output_stream_close;
131   stream_class->close_async = g_unix_output_stream_close_async;
132   stream_class->close_finish = g_unix_output_stream_close_finish;
133
134    /**
135    * GUnixOutputStream:fd:
136    *
137    * The file descriptor that the stream writes to.
138    *
139    * Since: 2.20
140    */
141   g_object_class_install_property (gobject_class,
142                                    PROP_FD,
143                                    g_param_spec_int ("fd",
144                                                      P_("File descriptor"),
145                                                      P_("The file descriptor to write to"),
146                                                      G_MININT, G_MAXINT, -1,
147                                                      G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
148
149   /**
150    * GUnixOutputStream:close-fd:
151    *
152    * Whether to close the file descriptor when the stream is closed.
153    *
154    * Since: 2.20
155    */
156   g_object_class_install_property (gobject_class,
157                                    PROP_CLOSE_FD,
158                                    g_param_spec_boolean ("close-fd",
159                                                          P_("Close file descriptor"),
160                                                          P_("Whether to close the file descriptor when the stream is closed"),
161                                                          TRUE,
162                                                          G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
163 }
164
165 static void
166 g_unix_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface)
167 {
168   iface->is_writable = g_unix_output_stream_pollable_is_writable;
169   iface->create_source = g_unix_output_stream_pollable_create_source;
170 }
171
172 static void
173 g_unix_output_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface)
174 {
175   iface->get_fd = (int (*) (GFileDescriptorBased *))g_unix_output_stream_get_fd;
176 }
177
178 static void
179 g_unix_output_stream_set_property (GObject         *object,
180                                    guint            prop_id,
181                                    const GValue    *value,
182                                    GParamSpec      *pspec)
183 {
184   GUnixOutputStream *unix_stream;
185
186   unix_stream = G_UNIX_OUTPUT_STREAM (object);
187
188   switch (prop_id)
189     {
190     case PROP_FD:
191       unix_stream->priv->fd = g_value_get_int (value);
192       if (lseek (unix_stream->priv->fd, 0, SEEK_CUR) == -1 && errno == ESPIPE)
193         unix_stream->priv->is_pipe_or_socket = TRUE;
194       else
195         unix_stream->priv->is_pipe_or_socket = FALSE;
196       break;
197     case PROP_CLOSE_FD:
198       unix_stream->priv->close_fd = g_value_get_boolean (value);
199       break;
200     default:
201       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
202       break;
203     }
204 }
205
206 static void
207 g_unix_output_stream_get_property (GObject    *object,
208                                    guint       prop_id,
209                                    GValue     *value,
210                                    GParamSpec *pspec)
211 {
212   GUnixOutputStream *unix_stream;
213
214   unix_stream = G_UNIX_OUTPUT_STREAM (object);
215
216   switch (prop_id)
217     {
218     case PROP_FD:
219       g_value_set_int (value, unix_stream->priv->fd);
220       break;
221     case PROP_CLOSE_FD:
222       g_value_set_boolean (value, unix_stream->priv->close_fd);
223       break;
224     default:
225       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
226     }
227 }
228
229 static void
230 g_unix_output_stream_init (GUnixOutputStream *unix_stream)
231 {
232   unix_stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (unix_stream,
233                                                    G_TYPE_UNIX_OUTPUT_STREAM,
234                                                    GUnixOutputStreamPrivate);
235
236   unix_stream->priv->fd = -1;
237   unix_stream->priv->close_fd = TRUE;
238 }
239
240 /**
241  * g_unix_output_stream_new:
242  * @fd: a UNIX file descriptor
243  * @close_fd: %TRUE to close the file descriptor when done
244  * 
245  * Creates a new #GUnixOutputStream for the given @fd. 
246  * 
247  * If @close_fd, is %TRUE, the file descriptor will be closed when 
248  * the output stream is destroyed.
249  * 
250  * Returns: a new #GOutputStream
251  **/
252 GOutputStream *
253 g_unix_output_stream_new (gint     fd,
254                           gboolean close_fd)
255 {
256   GUnixOutputStream *stream;
257
258   g_return_val_if_fail (fd != -1, NULL);
259
260   stream = g_object_new (G_TYPE_UNIX_OUTPUT_STREAM,
261                          "fd", fd,
262                          "close-fd", close_fd,
263                          NULL);
264   
265   return G_OUTPUT_STREAM (stream);
266 }
267
268 /**
269  * g_unix_output_stream_set_close_fd:
270  * @stream: a #GUnixOutputStream
271  * @close_fd: %TRUE to close the file descriptor when done
272  *
273  * Sets whether the file descriptor of @stream shall be closed
274  * when the stream is closed.
275  *
276  * Since: 2.20
277  */
278 void
279 g_unix_output_stream_set_close_fd (GUnixOutputStream *stream,
280                                    gboolean           close_fd)
281 {
282   g_return_if_fail (G_IS_UNIX_OUTPUT_STREAM (stream));
283
284   close_fd = close_fd != FALSE;
285   if (stream->priv->close_fd != close_fd)
286     {
287       stream->priv->close_fd = close_fd;
288       g_object_notify (G_OBJECT (stream), "close-fd");
289     }
290 }
291
292 /**
293  * g_unix_output_stream_get_close_fd:
294  * @stream: a #GUnixOutputStream
295  *
296  * Returns whether the file descriptor of @stream will be
297  * closed when the stream is closed.
298  *
299  * Return value: %TRUE if the file descriptor is closed when done
300  *
301  * Since: 2.20
302  */
303 gboolean
304 g_unix_output_stream_get_close_fd (GUnixOutputStream *stream)
305 {
306   g_return_val_if_fail (G_IS_UNIX_OUTPUT_STREAM (stream), FALSE);
307
308   return stream->priv->close_fd;
309 }
310
311 /**
312  * g_unix_output_stream_get_fd:
313  * @stream: a #GUnixOutputStream
314  *
315  * Return the UNIX file descriptor that the stream writes to.
316  *
317  * Return value: The file descriptor of @stream
318  *
319  * Since: 2.20
320  */
321 gint
322 g_unix_output_stream_get_fd (GUnixOutputStream *stream)
323 {
324   g_return_val_if_fail (G_IS_UNIX_OUTPUT_STREAM (stream), -1);
325
326   return stream->priv->fd;
327 }
328
329 static gssize
330 g_unix_output_stream_write (GOutputStream  *stream,
331                             const void     *buffer,
332                             gsize           count,
333                             GCancellable   *cancellable,
334                             GError        **error)
335 {
336   GUnixOutputStream *unix_stream;
337   gssize res = -1;
338   GPollFD poll_fds[2];
339   int nfds;
340   int poll_ret;
341
342   unix_stream = G_UNIX_OUTPUT_STREAM (stream);
343
344   poll_fds[0].fd = unix_stream->priv->fd;
345   poll_fds[0].events = G_IO_OUT;
346
347   if (unix_stream->priv->is_pipe_or_socket &&
348       g_cancellable_make_pollfd (cancellable, &poll_fds[1]))
349     nfds = 2;
350   else
351     nfds = 1;
352
353   while (1)
354     {
355       poll_fds[0].revents = poll_fds[1].revents = 0;
356       do
357         poll_ret = g_poll (poll_fds, nfds, -1);
358       while (poll_ret == -1 && errno == EINTR);
359
360       if (poll_ret == -1)
361         {
362           int errsv = errno;
363
364           g_set_error (error, G_IO_ERROR,
365                        g_io_error_from_errno (errsv),
366                        _("Error writing to file descriptor: %s"),
367                        g_strerror (errsv));
368           break;
369         }
370
371       if (g_cancellable_set_error_if_cancelled (cancellable, error))
372         break;
373
374       if (!poll_fds[0].revents)
375         continue;
376
377       res = write (unix_stream->priv->fd, buffer, count);
378       if (res == -1)
379         {
380           int errsv = errno;
381
382           if (errsv == EINTR || errsv == EAGAIN)
383             continue;
384
385           g_set_error (error, G_IO_ERROR,
386                        g_io_error_from_errno (errsv),
387                        _("Error writing to file descriptor: %s"),
388                        g_strerror (errsv));
389         }
390
391       break;
392     }
393
394   if (nfds == 2)
395     g_cancellable_release_fd (cancellable);
396   return res;
397 }
398
399 static gboolean
400 g_unix_output_stream_close (GOutputStream  *stream,
401                             GCancellable   *cancellable,
402                             GError        **error)
403 {
404   GUnixOutputStream *unix_stream;
405   int res;
406
407   unix_stream = G_UNIX_OUTPUT_STREAM (stream);
408
409   if (!unix_stream->priv->close_fd)
410     return TRUE;
411   
412   while (1)
413     {
414       /* This might block during the close. Doesn't seem to be a way to avoid it though. */
415       res = close (unix_stream->priv->fd);
416       if (res == -1)
417         {
418           int errsv = errno;
419
420           g_set_error (error, G_IO_ERROR,
421                        g_io_error_from_errno (errsv),
422                        _("Error closing file descriptor: %s"),
423                        g_strerror (errsv));
424         }
425       break;
426     }
427
428   return res != -1;
429 }
430
431 typedef struct {
432   GOutputStream *stream;
433   GAsyncReadyCallback callback;
434   gpointer user_data;
435 } CloseAsyncData;
436
437 static gboolean
438 close_async_cb (CloseAsyncData *data)
439 {
440   GUnixOutputStream *unix_stream;
441   GSimpleAsyncResult *simple;
442   GError *error = NULL;
443   gboolean result;
444   int res;
445
446   unix_stream = G_UNIX_OUTPUT_STREAM (data->stream);
447
448   if (!unix_stream->priv->close_fd)
449     {
450       result = TRUE;
451       goto out;
452     }
453   
454   while (1)
455     {
456       res = close (unix_stream->priv->fd);
457       if (res == -1)
458         {
459           int errsv = errno;
460
461           g_set_error (&error, G_IO_ERROR,
462                        g_io_error_from_errno (errsv),
463                        _("Error closing file descriptor: %s"),
464                        g_strerror (errsv));
465         }
466       break;
467     }
468   
469   result = res != -1;
470   
471  out:
472   simple = g_simple_async_result_new (G_OBJECT (data->stream),
473                                       data->callback,
474                                       data->user_data,
475                                       g_unix_output_stream_close_async);
476
477   if (!result)
478     g_simple_async_result_take_error (simple, error);
479
480   /* Complete immediately, not in idle, since we're already in a mainloop callout */
481   g_simple_async_result_complete (simple);
482   g_object_unref (simple);
483   
484   return FALSE;
485 }
486
487 static void
488 g_unix_output_stream_close_async (GOutputStream        *stream,
489                                   int                  io_priority,
490                                   GCancellable        *cancellable,
491                                   GAsyncReadyCallback  callback,
492                                   gpointer             user_data)
493 {
494   GSource *idle;
495   CloseAsyncData *data;
496
497   data = g_new0 (CloseAsyncData, 1);
498
499   data->stream = stream;
500   data->callback = callback;
501   data->user_data = user_data;
502   
503   idle = g_idle_source_new ();
504   g_source_set_callback (idle, (GSourceFunc)close_async_cb, data, g_free);
505   g_source_attach (idle, g_main_context_get_thread_default ());
506   g_source_unref (idle);
507 }
508
509 static gboolean
510 g_unix_output_stream_close_finish (GOutputStream  *stream,
511                                    GAsyncResult   *result,
512                                    GError        **error)
513 {
514   /* Failures handled in generic close_finish code */
515   return TRUE;
516 }
517
518 static gboolean
519 g_unix_output_stream_pollable_is_writable (GPollableOutputStream *stream)
520 {
521   GUnixOutputStream *unix_stream = G_UNIX_OUTPUT_STREAM (stream);
522   GPollFD poll_fd;
523   gint result;
524
525   poll_fd.fd = unix_stream->priv->fd;
526   poll_fd.events = G_IO_OUT;
527
528   do
529     result = g_poll (&poll_fd, 1, 0);
530   while (result == -1 && errno == EINTR);
531
532   return poll_fd.revents != 0;
533 }
534
535 static GSource *
536 g_unix_output_stream_pollable_create_source (GPollableOutputStream *stream,
537                                              GCancellable          *cancellable)
538 {
539   GUnixOutputStream *unix_stream = G_UNIX_OUTPUT_STREAM (stream);
540   GSource *inner_source, *pollable_source;
541
542   pollable_source = g_pollable_source_new (G_OBJECT (stream));
543
544   inner_source = _g_fd_source_new (unix_stream->priv->fd, G_IO_OUT, cancellable);
545   g_source_set_dummy_callback (inner_source);
546   g_source_add_child_source (pollable_source, inner_source);
547   g_source_unref (inner_source);
548
549   return pollable_source;
550 }