mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-23 10:42:11 +01:00
Tue Dec 8 18:49:56 1998 Owen Taylor <otaylor@redhat.com> * Start at adding thread-safety. (mostly work of Sebastian Wilhelmi <wilhelmi@ira.uka.de>) - configure.in now looks for a system thread implementation. Currently support is included for POSIX threads and Solaris threads. The default support is built into a separate library -lgthread. - The thread implementation can be modified by passing a vector of functions g_thread_init(). - The default or supplied functions are used to implement a small set of thread functions for mutexes, condition variables, and thread-private data. - GLib now uses these functions to provide thread safety. (In the sense that all global static data is locked... individual structures must still be locked by the caller.)
298 lines
6.4 KiB
C
298 lines
6.4 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 Library 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
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library 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.
|
|
*/
|
|
|
|
/*
|
|
* 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 {
|
|
gint fd;
|
|
};
|
|
|
|
struct _GIOUnixWatch {
|
|
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 guint g_io_unix_add_watch (GIOChannel *channel,
|
|
gint priority,
|
|
GIOCondition condition,
|
|
GIOFunc func,
|
|
gpointer user_data,
|
|
GDestroyNotify notify);
|
|
static gboolean g_io_unix_prepare (gpointer source_data,
|
|
GTimeVal *current_time,
|
|
gint *timeout);
|
|
static gboolean g_io_unix_check (gpointer source_data,
|
|
GTimeVal *current_time);
|
|
static gboolean g_io_unix_dispatch (gpointer source_data,
|
|
GTimeVal *current_time,
|
|
gpointer user_data);
|
|
static void g_io_unix_destroy (gpointer source_data);
|
|
|
|
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_add_watch,
|
|
g_io_unix_free,
|
|
};
|
|
|
|
static gboolean
|
|
g_io_unix_prepare (gpointer source_data,
|
|
GTimeVal *current_time,
|
|
gint *timeout)
|
|
{
|
|
*timeout = -1;
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
g_io_unix_check (gpointer source_data,
|
|
GTimeVal *current_time)
|
|
{
|
|
GIOUnixWatch *data = source_data;
|
|
|
|
return (data->pollfd.revents & data->condition);
|
|
}
|
|
|
|
static gboolean
|
|
g_io_unix_dispatch (gpointer source_data,
|
|
GTimeVal *current_time,
|
|
gpointer user_data)
|
|
|
|
{
|
|
GIOUnixWatch *data = source_data;
|
|
|
|
return (*data->callback)(data->channel,
|
|
data->pollfd.revents & data->condition,
|
|
user_data);
|
|
}
|
|
|
|
static void
|
|
g_io_unix_destroy (gpointer source_data)
|
|
{
|
|
GIOUnixWatch *data = source_data;
|
|
|
|
g_main_poll_remove (&data->pollfd);
|
|
g_io_channel_unref (data->channel);
|
|
g_free (data);
|
|
}
|
|
|
|
static GIOError
|
|
g_io_unix_read (GIOChannel *channel,
|
|
gchar *buf,
|
|
guint count,
|
|
guint *bytes_read)
|
|
{
|
|
GIOUnixChannel *unix_channel = channel->channel_data;
|
|
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:
|
|
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 = channel->channel_data;
|
|
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:
|
|
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 = channel->channel_data;
|
|
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 = channel->channel_data;
|
|
|
|
close (unix_channel->fd);
|
|
}
|
|
|
|
static void
|
|
g_io_unix_free (GIOChannel *channel)
|
|
{
|
|
GIOUnixChannel *unix_channel = channel->channel_data;
|
|
|
|
g_free (unix_channel);
|
|
}
|
|
|
|
static guint
|
|
g_io_unix_add_watch (GIOChannel *channel,
|
|
gint priority,
|
|
GIOCondition condition,
|
|
GIOFunc func,
|
|
gpointer user_data,
|
|
GDestroyNotify notify)
|
|
{
|
|
GIOUnixWatch *watch = g_new (GIOUnixWatch, 1);
|
|
GIOUnixChannel *unix_channel = channel->channel_data;
|
|
|
|
watch->channel = channel;
|
|
g_io_channel_ref (channel);
|
|
|
|
watch->callback = func;
|
|
watch->condition = condition;
|
|
|
|
watch->pollfd.fd = unix_channel->fd;
|
|
watch->pollfd.events = condition;
|
|
|
|
g_main_poll_add (priority, &watch->pollfd);
|
|
|
|
return g_source_add (priority, TRUE, &unix_watch_funcs, watch, user_data, notify);
|
|
}
|
|
|
|
GIOChannel *
|
|
g_io_channel_unix_new (gint fd)
|
|
{
|
|
GIOUnixChannel *unix_channel = g_new (GIOUnixChannel, 1);
|
|
|
|
unix_channel->fd = fd;
|
|
return g_io_channel_new (&unix_channel_funcs, unix_channel);
|
|
}
|
|
|
|
gint
|
|
g_io_channel_unix_get_fd (GIOChannel *channel)
|
|
{
|
|
GIOUnixChannel *unix_channel = channel->channel_data;
|
|
return unix_channel->fd;
|
|
}
|