plugins/elements/gstfdsink.c: handle EAGAIN, EINTR and short writes correctly. Also clean up some error cases, avoid ...

Original commit message from CVS:
* plugins/elements/gstfdsink.c: (gst_fd_sink_render),
(gst_fd_sink_check_fd), (gst_fd_sink_update_fd):
handle EAGAIN, EINTR and short writes correctly. Also clean
up some error cases, avoid a deadlock on bad file descriptors and
use GST_DEBUG_OBJECT.
Fixes #339843
This commit is contained in:
Wim Taymans 2006-04-28 13:16:03 +00:00
parent 1089154f2a
commit 09eeb714c2
2 changed files with 69 additions and 26 deletions

View file

@ -1,3 +1,12 @@
2006-04-28 Wim Taymans <wim@fluendo.com>
* plugins/elements/gstfdsink.c: (gst_fd_sink_render),
(gst_fd_sink_check_fd), (gst_fd_sink_update_fd):
handle EAGAIN, EINTR and short writes correctly. Also clean
up some error cases, avoid a deadlock on bad file descriptors and
use GST_DEBUG_OBJECT.
Fixes #339843
2006-04-28 Wim Taymans <wim@fluendo.com> 2006-04-28 Wim Taymans <wim@fluendo.com>
* gst/gstvalue.c: (gst_value_serialize_buffer), * gst/gstvalue.c: (gst_value_serialize_buffer),

View file

@ -26,6 +26,12 @@
* @see_also: #GstFdSrc * @see_also: #GstFdSrc
* *
* Write data to a unix file descriptor. * Write data to a unix file descriptor.
*
* This element will sycnhronize on the clock before writing the data on the
* socket. For file descriptors where this does not make sense (files, ...) the
* ::sync property can be used to disable synchronisation.
*
* Last reviewed on 2006-04-28 (0.10.6)
*/ */
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
@ -237,12 +243,20 @@ gst_fd_sink_render (GstBaseSink * sink, GstBuffer * buffer)
fd_set writefds; fd_set writefds;
gint retval; gint retval;
#endif #endif
guint8 *data;
guint size;
gint written;
fdsink = GST_FD_SINK (sink); fdsink = GST_FD_SINK (sink);
g_return_val_if_fail (fdsink->fd >= 0, GST_FLOW_ERROR); g_return_val_if_fail (fdsink->fd >= 0, GST_FLOW_ERROR);
data = GST_BUFFER_DATA (buffer);
size = GST_BUFFER_SIZE (buffer);
again:
#ifndef HAVE_WIN32 #ifndef HAVE_WIN32
FD_ZERO (&readfds); FD_ZERO (&readfds);
FD_SET (READ_SOCKET (fdsink), &readfds); FD_SET (READ_SOCKET (fdsink), &readfds);
@ -250,6 +264,8 @@ gst_fd_sink_render (GstBaseSink * sink, GstBuffer * buffer)
FD_SET (fdsink->fd, &writefds); FD_SET (fdsink->fd, &writefds);
do { do {
GST_DEBUG_OBJECT (fdsink, "going into select, have %d bytes to write",
size);
retval = select (FD_SETSIZE, &readfds, &writefds, NULL, NULL); retval = select (FD_SETSIZE, &readfds, &writefds, NULL, NULL);
} while ((retval == -1 && errno == EINTR)); } while ((retval == -1 && errno == EINTR));
@ -273,20 +289,32 @@ gst_fd_sink_render (GstBaseSink * sink, GstBuffer * buffer)
} }
#endif #endif
if (GST_BUFFER_DATA (buffer)) { GST_DEBUG_OBJECT (fdsink, "writing %d bytes to file descriptor %d", size,
guint bytes_written; fdsink->fd);
GST_DEBUG ("writing %d bytes to file descriptor %d", written = write (fdsink->fd, data, size);
GST_BUFFER_SIZE (buffer), fdsink->fd);
/* FIXME: short writes are perfectly valid and may happen; also, /* check for errors */
* we should probably handle EINTR and EAGAIN in a non-fatal way */ if (G_UNLIKELY (written < 0)) {
bytes_written = /* try to write again on non-fatal errors */
write (fdsink->fd, GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer)); if (errno == EAGAIN || errno == EINTR)
fdsink->bytes_written += bytes_written; goto again;
if (bytes_written != GST_BUFFER_SIZE (buffer))
goto write_error; /* else go to our error handler */
goto write_error;
} }
/* all is fine when we get here */
size -= written;
data += written;
fdsink->bytes_written += written;
GST_DEBUG_OBJECT (fdsink, "wrote %d bytes, %d left", written, size);
/* short write, select and try to write the remainder */
if (G_UNLIKELY (size > 0))
goto again;
return GST_FLOW_OK; return GST_FLOW_OK;
#ifndef HAVE_WIN32 #ifndef HAVE_WIN32
@ -345,19 +373,22 @@ gst_fd_sink_check_fd (GstFdSink * fdsink, int fd)
goto not_seekable; goto not_seekable;
} }
} else } else
GST_DEBUG ("File descriptor \"%d\" is seekable", fd); GST_DEBUG_OBJECT (fdsink, "File descriptor \"%d\" is seekable", fd);
return TRUE; return TRUE;
invalid: invalid:
GST_ELEMENT_ERROR (fdsink, RESOURCE, WRITE, {
(_("File descriptor \"%d\" is not valid."), fd), GST_ELEMENT_ERROR (fdsink, RESOURCE, WRITE,
("%s", g_strerror (errno))); (_("File descriptor \"%d\" is not valid."), fd),
return FALSE; ("%s", g_strerror (errno)));
return FALSE;
}
not_seekable: not_seekable:
GST_DEBUG ("File descriptor \"%d\" is a pipe", fd); {
return TRUE; GST_DEBUG_OBJECT (fdsink, "File descriptor \"%d\" is a pipe", fd);
return TRUE;
}
} }
static gboolean static gboolean
@ -417,19 +448,22 @@ gst_fd_sink_update_fd (GstFdSink * fdsink, int new_fd)
if (new_fd < 0) if (new_fd < 0)
return FALSE; return FALSE;
if (!gst_fd_sink_check_fd (fdsink, new_fd))
goto invalid;
/* assign the fd */
GST_OBJECT_LOCK (fdsink); GST_OBJECT_LOCK (fdsink);
if (!gst_fd_sink_check_fd (fdsink, new_fd)) {
GST_OBJECT_UNLOCK (fdsink);
return FALSE;
}
fdsink->fd = new_fd; fdsink->fd = new_fd;
g_free (fdsink->uri); g_free (fdsink->uri);
fdsink->uri = g_strdup_printf ("fd://%d", fdsink->fd); fdsink->uri = g_strdup_printf ("fd://%d", fdsink->fd);
GST_OBJECT_UNLOCK (fdsink); GST_OBJECT_UNLOCK (fdsink);
return TRUE; return TRUE;
invalid:
{
return FALSE;
}
} }
static void static void