Index: docs/reference/libedataserver/libedataserver-sections.txt
===================================================================
--- docs/reference/libedataserver/libedataserver-sections.txt	(revision 7644)
+++ docs/reference/libedataserver/libedataserver-sections.txt	(working copy)
@@ -83,6 +83,19 @@ E_IS_FILE_CACHE_CLASS
 </SECTION>
 
 <SECTION>
+<FILE>e-flag</FILE>
+<TITLE>EFlag</TITLE>
+EFlag
+e_flag_new
+e_flag_is_set
+e_flag_set
+e_flag_clear
+e_flag_wait
+e_flag_timed_wait
+e_flag_free
+</SECTION>
+
+<SECTION>
 <FILE>e-iterator</FILE>
 <TITLE>EIterator</TITLE>
 e_iterator_get
Index: docs/reference/libedataserver/libedataserver-docs.sgml
===================================================================
--- docs/reference/libedataserver/libedataserver-docs.sgml	(revision 7644)
+++ docs/reference/libedataserver/libedataserver-docs.sgml	(working copy)
@@ -16,6 +16,7 @@
     <xi:include href="xml/e-db3-utils.xml"/>
     <xi:include href="xml/e-dbhash.xml"/>
     <xi:include href="xml/e-file-cache.xml"/>
+    <xi:include href="xml/e-flag.xml"/>
     <xi:include href="xml/e-iconv.xml"/>
     <xi:include href="xml/e-iterator.xml"/>
     <xi:include href="xml/e-list-iterator.xml"/>
Index: docs/reference/libedataserver/tmpl/e-flag.sgml
===================================================================
--- docs/reference/libedataserver/tmpl/e-flag.sgml	(revision 0)
+++ docs/reference/libedataserver/tmpl/e-flag.sgml	(revision 0)
@@ -0,0 +1,89 @@
+<!-- ##### SECTION Title ##### -->
+EFlag
+
+<!-- ##### SECTION Short_Description ##### -->
+Simple thread synchronization
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+An #EFlag is a simple thread synchronization mechanism. It implements a
+thread-safe flag that can be blocked on.
+</para>
+
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### STRUCT EFlag ##### -->
+<para>
+The <structname>EFlag</structname> struct is an opaque data structure
+representing a thread-safe flag.  It should be accessed only by using
+the following functions.
+</para>
+
+
+<!-- ##### FUNCTION e_flag_new ##### -->
+<para>
+
+</para>
+
+@Returns: 
+
+
+<!-- ##### FUNCTION e_flag_is_set ##### -->
+<para>
+
+</para>
+
+@flag: 
+@Returns: 
+
+
+<!-- ##### FUNCTION e_flag_set ##### -->
+<para>
+
+</para>
+
+@flag: 
+
+
+<!-- ##### FUNCTION e_flag_clear ##### -->
+<para>
+
+</para>
+
+@flag: 
+
+
+<!-- ##### FUNCTION e_flag_wait ##### -->
+<para>
+
+</para>
+
+@flag: 
+
+
+<!-- ##### FUNCTION e_flag_timed_wait ##### -->
+<para>
+
+</para>
+
+@flag: 
+@abs_time: 
+@Returns: 
+
+
+<!-- ##### FUNCTION e_flag_free ##### -->
+<para>
+
+</para>
+
+@flag: 
+
+
Index: libedataserver/e-flag.h
===================================================================
--- libedataserver/e-flag.h	(revision 0)
+++ libedataserver/e-flag.h	(revision 0)
@@ -0,0 +1,43 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* 
+ * Copyright (C) 2007 Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 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.
+ */
+
+#ifndef E_FLAG_H
+#define E_FLAG_H
+
+/* An EFlag is essentially a binary semaphore with a more intuitive interface.
+ * Based on Python's threading.Event class ("EEvent" was already taken). */
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _EFlag EFlag;
+
+EFlag *		e_flag_new			(void);
+gboolean	e_flag_is_set			(EFlag *flag);
+void		e_flag_set			(EFlag *flag);
+void		e_flag_clear			(EFlag *flag);
+void		e_flag_wait			(EFlag *flag);
+gboolean	e_flag_timed_wait		(EFlag *flag,
+						 GTimeVal *abs_time);
+void		e_flag_free			(EFlag *flag);
+
+G_END_DECLS
+
+#endif /* E_FLAG_H */
Index: libedataserver/Makefile.am
===================================================================
--- libedataserver/Makefile.am	(revision 7644)
+++ libedataserver/Makefile.am	(working copy)
@@ -26,6 +26,7 @@ libedataserver_1_2_la_SOURCES =		\
 	e-dbhash.c			\
 	e-db3-utils.c			\
 	e-file-cache.c			\
+	e-flag.c			\
 	e-iconv.c			\
 	e-iterator.c			\
 	e-list.c			\
@@ -66,6 +67,7 @@ libedataserverinclude_HEADERS =		\
 	e-db3-utils.h			\
 	e-dbhash.h			\
 	e-file-cache.h			\
+	e-flag.h			\
 	e-iconv.h			\
 	e-iterator.h			\
 	e-list.h			\
Index: libedataserver/e-flag.c
===================================================================
--- libedataserver/e-flag.c	(revision 0)
+++ libedataserver/e-flag.c	(revision 0)
@@ -0,0 +1,171 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* 
+ * Copyright (C) 2007 Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 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.
+ */
+
+#include "e-flag.h"
+
+struct _EFlag {
+	GCond *cond;
+	GMutex *mutex;
+	gboolean is_set;
+};
+
+/**
+ * e_flag_new:
+ *
+ * Creates a new #EFlag object.  It is initially unset.
+ *
+ * Returns: a new #EFlag
+ **/
+EFlag *
+e_flag_new (void)
+{
+	EFlag *flag;
+
+	flag = g_slice_new (EFlag);
+	flag->cond = g_cond_new ();
+	flag->mutex = g_mutex_new ();
+	flag->is_set = FALSE;
+
+	return flag;
+}
+
+/**
+ * e_flag_is_set:
+ * @flag: an #EFlag
+ *
+ * Returns the state of @flag.
+ *
+ * Returns: %TRUE if @flag is set
+ **/
+gboolean
+e_flag_is_set (EFlag *flag)
+{
+	gboolean is_set;
+
+	g_return_val_if_fail (flag != NULL, FALSE);
+
+	g_mutex_lock (flag->mutex);
+	is_set = flag->is_set;
+	g_mutex_unlock (flag->mutex);
+
+	return is_set;
+}
+
+/**
+ * e_flag_set:
+ * @flag: an #EFlag
+ *
+ * Sets @flag.  All threads waiting on @flag are woken up.  Threads that
+ * call e_flag_wait() or e_flag_timed_wait() once @flag is set will not
+ * block at all.
+ **/
+void
+e_flag_set (EFlag *flag)
+{
+	g_return_if_fail (flag != NULL);
+
+	g_mutex_lock (flag->mutex);
+	flag->is_set = TRUE;
+	g_cond_broadcast (flag->cond);
+	g_mutex_unlock (flag->mutex);
+}
+
+/**
+ * e_flag_clear:
+ * @flag: an #EFlag
+ *
+ * Unsets @flag.  Subsequent calls to e_flag_wait() or e_flag_timed_wait()
+ * will block until @flag is set.
+ **/
+void
+e_flag_clear (EFlag *flag)
+{
+	g_return_if_fail (flag != NULL);
+
+	g_mutex_lock (flag->mutex);
+	flag->is_set = FALSE;
+	g_mutex_unlock (flag->mutex);
+}
+
+/**
+ * e_flag_wait:
+ * @flag: an #EFlag
+ *
+ * Blocks until @flag is set.  If @flag is already set, the function returns
+ * immediately.
+ **/
+void
+e_flag_wait (EFlag *flag)
+{
+	g_return_if_fail (flag != NULL);
+
+	g_mutex_lock (flag->mutex);
+	while (!flag->is_set)
+		g_cond_wait (flag->cond, flag->mutex);
+	g_mutex_unlock (flag->mutex);
+}
+
+/**
+ * e_flag_timed_wait:
+ * @flag: an #EFlag
+ * @abs_time: a #GTimeVal, determining the final time
+ *
+ * Blocks until @flag is set, or until the time specified by @abs_time.
+ * If @flag is already set, the function returns immediately.  The return
+ * value indicates the state of @flag after waiting.
+ *
+ * If @abs_time is %NULL, e_flag_timed_wait() acts like e_flag_wait().
+ *
+ * To easily calculate @abs_time, a combination of g_get_current_time() and
+ * g_time_val_add() can be used.
+ *
+ * Returns: %TRUE if @flag is now set
+ **/
+gboolean
+e_flag_timed_wait (EFlag *flag, GTimeVal *abs_time)
+{
+	gboolean is_set;
+
+	g_return_val_if_fail (flag != NULL, FALSE);
+
+	g_mutex_lock (flag->mutex);
+	while (!flag->is_set)
+		if (!g_cond_timed_wait (flag->cond, flag->mutex, abs_time))
+			break;
+	is_set = flag->is_set;
+	g_mutex_unlock (flag->mutex);
+
+	return is_set;
+}
+
+/**
+ * e_flag_free:
+ * @flag: an #EFlag
+ *
+ * Destroys @flag.
+ **/
+void
+e_flag_free (EFlag *flag)
+{
+	g_return_if_fail (flag != NULL);
+
+	g_cond_free (flag->cond);
+	g_mutex_free (flag->mutex);
+	g_slice_free (EFlag, flag);
+}
