thr_once.c revision 153496
12116Sjkh/*
22116Sjkh * Copyright (c) 2005, David Xu <davidxu@freebsd.org>
32116Sjkh * All rights reserved.
42116Sjkh *
52116Sjkh * Redistribution and use in source and binary forms, with or without
62116Sjkh * modification, are permitted provided that the following conditions
72116Sjkh * are met:
82116Sjkh * 1. Redistributions of source code must retain the above copyright
92116Sjkh *    notice unmodified, this list of conditions, and the following
102116Sjkh *    disclaimer.
118870Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
122116Sjkh *    notice, this list of conditions and the following disclaimer in the
132116Sjkh *    documentation and/or other materials provided with the distribution.
142116Sjkh *
152116Sjkh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
162116Sjkh * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
178870Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
182116Sjkh * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
192116Sjkh * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
202116Sjkh * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
212116Sjkh * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
222116Sjkh * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
232116Sjkh * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
242116Sjkh * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
252116Sjkh *
262116Sjkh * $FreeBSD: head/lib/libthr/thread/thr_once.c 153496 2005-12-17 09:42:45Z davidxu $
272116Sjkh *
282116Sjkh */
292116Sjkh
302116Sjkh#include "namespace.h"
312116Sjkh#include <pthread.h>
322116Sjkh#include "un-namespace.h"
332116Sjkh
342116Sjkh#include "thr_private.h"
352116Sjkh
362116Sjkh__weak_reference(_pthread_once, pthread_once);
372116Sjkh
382116Sjkh#define ONCE_NEVER_DONE		PTHREAD_NEEDS_INIT
392116Sjkh#define ONCE_DONE		PTHREAD_DONE_INIT
40#define	ONCE_IN_PROGRESS	0x02
41#define	ONCE_MASK		0x03
42
43static pthread_mutex_t		once_lock = PTHREAD_MUTEX_INITIALIZER;
44static pthread_cond_t		once_cv = PTHREAD_COND_INITIALIZER;
45
46/*
47 * POSIX:
48 * The pthread_once() function is not a cancellation point. However,
49 * if init_routine is a cancellation point and is canceled, the effect
50 * on once_control shall be as if pthread_once() was never called.
51 */
52
53static void
54once_cancel_handler(void *arg)
55{
56	pthread_once_t *once_control = arg;
57
58	_pthread_mutex_lock(&once_lock);
59	once_control->state = ONCE_NEVER_DONE;
60	_pthread_mutex_unlock(&once_lock);
61	_pthread_cond_broadcast(&once_cv);
62}
63
64int
65_pthread_once(pthread_once_t *once_control, void (*init_routine) (void))
66{
67	int wakeup = 0;
68
69	if (once_control->state == ONCE_DONE)
70		return (0);
71	_pthread_mutex_lock(&once_lock);
72	while (*(volatile int *)&(once_control->state) == ONCE_IN_PROGRESS)
73		_pthread_cond_wait(&once_cv, &once_lock);
74	/*
75	 * If previous thread was canceled, then the state still
76	 * could be ONCE_NEVER_DONE, we need to check it again.
77	 */
78	if (*(volatile int *)&(once_control->state) == ONCE_NEVER_DONE) {
79		once_control->state = ONCE_IN_PROGRESS;
80		_pthread_mutex_unlock(&once_lock);
81		_pthread_cleanup_push(once_cancel_handler, once_control);
82		init_routine();
83		_pthread_cleanup_pop(0);
84		_pthread_mutex_lock(&once_lock);
85		once_control->state = ONCE_DONE;
86		wakeup = 1;
87	}
88	_pthread_mutex_unlock(&once_lock);
89	if (wakeup)
90		_pthread_cond_broadcast(&once_cv);
91	return (0);
92}
93
94