thr_once.c revision 297706
172445Sassar/*
272445Sassar * Copyright (c) 2005, David Xu <davidxu@freebsd.org>
372445Sassar * All rights reserved.
472445Sassar *
572445Sassar * Redistribution and use in source and binary forms, with or without
672445Sassar * modification, are permitted provided that the following conditions
772445Sassar * are met:
872445Sassar * 1. Redistributions of source code must retain the above copyright
972445Sassar *    notice unmodified, this list of conditions, and the following
1072445Sassar *    disclaimer.
1172445Sassar * 2. Redistributions in binary form must reproduce the above copyright
1272445Sassar *    notice, this list of conditions and the following disclaimer in the
1372445Sassar *    documentation and/or other materials provided with the distribution.
1472445Sassar *
1572445Sassar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1672445Sassar * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1772445Sassar * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1872445Sassar * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1972445Sassar * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2072445Sassar * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2172445Sassar * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2272445Sassar * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2372445Sassar * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2472445Sassar * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2572445Sassar */
2672445Sassar
2772445Sassar#include <sys/cdefs.h>
2872445Sassar__FBSDID("$FreeBSD: head/lib/libthr/thread/thr_once.c 297706 2016-04-08 11:15:26Z kib $");
2972445Sassar
3072445Sassar#include "namespace.h"
3172445Sassar#include <pthread.h>
3272445Sassar#include "un-namespace.h"
3372445Sassar
3472445Sassar#include "thr_private.h"
3572445Sassar
3672445Sassar__weak_reference(_pthread_once, pthread_once);
3772445Sassar
3872445Sassar#define ONCE_NEVER_DONE		PTHREAD_NEEDS_INIT
3972445Sassar#define ONCE_DONE		PTHREAD_DONE_INIT
4072445Sassar#define	ONCE_IN_PROGRESS	0x02
4172445Sassar#define ONCE_WAIT		0x03
4272445Sassar
4372445Sassar/*
4472445Sassar * POSIX:
4572445Sassar * The pthread_once() function is not a cancellation point. However,
46178825Sdfr * if init_routine is a cancellation point and is canceled, the effect
4772445Sassar * on once_control shall be as if pthread_once() was never called.
4872445Sassar */
4972445Sassar
5072445Sassarstatic void
5172445Sassaronce_cancel_handler(void *arg)
5272445Sassar{
5372445Sassar	pthread_once_t *once_control;
5472445Sassar
5572445Sassar	once_control = arg;
5672445Sassar	if (atomic_cmpset_rel_int(&once_control->state, ONCE_IN_PROGRESS,
5772445Sassar	    ONCE_NEVER_DONE))
5872445Sassar		return;
5972445Sassar	atomic_store_rel_int(&once_control->state, ONCE_NEVER_DONE);
6072445Sassar	_thr_umtx_wake(&once_control->state, INT_MAX, 0);
6172445Sassar}
6272445Sassar
6372445Sassarint
6472445Sassar_pthread_once(pthread_once_t *once_control, void (*init_routine) (void))
6572445Sassar{
6672445Sassar	struct pthread *curthread;
6772445Sassar	int state;
6872445Sassar
6972445Sassar	_thr_check_init();
7072445Sassar
7172445Sassar	for (;;) {
7272445Sassar		state = once_control->state;
7372445Sassar		if (state == ONCE_DONE) {
7472445Sassar			atomic_thread_fence_acq();
7572445Sassar			return (0);
7672445Sassar		}
7772445Sassar		if (state == ONCE_NEVER_DONE) {
7872445Sassar			if (atomic_cmpset_int(&once_control->state, state,
7972445Sassar			    ONCE_IN_PROGRESS))
8072445Sassar				break;
8172445Sassar		} else if (state == ONCE_IN_PROGRESS) {
8272445Sassar			if (atomic_cmpset_int(&once_control->state, state,
8372445Sassar			    ONCE_WAIT))
84178825Sdfr				_thr_umtx_wait_uint(&once_control->state,
8572445Sassar				    ONCE_WAIT, NULL, 0);
86178825Sdfr		} else if (state == ONCE_WAIT) {
8772445Sassar			_thr_umtx_wait_uint(&once_control->state, state,
8872445Sassar			    NULL, 0);
8972445Sassar		} else
9072445Sassar			return (EINVAL);
9172445Sassar        }
9272445Sassar
9372445Sassar	curthread = _get_curthread();
9472445Sassar	THR_CLEANUP_PUSH(curthread, once_cancel_handler, once_control);
9572445Sassar	init_routine();
9672445Sassar	THR_CLEANUP_POP(curthread, 0);
9772445Sassar	if (atomic_cmpset_rel_int(&once_control->state, ONCE_IN_PROGRESS,
9872445Sassar	    ONCE_DONE))
9972445Sassar		return (0);
10072445Sassar	atomic_store_rel_int(&once_control->state, ONCE_DONE);
10172445Sassar	_thr_umtx_wake(&once_control->state, INT_MAX, 0);
10272445Sassar	return (0);
10372445Sassar}
10472445Sassar
10572445Sassarvoid
10672445Sassar_thr_once_init(void)
10772445Sassar{
10872445Sassar}
10972445Sassar