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