Page MenuHomeFreeBSD

D4076.id9921.diff
No OneTemporary

D4076.id9921.diff

Index: kern/kern_timeout.c
===================================================================
--- kern/kern_timeout.c
+++ kern/kern_timeout.c
@@ -136,6 +136,7 @@
*/
struct cc_exec {
struct callout *cc_curr;
+ void (*cc_drain)(void *);
#ifdef SMP
void (*ce_migration_func)(void *);
void *ce_migration_arg;
@@ -170,6 +171,7 @@
#define callout_migrating(c) ((c)->c_iflags & CALLOUT_DFRMIGRATION)
#define cc_exec_curr(cc, dir) cc->cc_exec_entity[dir].cc_curr
+#define cc_exec_drain(cc, dir) cc->cc_exec_entity[dir].cc_drain
#define cc_exec_next(cc) cc->cc_next
#define cc_exec_cancel(cc, dir) cc->cc_exec_entity[dir].cc_cancel
#define cc_exec_waiting(cc, dir) cc->cc_exec_entity[dir].cc_waiting
@@ -679,6 +681,7 @@
cc_exec_curr(cc, direct) = c;
cc_exec_cancel(cc, direct) = false;
+ cc_exec_drain(cc, direct) = NULL;
CC_UNLOCK(cc);
if (c_lock != NULL) {
class->lc_lock(c_lock, lock_status);
@@ -744,6 +747,15 @@
CC_LOCK(cc);
KASSERT(cc_exec_curr(cc, direct) == c, ("mishandled cc_curr"));
cc_exec_curr(cc, direct) = NULL;
+ if (cc_exec_drain(cc, direct)) {
+ void (*drain)(void *);
+
+ drain = cc_exec_drain(cc, direct);
+ cc_exec_drain(cc, direct) = NULL;
+ CC_UNLOCK(cc);
+ drain(c_arg);
+ CC_LOCK(cc);
+ }
if (cc_exec_waiting(cc, direct)) {
/*
* There is someone waiting for the
@@ -1145,7 +1157,7 @@
}
int
-_callout_stop_safe(struct callout *c, int safe)
+_callout_stop_safe(struct callout *c, int safe, void (*drain)(void *))
{
struct callout_cpu *cc, *old_cc;
struct lock_class *class;
@@ -1225,15 +1237,21 @@
* stop it by other means however.
*/
if (!(c->c_iflags & CALLOUT_PENDING)) {
- c->c_flags &= ~CALLOUT_ACTIVE;
-
/*
* If it wasn't on the queue and it isn't the current
* callout, then we can't stop it, so just bail.
+ * It probably has already been run (if locking
+ * is properly done). You could get here if the caller
+ * calls stop twice in a row for example. The second
+ * call would fall here without CALLOUT_ACTIVE set.
*/
+ c->c_flags &= ~CALLOUT_ACTIVE;
if (cc_exec_curr(cc, direct) != c) {
CTR3(KTR_CALLOUT, "failed to stop %p func %p arg %p",
c, c->c_func, c->c_arg);
+
+ KASSERT(drain != NULL,
+ ("async drain not allowed on stopped/expired timer"));
CC_UNLOCK(cc);
if (sq_locked)
sleepq_release(&cc_exec_waiting(cc, direct));
@@ -1298,7 +1316,7 @@
CC_LOCK(cc);
}
} else if (use_lock &&
- !cc_exec_cancel(cc, direct)) {
+ !cc_exec_cancel(cc, direct) && (drain == NULL)) {
/*
* The current callout is waiting for its
@@ -1305,7 +1323,9 @@
* lock which we hold. Cancel the callout
* and return. After our caller drops the
* lock, the callout will be skipped in
- * softclock().
+ * softclock(). This *only* works with a
+ * callout_stop() *not* callout_drain() or
+ * callout_async_drain().
*/
cc_exec_cancel(cc, direct) = true;
CTR3(KTR_CALLOUT, "cancelled %p func %p arg %p",
@@ -1351,11 +1371,17 @@
#endif
CTR3(KTR_CALLOUT, "postponing stop %p func %p arg %p",
c, c->c_func, c->c_arg);
+ if (drain) {
+ cc_exec_drain(cc, direct) = drain;
+ }
CC_UNLOCK(cc);
return (0);
}
CTR3(KTR_CALLOUT, "failed to stop %p func %p arg %p",
c, c->c_func, c->c_arg);
+ if (drain) {
+ cc_exec_drain(cc, direct) = drain;
+ }
CC_UNLOCK(cc);
KASSERT(!sq_locked, ("sleepqueue chain still locked"));
return (0);
Index: sys/callout.h
===================================================================
--- sys/callout.h
+++ sys/callout.h
@@ -81,7 +81,7 @@
*/
#define callout_active(c) ((c)->c_flags & CALLOUT_ACTIVE)
#define callout_deactivate(c) ((c)->c_flags &= ~CALLOUT_ACTIVE)
-#define callout_drain(c) _callout_stop_safe(c, 1)
+#define callout_drain(c) _callout_stop_safe(c, 1, NULL)
void callout_init(struct callout *, int);
void _callout_init_lock(struct callout *, struct lock_object *, int);
#define callout_init_mtx(c, mtx, flags) \
@@ -119,10 +119,11 @@
int callout_schedule_on(struct callout *, int, int);
#define callout_schedule_curcpu(c, on_tick) \
callout_schedule_on((c), (on_tick), PCPU_GET(cpuid))
-#define callout_stop(c) _callout_stop_safe(c, 0)
-int _callout_stop_safe(struct callout *, int);
+#define callout_stop(c) _callout_stop_safe(c, 0, NULL)
+int _callout_stop_safe(struct callout *, int, void (*)(void *));
void callout_process(sbintime_t now);
-
+#define callout_async_drain(c, d) \
+ _callout_stop_safe(c, 0, d)
#endif
#endif /* _SYS_CALLOUT_H_ */

File Metadata

Mime Type
text/plain
Expires
Wed, Feb 18, 6:00 PM (20 h, 25 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28852349
Default Alt Text
D4076.id9921.diff (4 KB)

Event Timeline