xref: /netbsd-src/sys/kern/subr_once.c (revision 88f5c690f5bca6efbe862ad67af5bfa73db547d8)
1*88f5c690Sryo /*	$NetBSD: subr_once.c,v 1.7 2019/03/19 08:16:51 ryo Exp $	*/
28d3549ebSyamt 
38d3549ebSyamt /*-
48d3549ebSyamt  * Copyright (c)2005 YAMAMOTO Takashi,
522557030Spooka  * Copyright (c)2008 Antti Kantee,
68d3549ebSyamt  * All rights reserved.
78d3549ebSyamt  *
88d3549ebSyamt  * Redistribution and use in source and binary forms, with or without
98d3549ebSyamt  * modification, are permitted provided that the following conditions
108d3549ebSyamt  * are met:
118d3549ebSyamt  * 1. Redistributions of source code must retain the above copyright
128d3549ebSyamt  *    notice, this list of conditions and the following disclaimer.
138d3549ebSyamt  * 2. Redistributions in binary form must reproduce the above copyright
148d3549ebSyamt  *    notice, this list of conditions and the following disclaimer in the
158d3549ebSyamt  *    documentation and/or other materials provided with the distribution.
168d3549ebSyamt  *
178d3549ebSyamt  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
188d3549ebSyamt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
198d3549ebSyamt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
208d3549ebSyamt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
218d3549ebSyamt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
228d3549ebSyamt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
238d3549ebSyamt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
248d3549ebSyamt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
258d3549ebSyamt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
268d3549ebSyamt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
278d3549ebSyamt  * SUCH DAMAGE.
288d3549ebSyamt  */
298d3549ebSyamt 
308d3549ebSyamt #include <sys/cdefs.h>
31*88f5c690Sryo __KERNEL_RCSID(0, "$NetBSD: subr_once.c,v 1.7 2019/03/19 08:16:51 ryo Exp $");
328d3549ebSyamt 
338d3549ebSyamt #include <sys/param.h>
348d3549ebSyamt #include <sys/systm.h>
3522557030Spooka #include <sys/condvar.h>
3622557030Spooka #include <sys/mutex.h>
378d3549ebSyamt #include <sys/once.h>
388d3549ebSyamt 
3922557030Spooka static kmutex_t oncemtx;
4022557030Spooka static kcondvar_t oncecv;
4122557030Spooka 
4222557030Spooka void
once_init(void)43b8817e4aScegger once_init(void)
4422557030Spooka {
4522557030Spooka 
4622557030Spooka 	mutex_init(&oncemtx, MUTEX_DEFAULT, IPL_NONE);
4722557030Spooka 	cv_init(&oncecv, "runonce");
4822557030Spooka }
4922557030Spooka 
50dae53410Syamt int
_init_once(once_t * o,int (* fn)(void))51*88f5c690Sryo _init_once(once_t *o, int (*fn)(void))
528d3549ebSyamt {
536dbf67ceSpooka 	/* Fastpath handled by RUN_ONCE() */
5422557030Spooka 
55*88f5c690Sryo 	int error;
56*88f5c690Sryo 
5722557030Spooka 	mutex_enter(&oncemtx);
58*88f5c690Sryo 	while (o->o_status == ONCE_RUNNING)
59*88f5c690Sryo 		cv_wait(&oncecv, &oncemtx);
60*88f5c690Sryo 
61*88f5c690Sryo 	if (o->o_refcnt++ == 0) {
626dbf67ceSpooka 		o->o_status = ONCE_RUNNING;
6322557030Spooka 		mutex_exit(&oncemtx);
6422557030Spooka 		o->o_error = fn();
6522557030Spooka 		mutex_enter(&oncemtx);
666dbf67ceSpooka 		o->o_status = ONCE_DONE;
6722557030Spooka 		cv_broadcast(&oncecv);
688d3549ebSyamt 	}
69*88f5c690Sryo 	KASSERT(o->o_refcnt != 0);	/* detect overflow */
70*88f5c690Sryo 
71*88f5c690Sryo 	while (o->o_status == ONCE_RUNNING)
7222557030Spooka 		cv_wait(&oncecv, &oncemtx);
73*88f5c690Sryo 	error = o->o_error;
7422557030Spooka 	mutex_exit(&oncemtx);
758d3549ebSyamt 
76*88f5c690Sryo 	return error;
77*88f5c690Sryo }
78*88f5c690Sryo 
79*88f5c690Sryo void
_fini_once(once_t * o,void (* fn)(void))80*88f5c690Sryo _fini_once(once_t *o, void (*fn)(void))
81*88f5c690Sryo {
82*88f5c690Sryo 	mutex_enter(&oncemtx);
83*88f5c690Sryo 	while (o->o_status == ONCE_RUNNING)
84*88f5c690Sryo 		cv_wait(&oncecv, &oncemtx);
85*88f5c690Sryo 
86*88f5c690Sryo 	KASSERT(o->o_refcnt != 0);	/* we need to call _init_once() once */
87*88f5c690Sryo 	if (--o->o_refcnt == 0) {
88*88f5c690Sryo 		o->o_status = ONCE_RUNNING;
89*88f5c690Sryo 		mutex_exit(&oncemtx);
90*88f5c690Sryo 		fn();
91*88f5c690Sryo 		mutex_enter(&oncemtx);
92*88f5c690Sryo 		o->o_status = ONCE_VIRGIN;
93*88f5c690Sryo 		cv_broadcast(&oncecv);
94*88f5c690Sryo 	}
95*88f5c690Sryo 
96*88f5c690Sryo 	mutex_exit(&oncemtx);
978d3549ebSyamt }
98