Sync with the new ipfw3 version.
[ipfw.git] / dummynet2 / include / sys / systm.h
index 238a7d3..db8ef7a 100644 (file)
@@ -1,6 +1,9 @@
 #ifndef _SYS_SYSTM_H_
 #define _SYS_SYSTM_H_
 
+#define CALLOUT_ACTIVE          0x0002 /* callout is currently active */
+#define CALLOUT_MPSAFE          0x0008 /* callout handler is mp safe */
+
 #ifndef _WIN32 /* this is the linux version */
 /* callout support, in <sys/callout.h> on FreeBSD */
 /*
@@ -25,49 +28,94 @@ callout_reset(struct callout *co, int ticks, void (*fn)(void *), void *arg)
 #define callout_drain(co)       del_timer(co)
 #define callout_stop(co)        del_timer(co)
 
-#define CALLOUT_ACTIVE          0x0002 /* callout is currently active */
-#define CALLOUT_MPSAFE          0x0008 /* callout handler is mp safe */
-
 #else /* _WIN32 */
+#include <ndis.h>
 
 /* This is the windows part for callout support */
 struct callout {
-       int dummy;
+       KTIMER thetimer;
+       KDPC timerdpc;
+       int dpcinitialized;
+       LARGE_INTEGER duetime;
 };
+
+void dummynet (void*);
+VOID dummynet_dpc(
+    __in struct _KDPC  *Dpc,
+    __in_opt PVOID  DeferredContext,
+    __in_opt PVOID  SystemArgument1,
+    __in_opt PVOID  SystemArgument2
+    );
+
+VOID ipfw_dpc(
+    __in struct _KDPC  *Dpc,
+    __in_opt PVOID  DeferredContext,
+    __in_opt PVOID  SystemArgument1,
+    __in_opt PVOID  SystemArgument2
+    );
+
+/* callout_reset must handle two problems:
+ * - dummynet() scheduler must be run always on the same processor
+ * because do_gettimeofday() is based on cpu performance counter, and
+ * _occasionally_ can leap backward in time if we query another cpu.
+ * typically this won't happen that much, and the cpu will almost always
+ * be the same even without the affinity restriction, but better to be sure.
+ * - ipfw_tick() does not have the granularity requirements of dummynet()
+ * but we need to pass a pointer as argument.
+ *
+ * for these reasons, if we are called for dummynet() timer,
+ * KeInitializeDpc is called only once as it should be, and the thread
+ * is forced on cpu0 (which is always present), while if we're called
+ * for ipfw_tick(), we re-initialize the DPC each time, using
+ * parameter DeferredContext to pass the needed pointer. since this
+ * timer is called only once a sec, this won't hurt that much.
+ */
 static __inline int
-callout_reset(struct callout *co, int ticks, void (*fn)(void *), void *arg)
+callout_reset(struct callout *co, int ticks, void (*fn)(void *), void *arg) 
 {
+       if(fn == &dummynet)
+       {
+               if(co->dpcinitialized == 0)
+               {
+                       KeInitializeDpc(&co->timerdpc, dummynet_dpc, NULL);
+                       KeSetTargetProcessorDpc(&co->timerdpc, 0);
+                       co->dpcinitialized = 1;
+               }
+       }
+       else
+       {
+               KeInitializeDpc(&co->timerdpc, ipfw_dpc, arg);
+       }
+       co->duetime.QuadPart = (-ticks)*10000;
+       KeSetTimer(&co->thetimer, co->duetime, &co->timerdpc);
        return 0;
 }
 
-#define callout_init(co, safe)
-#define callout_drain(co)
-#define callout_stop(co)
-#endif /* !_WIN32 */
+static __inline void
+callout_init(struct callout* co, int safe)
+{
+       printf("%s: initializing timer at %p\n",__FUNCTION__,co);
+       KeInitializeTimer(&co->thetimer);
+}
 
+static __inline int
+callout_drain(struct callout* co)
+{
+       BOOLEAN canceled = KeCancelTimer(&co->thetimer);
+       while (canceled != TRUE)
+       {
+               canceled = KeCancelTimer(&co->thetimer);
+       }
+       printf("%s: stopping timer at %p\n",__FUNCTION__,co);
+       return 0;
+}
 
-#if 0
-/* add out timer to the kernel global timer list */
-NTSTATUS 
-  IoInitializeTimer(
-    IN PDEVICE_OBJECT  DeviceObject,
-    IN PIO_TIMER_ROUTINE  TimerRoutine,
-    IN PVOID  Context
-    );
+static __inline int
+callout_stop(struct callout* co)
+{
+       return callout_drain(co);
+}
 
-/* see differences :
-IoInitializeDpcRequest
-       http://dsrg.mff.cuni.cz/~ceres/sch/osy/text/ch04s01s01.php
-       example http://www.beyondlogic.org/interrupts/winnt_isr_dpc.htm
-KeInitializeDpc  IRQL: Any level
-IoInitializeTimer IRQL: Passive level
-KeInitializeTimer */
-VOID 
-  KeInitializeDpc(
-    IN PRKDPC  Dpc,
-    IN PKDEFERRED_ROUTINE  DeferredRoutine,
-    IN PVOID  DeferredContext
-    );
-#endif /* commented out */ 
+#endif /* _WIN32 */
 
 #endif /* _SYS_SYSTM_H_ */