Module Name: src
Committed By: ryo
Date: Tue Mar 19 08:16:51 UTC 2019
Modified Files:
src/share/man/man9: RUN_ONCE.9
src/sys/kern: subr_once.c
src/sys/sys: once.h param.h
Log Message:
add INIT_ONCE(9), FINI_ONCE(9) with changing once_t.
Welcome to 8.99.36
To generate a diff of this commit:
cvs rdiff -u -r1.9 -r1.10 src/share/man/man9/RUN_ONCE.9
cvs rdiff -u -r1.6 -r1.7 src/sys/kern/subr_once.c
cvs rdiff -u -r1.6 -r1.7 src/sys/sys/once.h
cvs rdiff -u -r1.583 -r1.584 src/sys/sys/param.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/share/man/man9/RUN_ONCE.9
diff -u src/share/man/man9/RUN_ONCE.9:1.9 src/share/man/man9/RUN_ONCE.9:1.10
--- src/share/man/man9/RUN_ONCE.9:1.9 Mon Jul 3 21:28:48 2017
+++ src/share/man/man9/RUN_ONCE.9 Tue Mar 19 08:16:51 2019
@@ -1,4 +1,4 @@
-.\" $NetBSD: RUN_ONCE.9,v 1.9 2017/07/03 21:28:48 wiz Exp $
+.\" $NetBSD: RUN_ONCE.9,v 1.10 2019/03/19 08:16:51 ryo Exp $
.\"
.\" Copyright (c)2005 YAMAMOTO Takashi,
.\" All rights reserved.
@@ -25,12 +25,14 @@
.\" SUCH DAMAGE.
.\"
.\" ------------------------------------------------------------
-.Dd July 7, 2010
+.Dd Mar 19, 2019
.Dt RUN_ONCE 9
.Os
.\" ------------------------------------------------------------
.Sh NAME
-.Nm RUN_ONCE
+.Nm RUN_ONCE ,
+.Nm INIT_ONCE ,
+.Nm FINI_ONCE
.Nd Run a function exactly once
.\" ------------------------------------------------------------
.Sh SYNOPSIS
@@ -41,6 +43,12 @@
.Ft int
.Fn RUN_ONCE \
"once_t *control" "int (*init_func)(void)"
+.Ft int
+.Fn INIT_ONCE \
+"once_t *control" "int (*init_func)(void)"
+.Ft void
+.Fn FINI_ONCE \
+"once_t *control" "void (*fini_func)(void)"
.\" ------------------------------------------------------------
.Sh DESCRIPTION
.Fn RUN_ONCE
@@ -59,6 +67,25 @@ will try again each time it is called.
.Pp
.Fn RUN_ONCE
can sleep if it's called concurrently.
+.Pp
+.Fn INIT_ONCE
+is used in pair with
+.Fn FINI_ONCE .
+.Fn INIT_ONCE
+will only be run once similar with
+.Fn RUN_ONCE .
+.Fn FINI_ONCE
+will only be run at last time if it is called as many times as calling
+.Fn INIT_ONCE .
+When
+.Fn FINI_ONCE
+is executed, the next call to
+.Fn INIT_ONCE
+will be executed again. That is,
+.Fn INIT_ONCE
+and
+.Fn FINI_ONCE
+can be nested.
.\" ------------------------------------------------------------
.Sh RETURN VALUES
On failure,
Index: src/sys/kern/subr_once.c
diff -u src/sys/kern/subr_once.c:1.6 src/sys/kern/subr_once.c:1.7
--- src/sys/kern/subr_once.c:1.6 Sun Mar 15 17:14:40 2009
+++ src/sys/kern/subr_once.c Tue Mar 19 08:16:51 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: subr_once.c,v 1.6 2009/03/15 17:14:40 cegger Exp $ */
+/* $NetBSD: subr_once.c,v 1.7 2019/03/19 08:16:51 ryo Exp $ */
/*-
* Copyright (c)2005 YAMAMOTO Takashi,
@@ -28,7 +28,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: subr_once.c,v 1.6 2009/03/15 17:14:40 cegger Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_once.c,v 1.7 2019/03/19 08:16:51 ryo Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -48,13 +48,17 @@ once_init(void)
}
int
-_run_once(once_t *o, int (*fn)(void))
+_init_once(once_t *o, int (*fn)(void))
{
-
/* Fastpath handled by RUN_ONCE() */
+ int error;
+
mutex_enter(&oncemtx);
- if (o->o_status == ONCE_VIRGIN) {
+ while (o->o_status == ONCE_RUNNING)
+ cv_wait(&oncecv, &oncemtx);
+
+ if (o->o_refcnt++ == 0) {
o->o_status = ONCE_RUNNING;
mutex_exit(&oncemtx);
o->o_error = fn();
@@ -62,10 +66,32 @@ _run_once(once_t *o, int (*fn)(void))
o->o_status = ONCE_DONE;
cv_broadcast(&oncecv);
}
- while (o->o_status != ONCE_DONE)
+ KASSERT(o->o_refcnt != 0); /* detect overflow */
+
+ while (o->o_status == ONCE_RUNNING)
cv_wait(&oncecv, &oncemtx);
+ error = o->o_error;
mutex_exit(&oncemtx);
- KASSERT(o->o_status == ONCE_DONE);
- return o->o_error;
+ return error;
+}
+
+void
+_fini_once(once_t *o, void (*fn)(void))
+{
+ mutex_enter(&oncemtx);
+ while (o->o_status == ONCE_RUNNING)
+ cv_wait(&oncecv, &oncemtx);
+
+ KASSERT(o->o_refcnt != 0); /* we need to call _init_once() once */
+ if (--o->o_refcnt == 0) {
+ o->o_status = ONCE_RUNNING;
+ mutex_exit(&oncemtx);
+ fn();
+ mutex_enter(&oncemtx);
+ o->o_status = ONCE_VIRGIN;
+ cv_broadcast(&oncecv);
+ }
+
+ mutex_exit(&oncemtx);
}
Index: src/sys/sys/once.h
diff -u src/sys/sys/once.h:1.6 src/sys/sys/once.h:1.7
--- src/sys/sys/once.h:1.6 Sat Mar 3 19:21:59 2018
+++ src/sys/sys/once.h Tue Mar 19 08:16:51 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: once.h,v 1.6 2018/03/03 19:21:59 jdolecek Exp $ */
+/* $NetBSD: once.h,v 1.7 2019/03/19 08:16:51 ryo Exp $ */
/*-
* Copyright (c)2005 YAMAMOTO Takashi,
@@ -31,23 +31,29 @@
#define _SYS_ONCE_H_
typedef struct {
- unsigned o_status;
int o_error;
+ uint16_t o_refcnt;
+ uint16_t o_status;
#define ONCE_VIRGIN 0
#define ONCE_RUNNING 1
#define ONCE_DONE 2
} once_t;
void once_init(void);
-int _run_once(once_t *, int (*)(void));
+int _init_once(once_t *, int (*)(void));
+void _fini_once(once_t *, void (*)(void));
#define ONCE_DECL(o) \
- once_t (o) __read_mostly = { \
+ once_t (o) = { \
.o_status = 0, \
+ .o_refcnt = 0, \
};
#define RUN_ONCE(o, fn) \
(__predict_true((o)->o_status == ONCE_DONE) ? \
- ((o)->o_error) : _run_once((o), (fn)))
+ ((o)->o_error) : _init_once((o), (fn)))
+
+#define INIT_ONCE(o, fn) _init_once((o), (fn))
+#define FINI_ONCE(o, fn) _fini_once((o), (fn))
#endif /* _SYS_ONCE_H_ */
Index: src/sys/sys/param.h
diff -u src/sys/sys/param.h:1.583 src/sys/sys/param.h:1.584
--- src/sys/sys/param.h:1.583 Fri Mar 1 03:03:19 2019
+++ src/sys/sys/param.h Tue Mar 19 08:16:51 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: param.h,v 1.583 2019/03/01 03:03:19 christos Exp $ */
+/* $NetBSD: param.h,v 1.584 2019/03/19 08:16:51 ryo Exp $ */
/*-
* Copyright (c) 1982, 1986, 1989, 1993
@@ -67,7 +67,7 @@
* 2.99.9 (299000900)
*/
-#define __NetBSD_Version__ 899003500 /* NetBSD 8.99.35 */
+#define __NetBSD_Version__ 899003600 /* NetBSD 8.99.36 */
#define __NetBSD_Prereq__(M,m,p) (((((M) * 100000000) + \
(m) * 1000000) + (p) * 100) <= __NetBSD_Version__)