kernel - Add callout_stop_sync()
authorMatthew Dillon <dillon@apollo.backplane.com>
Tue, 8 Nov 2011 08:29:51 +0000 (00:29 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Tue, 8 Nov 2011 08:29:51 +0000 (00:29 -0800)
* Add a synchronous version of callout_stop() which ensure that the
  callout function has completed operation (if it was running) before
  returning.

sys/kern/kern_timeout.c
sys/sys/callout.h

index 5ca8f2d..8eed720 100644 (file)
@@ -399,6 +399,9 @@ callout_reset(struct callout *c, int to_ticks, void (*ftn)(void *),
  *
  * WARNING! This function can return while it's c_func is still running
  *         in the callout thread, a secondary check may be needed.
+ *         Use callout_stop_sync() to wait for any callout function to
+ *         complete before returning, being sure that no deadlock is
+ *         possible if you do.
  */
 int
 callout_stop(struct callout *c)
@@ -487,6 +490,30 @@ callout_stop(struct callout *c)
        return (1);
 }
 
+/*
+ * Issue a callout_stop() and ensure that any callout race completes
+ * before returning.  Does NOT de-initialized the callout.
+ */
+void
+callout_stop_sync(struct callout *c)
+{
+       softclock_pcpu_t sc;
+
+       if (c->c_flags & CALLOUT_DID_INIT) {
+               callout_stop(c);
+#ifdef SMP
+               sc = &softclock_pcpu_ary[c->c_gd->gd_cpuid];
+#else
+               sc = &softclock_pcpu_ary[0];
+#endif
+               if (sc->running == c) {
+                       while (sc->running == c)
+                               tsleep(&sc->running, 0, "crace", 1);
+               }
+               KKASSERT((c->c_flags & (CALLOUT_PENDING|CALLOUT_ACTIVE)) == 0);
+       }
+}
+
 /*
  * Terminate a callout
  *
index b279a5f..a74d1ca 100644 (file)
@@ -94,6 +94,7 @@ void  callout_init (struct callout *);
 void   callout_init_mp (struct callout *);
 void   callout_reset (struct callout *, int, void (*)(void *), void *);
 int    callout_stop (struct callout *);
+void   callout_stop_sync (struct callout *);
 void   callout_terminate (struct callout *);
 
 #endif