16-bit scheduler reorganized: run all tasks in their own thread.
Process creation sequence adapted to new scheduler.
This commit is contained in:
parent
ad6657e334
commit
ed49003188
|
@ -93,6 +93,8 @@ typedef struct _PDB
|
|||
void *server_pid; /* Server id for this process */
|
||||
HANDLE *dos_handles; /* Handles mapping DOS -> Win32 */
|
||||
struct _PDB *next; /* List reference - list of PDB's */
|
||||
WORD hInstance; /* hInstance on startup */
|
||||
WORD hPrevInstance; /* hPrevInstance on startup */
|
||||
} PDB;
|
||||
|
||||
/* Process flags */
|
||||
|
|
|
@ -107,8 +107,8 @@ typedef struct _TDB
|
|||
WORD more_thunks[6*4]; /* c2 Space for 6 more thunks */
|
||||
BYTE module_name[8]; /* f2 Module name for task */
|
||||
WORD magic; /* fa TDB signature */
|
||||
DWORD unused7; /* fc */
|
||||
PDB16 pdb; /* 100 PDB for this task */
|
||||
HANDLE hEvent; /* fc scheduler event handle */
|
||||
PDB16 pdb; /* 100 PDB for this task */
|
||||
} TDB;
|
||||
|
||||
#define TDB_MAGIC ('T' | ('D' << 8))
|
||||
|
@ -149,11 +149,10 @@ extern void (*TASK_AddTaskEntryBreakpoint)( HTASK16 hTask );
|
|||
extern BOOL TASK_Create( struct _THDB *thdb, struct _NE_MODULE *pModule,
|
||||
HINSTANCE16 hInstance, HINSTANCE16 hPrevInstance,
|
||||
UINT16 cmdShow );
|
||||
extern void TASK_StartTask( HTASK16 hTask );
|
||||
extern void TASK_KillTask( HTASK16 hTask );
|
||||
extern void TASK_KillCurrentTask( INT16 exitCode );
|
||||
extern HTASK16 TASK_GetNextTask( HTASK16 hTask );
|
||||
extern BOOL TASK_Reschedule(void);
|
||||
extern void TASK_Reschedule(void);
|
||||
extern void TASK_CallToStart(void);
|
||||
extern void TASK_InstallTHHook( THHOOK *pNewThook );
|
||||
|
||||
extern HQUEUE16 WINAPI SetThreadQueue16( DWORD thread, HQUEUE16 hQueue );
|
||||
|
|
521
loader/task.c
521
loader/task.c
|
@ -59,13 +59,8 @@ THHOOK *pThhook = &DefaultThhook;
|
|||
#define hFirstTask (pThhook->HeadTDB)
|
||||
#define hLockedTask (pThhook->LockTDB)
|
||||
|
||||
static HTASK16 hTaskToKill = 0;
|
||||
static UINT16 nTaskCount = 0;
|
||||
|
||||
static HANDLE TASK_ScheduleEvent = INVALID_HANDLE_VALUE;
|
||||
|
||||
static void TASK_YieldToSystem( void );
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* TASK_InstallTHHook
|
||||
|
@ -231,81 +226,54 @@ static BOOL TASK_FreeThunk( HTASK16 hTask, SEGPTR thunk )
|
|||
* 32-bit entry point for a new task. This function is responsible for
|
||||
* setting up the registers and jumping to the 16-bit entry point.
|
||||
*/
|
||||
static void TASK_CallToStart(void)
|
||||
void TASK_CallToStart(void)
|
||||
{
|
||||
TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
|
||||
NE_MODULE *pModule = NE_GetPtr( pTask->hModule );
|
||||
SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
|
||||
CONTEXT context;
|
||||
|
||||
SYSDEPS_SetCurThread( pTask->thdb );
|
||||
CLIENT_InitThread();
|
||||
/* Add task to 16-bit scheduler pool */
|
||||
TASK_Reschedule();
|
||||
|
||||
/* Terminate the stack frame chain */
|
||||
memset(THREAD_STACK16( pTask->thdb ), '\0', sizeof(STACK16FRAME));
|
||||
/* Registers at initialization must be:
|
||||
* ax zero
|
||||
* bx stack size in bytes
|
||||
* cx heap size in bytes
|
||||
* si previous app instance
|
||||
* di current app instance
|
||||
* bp zero
|
||||
* es selector to the PSP
|
||||
* ds dgroup of the application
|
||||
* ss stack selector
|
||||
* sp top of the stack
|
||||
*/
|
||||
|
||||
/* Initialize process critical section */
|
||||
InitializeCriticalSection( &PROCESS_Current()->crit_section );
|
||||
memset( &context, 0, sizeof(context) );
|
||||
CS_reg(&context) = GlobalHandleToSel16(pSegTable[pModule->cs - 1].hSeg);
|
||||
DS_reg(&context) = GlobalHandleToSel16(pSegTable[pModule->dgroup - 1].hSeg);
|
||||
ES_reg(&context) = pTask->hPDB;
|
||||
EIP_reg(&context) = pModule->ip;
|
||||
EBX_reg(&context) = pModule->stack_size;
|
||||
ECX_reg(&context) = pModule->heap_size;
|
||||
EDI_reg(&context) = context.SegDs;
|
||||
|
||||
/* Call USER signal proc */
|
||||
PROCESS_CallUserSignalProc( USIG_THREAD_INIT, 0 ); /* for initial thread */
|
||||
PROCESS_CallUserSignalProc( USIG_PROCESS_INIT, 0 );
|
||||
PROCESS_CallUserSignalProc( USIG_PROCESS_LOADED, 0 );
|
||||
PROCESS_CallUserSignalProc( USIG_PROCESS_RUNNING, 0 );
|
||||
TRACE_(task)("Starting main program: cs:ip=%04lx:%04x ds=%04lx ss:sp=%04x:%04x\n",
|
||||
CS_reg(&context), IP_reg(&context), DS_reg(&context),
|
||||
SELECTOROF(pTask->thdb->cur_stack),
|
||||
OFFSETOF(pTask->thdb->cur_stack) );
|
||||
|
||||
if (pModule->flags & NE_FFLAGS_WIN32)
|
||||
{
|
||||
ERR_(task)("Called for Win32 task!\n" );
|
||||
ExitProcess( 1 );
|
||||
}
|
||||
else if (pModule->dos_image)
|
||||
{
|
||||
DOSVM_Enter( NULL );
|
||||
ExitProcess( 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Registers at initialization must be:
|
||||
* ax zero
|
||||
* bx stack size in bytes
|
||||
* cx heap size in bytes
|
||||
* si previous app instance
|
||||
* di current app instance
|
||||
* bp zero
|
||||
* es selector to the PSP
|
||||
* ds dgroup of the application
|
||||
* ss stack selector
|
||||
* sp top of the stack
|
||||
*/
|
||||
CONTEXT context;
|
||||
|
||||
memset( &context, 0, sizeof(context) );
|
||||
CS_reg(&context) = GlobalHandleToSel16(pSegTable[pModule->cs - 1].hSeg);
|
||||
DS_reg(&context) = GlobalHandleToSel16(pSegTable[pModule->dgroup - 1].hSeg);
|
||||
ES_reg(&context) = pTask->hPDB;
|
||||
EIP_reg(&context) = pModule->ip;
|
||||
EBX_reg(&context) = pModule->stack_size;
|
||||
ECX_reg(&context) = pModule->heap_size;
|
||||
EDI_reg(&context) = context.SegDs;
|
||||
|
||||
TRACE_(task)("Starting main program: cs:ip=%04lx:%04x ds=%04lx ss:sp=%04x:%04x\n",
|
||||
CS_reg(&context), IP_reg(&context), DS_reg(&context),
|
||||
SELECTOROF(pTask->thdb->cur_stack),
|
||||
OFFSETOF(pTask->thdb->cur_stack) );
|
||||
|
||||
Callbacks->CallRegisterShortProc( &context, 0 );
|
||||
/* This should never return */
|
||||
ERR_(task)("Main program returned! (should never happen)\n" );
|
||||
ExitProcess( 1 );
|
||||
}
|
||||
Callbacks->CallRegisterShortProc( &context, 0 );
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* TASK_Create
|
||||
*
|
||||
* NOTE: This routine might be called by a Win32 thread. We don't have
|
||||
* any real problems with that, since we operated merely on a private
|
||||
* TDB structure that is not yet linked into the task list.
|
||||
* NOTE: This routine might be called by a Win32 thread. Thus, we need
|
||||
* to be careful to protect global data structures. We do this
|
||||
* by entering the Win16Lock while linking the task into the
|
||||
* global task list.
|
||||
*/
|
||||
BOOL TASK_Create( THDB *thdb, NE_MODULE *pModule, HINSTANCE16 hInstance,
|
||||
HINSTANCE16 hPrevInstance, UINT16 cmdShow)
|
||||
|
@ -314,10 +282,7 @@ BOOL TASK_Create( THDB *thdb, NE_MODULE *pModule, HINSTANCE16 hInstance,
|
|||
TDB *pTask;
|
||||
LPSTR cmd_line;
|
||||
WORD sp;
|
||||
char *stack32Top;
|
||||
char name[10];
|
||||
STACK16FRAME *frame16;
|
||||
STACK32FRAME *frame32;
|
||||
PDB *pdb32 = thdb->process;
|
||||
SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
|
||||
|
||||
|
@ -410,12 +375,18 @@ BOOL TASK_Create( THDB *thdb, NE_MODULE *pModule, HINSTANCE16 hInstance,
|
|||
pTask->dta = PTR_SEG_OFF_TO_SEGPTR( pTask->hPDB,
|
||||
(int)&pTask->pdb.cmdLine - (int)&pTask->pdb );
|
||||
|
||||
/* Create scheduler event for 16-bit tasks */
|
||||
|
||||
if ( !(pTask->flags & TDBF_WIN32) )
|
||||
{
|
||||
pTask->hEvent = CreateEventA( NULL, TRUE, FALSE, NULL );
|
||||
pTask->hEvent = ConvertToGlobalHandle( pTask->hEvent );
|
||||
}
|
||||
|
||||
/* Enter task handle into thread and process */
|
||||
|
||||
pTask->thdb->teb.htask16 = pTask->thdb->process->task = hTask;
|
||||
TRACE_(task)("module='%s' cmdline='%s' task=%04x\n", name, cmd_line, hTask );
|
||||
|
||||
if (pTask->flags & TDBF_WIN32) return TRUE;
|
||||
TRACE_(task)("module='%s' cmdline='%s' task=%04x\n", name, cmd_line, hTask );
|
||||
|
||||
/* If we have a DGROUP/hInstance, use it for 16-bit stack */
|
||||
|
||||
|
@ -427,47 +398,10 @@ BOOL TASK_Create( THDB *thdb, NE_MODULE *pModule, HINSTANCE16 hInstance,
|
|||
pTask->thdb->cur_stack = PTR_SEG_OFF_TO_SEGPTR( hInstance, sp );
|
||||
}
|
||||
|
||||
/* Create the 16-bit stack frame */
|
||||
/* If requested, add entry point breakpoint */
|
||||
|
||||
pTask->thdb->cur_stack -= sizeof(STACK16FRAME);
|
||||
frame16 = (STACK16FRAME *)PTR_SEG_TO_LIN( pTask->thdb->cur_stack );
|
||||
frame16->ebp = OFFSETOF( pTask->thdb->cur_stack ) + (int)&((STACK16FRAME *)0)->bp;
|
||||
frame16->bp = LOWORD(frame16->ebp);
|
||||
frame16->ds = frame16->es = hInstance;
|
||||
frame16->fs = 0;
|
||||
frame16->entry_point = 0;
|
||||
frame16->entry_cs = 0;
|
||||
frame16->mutex_count = 1; /* TASK_Reschedule is called from 16-bit code */
|
||||
/* The remaining fields will be initialized in TASK_Reschedule */
|
||||
|
||||
/* Create the 32-bit stack frame */
|
||||
|
||||
stack32Top = (char*)pTask->thdb->teb.stack_top;
|
||||
frame16->frame32 = frame32 = (STACK32FRAME *)stack32Top - 1;
|
||||
frame32->frame16 = pTask->thdb->cur_stack + sizeof(STACK16FRAME);
|
||||
frame32->edi = 0;
|
||||
frame32->esi = 0;
|
||||
frame32->edx = 0;
|
||||
frame32->ecx = 0;
|
||||
frame32->ebx = 0;
|
||||
frame32->retaddr = (DWORD)TASK_CallToStart;
|
||||
/* The remaining fields will be initialized in TASK_Reschedule */
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* TASK_StartTask
|
||||
*
|
||||
* NOTE: This routine might be called by a Win32 thread. Thus, we need
|
||||
* to be careful to protect global data structures. We do this
|
||||
* by entering the Win16Lock while linking the task into the
|
||||
* global task list.
|
||||
*/
|
||||
void TASK_StartTask( HTASK16 hTask )
|
||||
{
|
||||
TDB *pTask = (TDB *)GlobalLock16( hTask );
|
||||
if ( !pTask ) return;
|
||||
if ( TASK_AddTaskEntryBreakpoint )
|
||||
TASK_AddTaskEntryBreakpoint( hTask );
|
||||
|
||||
/* Add the task to the linked list */
|
||||
|
||||
|
@ -475,27 +409,9 @@ void TASK_StartTask( HTASK16 hTask )
|
|||
TASK_LinkTask( hTask );
|
||||
SYSLEVEL_LeaveWin16Lock();
|
||||
|
||||
TRACE_(task)("linked task %04x\n", hTask );
|
||||
|
||||
/* If requested, add entry point breakpoint */
|
||||
|
||||
if ( TASK_AddTaskEntryBreakpoint )
|
||||
TASK_AddTaskEntryBreakpoint( hTask );
|
||||
|
||||
/* Get the task up and running. */
|
||||
|
||||
if ( THREAD_IsWin16( pTask->thdb ) )
|
||||
{
|
||||
/* Post event to start the task */
|
||||
PostEvent16( hTask );
|
||||
|
||||
/* If we ourselves are a 16-bit task, we Yield() directly. */
|
||||
if ( THREAD_IsWin16( THREAD_Current() ) )
|
||||
OldYield16();
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* TASK_DeleteTask
|
||||
*/
|
||||
|
@ -608,60 +524,23 @@ void TASK_KillTask( HTASK16 hTask )
|
|||
if ( hLockedTask == hTask )
|
||||
hLockedTask = 0;
|
||||
|
||||
if ( hTaskToKill && ( hTaskToKill != hCurrentTask ) )
|
||||
{
|
||||
/* If another task is already marked for destruction, */
|
||||
/* we can kill it now, as we are in another context. */
|
||||
TASK_DeleteTask( hTaskToKill );
|
||||
hTaskToKill = 0;
|
||||
}
|
||||
TASK_DeleteTask( hTask );
|
||||
|
||||
/*
|
||||
* If hTask is not the task currently scheduled by the Win16
|
||||
* scheduler, we simply delete it; otherwise we mark it for
|
||||
* destruction. Note that if the current task is a 32-bit
|
||||
* one, hCurrentTask is *different* from GetCurrentTask()!
|
||||
*/
|
||||
/* When deleting the current task ... */
|
||||
if ( hTask == hCurrentTask )
|
||||
{
|
||||
assert( hTaskToKill == 0 || hTaskToKill == hCurrentTask );
|
||||
hTaskToKill = hCurrentTask;
|
||||
}
|
||||
else
|
||||
TASK_DeleteTask( hTask );
|
||||
DWORD lockCount;
|
||||
|
||||
SYSLEVEL_LeaveWin16Lock();
|
||||
}
|
||||
/* ... schedule another one ... */
|
||||
TASK_Reschedule();
|
||||
|
||||
/* ... and completely release the Win16Lock, just in case. */
|
||||
ReleaseThunkLock( &lockCount );
|
||||
|
||||
/***********************************************************************
|
||||
* TASK_KillCurrentTask
|
||||
*
|
||||
* Kill the currently running task. As it's not possible to kill the
|
||||
* current task like this, it is simply marked for destruction, and will
|
||||
* be killed when either TASK_Reschedule or this function is called again
|
||||
* in the context of another task.
|
||||
*/
|
||||
void TASK_KillCurrentTask( INT16 exitCode )
|
||||
{
|
||||
if ( !THREAD_IsWin16( THREAD_Current() ) )
|
||||
{
|
||||
FIXME_(task)("called for Win32 thread (%04x)!\n", THREAD_Current()->teb_sel);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(hCurrentTask == GetCurrentTask());
|
||||
|
||||
TRACE_(task)("Killing current task %04x\n", hCurrentTask );
|
||||
|
||||
TASK_KillTask( 0 );
|
||||
|
||||
TASK_YieldToSystem();
|
||||
|
||||
/* We should never return from this Yield() */
|
||||
|
||||
ERR_(task)("Return of the living dead %04x!!!\n", hCurrentTask);
|
||||
exit(1);
|
||||
SYSLEVEL_LeaveWin16Lock();
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -669,189 +548,170 @@ void TASK_KillCurrentTask( INT16 exitCode )
|
|||
*
|
||||
* This is where all the magic of task-switching happens!
|
||||
*
|
||||
* Note: This function should only be called via the TASK_YieldToSystem()
|
||||
* wrapper, to make sure that all the context is saved correctly.
|
||||
* 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 to 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.
|
||||
*
|
||||
* It must not call functions that may yield control.
|
||||
*/
|
||||
BOOL TASK_Reschedule(void)
|
||||
void TASK_Reschedule(void)
|
||||
{
|
||||
TDB *pOldTask = NULL, *pNewTask;
|
||||
HTASK16 hTask = 0;
|
||||
STACK16FRAME *newframe16;
|
||||
TDB *pOldTask = NULL, *pNewTask = NULL;
|
||||
HTASK16 hOldTask = 0, hNewTask = 0;
|
||||
enum { MODE_YIELD, MODE_SLEEP, MODE_WAKEUP } mode;
|
||||
DWORD lockCount;
|
||||
|
||||
/* Create scheduler event */
|
||||
if ( TASK_ScheduleEvent == INVALID_HANDLE_VALUE )
|
||||
SYSLEVEL_EnterWin16Lock();
|
||||
|
||||
/* Check what we need to do */
|
||||
hOldTask = GetCurrentTask();
|
||||
pOldTask = (TDB *)GlobalLock16( hOldTask );
|
||||
TRACE_(task)( "entered with hCurrentTask %04x by hTask %04x (pid %d)\n",
|
||||
hCurrentTask, hOldTask, getpid() );
|
||||
|
||||
if ( pOldTask && THREAD_IsWin16( THREAD_Current() ) )
|
||||
{
|
||||
TASK_ScheduleEvent = CreateEventA( NULL, TRUE, FALSE, NULL );
|
||||
TASK_ScheduleEvent = ConvertToGlobalHandle( TASK_ScheduleEvent );
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Get the initial task up and running */
|
||||
if (!hCurrentTask && GetCurrentTask())
|
||||
else
|
||||
{
|
||||
/* We need to remove one pair of stackframes (exept for Winelib) */
|
||||
STACK16FRAME *oldframe16 = CURRENT_STACK16;
|
||||
STACK32FRAME *oldframe32 = oldframe16? oldframe16->frame32 : NULL;
|
||||
STACK16FRAME *newframe16 = oldframe32? PTR_SEG_TO_LIN( oldframe32->frame16 ) : NULL;
|
||||
STACK32FRAME *newframe32 = newframe16? newframe16->frame32 : NULL;
|
||||
if (newframe32)
|
||||
/* 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
|
||||
{
|
||||
newframe16->entry_ip = oldframe16->entry_ip;
|
||||
newframe16->entry_cs = oldframe16->entry_cs;
|
||||
newframe16->ip = oldframe16->ip;
|
||||
newframe16->cs = oldframe16->cs;
|
||||
newframe32->ebp = oldframe32->ebp;
|
||||
newframe32->restore_addr = oldframe32->restore_addr;
|
||||
newframe32->codeselector = oldframe32->codeselector;
|
||||
|
||||
THREAD_Current()->cur_stack = oldframe32->frame16;
|
||||
/* nothing to do */
|
||||
SYSLEVEL_LeaveWin16Lock();
|
||||
return;
|
||||
}
|
||||
|
||||
hCurrentTask = GetCurrentTask();
|
||||
pNewTask = (TDB *)GlobalLock16( hCurrentTask );
|
||||
pNewTask->ss_sp = pNewTask->thdb->cur_stack;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* NOTE: As we are entered from 16-bit code, we hold the Win16Lock.
|
||||
We hang onto it thoughout most of this routine, so that accesses
|
||||
to global variables (most notably the task list) are protected. */
|
||||
assert(hCurrentTask == GetCurrentTask());
|
||||
|
||||
TRACE_(task)("entered with hTask %04x (pid %d)\n", hCurrentTask, getpid());
|
||||
|
||||
#ifdef CONFIG_IPC
|
||||
/* FIXME: What about the Win16Lock ??? */
|
||||
dde_reschedule();
|
||||
#endif
|
||||
/* First check if there's a task to kill */
|
||||
|
||||
if (hTaskToKill && (hTaskToKill != hCurrentTask))
|
||||
/* Find a task to yield to: check for DirectedYield() */
|
||||
if ( mode == MODE_YIELD && pOldTask && pOldTask->hYieldTo )
|
||||
{
|
||||
TASK_DeleteTask( hTaskToKill );
|
||||
hTaskToKill = 0;
|
||||
}
|
||||
|
||||
/* Find a task to yield to */
|
||||
|
||||
pOldTask = (TDB *)GlobalLock16( hCurrentTask );
|
||||
if (pOldTask && pOldTask->hYieldTo)
|
||||
{
|
||||
/* check for DirectedYield() */
|
||||
|
||||
hTask = pOldTask->hYieldTo;
|
||||
pNewTask = (TDB *)GlobalLock16( hTask );
|
||||
if( !pNewTask || !pNewTask->nEvents) hTask = 0;
|
||||
hNewTask = pOldTask->hYieldTo;
|
||||
pNewTask = (TDB *)GlobalLock16( hNewTask );
|
||||
if( !pNewTask || !pNewTask->nEvents) hNewTask = 0;
|
||||
pOldTask->hYieldTo = 0;
|
||||
}
|
||||
|
||||
while (!hTask)
|
||||
/* Find a task to yield to: check for pending events */
|
||||
if ( (mode == MODE_YIELD || mode == MODE_WAKEUP) && !hNewTask )
|
||||
{
|
||||
/* Find a task that has an event pending */
|
||||
|
||||
hTask = hFirstTask;
|
||||
while (hTask)
|
||||
hNewTask = hFirstTask;
|
||||
while (hNewTask)
|
||||
{
|
||||
pNewTask = (TDB *)GlobalLock16( hTask );
|
||||
pNewTask = (TDB *)GlobalLock16( hNewTask );
|
||||
|
||||
TRACE_(task)("\ttask = %04x, events = %i\n", hTask, pNewTask->nEvents);
|
||||
TRACE_(task)( "\ttask = %04x, events = %i\n",
|
||||
hNewTask, pNewTask->nEvents );
|
||||
|
||||
if (pNewTask->nEvents) break;
|
||||
hTask = pNewTask->hNext;
|
||||
hNewTask = pNewTask->hNext;
|
||||
}
|
||||
if (hLockedTask && (hTask != hLockedTask)) hTask = 0;
|
||||
if (hTask) break;
|
||||
|
||||
/* No task found, wait for some events to come in */
|
||||
|
||||
/* NOTE: We release the Win16Lock while waiting for events. This is to enable
|
||||
Win32 threads to thunk down to 16-bit temporarily. Since Win16
|
||||
tasks won't execute and Win32 threads are not allowed to enter
|
||||
TASK_Reschedule anyway, there should be no re-entrancy problem ... */
|
||||
|
||||
ResetEvent( TASK_ScheduleEvent );
|
||||
SYSLEVEL_ReleaseWin16Lock();
|
||||
WaitForSingleObject( TASK_ScheduleEvent, INFINITE );
|
||||
SYSLEVEL_RestoreWin16Lock();
|
||||
if (hLockedTask && (hNewTask != hLockedTask)) hNewTask = 0;
|
||||
}
|
||||
|
||||
if (hTask == hCurrentTask)
|
||||
/* If we are still the task with highest priority, just return ... */
|
||||
if ( mode == MODE_YIELD && hNewTask == hCurrentTask )
|
||||
{
|
||||
TRACE_(task)("returning to the current task (%04x)\n", hCurrentTask );
|
||||
SYSLEVEL_LeaveWin16Lock();
|
||||
|
||||
/* Allow Win32 threads to thunk down even while a Win16 task is
|
||||
in a tight PeekMessage() or Yield() loop ... */
|
||||
SYSLEVEL_ReleaseWin16Lock();
|
||||
SYSLEVEL_RestoreWin16Lock();
|
||||
|
||||
TRACE_(task)("returning to the current task(%04x)\n", hTask );
|
||||
return FALSE; /* Nothing to do */
|
||||
}
|
||||
pNewTask = (TDB *)GlobalLock16( hTask );
|
||||
TRACE_(task)("Switching to task %04x (%.8s)\n",
|
||||
hTask, pNewTask->module_name );
|
||||
|
||||
/* Make the task the last in the linked list (round-robin scheduling) */
|
||||
|
||||
pNewTask->priority++;
|
||||
TASK_UnlinkTask( hTask );
|
||||
TASK_LinkTask( hTask );
|
||||
pNewTask->priority--;
|
||||
|
||||
/* Finish initializing the new task stack if necessary */
|
||||
|
||||
newframe16 = THREAD_STACK16( pNewTask->thdb );
|
||||
if (!newframe16->entry_cs)
|
||||
{
|
||||
STACK16FRAME *oldframe16 = CURRENT_STACK16;
|
||||
STACK32FRAME *oldframe32 = oldframe16->frame32;
|
||||
STACK32FRAME *newframe32 = newframe16->frame32;
|
||||
newframe16->entry_ip = oldframe16->entry_ip;
|
||||
newframe16->entry_cs = oldframe16->entry_cs;
|
||||
newframe16->ip = oldframe16->ip;
|
||||
newframe16->cs = oldframe16->cs;
|
||||
newframe32->ebp = oldframe32->ebp;
|
||||
newframe32->restore_addr = oldframe32->restore_addr;
|
||||
newframe32->codeselector = oldframe32->codeselector;
|
||||
}
|
||||
|
||||
/* Switch to the new stack */
|
||||
|
||||
/* NOTE: We need to release/restore the Win16Lock, as the task
|
||||
switched to might be at another recursion level than
|
||||
the old task ... */
|
||||
|
||||
SYSLEVEL_ReleaseWin16Lock();
|
||||
|
||||
hCurrentTask = hTask;
|
||||
SYSDEPS_SetCurThread( pNewTask->thdb );
|
||||
pNewTask->ss_sp = pNewTask->thdb->cur_stack;
|
||||
|
||||
SYSLEVEL_RestoreWin16Lock();
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* TASK_YieldToSystem
|
||||
*
|
||||
* Scheduler interface, this way we ensure that all "unsafe" events are
|
||||
* processed outside the scheduler.
|
||||
*/
|
||||
static void TASK_YieldToSystem( void )
|
||||
{
|
||||
if ( !THREAD_IsWin16( THREAD_Current() ) )
|
||||
{
|
||||
FIXME_(task)("called for Win32 thread (%04x)!\n", THREAD_Current()->teb_sel);
|
||||
ReleaseThunkLock( &lockCount );
|
||||
RestoreThunkLock( lockCount );
|
||||
return;
|
||||
}
|
||||
|
||||
EVENT_Synchronize( FALSE );
|
||||
/* If no task to yield to found, suspend 16-bit scheduler ... */
|
||||
if ( mode == MODE_YIELD && !hNewTask )
|
||||
{
|
||||
TRACE_(task)("No currently active task\n");
|
||||
hCurrentTask = 0;
|
||||
}
|
||||
|
||||
Callbacks->CallTaskRescheduleProc();
|
||||
/* If we found a task to wake up, do it ... */
|
||||
if ( (mode == MODE_YIELD || mode == MODE_WAKEUP) && hNewTask )
|
||||
{
|
||||
TRACE_(task)("Switching to task %04x (%.8s)\n",
|
||||
hNewTask, pNewTask->module_name );
|
||||
|
||||
pNewTask->priority++;
|
||||
TASK_UnlinkTask( hNewTask );
|
||||
TASK_LinkTask( hNewTask );
|
||||
pNewTask->priority--;
|
||||
|
||||
hCurrentTask = hNewTask;
|
||||
SetEvent( pNewTask->hEvent );
|
||||
|
||||
/* This is set just in case some app reads it ... */
|
||||
pNewTask->ss_sp = pNewTask->thdb->cur_stack;
|
||||
}
|
||||
|
||||
/* If we need to put the current task to sleep, do it ... */
|
||||
if ( (mode == MODE_YIELD || mode == MODE_SLEEP) && hOldTask != hCurrentTask )
|
||||
{
|
||||
ResetEvent( pOldTask->hEvent );
|
||||
|
||||
ReleaseThunkLock( &lockCount );
|
||||
SYSLEVEL_CheckNotLevel( 1 );
|
||||
WaitForSingleObject( pOldTask->hEvent, INFINITE );
|
||||
RestoreThunkLock( lockCount );
|
||||
}
|
||||
|
||||
SYSLEVEL_LeaveWin16Lock();
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* InitTask (KERNEL.91)
|
||||
*
|
||||
|
@ -943,7 +803,7 @@ BOOL16 WINAPI WaitEvent16( HTASK16 hTask )
|
|||
pTask->nEvents--;
|
||||
return FALSE;
|
||||
}
|
||||
TASK_YieldToSystem();
|
||||
TASK_Reschedule();
|
||||
|
||||
/* When we get back here, we have an event */
|
||||
|
||||
|
@ -969,7 +829,10 @@ void WINAPI PostEvent16( HTASK16 hTask )
|
|||
}
|
||||
|
||||
pTask->nEvents++;
|
||||
SetEvent( TASK_ScheduleEvent );
|
||||
|
||||
/* If we are a 32-bit task, we might need to wake up the 16-bit scheduler */
|
||||
if ( !THREAD_IsWin16( THREAD_Current() ) )
|
||||
TASK_Reschedule();
|
||||
}
|
||||
|
||||
|
||||
|
@ -1028,7 +891,7 @@ void WINAPI OldYield16(void)
|
|||
}
|
||||
|
||||
if (pCurTask) pCurTask->nEvents++; /* Make sure we get back here */
|
||||
TASK_YieldToSystem();
|
||||
TASK_Reschedule();
|
||||
if (pCurTask) pCurTask->nEvents--;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "wine/winbase16.h"
|
||||
#include "process.h"
|
||||
#include "module.h"
|
||||
#include "neexe.h"
|
||||
|
@ -261,51 +262,6 @@ static BOOL PROCESS_BuildEnvDB( PDB *pdb )
|
|||
return ENV_BuildEnvironment( pdb );
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* PROCESS_InheritEnvDB
|
||||
*/
|
||||
static BOOL PROCESS_InheritEnvDB( PDB *pdb, LPCSTR cmd_line, LPCSTR env,
|
||||
BOOL inherit_handles, STARTUPINFOA *startup )
|
||||
{
|
||||
if (!(pdb->env_db = HeapAlloc(pdb->heap, HEAP_ZERO_MEMORY, sizeof(ENVDB))))
|
||||
return FALSE;
|
||||
InitializeCriticalSection( &pdb->env_db->section );
|
||||
|
||||
/* Copy the parent environment */
|
||||
|
||||
if (!ENV_InheritEnvironment( pdb, env )) return FALSE;
|
||||
|
||||
/* Copy the command line */
|
||||
|
||||
if (!(pdb->env_db->cmd_line = HEAP_strdupA( pdb->heap, 0, cmd_line )))
|
||||
return FALSE;
|
||||
|
||||
/* Remember startup info */
|
||||
if (!(pdb->env_db->startup_info =
|
||||
HeapAlloc( pdb->heap, HEAP_ZERO_MEMORY, sizeof(STARTUPINFOA) )))
|
||||
return FALSE;
|
||||
*pdb->env_db->startup_info = *startup;
|
||||
|
||||
/* Inherit the standard handles */
|
||||
if (pdb->env_db->startup_info->dwFlags & STARTF_USESTDHANDLES)
|
||||
{
|
||||
pdb->env_db->hStdin = pdb->env_db->startup_info->hStdInput;
|
||||
pdb->env_db->hStdout = pdb->env_db->startup_info->hStdOutput;
|
||||
pdb->env_db->hStderr = pdb->env_db->startup_info->hStdError;
|
||||
}
|
||||
else if (inherit_handles)
|
||||
{
|
||||
pdb->env_db->hStdin = pdb->parent->env_db->hStdin;
|
||||
pdb->env_db->hStdout = pdb->parent->env_db->hStdout;
|
||||
pdb->env_db->hStderr = pdb->parent->env_db->hStderr;
|
||||
}
|
||||
/* else will be done later on in PROCESS_Create */
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* PROCESS_CreateEnvDB
|
||||
*
|
||||
|
@ -455,15 +411,22 @@ BOOL PROCESS_Init(void)
|
|||
void PROCESS_Start(void)
|
||||
{
|
||||
UINT cmdShow = 0;
|
||||
LPTHREAD_START_ROUTINE entry;
|
||||
LPTHREAD_START_ROUTINE entry = NULL;
|
||||
THDB *thdb = THREAD_Current();
|
||||
PDB *pdb = thdb->process;
|
||||
NE_MODULE *pModule = NE_GetPtr( pdb->module );
|
||||
OFSTRUCT *ofs = (OFSTRUCT *)((char*)(pModule) + (pModule)->fileinfo);
|
||||
IMAGE_OPTIONAL_HEADER *header = &PE_HEADER(pModule->module32)->OptionalHeader;
|
||||
IMAGE_OPTIONAL_HEADER *header = !pModule->module32? NULL :
|
||||
&PE_HEADER(pModule->module32)->OptionalHeader;
|
||||
|
||||
/* Setup process flags */
|
||||
if (header->Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI) pdb->flags |= PDB32_CONSOLE_PROC;
|
||||
/* Get process type */
|
||||
enum { PROC_DOS, PROC_WIN16, PROC_WIN32 } type;
|
||||
if ( pdb->flags & PDB32_DOS_PROC )
|
||||
type = PROC_DOS;
|
||||
else if ( pdb->flags & PDB32_WIN16_PROC )
|
||||
type = PROC_WIN16;
|
||||
else
|
||||
type = PROC_WIN32;
|
||||
|
||||
/* Map system DLLs into this process (from initial process) */
|
||||
/* FIXME: this is a hack */
|
||||
|
@ -473,23 +436,32 @@ void PROCESS_Start(void)
|
|||
InitializeCriticalSection( &pdb->crit_section );
|
||||
|
||||
/* Create the heap */
|
||||
|
||||
if (!(pdb->heap = HeapCreate( HEAP_GROWABLE, header->SizeOfHeapReserve,
|
||||
header->SizeOfHeapCommit ))) goto error;
|
||||
if (!(pdb->heap = HeapCreate( HEAP_GROWABLE,
|
||||
header? header->SizeOfHeapReserve : 0x10000,
|
||||
header? header->SizeOfHeapCommit : 0 )))
|
||||
goto error;
|
||||
pdb->heap_list = pdb->heap;
|
||||
|
||||
/* Create the environment db */
|
||||
if (!PROCESS_CreateEnvDB()) goto error;
|
||||
|
||||
PROCESS_CallUserSignalProc( USIG_THREAD_INIT, 0 ); /* for initial thread */
|
||||
|
||||
/* Create a task for this process */
|
||||
if (pdb->env_db->startup_info->dwFlags & STARTF_USESHOWWINDOW)
|
||||
cmdShow = pdb->env_db->startup_info->wShowWindow;
|
||||
if (!TASK_Create( thdb, pModule, 0, 0, cmdShow )) goto error;
|
||||
if (!TASK_Create( thdb, pModule, pdb->hInstance, pdb->hPrevInstance, cmdShow ))
|
||||
goto error;
|
||||
|
||||
/* Link the task in the task list */
|
||||
TASK_StartTask( pdb->task );
|
||||
/* Note: The USIG_PROCESS_CREATE signal is supposed to be sent in the
|
||||
* context of the parent process. Actually, the USER signal proc
|
||||
* doesn't really care about that, but it *does* require that the
|
||||
* startup parameters are correctly set up, so that GetProcessDword
|
||||
* works. Furthermore, before calling the USER signal proc the
|
||||
* 16-bit stack must be set up, which it is only after TASK_Create
|
||||
* in the case of a 16-bit process. Thus, we send the signal here.
|
||||
*/
|
||||
PROCESS_CallUserSignalProc( USIG_PROCESS_CREATE, 0 );
|
||||
|
||||
PROCESS_CallUserSignalProc( USIG_THREAD_INIT, 0 ); /* for initial thread */
|
||||
|
||||
PROCESS_CallUserSignalProc( USIG_PROCESS_INIT, 0 );
|
||||
|
||||
|
@ -498,38 +470,59 @@ void PROCESS_Start(void)
|
|||
CloseHandle( pdb->load_done_evt );
|
||||
pdb->load_done_evt = INVALID_HANDLE_VALUE;
|
||||
|
||||
/* Send the debug event to the debugger */
|
||||
entry = (LPTHREAD_START_ROUTINE)RVA_PTR(pModule->module32,
|
||||
OptionalHeader.AddressOfEntryPoint);
|
||||
if (pdb->flags & PDB32_DEBUGGED)
|
||||
DEBUG_SendCreateProcessEvent( -1 /*FIXME*/, pModule->module32, entry );
|
||||
/* Perform Win32 specific process initialization */
|
||||
if ( type == PROC_WIN32 )
|
||||
{
|
||||
/* Send the debug event to the debugger */
|
||||
entry = (LPTHREAD_START_ROUTINE)RVA_PTR(pModule->module32,
|
||||
OptionalHeader.AddressOfEntryPoint);
|
||||
if (pdb->flags & PDB32_DEBUGGED)
|
||||
DEBUG_SendCreateProcessEvent( -1 /*FIXME*/, pModule->module32, entry );
|
||||
|
||||
/* Create 32-bit MODREF */
|
||||
if (!PE_CreateModule( pModule->module32, ofs, 0, FALSE )) goto error;
|
||||
/* Create 32-bit MODREF */
|
||||
if (!PE_CreateModule( pModule->module32, ofs, 0, FALSE )) goto error;
|
||||
|
||||
/* Increment EXE refcount */
|
||||
assert( pdb->exe_modref );
|
||||
pdb->exe_modref->refCount++;
|
||||
/* Increment EXE refcount */
|
||||
assert( pdb->exe_modref );
|
||||
pdb->exe_modref->refCount++;
|
||||
|
||||
/* Initialize thread-local storage */
|
||||
PE_InitTls();
|
||||
}
|
||||
|
||||
PROCESS_CallUserSignalProc( USIG_PROCESS_LOADED, 0 ); /* FIXME: correct location? */
|
||||
|
||||
/* Initialize thread-local storage */
|
||||
|
||||
PE_InitTls();
|
||||
|
||||
if ( pdb->flags & PDB32_CONSOLE_PROC )
|
||||
if ( (pdb->flags & PDB32_CONSOLE_PROC) || (pdb->flags & PDB32_DOS_PROC) )
|
||||
AllocConsole();
|
||||
|
||||
if ( type == PROC_WIN32 )
|
||||
{
|
||||
EnterCriticalSection( &pdb->crit_section );
|
||||
MODULE_DllProcessAttach( pdb->exe_modref, (LPVOID)1 );
|
||||
LeaveCriticalSection( &pdb->crit_section );
|
||||
}
|
||||
|
||||
/* Now call the entry point */
|
||||
|
||||
EnterCriticalSection( &pdb->crit_section );
|
||||
MODULE_DllProcessAttach( pdb->exe_modref, (LPVOID)1 );
|
||||
LeaveCriticalSection( &pdb->crit_section );
|
||||
|
||||
PROCESS_CallUserSignalProc( USIG_PROCESS_RUNNING, 0 );
|
||||
|
||||
TRACE_(relay)("(entryproc=%p)\n", entry );
|
||||
ExitProcess( entry(NULL) );
|
||||
switch ( type )
|
||||
{
|
||||
case PROC_DOS:
|
||||
TRACE_(relay)( "Starting DOS process\n" );
|
||||
DOSVM_Enter( NULL );
|
||||
ERR_(relay)( "DOSVM_Enter returned; should not happen!\n" );
|
||||
ExitProcess( 0 );
|
||||
|
||||
case PROC_WIN16:
|
||||
TRACE_(relay)( "Starting Win16 process\n" );
|
||||
TASK_CallToStart();
|
||||
ERR_(relay)( "TASK_CallToStart returned; should not happen!\n" );
|
||||
ExitProcess( 0 );
|
||||
|
||||
case PROC_WIN32:
|
||||
TRACE_(relay)( "Starting Win32 process (entryproc=%p)\n", entry );
|
||||
ExitProcess( entry(NULL) );
|
||||
}
|
||||
|
||||
error:
|
||||
ExitProcess( GetLastError() );
|
||||
|
@ -547,12 +540,11 @@ PDB *PROCESS_Create( NE_MODULE *pModule, LPCSTR cmd_line, LPCSTR env,
|
|||
BOOL inherit, DWORD flags, STARTUPINFOA *startup,
|
||||
PROCESS_INFORMATION *info )
|
||||
{
|
||||
HANDLE load_done_evt = INVALID_HANDLE_VALUE;
|
||||
DWORD size, commit;
|
||||
HANDLE handles[2], load_done_evt = INVALID_HANDLE_VALUE;
|
||||
DWORD exitcode, size;
|
||||
int server_thandle;
|
||||
struct new_process_request req;
|
||||
struct new_process_reply reply;
|
||||
UINT cmdShow = 0;
|
||||
THDB *thdb = NULL;
|
||||
PDB *parent = PROCESS_Current();
|
||||
PDB *pdb = PROCESS_CreatePDB( parent, inherit );
|
||||
|
@ -591,15 +583,23 @@ PDB *PROCESS_Create( NE_MODULE *pModule, LPCSTR cmd_line, LPCSTR env,
|
|||
((parent->flags & PDB32_DEBUGGED) && !(flags & DEBUG_ONLY_THIS_PROCESS)))
|
||||
pdb->flags |= PDB32_DEBUGGED;
|
||||
|
||||
if (pModule->module32)
|
||||
if (pModule->module32) /* Win32 process */
|
||||
{
|
||||
size = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfStackReserve;
|
||||
IMAGE_OPTIONAL_HEADER *header = &PE_HEADER(pModule->module32)->OptionalHeader;
|
||||
size = header->SizeOfStackReserve;
|
||||
if (header->Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)
|
||||
pdb->flags |= PDB32_CONSOLE_PROC;
|
||||
}
|
||||
else /* 16-bit process */
|
||||
else if (!pModule->dos_image) /* Win16 process */
|
||||
{
|
||||
size = 0;
|
||||
pdb->flags |= PDB32_WIN16_PROC;
|
||||
}
|
||||
else /* DOS process */
|
||||
{
|
||||
size = 0;
|
||||
pdb->flags |= PDB32_DOS_PROC;
|
||||
}
|
||||
|
||||
/* Create the main thread */
|
||||
|
||||
|
@ -609,84 +609,49 @@ PDB *PROCESS_Create( NE_MODULE *pModule, LPCSTR cmd_line, LPCSTR env,
|
|||
info->dwThreadId = (DWORD)thdb->teb.tid;
|
||||
thdb->startup = PROCESS_Start;
|
||||
|
||||
if (pModule->module32)
|
||||
/* Create the load-done event */
|
||||
load_done_evt = CreateEventA( NULL, TRUE, FALSE, NULL );
|
||||
DuplicateHandle( GetCurrentProcess(), load_done_evt,
|
||||
info->hProcess, &pdb->load_done_evt, 0, TRUE, DUPLICATE_SAME_ACCESS );
|
||||
|
||||
/* Pass module/instance to new process (FIXME: hack) */
|
||||
pdb->module = pModule->self;
|
||||
pdb->hInstance = hInstance;
|
||||
pdb->hPrevInstance = hPrevInstance;
|
||||
SYSDEPS_SpawnThread( thdb );
|
||||
|
||||
/* Wait until process is initialized (or initialization failed) */
|
||||
handles[0] = info->hProcess;
|
||||
handles[1] = load_done_evt;
|
||||
|
||||
switch ( WaitForMultipleObjects( 2, handles, FALSE, INFINITE ) )
|
||||
{
|
||||
HANDLE handles[2];
|
||||
DWORD exitcode;
|
||||
default:
|
||||
ERR_(process)( "WaitForMultipleObjects failed\n" );
|
||||
break;
|
||||
|
||||
/* Create the load-done event */
|
||||
load_done_evt = CreateEventA( NULL, TRUE, FALSE, NULL );
|
||||
DuplicateHandle( GetCurrentProcess(), load_done_evt,
|
||||
info->hProcess, &pdb->load_done_evt, 0, TRUE, DUPLICATE_SAME_ACCESS );
|
||||
case 0:
|
||||
/* Child initialization code returns error condition as exitcode */
|
||||
if ( GetExitCodeProcess( info->hProcess, &exitcode ) )
|
||||
SetLastError( exitcode );
|
||||
goto error;
|
||||
|
||||
/* Call USER signal proc */
|
||||
PROCESS_CallUserSignalProcHelper( USIG_PROCESS_CREATE, info->dwProcessId, 0,
|
||||
pdb->flags, startup->dwFlags );
|
||||
|
||||
/* Set the process module (FIXME: hack) */
|
||||
pdb->module = pModule->self;
|
||||
SYSDEPS_SpawnThread( thdb );
|
||||
|
||||
/* Wait until process is initialized (or initialization failed) */
|
||||
handles[0] = info->hProcess;
|
||||
handles[1] = load_done_evt;
|
||||
|
||||
switch ( WaitForMultipleObjects( 2, handles, FALSE, INFINITE ) )
|
||||
case 1:
|
||||
/* Get 16-bit task up and running */
|
||||
if ( pdb->flags & PDB32_WIN16_PROC )
|
||||
{
|
||||
default:
|
||||
ERR_(process)( "WaitForMultipleObjects failed\n" );
|
||||
break;
|
||||
/* Post event to start the task */
|
||||
PostEvent16( pdb->task );
|
||||
|
||||
case 0:
|
||||
/* Child initialization code returns error condition as exitcode */
|
||||
if ( GetExitCodeProcess( info->hProcess, &exitcode ) )
|
||||
SetLastError( exitcode );
|
||||
goto error;
|
||||
|
||||
case 1:
|
||||
break;
|
||||
/* If we ourselves are a 16-bit task, we Yield() directly. */
|
||||
if ( parent->flags & PDB32_WIN16_PROC )
|
||||
OldYield16();
|
||||
}
|
||||
|
||||
CloseHandle( load_done_evt );
|
||||
load_done_evt = INVALID_HANDLE_VALUE;
|
||||
break;
|
||||
}
|
||||
else /* Create a 16-bit process */
|
||||
{
|
||||
/* Create the heap */
|
||||
size = 0x10000;
|
||||
commit = 0;
|
||||
if (!(pdb->heap = HeapCreate( HEAP_GROWABLE, size, commit ))) goto error;
|
||||
pdb->heap_list = pdb->heap;
|
||||
|
||||
/* Inherit the env DB from the parent */
|
||||
if (!PROCESS_InheritEnvDB( pdb, cmd_line, env, inherit, startup )) goto error;
|
||||
|
||||
/* Duplicate the standard handles */
|
||||
if ((!(pdb->env_db->startup_info->dwFlags & STARTF_USESTDHANDLES)) && !inherit)
|
||||
{
|
||||
DuplicateHandle( GetCurrentProcess(), pdb->parent->env_db->hStdin,
|
||||
info->hProcess, &pdb->env_db->hStdin, 0, TRUE, DUPLICATE_SAME_ACCESS );
|
||||
DuplicateHandle( GetCurrentProcess(), pdb->parent->env_db->hStdout,
|
||||
info->hProcess, &pdb->env_db->hStdout, 0, TRUE, DUPLICATE_SAME_ACCESS );
|
||||
DuplicateHandle( GetCurrentProcess(), pdb->parent->env_db->hStderr,
|
||||
info->hProcess, &pdb->env_db->hStderr, 0, TRUE, DUPLICATE_SAME_ACCESS );
|
||||
}
|
||||
|
||||
/* Call USER signal proc */
|
||||
PROCESS_CallUserSignalProcHelper( USIG_PROCESS_CREATE, info->dwProcessId, 0,
|
||||
pdb->flags, startup->dwFlags );
|
||||
|
||||
/* Create a Win16 task for this process */
|
||||
if (startup->dwFlags & STARTF_USESHOWWINDOW) cmdShow = startup->wShowWindow;
|
||||
if (!TASK_Create( thdb, pModule, hInstance, hPrevInstance, cmdShow )) goto error;
|
||||
|
||||
/* Map system DLLs into this process (from initial process) */
|
||||
/* FIXME: this is a hack */
|
||||
pdb->modref_list = PROCESS_Initial()->modref_list;
|
||||
|
||||
/* Start the task */
|
||||
TASK_StartTask( pdb->task );
|
||||
}
|
||||
CloseHandle( load_done_evt );
|
||||
load_done_evt = INVALID_HANDLE_VALUE;
|
||||
|
||||
return pdb;
|
||||
|
||||
|
@ -708,9 +673,6 @@ void WINAPI ExitProcess( DWORD status )
|
|||
MODULE_DllProcessDetach( TRUE, (LPVOID)1 );
|
||||
LeaveCriticalSection( &PROCESS_Current()->crit_section );
|
||||
|
||||
if ( THREAD_IsWin16( THREAD_Current() ) )
|
||||
TASK_KillCurrentTask( status );
|
||||
|
||||
TASK_KillTask( 0 );
|
||||
TerminateProcess( GetCurrentProcess(), status );
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue