Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Sleep in driver worker thread?

1 view
Skip to first unread message

tdacosta

unread,
May 4, 2007, 11:09:01 AM5/4/07
to
I am writing a stream driver on a Cirrus EP9302 under Windows CE 6.0 where I
would like to have a worker thread that runs periodically to sample some
hardware lines that do not have interrupt capability. I have done this in
the past with CE 3.0 and 4.2 without issue, however with CE 6.0 I'm running
into an interesting failure--when I call the Sleep() function in the worker
thread with anything other than a parameter of INFINITE, I end up getting a
prefetch abort in the thread. I have so far tracked the abort down to the
OEMGetTickCount() function, but since I'm not using a hardware debugger, I
can't seem to get much past that. Sleep() works fine in the driver Init
function.

I've been looking at the various steam driver examples included with CE 6.0,
but they all seem be interrupt driven, where the IST threads wait on the
interrupt. Is there a problem with calling Sleep() within a thread created
by a kernel mode driver?

Here is my driver registry settings and the cut down code that still has the
abort occurring.

[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\Bsd]
"Dll"="bsd.Dll"
"Prefix"="BSD"
"Order"=dword:2
"IoBase"=dword:00000000
"Irq"=dword:ff
"IoLen"=dword:20
"DeviceArrayIndex"=dword:0

-------------------------------------------------------------------

BOOL WINAPI DllEntry(HANDLE hInstDll, DWORD dwReason, LPVOID lpvReserved)
{
switch ( dwReason )
{
case DLL_PROCESS_ATTACH:
DEBUGMSG(ZONE_INIT, (TEXT("BSD : DLL_PROCESS_ATTACH\r\n")));
DisableThreadLibraryCalls((HMODULE) hInstDll);
break;

case DLL_PROCESS_DETACH:
DEBUGMSG(ZONE_INIT, (TEXT("BSD : DLL_PROCESS_DETACH\r\n")));
break;
}

return (TRUE);
}


DWORD BSD_Init(DWORD dwInitParam)
{

RETAILMSG (1,(TEXT("+BSD_Init\r\n")));

//Start up the worker thread
g_hReadThread =
CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)BsdReadThread,0,NULL);

if ( g_hReadThread == NULL )
{
RETAILMSG(1, (TEXT("Fatal Error! Failed to create BSD worker
thread.\r\n")));
return (FALSE);
}
}

RETAILMSG (1,(TEXT("BSD_Init: About to sleep\r\n")));
Sleep(10);

RETAILMSG (1,(TEXT("-BSD_Init\r\n")));
return (TRUE);
}

BOOL BSD_Deinit(DWORD dwData)
{
FUNC("+BSD_Deinit");

FUNC("-BSD_Deinit");
return (TRUE);
}

DWORD BSD_Open (DWORD dwData, DWORD dwAccess, DWORD dwShareMode) {return (4);}
BOOL BSD_Close(DWORD dwData) {return (TRUE);}
DWORD BSD_Read (DWORD dwData, LPVOID pBuf, DWORD Len) {return (0);}
DWORD BSD_Write(DWORD dwData, LPCVOID pBuf, DWORD Len) {return (0);}
DWORD BSD_Seek (DWORD dwData, long pos, DWORD type) {return (DWORD)-1;}
VOID BSD_PowerUp (VOID) {}
VOID BSD_PowerDown(VOID) {}
BOOL BSD_IOControl(DWORD p1, DWORD p2, PBYTE p3, DWORD p4, PBYTE p5, DWORD
p6, PDWORD p7) {return 0}


DWORD WINAPI BsdReadThread( LPVOID lpParameter)
{
HANDLE dummyEvent;

RETAILMSG (1,(TEXT("+BSD_ReadThread\r\n")));
while ( 1 )
{
Sleep(100);
RETAILMSG (1,(TEXT("BSD_ReadThread: Tick.\r\n")));
}
RETAILMSG( 1, (TEXT( "-BSD_ReadThread\r\n" )) );
return (1);
}

tdacosta

unread,
May 4, 2007, 3:24:01 PM5/4/07
to
After some more investigation, I have found that if I delay the completion of
the driver Init function by placing a Sleep(10000) prior to the return, the
worker thread runs fine for the 10s that the Init function sleeps.

Is there something in the new CE 6.0 kernel model that I need to be aware of
relating to kernel drivers and this approach?

Josh Chang

unread,
May 7, 2007, 9:51:02 PM5/7/07
to
Hi tdacosta,

I have encountered this also. The working thread seems to end along with
the XXX_Init return.
There is another way that actually works is to use timer for this..I have
tested on WinCE60 and it works fine....here is the code example.

1. Mind the timer resolution, which is the 2nd parameter in the call to
"timeSetEvent", the smaller the accurate but it's a trade off between system
loading... usually, i set it to 1/10 of the sampling time (time interval for
your timer to enter to work).
2. Remember to have the lib link for use the timer --- Mmtimer.lib

typedef struct _DEVICE_INSTANCE {
LONG OpenCount; // Number of open handles.
CRITICAL_SECTION ControlMutex; // Access control for all
} DEVICE_INSTANCE, *PDEVICE_INSTANCE;


/******************************
* Run Timer
*******************************/
#define RUN_TIMER_PERIOD (60*1000) // 1 min in milliseconds

#define RUN_TIMER_RESOLUTION (RUN_TIMER_PERIOD/10) // take 1/10 of that of
RunTimer period

MMRESULT uRunTimerID = 0; // MMRESULT (equal to UINT or DWORD)
HINSTANCE g_hInstance;
CRITICAL_SECTION g_csControlMutex;

int StartRunTimer();
int StopRunTimer();
void CALLBACK RunTimerCallBack(UINT uID, UINT uMsg, DWORD_PTR dwUser,
DWORD_PTR dw1, DWORD_PTR dw2);

BOOL SCR_Deinit(IN OUT ULONG DeviceContext);

ULONG
SCR_Init(
IN ULONG RegistryPath
)
{
BOOL RoutineSuccess = FALSE;
PDEVICE_INSTANCE pDeviceInstance;
int nRet;

RETAILMSG(ZONE_INIT, (TEXT("SCR_Init(0x%x) entered.\r\n"), RegistryPath));


// Allocate a structure to hold the state for this instance. This value
// is used as a handle and is returned by this routine. When SMB_Open or
// SMB_Close is called, this handle will be passed in as a parameter.
//

pDeviceInstance = (PDEVICE_INSTANCE)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
sizeof(*pDeviceInstance));
if (pDeviceInstance == NULL)
{
RETAILMSG(ZONE_INIT, (TEXT("SCR_Init: Failed to allocate device
instance.\r\n")));
goto ErrorReturn;
}

//
// Initialize the mutex to protect the device's Control register's shadow.
//
g_csControlMutex = pDeviceInstance->ControlMutex;
InitializeCriticalSection(&pDeviceInstance->ControlMutex);

//
// Initialize Run Timer
//

// Start Timer
nRet = StartRunTimer();
if (nRet != 1)
{
RETAILMSG(ZONE_INIT, (TEXT("SCR_Init: StartRunTimer
failed(Errcode=%d)\r\n"), nRet));
goto ErrorReturn;
}
}

RoutineSuccess = TRUE;
ErrorReturn:
//
// If the initialization failed, clean up and return a NULL to signal
// failure.
//

if (RoutineSuccess == FALSE)
{
SCR_Deinit((ULONG)pDeviceInstance);
pDeviceInstance = NULL;
}

RETAILMSG(ZONE_INIT && (pDeviceInstance == NULL), (TEXT("SCR_Init
failed.\r\n")));

return (ULONG)pDeviceInstance;
}

BOOL
SCR_Deinit(
IN OUT ULONG DeviceContext
)
{
PDEVICE_INSTANCE pDeviceInstance;

pDeviceInstance = (PDEVICE_INSTANCE)DeviceContext;

RETAILMSG(ZONE_INIT, (TEXT("SCR_Deinit(0x%x) entered.\r\n"),
DeviceContext));
//
// Depending on how things should be handled, we can look at the open
// count and see if there are still open handles to the device before
// shutting it down. It is possible to wait until the handles are closed,
// or just shut the device down. In this case, we just print a debug
// message if there are still open handles.
//

RETAILMSG(ZONE_INIT && (pDeviceInstance->OpenCount != 0), (
TEXT("SCR_Deinit: Handles still open. Shutting down anyway.\r\n")));

//
// Close the handle to the mutex protecting the device's control shadow.
//
DeleteCriticalSection(&pDeviceInstance->ControlMutex);
//
// Finally, the device instance itself can be freed.
//

LocalFree(pDeviceInstance);

RETAILMSG(ZONE_INIT, (TEXT("SCR_Deinit returning TRUE.\r\n")));

return TRUE;
}

int StartRunTimer()
{
DWORD dwUser = 0;

// If hourly timer does not start
if (!uRunTimerID)
{
// Start it now
uRunTimerID = timeSetEvent(RUN_TIMER_PERIOD, // Period of timer
RUN_TIMER_RESOLUTION, // Timer resolution
RunTimerCallBack, // Callback function
dwUser, // user callback data
TIME_PERIODIC);
if(uRunTimerID == 0)
{
return 0;
}
}

return 1;
}

int StopRunTimer()
{
if (uRunTimerID) // If hourly timer started
{
MMRESULT ret = timeKillEvent(uRunTimerID);
if (ret != TIMERR_NOERROR)
{
return 0;
}

uRunTimerID = 0; // release timer ID
}

return 1;
}


//=============================================================================
// Run Timer
//
void CALLBACK RunTimerCallBack(UINT uID, // Timer identifier
UINT uMsg, // Not currently used
DWORD_PTR dwUser, // User information
DWORD_PTR dw1, // Windows reserved
DWORD_PTR dw2) // is also reserved
{

EnterCriticalSection(&g_csControlMutex);

// do the working thread tasks here

LeaveCriticalSection(&g_csControlMutex);

Dean Ramsier

unread,
May 15, 2007, 9:36:56 AM5/15/07
to
I don't know of any issues that would cause this to fail. Any chance your
driver is unloading?

--
Dean Ramsier - eMVP
BSQUARE Corporation


"tdacosta" <tdac...@discussions.microsoft.com> wrote in message
news:2B6E5494-4D0D-400D...@microsoft.com...

0 new messages