tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: CURRENT broken on Raspberry Pi 2?



>>>> Might I suggest a reference count?  RUN_ONCE() can initialize the mutex around the counter, and then the counter can keep track of the init's and fini's called, and only do the work on t
>he 0->1 edge and the 1->0 edge
>>> .
>>>
>>> You also need to destroy the mutex somewhen.
>>>
>>> RUN_ONCE needs to learn a bit more about life cycles.
>>
>> I made INIT_ONCE(9) and FINI_ONCE(9) with reference counter.
>> Is this OK like this?
>
>Hi,
>
>Thanks for working on this.
>
>At the moment your _{init,fini}_once are missing cv_broadcasts, but I 
>wonder if we can merge _{run,init}_once and avoid duplicate code.
>
>I'm not sure if _fini_done should ever wait.

Added tech-kern.

I fixed. thanks.
we need kernel version bump due to changing once_t and deleting _run_once().


cvs -q diff -aup sys/once.h kern/subr_once.c
Index: sys/once.h
===================================================================
RCS file: /src/cvs/cvsroot-netbsd/src/sys/sys/once.h,v
retrieving revision 1.6
diff -a -u -p -r1.6 once.h
--- sys/once.h	3 Mar 2018 19:21:59 -0000	1.6
+++ sys/once.h	11 Mar 2019 10:25:18 -0000
@@ -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: kern/subr_once.c
===================================================================
RCS file: /src/cvs/cvsroot-netbsd/src/sys/kern/subr_once.c,v
retrieving revision 1.6
diff -a -u -p -r1.6 subr_once.c
--- kern/subr_once.c	15 Mar 2009 17:14:40 -0000	1.6
+++ kern/subr_once.c	11 Mar 2019 10:33:37 -0000
@@ -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,34 @@ _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);
+	}
+
+	while (o->o_status == ONCE_RUNNING)
+		cv_wait(&oncecv, &oncemtx);
+	mutex_exit(&oncemtx);
 }



-- 
ryo shimizu


Home | Main Index | Thread Index | Old Index