Using pthread_once() in libc

John Baldwin jhb at freebsd.org
Thu Nov 19 17:06:45 UTC 2009


On Thursday 19 November 2009 12:02:30 pm John Baldwin wrote:
> On Thursday 19 November 2009 11:48:54 am Daniel Eischen wrote:
> > On Thu, 19 Nov 2009, John Baldwin wrote:
> > 
> > > I would like to provide a pthread_once()-like facility in libc that library
> > > bits can use to initialize data safely rather than trying to home-roll their
> > > own variants (see the recent commit to stdtime in libc).  Ideally what I
> > > would like to do is have libc use the "real" pthread_once() when libthr is
> > > linked in and fall back to a simple stub without libthr linked in.  I know we
> > > already do something like this for _spinlock() and friends.  My question is
> > > what is the most correct way to do this?  Should libc grow a new _once()
> > > symbol ala _spinlock() that is a weak symbol to a stub version and
> > > pthread_once() in thr_once.c would override that, or should there be a
> > > _pthread_once() in libc that is a stub in place of the current stub_zero?  I
> > > noticed a comment in thr_spinlock.c saying the spinlock stuff is kept for
> > > backwards compat.  Does this mean that for the future we would like to expose
> > > pthread symbols directly in libc?  Meaning would we rather have libc export a
> > > pthread_once() and that ideally libc would be using pthread_mutex_lock/unlock
> > > instead of _spinlock/unlock?
> > 
> > pthread_once() is already a stub in libc that gets overloaded with the
> > real thing when libthr is linked.  See libc/gen/_pthread_stubs.c.
> > Isn't that what you want or does it not serve your purpose?
> 
> Hmm, the libc stub will never run the init routine.  I would like to do
> something like this:

Perhaps this would work to fix pthread_once:

Index: gen/_pthread_stubs.c
===================================================================
--- gen/_pthread_stubs.c	(revision 199529)
+++ gen/_pthread_stubs.c	(working copy)
@@ -51,6 +51,8 @@
 
 static int		stub_main(void);
 static void 		*stub_null(void);
+static int		stub_once(pthread_once_t *once_control,
+			    void (*init_routine)(void));
 static struct pthread	*stub_self(void);
 static int		stub_zero(void);
 static int		stub_true(void);
@@ -105,7 +107,7 @@
 	{PJT_DUAL_ENTRY(stub_zero)},    /* PJT_MUTEX_LOCK */
 	{PJT_DUAL_ENTRY(stub_zero)},    /* PJT_MUTEX_TRYLOCK */
 	{PJT_DUAL_ENTRY(stub_zero)},    /* PJT_MUTEX_UNLOCK */
-	{PJT_DUAL_ENTRY(stub_zero)},    /* PJT_ONCE */
+	{PJT_DUAL_ENTRY(stub_once)},    /* PJT_ONCE */
 	{PJT_DUAL_ENTRY(stub_zero)},    /* PJT_RWLOCK_DESTROY */
 	{PJT_DUAL_ENTRY(stub_zero)},    /* PJT_RWLOCK_INIT */
 	{PJT_DUAL_ENTRY(stub_zero)},    /* PJT_RWLOCK_RDLOCK */
@@ -301,3 +303,14 @@
 {
 	exit(0);
 }
+
+static int
+stub_once(pthread_once_t *once_control, void (*init_routine)(void))
+{
+
+	if (once_control->state == ONCE_DONE)
+		return (0);
+	init_routine();
+	once_control->state = ONCE_DONE;
+	return (0);
+}

-- 
John Baldwin


More information about the freebsd-threads mailing list