Unified 16-bit and 32-bit scheduling a bit more.
diff --git a/loader/task.c b/loader/task.c
index 52e1270..4077211 100644
--- a/loader/task.c
+++ b/loader/task.c
@@ -69,12 +69,31 @@
*/
HTASK16 TASK_GetNextTask( HTASK16 hTask )
{
- TDB* pTask = (TDB*)GlobalLock16(hTask);
+ TDB* pTask = TASK_GetPtr( hTask );
if (pTask->hNext) return pTask->hNext;
return (hFirstTask != hTask) ? hFirstTask : 0;
}
+
+/***********************************************************************
+ * TASK_GetPtr
+ */
+TDB *TASK_GetPtr( HTASK16 hTask )
+{
+ return GlobalLock16( hTask );
+}
+
+
+/***********************************************************************
+ * TASK_GetCurrent
+ */
+TDB *TASK_GetCurrent(void)
+{
+ return TASK_GetPtr( GetCurrentTask() );
+}
+
+
/***********************************************************************
* TASK_LinkTask
*/
@@ -83,11 +102,11 @@
HTASK16 *prevTask;
TDB *pTask;
- if (!(pTask = (TDB *)GlobalLock16( hTask ))) return;
+ if (!(pTask = TASK_GetPtr( hTask ))) return;
prevTask = &hFirstTask;
while (*prevTask)
{
- TDB *prevTaskPtr = (TDB *)GlobalLock16( *prevTask );
+ TDB *prevTaskPtr = TASK_GetPtr( *prevTask );
if (prevTaskPtr->priority >= pTask->priority) break;
prevTask = &prevTaskPtr->hNext;
}
@@ -108,12 +127,12 @@
prevTask = &hFirstTask;
while (*prevTask && (*prevTask != hTask))
{
- pTask = (TDB *)GlobalLock16( *prevTask );
+ pTask = TASK_GetPtr( *prevTask );
prevTask = &pTask->hNext;
}
if (*prevTask)
{
- pTask = (TDB *)GlobalLock16( *prevTask );
+ pTask = TASK_GetPtr( *prevTask );
*prevTask = pTask->hNext;
pTask->hNext = 0;
nTaskCount--;
@@ -152,13 +171,13 @@
*
* Allocate a thunk for MakeProcInstance().
*/
-static SEGPTR TASK_AllocThunk( HTASK16 hTask )
+static SEGPTR TASK_AllocThunk(void)
{
TDB *pTask;
THUNKS *pThunk;
WORD sel, base;
-
- if (!(pTask = (TDB *)GlobalLock16( hTask ))) return 0;
+
+ if (!(pTask = TASK_GetCurrent())) return 0;
sel = pTask->hCSAlias;
pThunk = &pTask->thunks;
base = (int)pThunk - (int)pTask;
@@ -187,13 +206,13 @@
*
* Free a MakeProcInstance() thunk.
*/
-static BOOL TASK_FreeThunk( HTASK16 hTask, SEGPTR thunk )
+static BOOL TASK_FreeThunk( SEGPTR thunk )
{
TDB *pTask;
THUNKS *pThunk;
WORD sel, base;
-
- if (!(pTask = (TDB *)GlobalLock16( hTask ))) return 0;
+
+ if (!(pTask = TASK_GetCurrent())) return 0;
sel = pTask->hCSAlias;
pThunk = &pTask->thunks;
base = (int)pThunk - (int)pTask;
@@ -228,7 +247,7 @@
hTask = GlobalAlloc16( GMEM_FIXED | GMEM_ZEROINIT, sizeof(TDB) );
if (!hTask) return NULL;
- pTask = (TDB *)GlobalLock16( hTask );
+ pTask = TASK_GetPtr( hTask );
FarSetOwner16( hTask, pModule->self );
/* Fill the task structure */
@@ -340,7 +359,7 @@
TDB *pTask;
HGLOBAL16 hPDB;
- if (!(pTask = (TDB *)GlobalLock16( hTask ))) return;
+ if (!(pTask = TASK_GetPtr( hTask ))) return;
hPDB = pTask->hPDB;
pTask->magic = 0xdead; /* invalidate signature */
@@ -439,7 +458,7 @@
/* Enter the Win16Lock to protect global data structures */
_EnterWin16Lock();
- pTask = (TDB *)GlobalLock16( GetCurrentTask() );
+ pTask = TASK_GetCurrent();
if ( !pTask )
{
_LeaveWin16Lock();
@@ -466,11 +485,11 @@
if( nTaskCount )
{
- TDB* p = (TDB *)GlobalLock16( hFirstTask );
+ TDB* p = TASK_GetPtr( hFirstTask );
while( p )
{
if( p->hYieldTo == pTask->hSelf ) p->hYieldTo = 0;
- p = (TDB *)GlobalLock16( p->hNext );
+ p = TASK_GetPtr( p->hNext );
}
}
@@ -481,180 +500,10 @@
TASK_DeleteTask( pTask->hSelf );
- /* ... schedule another one ... */
- TASK_Reschedule();
-
/* ... and completely release the Win16Lock, just in case. */
ReleaseThunkLock( &lockCount );
}
-/***********************************************************************
- * TASK_Reschedule
- *
- * This is where all the magic of task-switching happens!
- *
- * 16-bit Windows performs non-preemptive (cooperative) multitasking.
- * This means that each 16-bit task runs until it voluntarily yields
- * control, at which point the scheduler gets active and selects the
- * next task to run.
- *
- * In Wine, all processes, even 16-bit ones, are scheduled preemptively
- * by the standard scheduler of the underlying OS. As many 16-bit apps
- * *rely* on the behaviour of the Windows scheduler, however, we have
- * to simulate that behaviour.
- *
- * This is achieved as follows: every 16-bit task is at time (except
- * during task creation and deletion) in one of two states: either it
- * is the one currently running, then the global variable hCurrentTask
- * contains its task handle, or it is not currently running, then it
- * is blocked on a special scheduler event, a global handle which
- * is stored in the task struct.
- *
- * When the current task yields control, this routine gets called. Its
- * purpose is to determine the next task to be active, signal the
- * scheduler event of that task, and then put the current task to sleep
- * waiting for *its* scheduler event to get signalled again.
- *
- * This routine can get called in a few other special situations as well:
- *
- * - On creation of a 16-bit task, the Unix process executing the task
- * calls TASK_Reschedule once it has completed its initialization.
- * At this point, the task needs to be blocked until its scheduler
- * event is signalled the first time (this will be done by the parent
- * process to get the task up and running).
- *
- * - When the task currently running terminates itself, this routine gets
- * called and has to schedule another task, *without* blocking the
- * terminating task.
- *
- * - When a 32-bit thread posts an event for a 16-bit task, it might be
- * the case that *no* 16-bit task is currently running. In this case
- * the task that has now an event pending is to be scheduled.
- *
- */
-void TASK_Reschedule(void)
-{
- TDB *pOldTask = NULL, *pNewTask = NULL;
- HTASK16 hOldTask = 0, hNewTask = 0;
- enum { MODE_YIELD, MODE_SLEEP, MODE_WAKEUP } mode;
- DWORD lockCount;
-
- _EnterWin16Lock();
-
- /* Check what we need to do */
- hOldTask = GetCurrentTask();
- pOldTask = (TDB *)GlobalLock16( hOldTask );
- TRACE( "entered with hCurrentTask %04x by hTask %04x (pid %ld)\n",
- hCurrentTask, hOldTask, (long) getpid() );
-
- if ( pOldTask && THREAD_IsWin16( NtCurrentTeb() ) )
- {
- /* We are called by an active (non-deleted) 16-bit task */
-
- /* If we don't even have a current task, or else the current
- task has yielded, we'll need to schedule a new task and
- (possibly) put the calling task to sleep. Otherwise, we
- only block the caller. */
-
- if ( !hCurrentTask || hCurrentTask == hOldTask )
- mode = MODE_YIELD;
- else
- mode = MODE_SLEEP;
- }
- else
- {
- /* We are called by a deleted 16-bit task or a 32-bit thread */
-
- /* The only situation where we need to do something is if we
- now do not have a current task. Then, we'll need to wake up
- some task that has events pending. */
-
- if ( !hCurrentTask || hCurrentTask == hOldTask )
- mode = MODE_WAKEUP;
- else
- {
- /* nothing to do */
- _LeaveWin16Lock();
- return;
- }
- }
-
- /* Find a task to yield to: check for DirectedYield() */
- if ( mode == MODE_YIELD && pOldTask && pOldTask->hYieldTo )
- {
- hNewTask = pOldTask->hYieldTo;
- pNewTask = (TDB *)GlobalLock16( hNewTask );
- if( !pNewTask || !pNewTask->nEvents || !pNewTask->teb) hNewTask = 0;
- pOldTask->hYieldTo = 0;
- }
-
- /* Find a task to yield to: check for pending events */
- if ( (mode == MODE_YIELD || mode == MODE_WAKEUP) && !hNewTask )
- {
- hNewTask = hFirstTask;
- while (hNewTask)
- {
- pNewTask = (TDB *)GlobalLock16( hNewTask );
-
- TRACE( "\ttask = %04x, events = %i\n", hNewTask, pNewTask->nEvents );
-
- if (pNewTask->nEvents) break;
- hNewTask = pNewTask->hNext;
- }
- if (hLockedTask && (hNewTask != hLockedTask)) hNewTask = 0;
- }
-
- /* If we are still the task with highest priority, just return ... */
- if ( mode == MODE_YIELD && hNewTask && hNewTask == hCurrentTask )
- {
- TRACE("returning to the current task (%04x)\n", hCurrentTask );
- _LeaveWin16Lock();
-
- /* Allow Win32 threads to thunk down even while a Win16 task is
- in a tight PeekMessage() or Yield() loop ... */
- ReleaseThunkLock( &lockCount );
- RestoreThunkLock( lockCount );
- return;
- }
-
- /* If no task to yield to found, suspend 16-bit scheduler ... */
- if ( mode == MODE_YIELD && !hNewTask )
- {
- TRACE("No currently active task\n");
- hCurrentTask = 0;
- }
-
- /* If we found a task to wake up, do it ... */
- if ( (mode == MODE_YIELD || mode == MODE_WAKEUP) && hNewTask )
- {
- TRACE("Switching to task %04x (%.8s)\n",
- hNewTask, pNewTask->module_name );
-
- pNewTask->priority++;
- TASK_UnlinkTask( hNewTask );
- TASK_LinkTask( hNewTask );
- pNewTask->priority--;
-
- hCurrentTask = hNewTask;
- NtSetEvent( pNewTask->hEvent, NULL );
-
- /* This is set just in case some app reads it ... */
- pNewTask->ss_sp = pNewTask->teb->cur_stack;
- }
-
- /* If we need to put the current task to sleep, do it ... */
- if ( (mode == MODE_YIELD || mode == MODE_SLEEP) && hOldTask != hCurrentTask )
- {
- NtResetEvent( pOldTask->hEvent, NULL );
-
- ReleaseThunkLock( &lockCount );
- SYSLEVEL_CheckNotLevel( 1 );
- WaitForSingleObject( pOldTask->hEvent, INFINITE );
- RestoreThunkLock( lockCount );
- }
-
- _LeaveWin16Lock();
-}
/***********************************************************************
* InitTask (KERNEL.91)
@@ -668,7 +517,7 @@
SEGPTR ptr;
context->Eax = 0;
- if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return;
+ if (!(pTask = TASK_GetCurrent())) return;
/* Note: we need to trust that BX/CX contain the stack/heap sizes,
as some apps, notably Visual Basic apps, *modify* the heap/stack
@@ -728,7 +577,7 @@
TDB *pTask;
if (!hTask) hTask = GetCurrentTask();
- pTask = (TDB *)GlobalLock16( hTask );
+ pTask = TASK_GetPtr( hTask );
if ( !THREAD_IsWin16( NtCurrentTeb() ) )
{
@@ -741,11 +590,20 @@
pTask->nEvents--;
return FALSE;
}
- TASK_Reschedule();
- /* When we get back here, we have an event */
+ if (pTask->teb == NtCurrentTeb())
+ {
+ DWORD lockCount;
- if (pTask->nEvents > 0) pTask->nEvents--;
+ NtResetEvent( pTask->hEvent, NULL );
+ ReleaseThunkLock( &lockCount );
+ SYSLEVEL_CheckNotLevel( 1 );
+ WaitForSingleObject( pTask->hEvent, INFINITE );
+ RestoreThunkLock( lockCount );
+ if (pTask->nEvents > 0) pTask->nEvents--;
+ }
+ else FIXME("for other task %04x cur=%04x\n",pTask->hSelf,GetCurrentTask());
+
return TRUE;
}
@@ -758,7 +616,7 @@
TDB *pTask;
if (!hTask) hTask = GetCurrentTask();
- if (!(pTask = (TDB *)GlobalLock16( hTask ))) return;
+ if (!(pTask = TASK_GetPtr( hTask ))) return;
if ( !THREAD_IsWin16( pTask->teb ) )
{
@@ -768,9 +626,7 @@
pTask->nEvents++;
- /* If we are a 32-bit task, we might need to wake up the 16-bit scheduler */
- if ( !THREAD_IsWin16( NtCurrentTeb() ) )
- TASK_Reschedule();
+ if (pTask->nEvents == 1) NtSetEvent( pTask->hEvent, NULL );
}
@@ -783,14 +639,14 @@
INT16 newpriority;
if (!hTask) hTask = GetCurrentTask();
- if (!(pTask = (TDB *)GlobalLock16( hTask ))) return;
+ if (!(pTask = TASK_GetPtr( hTask ))) return;
newpriority = pTask->priority + delta;
if (newpriority < -32) newpriority = -32;
else if (newpriority > 15) newpriority = 15;
pTask->priority = newpriority + 1;
- TASK_UnlinkTask( hTask );
- TASK_LinkTask( hTask );
+ TASK_UnlinkTask( pTask->hSelf );
+ TASK_LinkTask( pTask->hSelf );
pTask->priority--;
}
@@ -820,17 +676,10 @@
*/
void WINAPI OldYield16(void)
{
- TDB *pCurTask = (TDB *)GlobalLock16( GetCurrentTask() );
+ DWORD count;
- if ( !THREAD_IsWin16( NtCurrentTeb() ) )
- {
- FIXME("called for Win32 thread (%04x)!\n", NtCurrentTeb()->teb_sel);
- return;
- }
-
- if (pCurTask) pCurTask->nEvents++; /* Make sure we get back here */
- TASK_Reschedule();
- if (pCurTask) pCurTask->nEvents--;
+ ReleaseThunkLock(&count);
+ RestoreThunkLock(count);
}
/***********************************************************************
@@ -849,7 +698,7 @@
*/
void WINAPI DirectedYield16( HTASK16 hTask )
{
- TDB *pCurTask = (TDB *)GlobalLock16( GetCurrentTask() );
+ TDB *pCurTask = TASK_GetCurrent();
if ( !THREAD_IsWin16( NtCurrentTeb() ) )
{
@@ -870,7 +719,7 @@
*/
void WINAPI Yield16(void)
{
- TDB *pCurTask = (TDB *)GlobalLock16( GetCurrentTask() );
+ TDB *pCurTask = TASK_GetCurrent();
if (pCurTask) pCurTask->hYieldTo = 0;
if (pCurTask && pCurTask->hQueue && Callout.UserYield16) Callout.UserYield16();
@@ -938,7 +787,7 @@
if (NE_GetPtr(FarGetOwner16(hInstance))->flags & NE_FFLAGS_LIBMODULE)
return func;
- thunkaddr = TASK_AllocThunk( GetCurrentTask() );
+ thunkaddr = TASK_AllocThunk();
if (!thunkaddr) return (FARPROC16)0;
thunk = MapSL( thunkaddr );
lfunc = MapSL( (SEGPTR)func );
@@ -967,7 +816,7 @@
void WINAPI FreeProcInstance16( FARPROC16 func )
{
TRACE("(%08lx)\n", (DWORD)func );
- TASK_FreeThunk( GetCurrentTask(), (SEGPTR)func );
+ TASK_FreeThunk( (SEGPTR)func );
}
/**********************************************************************
@@ -1103,7 +952,7 @@
TDB *pTask;
if (!hTask) hTask = GetCurrentTask();
- if (!(pTask = (TDB *)GlobalLock16( hTask ))) return 0;
+ if (!(pTask = TASK_GetPtr( hTask ))) return 0;
hPrev = pTask->hQueue;
pTask->hQueue = hQueue;
@@ -1120,7 +969,7 @@
TDB *pTask;
if (!hTask) hTask = GetCurrentTask();
- if (!(pTask = (TDB *)GlobalLock16( hTask ))) return 0;
+ if (!(pTask = TASK_GetPtr( hTask ))) return 0;
return pTask->hQueue;
}
@@ -1154,7 +1003,7 @@
else if ( HIWORD(thread) )
teb = THREAD_IdToTEB( thread );
else if ( IsTask16( (HTASK16)thread ) )
- teb = ((TDB *)GlobalLock16( (HANDLE16)thread ))->teb;
+ teb = (TASK_GetPtr( (HANDLE16)thread ))->teb;
return (HQUEUE16)(teb? teb->queue : 0);
}
@@ -1170,7 +1019,7 @@
else if ( HIWORD(thread) )
teb = THREAD_IdToTEB( thread );
else if ( IsTask16( (HTASK16)thread ) )
- teb = ((TDB *)GlobalLock16( (HANDLE16)thread ))->teb;
+ teb = (TASK_GetPtr( (HANDLE16)thread ))->teb;
if ( teb ) teb->queue = (HQUEUE16) hQueue;
}
@@ -1213,7 +1062,7 @@
INSTANCEDATA *pData;
UINT16 copySize;
- if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return;
+ if (!(pTask = TASK_GetCurrent())) return;
if (!(pData = (INSTANCEDATA *)GlobalLock16( seg ))) return;
TRACE("old=%04x:%04x new=%04x:%04x\n",
SELECTOROF( pTask->teb->cur_stack ),
@@ -1333,7 +1182,7 @@
{
TDB *pTask;
- if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return 0;
+ if (!(pTask = TASK_GetCurrent())) return 0;
return MAKELONG(pTask->hPDB, 0); /* FIXME */
}
@@ -1367,7 +1216,7 @@
{
TDB *pTask;
- if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return 0;
+ if (!(pTask = TASK_GetCurrent())) return 0;
return pTask->version;
}
@@ -1378,7 +1227,7 @@
UINT16 WINAPI SetErrorMode16( UINT16 mode )
{
TDB *pTask;
- if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return 0;
+ if (!(pTask = TASK_GetCurrent())) return 0;
pTask->error_mode = mode;
return SetErrorMode( mode );
}
@@ -1403,7 +1252,7 @@
{
TDB *pTask;
- if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return 0;
+ if (!(pTask = TASK_GetCurrent())) return 0;
return GlobalHandleToSel16(pTask->hInstance);
}
@@ -1415,7 +1264,7 @@
TDB *pTask;
WORD selector;
- if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return 0;
+ if (!(pTask = TASK_GetCurrent())) return 0;
if (!(pTask->flags & TDBF_WIN32)) return 0;
selector = GlobalHandleToSel16( pTask->hModule );
CURRENT_DS = selector;
@@ -1430,7 +1279,7 @@
{
TDB *pTask;
- if (!(pTask = (TDB *)GlobalLock16( hTask ))) return FALSE;
+ if (!(pTask = TASK_GetPtr( hTask ))) return FALSE;
if (GlobalSize16( hTask ) < sizeof(TDB)) return FALSE;
return (pTask->magic == TDB_MAGIC);
}
@@ -1454,7 +1303,7 @@
FARPROC16 oldProc;
if (!hTask) hTask = GetCurrentTask();
- if (!(pTask = (TDB *)GlobalLock16( hTask ))) return NULL;
+ if (!(pTask = TASK_GetPtr( hTask ))) return NULL;
oldProc = pTask->userhandler;
pTask->userhandler = proc;
return oldProc;
@@ -1468,7 +1317,7 @@
/* ### stop build ### */
void TASK_CallTaskSignalProc( UINT16 uCode, HANDLE16 hTaskOrModule )
{
- TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
+ TDB *pTask = TASK_GetCurrent();
if ( !pTask || !pTask->userhandler ) return;
TASK_CallTo16_word_wwwww( pTask->userhandler,
@@ -1491,7 +1340,7 @@
{
TDB *pTask;
- if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return 0;
+ if (!(pTask = TASK_GetCurrent())) return 0;
if (oldmode) *oldmode = pTask->signal_flags;
pTask->signal_flags = newmode;
if (oldhandler) *oldhandler = pTask->sighandler;
@@ -1511,7 +1360,7 @@
{
TDB *pTask;
- if (!(pTask = (TDB *)GlobalLock16( GetCurrentTask() ))) return;
+ if (!(pTask = TASK_GetCurrent())) return;
pTask->discardhandler = proc;
}
@@ -1534,7 +1383,7 @@
*hTask = hFirstTask;
while (*hTask)
{
- TDB *pTask = (TDB *)GlobalLock16( *hTask );
+ TDB *pTask = TASK_GetPtr( *hTask );
if ((*hTask == handle) ||
(pTask->hInstance == handle) ||
(pTask->hQueue == handle) ||
@@ -1553,7 +1402,7 @@
*hTask = hFirstTask;
while (*hTask)
{
- TDB *pTask = (TDB *)GlobalLock16( *hTask );
+ TDB *pTask = TASK_GetPtr( *hTask );
if ((*hTask == owner) ||
(pTask->hInstance == owner) ||
(pTask->hQueue == owner) ||
@@ -1608,7 +1457,7 @@
/* make sure that task and hInstance are valid (skip initial Wine task !) */
while (1) {
- pTask = (TDB *)GlobalLock16( lpte->hNext );
+ pTask = TASK_GetPtr( lpte->hNext );
if (!pTask || pTask->magic != TDB_MAGIC) return FALSE;
if (pTask->hInstance)
break;
@@ -1650,7 +1499,7 @@
*/
void WINAPI FatalAppExit16( UINT16 action, LPCSTR str )
{
- TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
+ TDB *pTask = TASK_GetCurrent();
if (!pTask || !(pTask->error_mode & SEM_NOGPFAULTERRORBOX))
{
@@ -1721,7 +1570,7 @@
TDB *pTask;
if (!hTask) hTask = GetCurrentTask();
- if (!(pTask=(TDB *)GlobalLock16( (HTASK16)hTask ))) return 0;
+ if (!(pTask=TASK_GetPtr( (HTASK16)hTask ))) return 0;
if (GlobalSize16(hTask) < sizeof(TDB)) return 0;
return pTask->compat_flags;
}