aboutsummaryrefslogtreecommitdiffstats
path: root/camel/camel-operation.c
diff options
context:
space:
mode:
Diffstat (limited to 'camel/camel-operation.c')
-rw-r--r--camel/camel-operation.c687
1 files changed, 0 insertions, 687 deletions
diff --git a/camel/camel-operation.c b/camel/camel-operation.c
deleted file mode 100644
index 03c0c77617..0000000000
--- a/camel/camel-operation.c
+++ /dev/null
@@ -1,687 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Authors: Michael Zucchi <NotZed@ximian.com>
- *
- * Copyright 2003 Ximian, Inc. (www.ximian.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
- *
- */
-
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <glib.h>
-
-#include <stdio.h>
-#include <sys/time.h>
-#include <unistd.h>
-#include <pthread.h>
-#ifdef HAVE_NSS
-#include <nspr.h>
-#endif
-
-#include "camel-operation.h"
-#include "e-util/e-msgport.h"
-
-#define d(x)
-
-/* ********************************************************************** */
-
-struct _status_stack {
- guint32 flags;
- char *msg;
- int pc; /* last pc reported */
- unsigned int stamp; /* last stamp reported */
-};
-
-struct _CamelOperation {
- struct _CamelOperation *next;
- struct _CamelOperation *prev;
-
- pthread_t id; /* id of running thread */
- guint32 flags; /* cancelled ? */
- int blocked; /* cancellation blocked depth */
- int refcount;
-
- CamelOperationStatusFunc status;
- void *status_data;
- unsigned int status_update;
-
- /* stack of status messages (struct _status_stack *) */
- GSList *status_stack;
- struct _status_stack *lastreport;
-
- EMsgPort *cancel_port;
- int cancel_fd;
-#ifdef HAVE_NSS
- PRFileDesc *cancel_prfd;
-#endif
-};
-
-#define CAMEL_OPERATION_CANCELLED (1<<0)
-#define CAMEL_OPERATION_TRANSIENT (1<<1)
-
-/* Delay before a transient operation has any effect on the status */
-#define CAMEL_OPERATION_TRANSIENT_DELAY (5)
-
-static pthread_mutex_t operation_lock = PTHREAD_MUTEX_INITIALIZER;
-#define LOCK() pthread_mutex_lock(&operation_lock)
-#define UNLOCK() pthread_mutex_unlock(&operation_lock)
-
-
-static unsigned int stamp (void);
-static EDList operation_list = E_DLIST_INITIALISER(operation_list);
-static pthread_key_t operation_key;
-
-typedef struct _CamelOperationMsg {
- EMsg msg;
-} CamelOperationMsg ;
-
-/**
- * camel_operation_init:
- * @void:
- *
- * Init internal variables. Only call this once.
- **/
-void
-camel_operation_init(void)
-{
- pthread_key_create(&operation_key, NULL);
-}
-
-/**
- * camel_operation_new:
- * @status: Callback for receiving status messages. This will always
- * be called with an internal lock held.
- * @status_data: User data.
- *
- * Create a new camel operation handle. Camel operation handles can
- * be used in a multithreaded application (or a single operation
- * handle can be used in a non threaded appliation) to cancel running
- * operations and to obtain notification messages of the internal
- * status of messages.
- *
- * Return value: A new operation handle.
- **/
-CamelOperation *
-camel_operation_new (CamelOperationStatusFunc status, void *status_data)
-{
- CamelOperation *cc;
-
- cc = g_malloc0(sizeof(*cc));
-
- cc->flags = 0;
- cc->blocked = 0;
- cc->refcount = 1;
- cc->status = status;
- cc->status_data = status_data;
- cc->cancel_port = e_msgport_new();
- cc->cancel_fd = -1;
-
- LOCK();
- e_dlist_addtail(&operation_list, (EDListNode *)cc);
- UNLOCK();
-
- return cc;
-}
-
-/**
- * camel_operation_mute:
- * @cc:
- *
- * mutes a camel operation permanently. from this point on you will never
- * receive operation updates, even if more are sent.
- **/
-void
-camel_operation_mute(CamelOperation *cc)
-{
- LOCK();
- cc->status = NULL;
- cc->status_data = NULL;
- UNLOCK();
-}
-
-/**
- * camel_operation_registered:
- *
- * Returns the registered operation, or %NULL if none registered.
- **/
-CamelOperation *
-camel_operation_registered (void)
-{
- CamelOperation *cc = (CamelOperation *)pthread_getspecific(operation_key);
-
- if (cc)
- camel_operation_ref(cc);
-
- return cc;
-}
-
-/**
- * camel_operation_ref:
- * @cc: operation context
- *
- * Add a reference to the CamelOperation @cc.
- **/
-void
-camel_operation_ref (CamelOperation *cc)
-{
- g_assert(cc->refcount > 0);
-
- LOCK();
- cc->refcount++;
- UNLOCK();
-}
-
-/**
- * camel_operation_unref:
- * @cc: operation context
- *
- * Unref and potentially free @cc.
- **/
-void
-camel_operation_unref (CamelOperation *cc)
-{
- GSList *n;
-
- g_assert(cc->refcount > 0);
-
- LOCK();
- if (cc->refcount == 1) {
- CamelOperationMsg *msg;
-
- e_dlist_remove((EDListNode *)cc);
-
- while ((msg = (CamelOperationMsg *)e_msgport_get(cc->cancel_port)))
- g_free(msg);
-
- e_msgport_destroy(cc->cancel_port);
-
- n = cc->status_stack;
- while (n) {
- g_warning("Camel operation status stack non empty: %s", (char *)n->data);
- g_free(n->data);
- n = n->next;
- }
- g_slist_free(cc->status_stack);
-
- g_free(cc);
- } else {
- cc->refcount--;
- }
- UNLOCK();
-}
-
-/**
- * camel_operation_cancel_block:
- * @cc: operation context
- *
- * Block cancellation for this operation. If @cc is NULL, then the
- * current thread is blocked.
- **/
-void
-camel_operation_cancel_block (CamelOperation *cc)
-{
- if (cc == NULL)
- cc = (CamelOperation *)pthread_getspecific(operation_key);
-
- if (cc) {
- LOCK();
- cc->blocked++;
- UNLOCK();
- }
-}
-
-/**
- * camel_operation_cancel_unblock:
- * @cc: operation context
- *
- * Unblock cancellation, when the unblock count reaches the block
- * count, then this operation can be cancelled. If @cc is NULL, then
- * the current thread is unblocked.
- **/
-void
-camel_operation_cancel_unblock (CamelOperation *cc)
-{
- if (cc == NULL)
- cc = (CamelOperation *)pthread_getspecific(operation_key);
-
- if (cc) {
- LOCK();
- cc->blocked--;
- UNLOCK();
- }
-}
-
-/**
- * camel_operation_cancel:
- * @cc: operation context
- *
- * Cancel a given operation. If @cc is NULL then all outstanding
- * operations are cancelled.
- **/
-void
-camel_operation_cancel (CamelOperation *cc)
-{
- CamelOperationMsg *msg;
-
- LOCK();
-
- if (cc == NULL) {
- CamelOperation *cn;
-
- cc = (CamelOperation *)operation_list.head;
- cn = cc->next;
- while (cn) {
- cc->flags |= CAMEL_OPERATION_CANCELLED;
- msg = g_malloc0(sizeof(*msg));
- e_msgport_put(cc->cancel_port, (EMsg *)msg);
- cc = cn;
- cn = cn->next;
- }
- } else if ((cc->flags & CAMEL_OPERATION_CANCELLED) == 0) {
- d(printf("cancelling thread %d\n", cc->id));
-
- cc->flags |= CAMEL_OPERATION_CANCELLED;
- msg = g_malloc0(sizeof(*msg));
- e_msgport_put(cc->cancel_port, (EMsg *)msg);
- }
-
- UNLOCK();
-}
-
-/**
- * camel_operation_register:
- * @cc: operation context
- *
- * Register a thread or the main thread for cancellation through @cc.
- * If @cc is NULL, then a new cancellation is created for this thread.
- *
- * All calls to operation_register() should be matched with calls to
- * operation_unregister(), or resources will be lost.
- *
- * Return Value: Returns @cc, or if NULL, the new operation.
- *
- **/
-CamelOperation *
-camel_operation_register (CamelOperation *cc)
-{
- CamelOperation *oldcc = pthread_getspecific(operation_key);
-
- pthread_setspecific(operation_key, cc);
-
- return oldcc;
-}
-
-/**
- * camel_operation_unregister:
- * @cc: operation context
- *
- * Unregister the current thread.
- **/
-void
-camel_operation_unregister (CamelOperation *cc)
-{
- pthread_setspecific(operation_key, NULL);
-}
-
-/**
- * camel_operation_cancel_check:
- * @cc: operation context
- *
- * Check if cancellation has been applied to @cc. If @cc is NULL,
- * then the CamelOperation registered for the current thread is used.
- *
- * Return value: TRUE if the operation has been cancelled.
- **/
-gboolean
-camel_operation_cancel_check (CamelOperation *cc)
-{
- CamelOperationMsg *msg;
- int cancelled;
-
- d(printf("checking for cancel in thread %d\n", pthread_self()));
-
- if (cc == NULL)
- cc = (CamelOperation *)pthread_getspecific(operation_key);
-
- LOCK();
-
- if (cc == NULL || cc->blocked > 0) {
- d(printf("ahah! cancellation is blocked\n"));
- cancelled = FALSE;
- } else if (cc->flags & CAMEL_OPERATION_CANCELLED) {
- d(printf("previously cancelled\n"));
- cancelled = TRUE;
- } else if ((msg = (CamelOperationMsg *)e_msgport_get(cc->cancel_port))) {
- d(printf("Got cancellation message\n"));
- g_free(msg);
- cc->flags |= CAMEL_OPERATION_CANCELLED;
- cancelled = TRUE;
- } else
- cancelled = FALSE;
-
- UNLOCK();
-
- return cancelled;
-}
-
-/**
- * camel_operation_cancel_fd:
- * @cc: operation context
- *
- * Retrieve a file descriptor that can be waited on (select, or poll)
- * for read, to asynchronously detect cancellation.
- *
- * Return value: The fd, or -1 if cancellation is not available
- * (blocked, or has not been registered for this thread).
- **/
-int
-camel_operation_cancel_fd (CamelOperation *cc)
-{
- if (cc == NULL)
- cc = (CamelOperation *)pthread_getspecific(operation_key);
-
- if (cc == NULL || cc->blocked)
- return -1;
-
- LOCK();
-
- if (cc->cancel_fd == -1)
- cc->cancel_fd = e_msgport_fd(cc->cancel_port);
-
- UNLOCK();
-
- return cc->cancel_fd;
-}
-
-#ifdef HAVE_NSS
-/**
- * camel_operation_cancel_prfd:
- * @cc: operation context
- *
- * Retrieve a file descriptor that can be waited on (select, or poll)
- * for read, to asynchronously detect cancellation.
- *
- * Return value: The fd, or NULL if cancellation is not available
- * (blocked, or has not been registered for this thread).
- **/
-PRFileDesc *
-camel_operation_cancel_prfd (CamelOperation *cc)
-{
- if (cc == NULL)
- cc = (CamelOperation *)pthread_getspecific(operation_key);
-
- if (cc == NULL || cc->blocked)
- return NULL;
-
- LOCK();
-
- if (cc->cancel_prfd == NULL)
- cc->cancel_prfd = e_msgport_prfd(cc->cancel_port);
-
- UNLOCK();
-
- return cc->cancel_prfd;
-}
-#endif /* HAVE_NSS */
-
-/**
- * camel_operation_start:
- * @cc: operation context
- * @what: action being performed (printf-style format string)
- * @Varargs: varargs
- *
- * Report the start of an operation. All start operations should have
- * similar end operations.
- **/
-void
-camel_operation_start (CamelOperation *cc, char *what, ...)
-{
- va_list ap;
- char *msg;
- struct _status_stack *s;
-
- if (cc == NULL)
- cc = (CamelOperation *)pthread_getspecific(operation_key);
-
- if (cc == NULL)
- return;
-
- LOCK();
-
- if (cc->status == NULL) {
- UNLOCK();
- return;
- }
-
- va_start(ap, what);
- msg = g_strdup_vprintf(what, ap);
- va_end(ap);
- cc->status_update = 0;
- s = g_malloc0(sizeof(*s));
- s->msg = msg;
- s->flags = 0;
- cc->lastreport = s;
- cc->status_stack = g_slist_prepend(cc->status_stack, s);
-
- UNLOCK();
-
- cc->status(cc, msg, CAMEL_OPERATION_START, cc->status_data);
-
- d(printf("start '%s'\n", msg, pc));
-}
-
-/**
- * camel_operation_start_transient:
- * @cc: operation context
- * @what: printf-style format string describing the action being performed
- * @Varargs: varargs
- *
- * Start a transient event. We only update this to the display if it
- * takes very long to process, and if we do, we then go back to the
- * previous state when finished.
- **/
-void
-camel_operation_start_transient (CamelOperation *cc, char *what, ...)
-{
- va_list ap;
- char *msg;
- struct _status_stack *s;
-
- if (cc == NULL)
- cc = (CamelOperation *)pthread_getspecific(operation_key);
-
- if (cc == NULL || cc->status == NULL)
- return;
-
- LOCK();
-
- va_start(ap, what);
- msg = g_strdup_vprintf(what, ap);
- va_end(ap);
- cc->status_update = 0;
- s = g_malloc0(sizeof(*s));
- s->msg = msg;
- s->flags = CAMEL_OPERATION_TRANSIENT;
- s->stamp = stamp();
- cc->status_stack = g_slist_prepend(cc->status_stack, s);
- d(printf("start '%s'\n", msg, pc));
-
- UNLOCK();
-
- /* we dont report it yet */
- /*cc->status(cc, msg, CAMEL_OPERATION_START, cc->status_data);*/
-}
-
-static unsigned int stamp(void)
-{
- struct timeval tv;
-
- gettimeofday(&tv, NULL);
- /* update 4 times/second */
- return (tv.tv_sec * 4) + tv.tv_usec / (1000000/4);
-}
-
-/**
- * camel_operation_progress:
- * @cc: Operation to report to.
- * @pc: Percent complete, 0 to 100.
- *
- * Report progress on the current operation. If @cc is NULL, then the
- * currently registered operation is used. @pc reports the current
- * percentage of completion, which should be in the range of 0 to 100.
- *
- * If the total percentage is not know, then use
- * camel_operation_progress_count().
- **/
-void
-camel_operation_progress (CamelOperation *cc, int pc)
-{
- unsigned int now;
- struct _status_stack *s;
- char *msg = NULL;
-
- if (cc == NULL)
- cc = (CamelOperation *)pthread_getspecific(operation_key);
-
- if (cc == NULL)
- return;
-
- LOCK();
-
- if (cc->status == NULL || cc->status_stack == NULL) {
- UNLOCK();
- return;
- }
-
- s = cc->status_stack->data;
- s->pc = pc;
-
- /* Transient messages dont start updating till 4 seconds after
- they started, then they update every second */
- now = stamp();
- if (cc->status_update == now) {
- cc = NULL;
- } else if (s->flags & CAMEL_OPERATION_TRANSIENT) {
- if (s->stamp + CAMEL_OPERATION_TRANSIENT_DELAY > now) {
- cc = NULL;
- } else {
- cc->status_update = now;
- cc->lastreport = s;
- msg = g_strdup(s->msg);
- }
- } else {
- s->stamp = cc->status_update = now;
- cc->lastreport = s;
- msg = g_strdup(s->msg);
- }
-
- UNLOCK();
-
- if (cc) {
- cc->status(cc, msg, pc, cc->status_data);
- g_free(msg);
- }
-}
-
-/**
- * camel_operation_progress_count:
- * @cc: operation context
- * @sofar:
- *
- **/
-void
-camel_operation_progress_count (CamelOperation *cc, int sofar)
-{
- camel_operation_progress(cc, sofar);
-}
-
-/**
- * camel_operation_end:
- * @cc: operation context
- * @what: Format string.
- * @Varargs: varargs
- *
- * Report the end of an operation. If @cc is NULL, then the currently
- * registered operation is notified.
- **/
-void
-camel_operation_end (CamelOperation *cc)
-{
- struct _status_stack *s, *p;
- unsigned int now;
- char *msg = NULL;
- int pc = 0;
-
- if (cc == NULL)
- cc = (CamelOperation *)pthread_getspecific(operation_key);
-
- if (cc == NULL)
- return;
-
- LOCK();
-
- if (cc->status == NULL || cc->status_stack == NULL) {
- UNLOCK();
- return;
- }
-
- /* so what we do here is this. If the operation that just
- * ended was transient, see if we have any other transient
- * messages that haven't been updated yet above us, otherwise,
- * re-update as a non-transient at the last reported pc */
- now = stamp();
- s = cc->status_stack->data;
- if (s->flags & CAMEL_OPERATION_TRANSIENT) {
- if (cc->lastreport == s) {
- GSList *l = cc->status_stack->next;
- while (l) {
- p = l->data;
- if (p->flags & CAMEL_OPERATION_TRANSIENT) {
- if (p->stamp + CAMEL_OPERATION_TRANSIENT_DELAY < now) {
- msg = g_strdup(p->msg);
- pc = p->pc;
- cc->lastreport = p;
- break;
- }
- } else {
- msg = g_strdup(p->msg);
- pc = p->pc;
- cc->lastreport = p;
- break;
- }
- l = l->next;
- }
- }
- g_free(s->msg);
- } else {
- msg = s->msg;
- pc = CAMEL_OPERATION_END;
- cc->lastreport = s;
- }
- g_free(s);
- cc->status_stack = g_slist_remove_link(cc->status_stack, cc->status_stack);
-
- UNLOCK();
-
- if (msg) {
- cc->status(cc, msg, pc, cc->status_data);
- g_free(msg);
- }
-}