From 52bfac6de0b56e4168c59be344cf6171433df936 Mon Sep 17 00:00:00 2001 From: Bill Paul Date: Thu, 25 Mar 2004 08:23:08 +0000 Subject: - In kern_ndis.c, implement ndis_unsched(), the complement to ndis_sched(), which pulls a job off a thread work queue (assuming it hasn't run yet). This is needed for KeRemoveQueueDpc(). - In subr_ntoskrnl.c, implement KeInsertQueueDpc() and KeRemoveQueueDpc(), to go with KeInitializeDpc() to round out the API. Also change the KeTimer implementation to use this API instead of the private timer callout scheduler. Functionality of the timer API remains unchanged, but we get a couple new Windows kernel API routines and more closely imitate the way thing works in Windows. (As of yet I haven't encountered any drivers that use KeInsertQueueDpc() or KeRemoveQueueDpc(), but it doesn't hurt to have them.) --- sys/compat/ndis/kern_ndis.c | 33 +++++++++++++++++ sys/compat/ndis/subr_ntoskrnl.c | 81 +++++++++++++++++++++++++++-------------- 2 files changed, 86 insertions(+), 28 deletions(-) (limited to 'sys/compat') diff --git a/sys/compat/ndis/kern_ndis.c b/sys/compat/ndis/kern_ndis.c index 89cc5e6e9f1e0..f633a1c895d4b 100644 --- a/sys/compat/ndis/kern_ndis.c +++ b/sys/compat/ndis/kern_ndis.c @@ -402,6 +402,39 @@ ndis_shrink_thrqueue(cnt) return(0); } +int +ndis_unsched(func, arg, t) + void (*func)(void *); + void *arg; + int t; +{ + struct ndis_req *r; + struct ndisqhead *q; + struct proc *p; + + if (t == NDIS_TASKQUEUE) { + q = &ndis_ttodo; + p = ndis_tproc.np_p; + } else { + q = &ndis_itodo; + p = ndis_iproc.np_p; + } + + mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx); + STAILQ_FOREACH(r, q, link) { + if (r->nr_func == func && r->nr_arg == arg) { + STAILQ_REMOVE(q, r, ndis_req, link); + STAILQ_INSERT_HEAD(&ndis_free, r, link); + mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); + return(0); + } + } + + mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); + + return(ENOENT); +} + int ndis_sched(func, arg, t) void (*func)(void *); diff --git a/sys/compat/ndis/subr_ntoskrnl.c b/sys/compat/ndis/subr_ntoskrnl.c index cfc11ee6dedc6..c58e8a390fc6a 100644 --- a/sys/compat/ndis/subr_ntoskrnl.c +++ b/sys/compat/ndis/subr_ntoskrnl.c @@ -85,7 +85,7 @@ __stdcall static uint32_t ntoskrnl_waitforobjs(uint32_t, int64_t *, wait_block *); static void ntoskrnl_wakeup(void *); static void ntoskrnl_timercall(void *); -static void ntoskrnl_timersched(void *); +static void ntoskrnl_run_dpc(void *); __stdcall static void ntoskrnl_writereg_ushort(uint16_t *, uint16_t); __stdcall static uint16_t ntoskrnl_readreg_ushort(uint16_t *); __stdcall static void ntoskrnl_writereg_ulong(uint32_t *, uint32_t); @@ -1641,31 +1641,14 @@ ntoskrnl_debugger(void) return; } -/* - * We run all timer callouts in the ndis swi thread to take - * advantage of its larger stack size. If we don't do this, - * the callout will run in the clock ithread context. - */ - -static void -ntoskrnl_timersched(arg) - void *arg; -{ - ndis_sched(ntoskrnl_timercall, arg, NDIS_SWI); - return; -} - static void ntoskrnl_timercall(arg) void *arg; { ktimer *timer; - __stdcall kdpc_func timerfunc; - kdpc *dpc; struct timeval tv; timer = arg; - dpc = timer->k_dpc; /* * If this is a periodic timer, re-arm it @@ -1680,14 +1663,11 @@ ntoskrnl_timercall(arg) tv.tv_sec = 0; tv.tv_usec = timer->k_period * 1000; timer->k_handle = - timeout(ntoskrnl_timersched, timer, tvtohz(&tv)); + timeout(ntoskrnl_timercall, timer, tvtohz(&tv)); } - if (dpc != NULL) { - timerfunc = (kdpc_func)dpc->k_deferedfunc; - timerfunc(dpc, dpc->k_deferredctx, - dpc->k_sysarg1, dpc->k_sysarg2); - } + if (timer->k_dpc != NULL) + ntoskrnl_queue_dpc(timer->k_dpc, NULL, NULL); ntoskrnl_wakeup(&timer->k_header); @@ -1727,6 +1707,25 @@ ntoskrnl_init_timer_ex(timer, type) return; } +/* + * This is a wrapper for Windows deferred procedure calls that + * have been placed on an NDIS thread work queue. We need it + * since the DPC could be a _stdcall function. + */ +static void +ntoskrnl_run_dpc(arg) + void *arg; +{ + __stdcall kdpc_func dpcfunc; + kdpc *dpc; + + dpc = arg; + dpcfunc = (kdpc_func)dpc->k_deferedfunc; + dpcfunc(dpc, dpc->k_deferredctx, dpc->k_sysarg1, dpc->k_sysarg2); + + return; +} + __stdcall void ntoskrnl_init_dpc(dpc, dpcfunc, dpcctx) kdpc *dpc; @@ -1742,6 +1741,30 @@ ntoskrnl_init_dpc(dpc, dpcfunc, dpcctx) return; } +__stdcall uint8_t +ntoskrnl_queue_dpc(dpc, sysarg1, sysarg2) + kdpc *dpc; + void *sysarg1; + void *sysarg2; +{ + dpc->k_sysarg1 = sysarg1; + dpc->k_sysarg2 = sysarg2; + if (ndis_sched(ntoskrnl_run_dpc, dpc, NDIS_SWI)) + return(FALSE); + + return(TRUE); +} + +__stdcall uint8_t +ntoskrnl_dequeue_dpc(dpc) + kdpc *dpc; +{ + if (ndis_unsched(ntoskrnl_run_dpc, dpc, NDIS_SWI)) + return(FALSE); + + return(TRUE); +} + __stdcall uint8_t ntoskrnl_set_timer_ex(timer, duetime, period, dpc) ktimer *timer; @@ -1758,7 +1781,7 @@ ntoskrnl_set_timer_ex(timer, duetime, period, dpc) if (timer->k_handle.callout != NULL && callout_pending(timer->k_handle.callout)) { - untimeout(ntoskrnl_timersched, timer, timer->k_handle); + untimeout(ntoskrnl_timercall, timer, timer->k_handle); pending = TRUE; } else pending = FALSE; @@ -1783,7 +1806,7 @@ ntoskrnl_set_timer_ex(timer, duetime, period, dpc) } } - timer->k_handle = timeout(ntoskrnl_timersched, timer, tvtohz(&tv)); + timer->k_handle = timeout(ntoskrnl_timercall, timer, tvtohz(&tv)); return(pending); } @@ -1812,7 +1835,7 @@ ntoskrnl_cancel_timer(timer) else pending = FALSE; - untimeout(ntoskrnl_timersched, timer, timer->k_handle); + untimeout(ntoskrnl_timercall, timer, timer->k_handle); return(pending); } @@ -1925,11 +1948,13 @@ image_patch_table ntoskrnl_functbl[] = { { "KeReadStateEvent", (FUNC)ntoskrnl_read_event }, { "KeInitializeTimer", (FUNC)ntoskrnl_init_timer }, { "KeInitializeTimerEx", (FUNC)ntoskrnl_init_timer_ex }, - { "KeInitializeDpc", (FUNC)ntoskrnl_init_dpc }, { "KeSetTimer", (FUNC)ntoskrnl_set_timer }, { "KeSetTimerEx", (FUNC)ntoskrnl_set_timer_ex }, { "KeCancelTimer", (FUNC)ntoskrnl_cancel_timer }, { "KeReadStateTimer", (FUNC)ntoskrnl_read_timer }, + { "KeInitializeDpc", (FUNC)ntoskrnl_init_dpc }, + { "KeInsertQueueDpc", (FUNC)ntoskrnl_queue_dpc }, + { "KeRemoveQueueDpc", (FUNC)ntoskrnl_dequeue_dpc }, { "ObReferenceObjectByHandle", (FUNC)ntoskrnl_objref }, { "ObfDereferenceObject", (FUNC)ntoskrnl_objderef }, { "ZwClose", (FUNC)ntoskrnl_zwclose }, -- cgit v1.3