📄 locplugin.cpp
字号:
done:
for (DWORD i = 0; i < m_numGeneratedReportTypes; i++) {
// Resolver stop may have been called on another thread. This takes them
// to state PLUGIN_STATE_SHUTTING_DOWN, it's this thread's responsibility
// to turn them off.
// If yet another thread registered for a report type this resolver
// generates after Resolver.Stop() but before we got here, then
// it will have its state set as PLUGIN_STATE_STARTING_UP and it will be
// available for scheduling just as it should be.
if (m_reportStates[i] == PLUGIN_STATE_SHUTTING_DOWN)
SetState(&m_generatedReportTypes[i],PLUGIN_STATE_OFF);
}
// Reset this regardless of previous value.
m_immediateRestart = FALSE;
DEBUGMSG(ZONE_RESOLVER | ZONE_THREAD,(L"LOC: Ending ResolverGetLocation thread for resolver <%s>\r\n",GetName()));
g_pLocLock->Unlock();
}
// A provider that generates a report that the resolver can resolve
// indicates it (via the report collector) by calling this function.
// Possibly save new provider report and possibly spin worker thread
void resolver_t::NewReportFromProvider(provider_t *pProv, reportCol_t *pRC) {
DEBUGCHK(g_pLocLock->IsLocked());
DEBUGCHK(pProv->GetState() == PLUGIN_STATE_ON);
if (m_pluginState <= PLUGIN_STATE_SHUTTING_DOWN) {
// Resolvers are always given indications of new reports, even when
// they're not active. Check that we care about report here.
return;
}
// Do checks to make sure that the provider generating this report is one
// that we care about. Consider for instance a system with Providers P1
// and P2, P1 higher priority, both capable of generating reports for this
// resolver. If P1 has given us a report already, when P2 calls this function
// we want to IGNORE P2's report since P1 was higher priority.
// Relying on the reports collector's priority filtering to do this work
// for the resolver will not work in all cases, so do it again here.
if (m_providerGenerator == NULL) {
// No provider registered yet, so use this provider
;
}
else if (m_providerGenerator->GetState() != PLUGIN_STATE_ON) {
// We have another (possibly higher priority) plugin associated
// with this RC already, however that plugin is not active.
// In this case, take what we can get and use the plugin that is
// currently generating data for us.
DEBUGCHK(m_providersAvailable);
}
else if (m_providerGenerator->GetStartOrder() < pProv->GetStartOrder())
{
// We have another plugin generating reports and it is of higher
// priority, so ignore any reports this plugin happens to generate.
DEBUGMSG(ZONE_PLUGIN,(L"LOC: Resolver <%s> ignores provider <%s> report since a higher prio plugin generates a supported type for this resolver\r\n",
GetName(),pProv->GetName()));
DEBUGCHK(m_providersAvailable);
return;
}
// There must be a provider available for us to have got this reports.
m_providersAvailable = TRUE;
m_providerGenerator = pProv;
m_reportCollector = pRC;
// Store the report the provider generated
DEBUGMSG(ZONE_PLUGIN,(L"LOC: Provider <%s> has given resolver <%s> a new report to resolve\r\n",
pProv->GetName(),GetName()));
if (m_workerThrdCookie == 0) {
// m_workerThrdCookie != 0 means thread has already been scheduled.
// Only schedule one thread per resolver.
ScheduleNextResolution();
}
}
// When there are no providers that generate any reports this resolver
// can support, then record this and take resolver to an unavailable state.
void resolver_t::NoProvidersAvailable(void) {
DEBUGCHK(g_pLocLock->IsLocked());
DEBUGCHK(m_providersAvailable);
DEBUGMSG(ZONE_RESOLVER,(L"LOC: Resolver <%s> does not have any providers available currently. Moving to unavailable state\r\n",
GetName()));
m_providersAvailable = FALSE;
// Mark any report type that is starting up or ON as unavailable.
for (DWORD i = 0; i < m_numSupportedReportTypes; i++) {
if (m_reportStates[i] > PLUGIN_STATE_UNAVAILABLE)
SetState(&m_generatedReportTypes[i],PLUGIN_STATE_UNAVAILABLE);
}
// Unschedule the worker thread, if there is one and if we can.
// This will NOT terminate a running ResolverGetLocation thread, but if
// one was scheduled to run in the future it will make sure we don't bother
// doing this work.
if (m_workerThrdCookie && g_pThreadPool->UnScheduleEvent(m_workerThrdCookie)) {
DEBUGMSG(ZONE_RESOLVER | ZONE_THREAD, (L"LOC: Unscheduled ResolverGetLocation worker cookie <%d> because of no available provs\r\n",
m_workerThrdCookie));
m_workerThrdCookie = 0;
}
}
// Determine how far into the future the next call to GetResolverLocation worker
// thread should be. This is based on the last time the resolver was called,
// whether the call was successful (at least one report resolved) or not,
// and the resolver's registry config for requery timeouts.
DWORD resolver_t::DetermineDelayUntilNextResolution(void) {
DWORD timeout;
if (GetState() == PLUGIN_STATE_UNAVAILABLE) {
// Last attempt to query plugin failed
timeout = m_retryOnFailure;
}
else {
// Last attempt to query plugin was successful (for at least one report)
// or this is the first time we're starting up the plugin after it
// has been stopped for a while.
timeout = m_minRequery;
}
__int64 currentTime;
GetCurrentFT((FILETIME*)¤tTime);
__int64 resDeltaFT = currentTime - m_lastResolution;
if ((resDeltaFT < 0) || ((resDeltaFT / SVS_FILETIME_TO_MILLISECONDS) > MAXDWORD)) {
// The system clock has moved backwards or way into future since
// the last resolution. In this case just
// schedule the next resolution to be immediate.
return 0;
}
// Number of milliseconds since last resolution.
DWORD resDeltaMS = (resDeltaFT / SVS_FILETIME_TO_MILLISECONDS);
if (resDeltaMS < timeout) {
// The next time we should be scheduled is in the future
return (timeout - resDeltaMS);
}
// Otherwise we should schedule the resolution to run immediately.
return 0;
}
// Schedule the next thread to call ResolverGetLocation on this resolver.
void resolver_t::ScheduleNextResolution(void) {
DEBUGCHK(g_pLocLock->IsLocked());
DEBUGCHK(m_workerThrdCookie == 0);
DWORD delay;
if (m_getRepThrdCalledFirstTime == TRUE) {
delay = DetermineDelayUntilNextResolution();
}
else {
// This is the first time ResolverGetLocation is to be scheduled.
// Schedule it immediately.
delay = 0;
}
DEBUGMSG(ZONE_RESOLVER,(L"LOC: Scheduling resolver thread for <%s> to run <%d> ms from now\r\n",
GetName(),delay));
m_workerThrdCookie = g_pThreadPool->ScheduleEvent(GetResolverLocationThread,this,delay);
#ifdef DEBUG
if (m_workerThrdCookie == 0) {
DEBUGMSG_OOM();
}
else {
DEBUGMSG(ZONE_RESOLVER | ZONE_THREAD,(L"LOC: Spinning GetResolverLocation thread for resolver <%s>, cookie=<0x%08x>\r\n",
GetName(),m_workerThrdCookie));
}
#endif
}
// Thread spun to call resolver's ResolverStop export. We have to
// check to make sure resolver hasn't been restarted in the interim.
void resolver_t::StopPlugin(void) {
DEBUGCHK(g_pLocLock->IsLocked());
DEBUGCHK(m_immediateRestart == FALSE);
// UnScheduleEvent only returns TRUE if the scheduled worker thread
// was not running. So try to unschedule the worker if possible.
if (m_workerThrdCookie && g_pThreadPool->UnScheduleEvent(m_workerThrdCookie)) {
DEBUGMSG(ZONE_RESOLVER | ZONE_THREAD,(L"LOC: Unscheduled GetResolverLocation thread for <%s>, cookie=<0x%08x>\r\n",
GetName(),m_workerThrdCookie));
m_workerThrdCookie = 0;
}
// Reset this, regardless of whether provider(s) is available or not, because
// the other place we reset this (NewReportFromProvider) will not be called
// now that resolver has been stopped. If no providers are available
// the next time resolver is attempted to be started, then the startup
// logic will do the right thing and not try to restart this resolver.
m_providersAvailable = TRUE;
if (m_getRepThrdCalledFirstTime == FALSE) {
// Possible in case where the stop was called before the worker
// thread got started. Since resolver's GetResolverLocation was never
// called, don't bother calling its stop routine.
// This could happen if a resolver requested a provider to generate
// reports for it, but the resolver was asked to stop before the provider
// generated a report.
// Transition straight to OFF - no more work required here
SetAllReportStates(PLUGIN_STATE_OFF);
return;
}
if (m_workerThrdCookie == 0) {
// If the worker thread isn't running, then we can immediately transition
// to the off-state.
SetAllReportStates(PLUGIN_STATE_OFF);
}
else {
// If the worker thread is running, then we can't immediately indicate
// the report states as off. We need instead to to mark them as
// shutting down and leave it to worker to set them as off once it has
// returned from its call to ResolverGetLocation.
for (DWORD i = 0; i < m_numGeneratedReportTypes; i++) {
// Update state only if it was previously on (don't take
// a state from Off->ShuttingDown for instance)
if (m_reportStates[i] >= PLUGIN_STATE_UNAVAILABLE)
m_reportStates[i] = PLUGIN_STATE_SHUTTING_DOWN;
}
m_pluginState = PLUGIN_STATE_SHUTTING_DOWN;
}
CallResStop();
m_getRepThrdCalledFirstTime = FALSE;
DEBUGMSG(ZONE_RESOLVER | ZONE_THREAD,(L"LOC: Completed ResolverStop thread for resolver <%s>\r\n",GetName()));
}
// Calls ResolverInitialize export
DWORD resolver_t::CallResInit(RESOLVER_INFORMATION *pResInfo) {
DEBUGCHK(g_pLocLock->IsLocked());
DWORD err;
__try {
DEBUGMSG(ZONE_RESOLVER,(L"LOC: Calling ResolverInitialize on DLL=<%s>\r\n",GetName()));
// Initialize is only called on LF startup. OK to hold lock.
err = m_pfnInitialize(pResInfo);
DEBUGMSG(ZONE_RESOLVER,(L"LOC: ResolverInitialize on DLL=<%s> returned <0x%08x>\r\n",GetName(),err));
} __except(REPORT_EXCEPTION_TO_WATSON()) {
DEBUGMSG(ZONE_ERROR,(L"LOC: ERROR: ResolverInitialize caused an exception in DLL=<%s>\r\n",GetName()));
// ReportFatalError(); // Do not call this - plugin constructor will immediately unload it on any error on init.
err = ERROR_INTERNAL_ERROR;
}
return err;
}
// Calls ResolverGetLocation export
DWORD resolver_t::CallResGetLocation(RESOLVER_CONTROL_BLOCK *pResControlBlock) {
g_pLocLock->Unlock();
DWORD err;
__try {
DEBUGMSG(ZONE_RESOLVER,(L"LOC: Calling ResolverGetLocation on DLL=<%s>\r\n",GetName()));
err = m_pfnGetLocation(pResControlBlock);
DEBUGMSG(ZONE_RESOLVER,(L"LOC: ResolverGetLocation on DLL=<%s> returned <0x%08x>\r\n",GetName(),err));
} __except(REPORT_EXCEPTION_TO_WATSON()) {
DEBUGMSG(ZONE_ERROR,(L"LOC: ERROR: ResolverGetLocation caused an exception in DLL=<%s>\r\n",GetName()));
ReportFatalError();
err = ERROR_INTERNAL_ERROR;
}
g_pLocLock->Lock();
return err;
}
// Calls ResolverStop export. See CallProvStop() comments for more info.
DWORD resolver_t::CallResStop(void) {
DEBUGCHK(g_pLocLock->IsLocked());
DEBUGCHK(m_getRepThrdCalledFirstTime == TRUE);
DWORD err;
__try {
DEBUGMSG(ZONE_RESOLVER,(L"LOC: Calling ResolverStop on DLL=<%s>\r\n",GetName()));
err = m_pfnStop();
DEBUGMSG(ZONE_RESOLVER,(L"LOC: ResolverStop on DLL=<%s> returned <0x%08x>\r\n",GetName(),err));
} __except(REPORT_EXCEPTION_TO_WATSON()) {
DEBUGMSG(ZONE_ERROR,(L"LOC: ERROR: ResolverStop caused an exception in DLL=<%s>\r\n",GetName()));
ReportFatalError();
err = ERROR_INTERNAL_ERROR;
}
return err;
}
// Calls ResolverUnInitialize export
DWORD resolver_t::CallResUnInit(void) {
DEBUGCHK(g_pLocLock->IsLocked());
DWORD err;
__try {
DEBUGMSG(ZONE_RESOLVER,(L"LOC: Calling ResolverUnInitialize on DLL=<%s>\r\n",GetName()));
// Uninit is only called on LF shutdown. OK to hold lock.
err = m_pfnUnInitialize();
DEBUGMSG(ZONE_RESOLVER,(L"LOC: ResolverUnInitialize on DLL=<%s> returned <0x%08x>\r\n",GetName(),err));
} __except(REPORT_EXCEPTION_TO_WATSON()) {
DEBUGMSG(ZONE_ERROR,(L"LOC: ERROR: ResolverUnInitialize caused an exception in DLL=<%s>\r\n",GetName()));
err = ERROR_INTERNAL_ERROR;
// ReportFatalError(); - since the plugin is being unloaded anyway, don't bother
}
return err;
}
// Calls ResolverIoctlOpen export
DWORD resolver_t::CallResIoctlOpen(void) {
m_numActiveIoctlCallers++;
g_pLocLock->Unlock();
DWORD err;
__try {
DEBUGMSG(ZONE_RESOLVER,(L"LOC: Calling ResolverIoctlOpen on DLL=<%s>\r\n",GetName()));
err = m_pfnIoctlOpen();
DEBUGMSG(ZONE_RESOLVER,(L"LOC: ResolverIoctlOpen on DLL=<%s> returned <0x%08x>\r\n",GetName(),err));
} __except(REPORT_EXCEPTION_TO_WATSON()) {
DEBUGMSG(ZONE_ERROR,(L"LOC: ERROR: ResolverIoctlOpen caused an exception in DLL=<%s>\r\n",GetName()));
ReportFatalError();
err = ERROR_INTERNAL_ERROR;
}
g_pLocLock->Lock();
m_numActiveIoctlCallers--;
return err;
}
// Calls ResolverIoctlCall export
DWORD resolver_t::CallResIoctlCall(HANDLE h, DWORD dwCode, BYTE *pBufIn, DWORD cbIn, BYTE *pBufOut, DWORD *pcbOut) {
m_numActiveIoctlCallers++;
g_pLocLock->Unlock();
DWORD err;
__try {
DEBUGMSG(ZONE_RESOLVER,(L"LOC: Calling ResolverIoctlCall on DLL=<%s>\r\n",GetName()));
err = m_pfnIoctlCall(h, dwCode, pBufIn, cbIn, pBufOut, pcbOut);
DEBUGMSG(ZONE_RESOLVER,(L"LOC: ResolverIoctlCall on DLL=<%s> returned <0x%08x>\r\n",GetName(),err));
} __except(REPORT_EXCEPTION_TO_WATSON()) {
DEBUGMSG(ZONE_ERROR,(L"LOC: ERROR: ResolverIoctlCall caused an exception in DLL=<%s>\r\n",GetName()));
ReportFatalError();
err = ERROR_INTERNAL_ERROR;
}
g_pLocLock->Lock();
m_numActiveIoctlCallers--;
return err;
}
// Calls ResolverIoctlClose export
DWORD resolver_t::CallResIoctlClose(HANDLE h) {
m_numActiveIoctlCallers++;
g_pLocLock->Unlock();
DWORD err;
__try {
DEBUGMSG(ZONE_RESOLVER,(L"LOC: Calling ResolverIoctlClose on DLL=<%s>\r\n",GetName()));
err = m_pfnIoctlClose(h);
DEBUGMSG(ZONE_RESOLVER,(L"LOC: ResolverIoctlClose on DLL=<%s> returned <0x%08x>\r\n",GetName(),err));
} __except(REPORT_EXCEPTION_TO_WATSON()) {
DEBUGMSG(ZONE_ERROR,(L"LOC: ERROR: ResolverIoctlClose caused an exception in DLL=<%s>\r\n",GetName()));
ReportFatalError();
err = ERROR_INTERNAL_ERROR;
}
g_pLocLock->Lock();
m_numActiveIoctlCallers--;
return err;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -