--- glib-1.3.13.org/glib/gthread.h	Wed Sep 19 14:46:39 2001
+++ glib-1.3.13/glib/gthread.h	Mon Feb 18 23:06:21 2002
@@ -179,6 +179,17 @@
           (cond, mutex, abs_time, G_MUTEX_DEBUG_MAGIC, G_STRLOC) : TRUE)
 #endif /* G_ERRORCHECK_MUTEXES */
 
+#define G_THREAD_ONCE_INIT (0)
+typedef volatile unsigned GThreadOnce;
+typedef void (* GThreadOnceFunction) (void);
+void g_thread_once_real (GThreadOnce *, GThreadOnceFunction);
+#define g_thread_once(o, f) \
+	G_STMT_START { \
+	       if (2 != (o)) \
+		       g_thread_once_real (&(o), (f)); \
+	} G_STMT_END
+
+
 #define g_thread_supported()    (g_threads_got_initialized)
 #define g_mutex_new()            G_THREAD_UF (mutex_new,      ())
 #define g_cond_new()             G_THREAD_UF (cond_new,       ())
--- glib-1.3.13.org/glib/gthread.c	Wed Sep 19 14:46:39 2001
+++ glib-1.3.13/glib/gthread.c	Mon Feb 18 23:13:45 2002
@@ -65,6 +65,11 @@
    g_thread_functions_for_glib_use.thread_equal (&(thread1), &(thread2)) :\
    g_system_thread_equal_simple((thread1), (thread2)))
 
+enum {
+	G_ONCE_INPROGRESS = 1,
+	G_ONCE_INITIALIZED = 2
+};
+
 GQuark 
 g_thread_error_quark (void)
 {
@@ -150,6 +155,8 @@
 static GPrivate *g_thread_specific_private = NULL;
 static GSList   *g_thread_all_threads = NULL;
 static GSList   *g_thread_free_indeces = NULL;
+static GMutex   *g_mutex_once = NULL;
+static GCond    *g_cond_once = NULL;
 
 G_LOCK_DEFINE_STATIC (g_thread);
 
@@ -171,6 +178,9 @@
   G_THREAD_UF (thread_self, (&main_thread->system_thread));
 
   g_mutex_protect_static_mutex_allocation = g_mutex_new ();
+
+  g_mutex_once = g_mutex_new ();
+  g_cond_once  = g_cond_new ();
 }
 
 void 
@@ -821,3 +831,30 @@
     }
   g_static_mutex_free (&lock->mutex);
 }
+
+void g_thread_once_real (GThreadOnce *once, GThreadOnceFunction once_func)
+{
+	g_return_if_fail (once);
+	g_return_if_fail (once_func);
+
+	if (G_ONCE_INITIALIZED == *once)
+		return;
+
+	g_mutex_lock (g_mutex_once);
+	while (G_ONCE_INPROGRESS == *once)
+		g_cond_wait (g_cond_once, g_mutex_once);
+	if (G_ONCE_INITIALIZED == *once) {
+		g_mutex_unlock (g_mutex_once);
+		return;
+	}
+	*once = G_ONCE_INPROGRESS;
+	g_mutex_unlock (g_mutex_once);
+
+	(* once_func) ();
+
+	g_mutex_lock (g_mutex_once);
+	*once = G_ONCE_INITIALIZED;
+	g_cond_broadcast (g_cond_once);
+	g_mutex_unlock (g_mutex_once);
+}
+
--- glib-1.3.13.org/tests/thread-test.c	Fri May 18 10:44:57 2001
+++ glib-1.3.13/tests/thread-test.c	Tue Feb 19 00:18:53 2002
@@ -276,14 +276,154 @@
   g_assert (test_g_static_rw_lock_state == 0);
 }
 
+
+enum { ONCE_SIZE = 20 };
+static struct
+{
+	GThreadOnce	once;
+	unsigned	cnt;
+} test_g_thread_once_cb[ONCE_SIZE];
+
+#define DEFINE_TEST_G_THREAD_ONCE_INIT_FUNC(x) \
+static void \
+test_g_thread_once_init_func_ ## x (void) \
+{ \
+	g_thread_yield (); \
+	test_g_thread_once_cb[x].cnt += 1; \
+	g_thread_yield (); \
+}
+
+DEFINE_TEST_G_THREAD_ONCE_INIT_FUNC(0)
+DEFINE_TEST_G_THREAD_ONCE_INIT_FUNC(1)
+DEFINE_TEST_G_THREAD_ONCE_INIT_FUNC(2)
+DEFINE_TEST_G_THREAD_ONCE_INIT_FUNC(3)
+DEFINE_TEST_G_THREAD_ONCE_INIT_FUNC(4)
+DEFINE_TEST_G_THREAD_ONCE_INIT_FUNC(5)
+DEFINE_TEST_G_THREAD_ONCE_INIT_FUNC(6)
+DEFINE_TEST_G_THREAD_ONCE_INIT_FUNC(7)
+DEFINE_TEST_G_THREAD_ONCE_INIT_FUNC(8)
+DEFINE_TEST_G_THREAD_ONCE_INIT_FUNC(9)
+DEFINE_TEST_G_THREAD_ONCE_INIT_FUNC(10)
+DEFINE_TEST_G_THREAD_ONCE_INIT_FUNC(11)
+DEFINE_TEST_G_THREAD_ONCE_INIT_FUNC(12)
+DEFINE_TEST_G_THREAD_ONCE_INIT_FUNC(13)
+DEFINE_TEST_G_THREAD_ONCE_INIT_FUNC(14)
+DEFINE_TEST_G_THREAD_ONCE_INIT_FUNC(15)
+DEFINE_TEST_G_THREAD_ONCE_INIT_FUNC(16)
+DEFINE_TEST_G_THREAD_ONCE_INIT_FUNC(17)
+DEFINE_TEST_G_THREAD_ONCE_INIT_FUNC(18)
+DEFINE_TEST_G_THREAD_ONCE_INIT_FUNC(19)
+
+#define TEST_G_THREAD_ONCE_CALL(x) \
+	g_thread_once (test_g_thread_once_cb[x].once, test_g_thread_once_init_func_ ## x)
+
+static gpointer
+test_g_thread_once_thread_inc (gpointer data)
+{
+	TEST_G_THREAD_ONCE_CALL(0);
+	TEST_G_THREAD_ONCE_CALL(1);
+	TEST_G_THREAD_ONCE_CALL(2);
+	TEST_G_THREAD_ONCE_CALL(3);
+	TEST_G_THREAD_ONCE_CALL(4);
+	TEST_G_THREAD_ONCE_CALL(5);
+	TEST_G_THREAD_ONCE_CALL(6);
+	TEST_G_THREAD_ONCE_CALL(7);
+	TEST_G_THREAD_ONCE_CALL(8);
+	TEST_G_THREAD_ONCE_CALL(9);
+	TEST_G_THREAD_ONCE_CALL(10);
+	TEST_G_THREAD_ONCE_CALL(11);
+	TEST_G_THREAD_ONCE_CALL(12);
+	TEST_G_THREAD_ONCE_CALL(13);
+	TEST_G_THREAD_ONCE_CALL(14);
+	TEST_G_THREAD_ONCE_CALL(15);
+	TEST_G_THREAD_ONCE_CALL(16);
+	TEST_G_THREAD_ONCE_CALL(17);
+	TEST_G_THREAD_ONCE_CALL(18);
+	TEST_G_THREAD_ONCE_CALL(19);
+
+	return NULL;
+}
+
+
+static gpointer
+test_g_thread_once_thread_dec (gpointer data)
+{
+	TEST_G_THREAD_ONCE_CALL(19);
+	TEST_G_THREAD_ONCE_CALL(18);
+	TEST_G_THREAD_ONCE_CALL(17);
+	TEST_G_THREAD_ONCE_CALL(16);
+	TEST_G_THREAD_ONCE_CALL(15);
+	TEST_G_THREAD_ONCE_CALL(14);
+	TEST_G_THREAD_ONCE_CALL(13);
+	TEST_G_THREAD_ONCE_CALL(12);
+	TEST_G_THREAD_ONCE_CALL(11);
+	TEST_G_THREAD_ONCE_CALL(10);
+	TEST_G_THREAD_ONCE_CALL(9);
+	TEST_G_THREAD_ONCE_CALL(8);
+	TEST_G_THREAD_ONCE_CALL(7);
+	TEST_G_THREAD_ONCE_CALL(6);
+	TEST_G_THREAD_ONCE_CALL(5);
+	TEST_G_THREAD_ONCE_CALL(4);
+	TEST_G_THREAD_ONCE_CALL(3);
+	TEST_G_THREAD_ONCE_CALL(2);
+	TEST_G_THREAD_ONCE_CALL(1);
+	TEST_G_THREAD_ONCE_CALL(0);
+
+	return NULL;
+}
+
+
+static void
+test_g_thread_once (void)
+{
+	gsize idx;
+	GThread *t1, *t2, *t3, *t4, *t5, *t6;
+
+	for (idx = 0; idx < ONCE_SIZE; ++idx) {
+		test_g_thread_once_cb[idx].once = G_THREAD_ONCE_INIT;
+		test_g_thread_once_cb[idx].cnt  = 0;
+	}
+
+	t1 = g_thread_create (& test_g_thread_once_thread_inc, NULL, TRUE, NULL);
+	t2 = g_thread_create (& test_g_thread_once_thread_dec, NULL, TRUE, NULL);
+	t3 = g_thread_create (& test_g_thread_once_thread_inc, NULL, TRUE, NULL);
+	t4 = g_thread_create (& test_g_thread_once_thread_dec, NULL, TRUE, NULL);
+	t5 = g_thread_create (& test_g_thread_once_thread_inc, NULL, TRUE, NULL);
+	t6 = g_thread_create (& test_g_thread_once_thread_dec, NULL, TRUE, NULL);
+
+	g_thread_join (t1);
+	g_thread_join (t2);
+	g_thread_join (t3);
+	g_thread_join (t4);
+	g_thread_join (t5);
+	g_thread_join (t6);
+
+	for (idx = 0; idx < ONCE_SIZE; ++idx) {
+		g_assert (1 == test_g_thread_once_cb[idx].cnt);
+	}
+}
+
+
+void (* all_tests[])(void) =
+{
+	&test_g_mutex,
+	&test_g_static_rec_mutex,
+	&test_g_static_private,
+	&test_g_static_rw_lock,
+	&test_g_thread_once
+};
+
 /* run all the tests */
 void
 run_all_tests()
 {
-  test_g_mutex ();
-  test_g_static_rec_mutex ();
-  test_g_static_private ();
-  test_g_static_rw_lock ();
+	gsize idx;
+
+	for (idx = 0; idx < G_N_ELEMENTS(all_tests); ++idx) {
+		(* all_tests[idx]) ();
+		g_print (".");
+	}
+	g_print ("\n");
 }
 
 int 
