#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 */
/*
#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_ */