diff --git a/include/task.h b/include/task.h index 53bf161afda..397b9ec5ded 100644 --- a/include/task.h +++ b/include/task.h @@ -150,6 +150,7 @@ 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); diff --git a/loader/task.c b/loader/task.c index 8adcb13eebf..c2724e746cc 100644 --- a/loader/task.c +++ b/loader/task.c @@ -57,7 +57,7 @@ THHOOK *pThhook = &DefaultThhook; static HTASK16 hTaskToKill = 0; static UINT16 nTaskCount = 0; -static void TASK_YieldToSystem(TDB*); +static void TASK_YieldToSystem( void ); extern BOOL THREAD_InitDone; @@ -240,48 +240,8 @@ static void TASK_CallToStart(void) if (pModule->flags & NE_FFLAGS_WIN32) { - /* FIXME: all this is an ugly hack */ - - OFSTRUCT *ofs = (OFSTRUCT *)((char*)(pModule) + (pModule)->fileinfo); - LPTHREAD_START_ROUTINE entry = (LPTHREAD_START_ROUTINE) - RVA_PTR(pModule->module32, OptionalHeader.AddressOfEntryPoint); - - /* Create 32-bit MODREF */ - if ( !PE_CreateModule( pModule->module32, ofs, 0, FALSE ) ) - { - ERR( task, "Could not initialize process\n" ); - ExitProcess( 1 ); - } - - /* Initialize Thread-Local Storage */ - PE_InitTls( pTask->thdb ); - - if (PE_HEADER(pModule->module32)->OptionalHeader.Subsystem==IMAGE_SUBSYSTEM_WINDOWS_CUI) - AllocConsole(); - - MODULE_InitializeDLLs( 0, DLL_PROCESS_ATTACH, (LPVOID)-1 ); - TRACE(relay, "(entryproc=%p)\n", entry ); - -#if 1 - ExitProcess( entry(NULL) ); -#else -{ - DWORD size = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfStackReserve; - DWORD id; - THDB *thdb; - - CreateThread( NULL, size, entry, NULL, 0, &id ); - thdb = THREAD_IdToTHDB( id ); - - while ( thdb->exit_code == 0x103 ) - { - WaitEvent16( 0 ); - QUEUE_Signal( pTask->hSelf ); - } - - ExitProcess( thdb->exit_code ); -} -#endif + ERR( task, "Called for Win32 task!\n" ); + ExitProcess( 1 ); } else if (pModule->dos_image) { @@ -356,7 +316,7 @@ BOOL TASK_Create( THDB *thdb, NE_MODULE *pModule, HINSTANCE16 hInstance, /* Fill the task structure */ - pTask->nEvents = 1; /* So the task can be started */ + pTask->nEvents = 0; pTask->hSelf = hTask; pTask->flags = 0; @@ -498,6 +458,9 @@ BOOL TASK_Create( THDB *thdb, NE_MODULE *pModule, HINSTANCE16 hInstance, */ void TASK_StartTask( HTASK16 hTask ) { + TDB *pTask = (TDB *)GlobalLock16( hTask ); + if ( !pTask ) return; + /* Add the task to the linked list */ SYSLEVEL_EnterWin16Lock(); @@ -511,15 +474,26 @@ void TASK_StartTask( HTASK16 hTask ) if ( TASK_AddTaskEntryBreakpoint ) TASK_AddTaskEntryBreakpoint( hTask ); - /* Get the task up and running. If we ourselves are a 16-bit task, - we simply Yield(). If we are 32-bit however, we need to signal - the main process somehow (NOT YET IMPLEMENTED!) */ + /* Get the task up and running. */ - if ( THREAD_IsWin16( THREAD_Current() ) ) - OldYield16(); + if ( THREAD_IsWin16( pTask->thdb ) ) + { + pTask->nEvents++; + + /* If we ourselves are a 16-bit task, we simply Yield(). + If we are 32-bit however, we need to signal the scheduler. */ + + if ( THREAD_IsWin16( THREAD_Current() ) ) + OldYield16(); + else + EVENT_WakeUp(); + } else - /* wake-up the scheduler waiting in EVENT_WaitNetEvent */ - EVENT_WakeUp(); + { + /* To start a 32-bit task, we spawn its initial thread. */ + + SYSDEPS_SpawnThread( pTask->thdb ); + } } @@ -560,37 +534,25 @@ static void TASK_DeleteTask( HTASK16 hTask ) GlobalFreeAll16( hPDB ); } - /*********************************************************************** - * 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. + * TASK_KillTask */ -void TASK_KillCurrentTask( INT16 exitCode ) +void TASK_KillTask( HTASK16 hTask ) { - TDB* pTask = (TDB*) GlobalLock16( GetCurrentTask() ); - NE_MODULE* pModule = NE_GetPtr( pTask->hModule ); - if (!pTask) USER_ExitWindows(); /* No current task yet */ + TDB *pTask; - if ( !THREAD_IsWin16( THREAD_Current() ) ) + /* Enter the Win16Lock to protect global data structures */ + SYSLEVEL_EnterWin16Lock(); + + if ( !hTask ) hTask = GetCurrentTask(); + pTask = (TDB *)GlobalLock16( hTask ); + if ( !pTask ) { - FIXME(task, "called for Win32 thread (%04x)!\n", THREAD_Current()->teb_sel); + SYSLEVEL_LeaveWin16Lock(); return; } - /* Enter the Win16Lock to protect global data structures - NOTE: We never explicitly leave it again. This shouldn't matter - though, as it will be released in TASK_Reschedule and this - task won't ever get scheduled again ... */ - - SYSLEVEL_EnterWin16Lock(); - - assert(hCurrentTask == GetCurrentTask()); - - TRACE(task, "Killing task %04x\n", hCurrentTask ); + TRACE(task, "Killing task %04x\n", hTask ); /* Delete active sockets */ @@ -598,9 +560,12 @@ void TASK_KillCurrentTask( INT16 exitCode ) WINSOCK_DeleteTaskWSI( pTask, pTask->pwsi ); #ifdef MZ_SUPPORTED +{ /* Kill DOS VM task */ + NE_MODULE *pModule = NE_GetPtr( pTask->hModule ); if ( pModule->lpDosTask ) MZ_KillModule( pModule->lpDosTask ); +} #endif /* Perform USER cleanup */ @@ -609,13 +574,6 @@ void TASK_KillCurrentTask( INT16 exitCode ) pTask->userhandler( hCurrentTask, USIG_TERMINATION, 0, pTask->hInstance, pTask->hQueue ); - 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 ); - } - if (nTaskCount <= 1) { TRACE(task, "this is the last task, exiting\n" ); @@ -631,22 +589,71 @@ void TASK_KillCurrentTask( INT16 exitCode ) Callout.PostAppMessage16( PROCESS_Initial()->task, WM_NULL, 0, 0 ); /* Remove the task from the list to be sure we never switch back to it */ - TASK_UnlinkTask( hCurrentTask ); + TASK_UnlinkTask( hTask ); if( nTaskCount ) { TDB* p = (TDB *)GlobalLock16( hFirstTask ); while( p ) { - if( p->hYieldTo == hCurrentTask ) p->hYieldTo = 0; + if( p->hYieldTo == hTask ) p->hYieldTo = 0; p = (TDB *)GlobalLock16( p->hNext ); } } - hTaskToKill = hCurrentTask; - hLockedTask = 0; - pTask->nEvents = 0; - TASK_YieldToSystem(pTask); + + 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; + } + + /* + * 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()! + */ + if ( hTask == hCurrentTask ) + { + assert( hTaskToKill == 0 || hTaskToKill == hCurrentTask ); + hTaskToKill = hCurrentTask; + } + else + TASK_DeleteTask( hTask ); + + SYSLEVEL_LeaveWin16Lock(); +} + + +/*********************************************************************** + * 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() */ @@ -824,7 +831,7 @@ BOOL TASK_Reschedule(void) * Scheduler interface, this way we ensure that all "unsafe" events are * processed outside the scheduler. */ -void TASK_YieldToSystem(TDB* pTask) +static void TASK_YieldToSystem( void ) { if ( !THREAD_IsWin16( THREAD_Current() ) ) { @@ -944,7 +951,7 @@ BOOL16 WINAPI WaitEvent16( HTASK16 hTask ) pTask->nEvents--; return FALSE; } - TASK_YieldToSystem(pTask); + TASK_YieldToSystem(); /* When we get back here, we have an event */ @@ -963,6 +970,12 @@ void WINAPI PostEvent16( HTASK16 hTask ) if (!hTask) hTask = GetCurrentTask(); if (!(pTask = (TDB *)GlobalLock16( hTask ))) return; + if ( !THREAD_IsWin16( pTask->thdb ) ) + { + FIXME( task, "called for Win32 thread (%04x)!\n", pTask->thdb->teb_sel ); + return; + } + pTask->nEvents++; if ( !THREAD_IsWin16( THREAD_Current() ) ) @@ -1028,7 +1041,7 @@ void WINAPI OldYield16(void) } if (pCurTask) pCurTask->nEvents++; /* Make sure we get back here */ - TASK_YieldToSystem(pCurTask); + TASK_YieldToSystem(); if (pCurTask) pCurTask->nEvents--; } diff --git a/scheduler/process.c b/scheduler/process.c index 5f7bb342025..02c0dfaf654 100644 --- a/scheduler/process.c +++ b/scheduler/process.c @@ -288,6 +288,7 @@ BOOL PROCESS_Init(void) initial_pdb.ring0_threads = 1; initial_pdb.group = &initial_pdb; initial_pdb.priority = 8; /* Normal */ + initial_pdb.flags = PDB32_WIN16_PROC; /* Initialize virtual memory management */ if (!VIRTUAL_Init()) return FALSE; @@ -330,8 +331,11 @@ void PROCESS_Start(void) LPTHREAD_START_ROUTINE entry; THDB *thdb = THREAD_Current(); PDB *pdb = thdb->process; - NE_MODULE *pModule = (NE_MODULE *)thdb->entry_arg; /* hack */ + TDB *pTask = (TDB *)GlobalLock16( pdb->task ); + NE_MODULE *pModule = NE_GetPtr( pTask->hModule ); + OFSTRUCT *ofs = (OFSTRUCT *)((char*)(pModule) + (pModule)->fileinfo); +#if 0 /* Initialize the critical section */ InitializeCriticalSection( &pdb->crit_section ); @@ -347,10 +351,10 @@ void PROCESS_Start(void) if (!PROCESS_CreateEnvDB()) goto error; -#if 0 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; + #endif /* Map system DLLs into this process (from initial process) */ @@ -358,10 +362,7 @@ void PROCESS_Start(void) pdb->modref_list = PROCESS_Initial()->modref_list; /* Create 32-bit MODREF */ - { - OFSTRUCT *ofs = (OFSTRUCT *)((char*)(pModule) + (pModule)->fileinfo); - if (!PE_CreateModule( pModule->module32, ofs, 0, FALSE )) goto error; - } + if (!PE_CreateModule( pModule->module32, ofs, 0, FALSE )) goto error; /* Initialize thread-local storage */ @@ -463,6 +464,7 @@ PDB *PROCESS_Create( NE_MODULE *pModule, LPCSTR cmd_line, LPCSTR env, goto error; info->hThread = server_thandle; info->dwThreadId = (DWORD)thdb->server_tid; + thdb->startup = PROCESS_Start; /* Duplicate the standard handles */ @@ -509,20 +511,13 @@ error: */ void WINAPI ExitProcess( DWORD status ) { - PDB *pdb = PROCESS_Current(); - TDB *pTask = (TDB *)GlobalLock16( pdb->task ); - if ( pTask ) pTask->nEvents++; - MODULE_InitializeDLLs( 0, DLL_PROCESS_DETACH, NULL ); - if ( pTask && pTask->thdb != THREAD_Current() ) - TerminateProcess( GetCurrentProcess(), status ); + if ( THREAD_IsWin16( THREAD_Current() ) ) + TASK_KillCurrentTask( status ); - /* FIXME: should kill all running threads of this process */ - pdb->exit_code = status; - - __RESTORE_ES; /* Necessary for Pietrek's showseh example program */ - TASK_KillCurrentTask( status ); + TASK_KillTask( 0 ); + TerminateProcess( GetCurrentProcess(), status ); } diff --git a/scheduler/thread.c b/scheduler/thread.c index f08cde6f5dc..4a6f5f10be8 100644 --- a/scheduler/thread.c +++ b/scheduler/thread.c @@ -54,13 +54,7 @@ THDB *THREAD_Current(void) */ BOOL THREAD_IsWin16( THDB *thdb ) { - if (!thdb || !thdb->process) - return TRUE; - else - { - TDB* pTask = (TDB*)GlobalLock16( thdb->process->task ); - return !pTask || pTask->thdb == thdb; - } + return !thdb || !(thdb->teb.flags & TEBF_WIN32); } /*********************************************************************** @@ -188,7 +182,7 @@ THDB *THREAD_CreateInitialThread( PDB *pdb, int server_fd ) initial_thdb.process = pdb; initial_thdb.teb.except = (void *)-1; initial_thdb.teb.self = &initial_thdb.teb; - initial_thdb.teb.flags = TEBF_WIN32; + initial_thdb.teb.flags = /* TEBF_WIN32 */ 0; initial_thdb.teb.tls_ptr = initial_thdb.tls_array; initial_thdb.teb.process = pdb; initial_thdb.exit_code = 0x103; /* STILL_ACTIVE */