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