thr_once.c revision 144518
1112918Sjeff/* 2112918Sjeff * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. 3112918Sjeff * All rights reserved. 4112918Sjeff * 5112918Sjeff * Redistribution and use in source and binary forms, with or without 6112918Sjeff * modification, are permitted provided that the following conditions 7112918Sjeff * are met: 8112918Sjeff * 1. Redistributions of source code must retain the above copyright 9112918Sjeff * notice, this list of conditions and the following disclaimer. 10112918Sjeff * 2. Redistributions in binary form must reproduce the above copyright 11112918Sjeff * notice, this list of conditions and the following disclaimer in the 12112918Sjeff * documentation and/or other materials provided with the distribution. 13112918Sjeff * 3. All advertising materials mentioning features or use of this software 14112918Sjeff * must display the following acknowledgement: 15112918Sjeff * This product includes software developed by John Birrell. 16112918Sjeff * 4. Neither the name of the author nor the names of any co-contributors 17112918Sjeff * may be used to endorse or promote products derived from this software 18112918Sjeff * without specific prior written permission. 19112918Sjeff * 20112918Sjeff * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 21112918Sjeff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22112918Sjeff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23112918Sjeff * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24112918Sjeff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25112918Sjeff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26112918Sjeff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27112918Sjeff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28112918Sjeff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29112918Sjeff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30112918Sjeff * SUCH DAMAGE. 31112918Sjeff * 32112918Sjeff * $FreeBSD: head/lib/libthr/thread/thr_once.c 144518 2005-04-02 01:20:00Z davidxu $ 33112918Sjeff */ 34144518Sdavidxu 35144518Sdavidxu#include "namespace.h" 36112918Sjeff#include <pthread.h> 37144518Sdavidxu#include "un-namespace.h" 38144518Sdavidxu 39112918Sjeff#include "thr_private.h" 40112918Sjeff 41112918Sjeff__weak_reference(_pthread_once, pthread_once); 42112918Sjeff 43144518Sdavidxu#define ONCE_NEVER_DONE PTHREAD_NEEDS_INIT 44144518Sdavidxu#define ONCE_DONE PTHREAD_DONE_INIT 45144518Sdavidxu#define ONCE_IN_PROGRESS 0x02 46144518Sdavidxu#define ONCE_MASK 0x03 47144518Sdavidxu 48144518Sdavidxustatic pthread_mutex_t once_lock = PTHREAD_MUTEX_INITIALIZER; 49144518Sdavidxustatic pthread_cond_t once_cv = PTHREAD_COND_INITIALIZER; 50144518Sdavidxu 51144518Sdavidxu/* 52144518Sdavidxu * POSIX: 53144518Sdavidxu * The pthread_once() function is not a cancellation point. However, 54144518Sdavidxu * if init_routine is a cancellation point and is canceled, the effect 55144518Sdavidxu * on once_control shall be as if pthread_once() was never called. 56144518Sdavidxu */ 57144518Sdavidxu 58144518Sdavidxustatic void 59144518Sdavidxuonce_cancel_handler(void *arg) 60144518Sdavidxu{ 61144518Sdavidxu pthread_once_t *once_control = arg; 62144518Sdavidxu 63144518Sdavidxu _pthread_mutex_lock(&once_lock); 64144518Sdavidxu once_control->state = ONCE_NEVER_DONE; 65144518Sdavidxu _pthread_mutex_unlock(&once_lock); 66144518Sdavidxu _pthread_cond_broadcast(&once_cv); 67144518Sdavidxu} 68144518Sdavidxu 69112918Sjeffint 70144518Sdavidxu_pthread_once(pthread_once_t *once_control, void (*init_routine) (void)) 71112918Sjeff{ 72144518Sdavidxu int wakeup = 0; 73144518Sdavidxu 74144518Sdavidxu if (once_control->state == ONCE_DONE) 75144518Sdavidxu return (0); 76144518Sdavidxu _pthread_mutex_lock(&once_lock); 77144518Sdavidxu while (*(volatile int *)&(once_control->state) == ONCE_IN_PROGRESS) 78144518Sdavidxu _pthread_cond_wait(&once_cv, &once_lock); 79144518Sdavidxu /* 80144518Sdavidxu * If previous thread was canceled, then the state still 81144518Sdavidxu * could be ONCE_NEVER_DONE, we need to check it again. 82144518Sdavidxu */ 83144518Sdavidxu if (*(volatile int *)&(once_control->state) == ONCE_NEVER_DONE) { 84144518Sdavidxu once_control->state = ONCE_IN_PROGRESS; 85144518Sdavidxu _pthread_mutex_unlock(&once_lock); 86144518Sdavidxu _pthread_cleanup_push(once_cancel_handler, once_control); 87144518Sdavidxu init_routine(); 88144518Sdavidxu _pthread_cleanup_pop(0); 89144518Sdavidxu _pthread_mutex_lock(&once_lock); 90144518Sdavidxu once_control->state = ONCE_DONE; 91144518Sdavidxu wakeup = 1; 92112918Sjeff } 93144518Sdavidxu _pthread_mutex_unlock(&once_lock); 94144518Sdavidxu if (wakeup) 95144518Sdavidxu _pthread_cond_broadcast(&once_cv); 96112918Sjeff return (0); 97112918Sjeff} 98144518Sdavidxu 99