mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-26 07:26:15 +01:00
e2fd4e2bd0
Tue Dec 5 12:23:04 2000 Owen Taylor <otaylor@redhat.com> * gmain.[hc]: Major change in API for creating sources to handle multiple main loops (GMainContext *). GSources are now exposed as GSource * and implemented with structure derivation. * giochannel.[ch]: Changed vtable for GIOChannel to correspond to the new mainloop API, add g_io_channel_create_watch(). * gtypes.h: Move GTimeVal here. * gthread.h: Remove gmain.h include to avoid circularity. * giounix.c: Update for new GMain API. * giowin32.c: Update for new GMain API. (No check for proper compilation or working.) * timeloop.c timeloop-basic.c: A benchmarking program for the main loop comparing the main loop against a hand-written (timeloop-basic.c) variant. * tests/mainloop-test.c: New torture test of mainloop. * docs/Changes-2.0.txt: Started. Added text about changes to GMain. * gmain.c (g_main_add_poll_unlocked): Initial fd->revents to zero. (#8482, Benjamin Kahn)
313 lines
6.7 KiB
C
313 lines
6.7 KiB
C
/* GLIB - Library of useful routines for C programming
|
|
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
|
*
|
|
* giounix.c: IO Channels using unix file descriptors
|
|
* Copyright 1998 Owen Taylor
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
/*
|
|
* Modified by the GLib Team and others 1997-2000. See the AUTHORS
|
|
* file for a list of people on the GLib Team. See the ChangeLog
|
|
* files for a list of changes. These files are distributed with
|
|
* GLib at ftp://ftp.gtk.org/pub/gtk/.
|
|
*/
|
|
|
|
/*
|
|
* MT safe
|
|
*/
|
|
|
|
#include "glib.h"
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
|
|
/*
|
|
* Unix IO Channels
|
|
*/
|
|
|
|
typedef struct _GIOUnixChannel GIOUnixChannel;
|
|
typedef struct _GIOUnixWatch GIOUnixWatch;
|
|
|
|
struct _GIOUnixChannel
|
|
{
|
|
GIOChannel channel;
|
|
gint fd;
|
|
};
|
|
|
|
struct _GIOUnixWatch
|
|
{
|
|
GSource source;
|
|
GPollFD pollfd;
|
|
GIOChannel *channel;
|
|
GIOCondition condition;
|
|
GIOFunc callback;
|
|
};
|
|
|
|
|
|
static GIOError g_io_unix_read (GIOChannel *channel,
|
|
gchar *buf,
|
|
guint count,
|
|
guint *bytes_written);
|
|
static GIOError g_io_unix_write (GIOChannel *channel,
|
|
gchar *buf,
|
|
guint count,
|
|
guint *bytes_written);
|
|
static GIOError g_io_unix_seek (GIOChannel *channel,
|
|
gint offset,
|
|
GSeekType type);
|
|
static void g_io_unix_close (GIOChannel *channel);
|
|
static void g_io_unix_free (GIOChannel *channel);
|
|
static GSource *g_io_unix_create_watch (GIOChannel *channel,
|
|
GIOCondition condition);
|
|
|
|
static gboolean g_io_unix_prepare (GSource *source,
|
|
gint *timeout);
|
|
static gboolean g_io_unix_check (GSource *source);
|
|
static gboolean g_io_unix_dispatch (GSource *source,
|
|
GSourceFunc callback,
|
|
gpointer user_data);
|
|
static void g_io_unix_destroy (GSource *source);
|
|
|
|
GSourceFuncs unix_watch_funcs = {
|
|
g_io_unix_prepare,
|
|
g_io_unix_check,
|
|
g_io_unix_dispatch,
|
|
g_io_unix_destroy
|
|
};
|
|
|
|
GIOFuncs unix_channel_funcs = {
|
|
g_io_unix_read,
|
|
g_io_unix_write,
|
|
g_io_unix_seek,
|
|
g_io_unix_close,
|
|
g_io_unix_create_watch,
|
|
g_io_unix_free,
|
|
};
|
|
|
|
static gboolean
|
|
g_io_unix_prepare (GSource *source,
|
|
gint *timeout)
|
|
{
|
|
*timeout = -1;
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
g_io_unix_check (GSource *source)
|
|
{
|
|
GIOUnixWatch *watch = (GIOUnixWatch *)source;
|
|
|
|
return (watch->pollfd.revents & watch->condition);
|
|
}
|
|
|
|
static gboolean
|
|
g_io_unix_dispatch (GSource *source,
|
|
GSourceFunc callback,
|
|
gpointer user_data)
|
|
|
|
{
|
|
GIOFunc func = (GIOFunc)callback;
|
|
GIOUnixWatch *watch = (GIOUnixWatch *)source;
|
|
|
|
if (!func)
|
|
{
|
|
g_warning ("IO watch dispatched without callback\n"
|
|
"You must call g_source_connect().");
|
|
return FALSE;
|
|
}
|
|
|
|
return (*func) (watch->channel,
|
|
watch->pollfd.revents & watch->condition,
|
|
user_data);
|
|
}
|
|
|
|
static void
|
|
g_io_unix_destroy (GSource *source)
|
|
{
|
|
GIOUnixWatch *watch = (GIOUnixWatch *)source;
|
|
|
|
g_io_channel_unref (watch->channel);
|
|
}
|
|
|
|
static GIOError
|
|
g_io_unix_read (GIOChannel *channel,
|
|
gchar *buf,
|
|
guint count,
|
|
guint *bytes_read)
|
|
{
|
|
GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
|
|
gint result;
|
|
|
|
result = read (unix_channel->fd, buf, count);
|
|
|
|
if (result < 0)
|
|
{
|
|
*bytes_read = 0;
|
|
switch (errno)
|
|
{
|
|
case EINVAL:
|
|
return G_IO_ERROR_INVAL;
|
|
case EAGAIN:
|
|
case EINTR:
|
|
return G_IO_ERROR_AGAIN;
|
|
default:
|
|
return G_IO_ERROR_UNKNOWN;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*bytes_read = result;
|
|
return G_IO_ERROR_NONE;
|
|
}
|
|
}
|
|
|
|
static GIOError
|
|
g_io_unix_write(GIOChannel *channel,
|
|
gchar *buf,
|
|
guint count,
|
|
guint *bytes_written)
|
|
{
|
|
GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
|
|
gint result;
|
|
|
|
result = write (unix_channel->fd, buf, count);
|
|
|
|
if (result < 0)
|
|
{
|
|
*bytes_written = 0;
|
|
switch (errno)
|
|
{
|
|
case EINVAL:
|
|
return G_IO_ERROR_INVAL;
|
|
case EAGAIN:
|
|
case EINTR:
|
|
return G_IO_ERROR_AGAIN;
|
|
default:
|
|
return G_IO_ERROR_UNKNOWN;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*bytes_written = result;
|
|
return G_IO_ERROR_NONE;
|
|
}
|
|
}
|
|
|
|
static GIOError
|
|
g_io_unix_seek (GIOChannel *channel,
|
|
gint offset,
|
|
GSeekType type)
|
|
{
|
|
GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
|
|
int whence;
|
|
off_t result;
|
|
|
|
switch (type)
|
|
{
|
|
case G_SEEK_SET:
|
|
whence = SEEK_SET;
|
|
break;
|
|
case G_SEEK_CUR:
|
|
whence = SEEK_CUR;
|
|
break;
|
|
case G_SEEK_END:
|
|
whence = SEEK_END;
|
|
break;
|
|
default:
|
|
g_warning ("g_io_unix_seek: unknown seek type");
|
|
return G_IO_ERROR_UNKNOWN;
|
|
}
|
|
|
|
result = lseek (unix_channel->fd, offset, whence);
|
|
|
|
if (result < 0)
|
|
{
|
|
switch (errno)
|
|
{
|
|
case EINVAL:
|
|
return G_IO_ERROR_INVAL;
|
|
default:
|
|
return G_IO_ERROR_UNKNOWN;
|
|
}
|
|
}
|
|
else
|
|
return G_IO_ERROR_NONE;
|
|
}
|
|
|
|
|
|
static void
|
|
g_io_unix_close (GIOChannel *channel)
|
|
{
|
|
GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
|
|
|
|
close (unix_channel->fd);
|
|
}
|
|
|
|
static void
|
|
g_io_unix_free (GIOChannel *channel)
|
|
{
|
|
GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
|
|
|
|
g_free (unix_channel);
|
|
}
|
|
|
|
static GSource *
|
|
g_io_unix_create_watch (GIOChannel *channel,
|
|
GIOCondition condition)
|
|
{
|
|
GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
|
|
GSource *source;
|
|
GIOUnixWatch *watch;
|
|
|
|
|
|
source = g_source_new (&unix_watch_funcs, sizeof (GIOUnixWatch));
|
|
watch = (GIOUnixWatch *)source;
|
|
|
|
watch->channel = channel;
|
|
g_io_channel_ref (channel);
|
|
|
|
watch->condition = condition;
|
|
|
|
watch->pollfd.fd = unix_channel->fd;
|
|
watch->pollfd.events = condition;
|
|
|
|
g_source_add_poll (source, &watch->pollfd);
|
|
|
|
return source;
|
|
}
|
|
|
|
GIOChannel *
|
|
g_io_channel_unix_new (gint fd)
|
|
{
|
|
GIOUnixChannel *unix_channel = g_new (GIOUnixChannel, 1);
|
|
GIOChannel *channel = (GIOChannel *)unix_channel;
|
|
|
|
g_io_channel_init (channel);
|
|
channel->funcs = &unix_channel_funcs;
|
|
|
|
unix_channel->fd = fd;
|
|
return channel;
|
|
}
|
|
|
|
gint
|
|
g_io_channel_unix_get_fd (GIOChannel *channel)
|
|
{
|
|
GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
|
|
return unix_channel->fd;
|
|
}
|