Subject: Re: timedwork
To: None <plunky@rya-online.net>
From: YAMAMOTO Takashi <yamt@mwd.biglobe.ne.jp>
List: tech-kern
Date: 01/13/2007 21:11:06
--NextPart-20070113210704-2118200
Content-Type: Text/Plain; charset=us-ascii

> I'm thinking something like:
> 
> 	callout_init(&c);
> 	callout_setwork(&c, func, arg);
> 	callout_schedule(&c, timeout);

i implemented it.  see the attached patch.

once callout_setwork() is called on a callout,
callout_schedule() is only legal operation on the callout.
(i'm not a fan of making primitives have rich functionalities...)

YAMAMOTO Takashi

--NextPart-20070113210704-2118200
Content-Type: Text/Plain; charset=us-ascii
Content-Disposition: attachment; filename="a.diff"

Index: sys/callout.h
===================================================================
--- sys/callout.h	(revision 1464)
+++ sys/callout.h	(working copy)
@@ -68,6 +68,8 @@
 #ifndef _SYS_CALLOUT_H_
 #define _SYS_CALLOUT_H_
 
+#include <sys/workqueue.h>
+
 /*
  * The following funkyness is to appease gcc3's strict aliasing.
  */
@@ -90,19 +92,25 @@ struct callout_circq {
 #define	cq_prev_l	cq_prev.list
 
 struct callout {
-	struct callout_circq c_list;		/* linkage on queue */
+	union {
+		struct callout_circq u_list;	/* linkage on queue */
+		struct work u_work;
+	} c_u;
 	void	(*c_func)(void *);		/* function to call */
 	void	*c_arg;				/* function argument */
 	int	c_time;				/* when callout fires */
 	int	c_flags;			/* state of this entry */
 };
+#define	c_list	c_u.u_list
+#define	c_work	c_u.u_work
 
+#define	CALLOUT_THREAD		0x0001	/* invoked in a thread context. */
 #define	CALLOUT_PENDING		0x0002	/* callout is on the queue */
 #define	CALLOUT_FIRED		0x0004	/* callout has fired */
 #define	CALLOUT_INVOKING	0x0008	/* callout function is being invoked */
 
 #define	CALLOUT_INITIALIZER_SETFUNC(func, arg)				\
-				{ {{NULL}, {NULL}}, func, arg, 0, 0 }
+	{ .c_func = func, .c_arg = arg }
 
 #define	CALLOUT_INITIALIZER	CALLOUT_INITIALIZER_SETFUNC(NULL, NULL)
 
@@ -110,6 +118,7 @@ struct callout {
 void	callout_startup(void);
 void	callout_init(struct callout *);
 void	callout_setfunc(struct callout *, void (*)(void *), void *);
+int	callout_setwork(struct callout *, void (*)(void *), void *);
 void	callout_reset(struct callout *, int, void (*)(void *), void *);
 void	callout_schedule(struct callout *, int);
 void	callout_stop(struct callout *);
Index: kern/kern_timeout.c
===================================================================
--- kern/kern_timeout.c	(revision 1885)
+++ kern/kern_timeout.c	(working copy)
@@ -78,6 +78,8 @@ __KERNEL_RCSID(0, "$NetBSD: kern_timeout
 #include <sys/kernel.h>
 #include <sys/lock.h>
 #include <sys/callout.h>
+#include <sys/once.h>
+#include <sys/workqueue.h>
 
 #ifdef DDB
 #include <machine/db_machdep.h>
@@ -193,6 +195,8 @@ do {									\
 static struct evcnt callout_ev_late;
 #endif
 
+static struct workqueue *callout_workqueue;
+
 /*
  * callout_startup:
  *
@@ -267,6 +271,40 @@ callout_reset(struct callout *c, int to_
 	CALLOUT_UNLOCK(s);
 }
 
+static void
+callout_worker(struct work *wk, void *arg)
+{
+	struct callout *c = (void *)wk;
+
+	KASSERT(&c->c_work == wk);
+	(*c->c_func)(c->c_arg);
+}
+
+static int
+calloutthread_init(void)
+{
+
+	return workqueue_create(&callout_workqueue, "callout",
+	    callout_worker, NULL, PUSER - 1, IPL_SOFTCLOCK, 0);
+}
+
+/*
+ */
+int
+callout_setwork(struct callout *c, void (*func)(void *), void *arg)
+{
+	static ONCE_DECL(control);
+	int error;
+
+	error = RUN_ONCE(&control, calloutthread_init);
+	if (error) {
+		return error;
+	}
+	c->c_flags |= CALLOUT_THREAD;
+	callout_setfunc(c, func, arg);
+	return 0;
+}
+
 /*
  * callout_schedule:
  *
@@ -380,12 +418,19 @@ softclock(void *v)
 			c->c_flags = (c->c_flags  & ~CALLOUT_PENDING) |
 			    (CALLOUT_FIRED|CALLOUT_INVOKING);
 
-			func = c->c_func;
-			arg = c->c_arg;
+			if ((c->c_flags & CALLOUT_THREAD) != 0) {
+				CALLOUT_UNLOCK(s);
+				workqueue_enqueue(callout_workqueue,
+				    &c->c_work);
+				CALLOUT_LOCK(s);
+			} else {
+				func = c->c_func;
+				arg = c->c_arg;
 
-			CALLOUT_UNLOCK(s);
-			(*func)(arg);
-			CALLOUT_LOCK(s);
+				CALLOUT_UNLOCK(s);
+				(*func)(arg);
+				CALLOUT_LOCK(s);
+			}
 		}
 	}
 

--NextPart-20070113210704-2118200--