GCancellable: port to GWakeup

This commit is contained in:
Ryan Lortie 2011-07-25 15:02:28 +02:00
parent 777e40989e
commit 0a971e46bf

View File

@ -22,18 +22,7 @@
#include "config.h" #include "config.h"
#include "glib.h" #include "glib.h"
#ifdef G_OS_UNIX
#include "glib-unix.h"
#ifdef HAVE_EVENTFD
#include <sys/eventfd.h>
#endif
#endif
#include <gioerror.h> #include <gioerror.h>
#ifdef G_OS_WIN32
#include <errno.h>
#include <windows.h>
#include <io.h>
#endif
#include "gcancellable.h" #include "gcancellable.h"
#include "glibintl.h" #include "glibintl.h"
@ -60,12 +49,7 @@ struct _GCancellablePrivate
guint cancelled_running_waiting : 1; guint cancelled_running_waiting : 1;
guint fd_refcount; guint fd_refcount;
/* If cancel_pipe[0] is != -1 and cancel_pipe[1] is -1, it is an eventfd */ GWakeup *wakeup;
int cancel_pipe[2];
#ifdef G_OS_WIN32
HANDLE event;
#endif
}; };
static guint signals[LAST_SIGNAL] = { 0 }; static guint signals[LAST_SIGNAL] = { 0 };
@ -75,41 +59,14 @@ G_DEFINE_TYPE (GCancellable, g_cancellable, G_TYPE_OBJECT);
static GStaticPrivate current_cancellable = G_STATIC_PRIVATE_INIT; static GStaticPrivate current_cancellable = G_STATIC_PRIVATE_INIT;
G_LOCK_DEFINE_STATIC(cancellable); G_LOCK_DEFINE_STATIC(cancellable);
static GCond *cancellable_cond = NULL; static GCond *cancellable_cond = NULL;
static void
g_cancellable_close_pipe (GCancellable *cancellable)
{
GCancellablePrivate *priv;
priv = cancellable->priv;
if (priv->cancel_pipe[0] != -1)
{
close (priv->cancel_pipe[0]);
priv->cancel_pipe[0] = -1;
}
if (priv->cancel_pipe[1] != -1)
{
close (priv->cancel_pipe[1]);
priv->cancel_pipe[1] = -1;
}
#ifdef G_OS_WIN32
if (priv->event)
{
CloseHandle (priv->event);
priv->event = NULL;
}
#endif
}
static void static void
g_cancellable_finalize (GObject *object) g_cancellable_finalize (GObject *object)
{ {
GCancellable *cancellable = G_CANCELLABLE (object); GCancellable *cancellable = G_CANCELLABLE (object);
g_cancellable_close_pipe (cancellable); if (cancellable->priv->wakeup)
g_wakeup_free (cancellable->priv->wakeup);
G_OBJECT_CLASS (g_cancellable_parent_class)->finalize (object); G_OBJECT_CLASS (g_cancellable_parent_class)->finalize (object);
} }
@ -195,88 +152,12 @@ g_cancellable_class_init (GCancellableClass *klass)
} }
static void
g_cancellable_write_cancelled (GCancellable *cancellable)
{
gssize c;
GCancellablePrivate *priv;
const char ch = 'x';
priv = cancellable->priv;
#ifdef G_OS_WIN32
if (priv->event)
SetEvent (priv->event);
#else
if (priv->cancel_pipe[0] == -1)
return;
g_assert (cancellable->priv->cancelled);
#ifdef HAVE_EVENTFD
if (priv->cancel_pipe[1] == -1)
{
guint64 buf = 1;
do
c = write (priv->cancel_pipe[0], &buf, sizeof (buf));
while (c == -1 && errno == EINTR);
return;
}
#endif /* HAVE_EVENTFD */
do
c = write (priv->cancel_pipe[1], &ch, 1);
while (c == -1 && errno == EINTR);
#endif /* G_OS_WIN32 */
}
#ifndef G_OS_WIN32
static void
g_cancellable_open_pipe (GCancellable *cancellable)
{
GCancellablePrivate *priv;
priv = cancellable->priv;
#ifdef HAVE_EVENTFD
priv->cancel_pipe[0] = eventfd (0, EFD_CLOEXEC | EFD_NONBLOCK);
if (priv->cancel_pipe[0] >= 0)
{
if (priv->cancelled)
g_cancellable_write_cancelled (cancellable);
return;
}
else if (!(errno == ENOSYS || errno == EINVAL))
{
return;
}
/* Fall through on ENOSYS or EINVAL */
#endif
if (g_unix_open_pipe (priv->cancel_pipe, FD_CLOEXEC, NULL))
{
/* Make them nonblocking, just to be sure we don't block
* on errors and stuff
*/
g_unix_set_fd_nonblocking (priv->cancel_pipe[0], TRUE, NULL);
g_unix_set_fd_nonblocking (priv->cancel_pipe[1], TRUE, NULL);
if (priv->cancelled)
g_cancellable_write_cancelled (cancellable);
}
}
#endif
static void static void
g_cancellable_init (GCancellable *cancellable) g_cancellable_init (GCancellable *cancellable)
{ {
cancellable->priv = G_TYPE_INSTANCE_GET_PRIVATE (cancellable, cancellable->priv = G_TYPE_INSTANCE_GET_PRIVATE (cancellable,
G_TYPE_CANCELLABLE, G_TYPE_CANCELLABLE,
GCancellablePrivate); GCancellablePrivate);
cancellable->priv->cancel_pipe[0] = -1;
cancellable->priv->cancel_pipe[1] = -1;
} }
/** /**
@ -388,37 +269,11 @@ g_cancellable_reset (GCancellable *cancellable)
g_cond_wait (cancellable_cond, g_cond_wait (cancellable_cond,
g_static_mutex_get_mutex (& G_LOCK_NAME (cancellable))); g_static_mutex_get_mutex (& G_LOCK_NAME (cancellable)));
} }
if (priv->cancelled) if (priv->cancelled)
{ {
/* Make sure we're not leaving old cancel state around */ if (priv->wakeup)
g_wakeup_acknowledge (priv->wakeup);
#ifdef G_OS_WIN32
if (priv->event)
ResetEvent (priv->event);
#endif
if (priv->cancel_pipe[0] != -1)
{
gssize c;
#ifdef HAVE_EVENTFD
if (priv->cancel_pipe[1] == -1)
{
guint64 buf;
do
c = read (priv->cancel_pipe[0], &buf, sizeof(buf));
while (c == -1 && errno == EINTR);
}
else
#endif
{
char ch;
do
c = read (priv->cancel_pipe[0], &ch, 1);
while (c == -1 && errno == EINTR);
}
}
priv->cancelled = FALSE; priv->cancelled = FALSE;
} }
@ -490,27 +345,15 @@ g_cancellable_set_error_if_cancelled (GCancellable *cancellable,
int int
g_cancellable_get_fd (GCancellable *cancellable) g_cancellable_get_fd (GCancellable *cancellable)
{ {
GCancellablePrivate *priv; GPollFD pollfd;
int fd;
if (cancellable == NULL)
return -1;
priv = cancellable->priv;
#ifdef G_OS_WIN32 #ifdef G_OS_WIN32
return -1; pollfd.fd = -1;
#else #else
G_LOCK(cancellable); g_cancellable_make_pollfd (cancellable, &pollfd);
if (priv->cancel_pipe[0] == -1)
g_cancellable_open_pipe (cancellable);
fd = priv->cancel_pipe[0];
if (fd != -1)
priv->fd_refcount++;
G_UNLOCK(cancellable);
#endif #endif
return fd; return pollfd.fd;
} }
/** /**
@ -550,39 +393,21 @@ g_cancellable_make_pollfd (GCancellable *cancellable, GPollFD *pollfd)
return FALSE; return FALSE;
g_return_val_if_fail (G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (G_IS_CANCELLABLE (cancellable), FALSE);
{ G_LOCK(cancellable);
#ifdef G_OS_WIN32
GCancellablePrivate *priv;
priv = cancellable->priv; cancellable->priv->fd_refcount++;
G_LOCK(cancellable);
if (priv->event == NULL)
{
/* A manual reset anonymous event, starting unset */
priv->event = CreateEvent (NULL, TRUE, FALSE, NULL);
if (priv->event == NULL)
{
G_UNLOCK(cancellable);
return FALSE;
}
if (priv->cancelled)
SetEvent(priv->event);
}
priv->fd_refcount++;
G_UNLOCK(cancellable);
pollfd->fd = (gintptr)priv->event; if (cancellable->priv->wakeup == NULL)
#else /* !G_OS_WIN32 */ {
int fd = g_cancellable_get_fd (cancellable); cancellable->priv->wakeup = g_wakeup_new ();
if (fd == -1) if (cancellable->priv->cancelled)
return FALSE; g_wakeup_signal (cancellable->priv->wakeup);
pollfd->fd = fd; }
#endif /* G_OS_WIN32 */
}
pollfd->events = G_IO_IN; g_wakeup_get_pollfd (cancellable->priv->wakeup, pollfd);
pollfd->revents = 0;
G_UNLOCK(cancellable);
return TRUE; return TRUE;
} }
@ -619,7 +444,10 @@ g_cancellable_release_fd (GCancellable *cancellable)
G_LOCK (cancellable); G_LOCK (cancellable);
priv->fd_refcount--; priv->fd_refcount--;
if (priv->fd_refcount == 0) if (priv->fd_refcount == 0)
g_cancellable_close_pipe (cancellable); {
g_wakeup_free (priv->wakeup);
priv->wakeup = NULL;
}
G_UNLOCK (cancellable); G_UNLOCK (cancellable);
} }
@ -662,8 +490,9 @@ g_cancellable_cancel (GCancellable *cancellable)
priv->cancelled = TRUE; priv->cancelled = TRUE;
priv->cancelled_running = TRUE; priv->cancelled_running = TRUE;
g_cancellable_write_cancelled (cancellable); if (priv->wakeup)
g_wakeup_signal (priv->wakeup);
G_UNLOCK(cancellable); G_UNLOCK(cancellable);