16-bit scheduler reorganized: run all tasks in their own thread.
[wine] / scheduler / process.c
1 /*
2  * Win32 processes
3  *
4  * Copyright 1996, 1998 Alexandre Julliard
5  */
6
7 #include <assert.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include "wine/winbase16.h"
12 #include "process.h"
13 #include "module.h"
14 #include "neexe.h"
15 #include "file.h"
16 #include "global.h"
17 #include "heap.h"
18 #include "task.h"
19 #include "ldt.h"
20 #include "syslevel.h"
21 #include "thread.h"
22 #include "winerror.h"
23 #include "pe_image.h"
24 #include "task.h"
25 #include "server.h"
26 #include "callback.h"
27 #include "debugtools.h"
28
29 DECLARE_DEBUG_CHANNEL(process)
30 DECLARE_DEBUG_CHANNEL(relay)
31 DECLARE_DEBUG_CHANNEL(win32)
32
33
34 /* The initial process PDB */
35 static PDB initial_pdb;
36
37 static PDB *PROCESS_First = &initial_pdb;
38
39 /***********************************************************************
40  *           PROCESS_Current
41  */
42 PDB *PROCESS_Current(void)
43 {
44     return THREAD_Current()->process;
45 }
46
47 /***********************************************************************
48  *           PROCESS_Initial
49  *
50  * FIXME: This works only while running all processes in the same
51  *        address space (or, at least, the initial process is mapped
52  *        into all address spaces as is KERNEL32 in Windows 95)
53  *
54  */
55 PDB *PROCESS_Initial(void)
56 {
57     return &initial_pdb;
58 }
59
60 /***********************************************************************
61  *           PROCESS_QueryInfo
62  *
63  * Retrieve information about a process
64  */
65 static BOOL PROCESS_QueryInfo( HANDLE handle,
66                                  struct get_process_info_reply *reply )
67 {
68     struct get_process_info_request req;
69     req.handle = handle;
70     CLIENT_SendRequest( REQ_GET_PROCESS_INFO, -1, 1, &req, sizeof(req) );
71     return !CLIENT_WaitSimpleReply( reply, sizeof(*reply), NULL );
72 }
73
74 /***********************************************************************
75  *           PROCESS_IsCurrent
76  *
77  * Check if a handle is to the current process
78  */
79 BOOL PROCESS_IsCurrent( HANDLE handle )
80 {
81     struct get_process_info_reply reply;
82     return (PROCESS_QueryInfo( handle, &reply ) &&
83             (reply.pid == PROCESS_Current()->server_pid));
84 }
85
86
87 /***********************************************************************
88  *           PROCESS_IdToPDB
89  *
90  * Convert a process id to a PDB, making sure it is valid.
91  */
92 PDB *PROCESS_IdToPDB( DWORD id )
93 {
94     PDB *pdb;
95
96     if (!id) return PROCESS_Current();
97     pdb = PROCESS_First;
98     while (pdb)
99     {
100         if ((DWORD)pdb->server_pid == id) return pdb;
101         pdb = pdb->next;
102     }
103     SetLastError( ERROR_INVALID_PARAMETER );
104     return NULL;
105 }
106
107
108 /***********************************************************************
109  *           PROCESS_CallUserSignalProc
110  *
111  * FIXME:  Some of the signals aren't sent correctly!
112  *
113  * The exact meaning of the USER signals is undocumented, but this 
114  * should cover the basic idea:
115  *
116  * USIG_DLL_UNLOAD_WIN16
117  *     This is sent when a 16-bit module is unloaded.
118  *
119  * USIG_DLL_UNLOAD_WIN32
120  *     This is sent when a 32-bit module is unloaded.
121  *
122  * USIG_DLL_UNLOAD_ORPHANS
123  *     This is sent after the last Win3.1 module is unloaded,
124  *     to allow removal of orphaned menus.
125  *
126  * USIG_FAULT_DIALOG_PUSH
127  * USIG_FAULT_DIALOG_POP
128  *     These are called to allow USER to prepare for displaying a
129  *     fault dialog, even though the fault might have happened while
130  *     inside a USER critical section.
131  *
132  * USIG_THREAD_INIT
133  *     This is called from the context of a new thread, as soon as it
134  *     has started to run.
135  *
136  * USIG_THREAD_EXIT
137  *     This is called, still in its context, just before a thread is
138  *     about to terminate.
139  *
140  * USIG_PROCESS_CREATE
141  *     This is called, in the parent process context, after a new process
142  *     has been created.
143  *
144  * USIG_PROCESS_INIT
145  *     This is called in the new process context, just after the main thread
146  *     has started execution (after the main thread's USIG_THREAD_INIT has
147  *     been sent).
148  *
149  * USIG_PROCESS_LOADED
150  *     This is called after the executable file has been loaded into the
151  *     new process context.
152  *
153  * USIG_PROCESS_RUNNING
154  *     This is called immediately before the main entry point is called.
155  *
156  * USIG_PROCESS_EXIT
157  *     This is called in the context of a process that is about to
158  *     terminate (but before the last thread's USIG_THREAD_EXIT has
159  *     been sent).
160  *
161  * USIG_PROCESS_DESTROY
162  *     This is called after a process has terminated.
163  *
164  *
165  * The meaning of the dwFlags bits is as follows:
166  *
167  * USIG_FLAGS_WIN32
168  *     Current process is 32-bit.
169  *
170  * USIG_FLAGS_GUI
171  *     Current process is a (Win32) GUI process.
172  *
173  * USIG_FLAGS_FEEDBACK 
174  *     Current process needs 'feedback' (determined from the STARTUPINFO
175  *     flags STARTF_FORCEONFEEDBACK / STARTF_FORCEOFFFEEDBACK).
176  *
177  * USIG_FLAGS_FAULT
178  *     The signal is being sent due to a fault.
179  */
180 static void PROCESS_CallUserSignalProcHelper( UINT uCode, DWORD dwThreadOrProcessId,
181                                               HMODULE hModule, DWORD flags, DWORD startup_flags )
182 {
183     DWORD dwFlags = 0;
184
185     /* Determine dwFlags */
186
187     if ( !(flags & PDB32_WIN16_PROC) ) dwFlags |= USIG_FLAGS_WIN32;
188
189     if ( !(flags & PDB32_CONSOLE_PROC) ) dwFlags |= USIG_FLAGS_GUI;
190
191     if ( dwFlags & USIG_FLAGS_GUI )
192     {
193         /* Feedback defaults to ON */
194         if ( !(startup_flags & STARTF_FORCEOFFFEEDBACK) )
195             dwFlags |= USIG_FLAGS_FEEDBACK;
196     }
197     else
198     {
199         /* Feedback defaults to OFF */
200         if (startup_flags & STARTF_FORCEONFEEDBACK)
201             dwFlags |= USIG_FLAGS_FEEDBACK;
202     }
203
204     /* Convert module handle to 16-bit */
205
206     if ( HIWORD( hModule ) )
207         hModule = MapHModuleLS( hModule );
208
209     /* Call USER signal proc */
210
211     if ( Callout.UserSignalProc )
212         Callout.UserSignalProc( uCode, dwThreadOrProcessId, dwFlags, hModule );
213 }
214
215 /* Call USER signal proc for the current thread/process */
216 void PROCESS_CallUserSignalProc( UINT uCode, HMODULE hModule )
217 {
218     DWORD dwThreadOrProcessId;
219
220     /* Get thread or process ID */
221     if ( uCode == USIG_THREAD_INIT || uCode == USIG_THREAD_EXIT )
222         dwThreadOrProcessId = GetCurrentThreadId();
223     else
224         dwThreadOrProcessId = GetCurrentProcessId();
225
226     PROCESS_CallUserSignalProcHelper( uCode, dwThreadOrProcessId, hModule,
227                                       PROCESS_Current()->flags,
228                                       PROCESS_Current()->env_db->startup_info->dwFlags );
229 }
230
231
232 /***********************************************************************
233  *           PROCESS_BuildEnvDB
234  *
235  * Build the env DB for the initial process
236  */
237 static BOOL PROCESS_BuildEnvDB( PDB *pdb )
238 {
239     /* Allocate the env DB (FIXME: should not be on the system heap) */
240
241     if (!(pdb->env_db = HeapAlloc(SystemHeap,HEAP_ZERO_MEMORY,sizeof(ENVDB))))
242         return FALSE;
243     InitializeCriticalSection( &pdb->env_db->section );
244
245     /* Allocate startup info */
246     if (!(pdb->env_db->startup_info = 
247           HeapAlloc( SystemHeap, HEAP_ZERO_MEMORY, sizeof(STARTUPINFOA) )))
248         return FALSE;
249
250     /* Allocate the standard handles */
251
252     pdb->env_db->hStdin  = FILE_DupUnixHandle( 0, GENERIC_READ );
253     pdb->env_db->hStdout = FILE_DupUnixHandle( 1, GENERIC_WRITE );
254     pdb->env_db->hStderr = FILE_DupUnixHandle( 2, GENERIC_WRITE );
255
256     /* Build the command-line */
257
258     pdb->env_db->cmd_line = HEAP_strdupA( SystemHeap, 0, "kernel32" );
259
260     /* Build the environment strings */
261
262     return ENV_BuildEnvironment( pdb );
263 }
264
265 /***********************************************************************
266  *           PROCESS_CreateEnvDB
267  *
268  * Create the env DB for a newly started process.
269  */
270 static BOOL PROCESS_CreateEnvDB(void)
271 {
272     struct init_process_request req;
273     struct init_process_reply reply;
274     STARTUPINFOA *startup;
275     ENVDB *env_db;
276     char cmd_line[4096];
277     int len;
278     PDB *pdb = PROCESS_Current();
279
280     /* Retrieve startup info from the server */
281
282     req.dummy = 0;
283     CLIENT_SendRequest( REQ_INIT_PROCESS, -1, 1, &req, sizeof(req) );
284     if (CLIENT_WaitReply( &len, NULL, 2, &reply, sizeof(reply), cmd_line, sizeof(cmd_line) ))
285         return FALSE;
286
287     /* Allocate the env DB */
288
289     if (!(env_db = HeapAlloc( pdb->heap, HEAP_ZERO_MEMORY, sizeof(ENVDB) )))
290         return FALSE;
291     pdb->env_db = env_db;
292     InitializeCriticalSection( &env_db->section );
293
294     /* Allocate and fill the startup info */
295     if (!(startup = HeapAlloc( pdb->heap, HEAP_ZERO_MEMORY, sizeof(STARTUPINFOA) )))
296         return FALSE;
297     env_db->startup_info = startup;
298     startup->dwFlags     = reply.start_flags;
299     startup->wShowWindow = reply.cmd_show;
300     env_db->hStdin  = startup->hStdInput  = reply.hstdin;
301     env_db->hStdout = startup->hStdOutput = reply.hstdout;
302     env_db->hStderr = startup->hStdError  = reply.hstderr;
303
304     /* Copy the parent environment */
305
306     if (!ENV_InheritEnvironment( pdb, reply.env_ptr )) return FALSE;
307
308     /* Copy the command line */
309
310     if (!(pdb->env_db->cmd_line = HEAP_strdupA( pdb->heap, 0, cmd_line )))
311         return FALSE;
312
313     return TRUE;
314 }
315
316
317 /***********************************************************************
318  *           PROCESS_FreePDB
319  *
320  * Free a PDB and all associated storage.
321  */
322 void PROCESS_FreePDB( PDB *pdb )
323 {
324     PDB **pptr = &PROCESS_First;
325
326     ENV_FreeEnvironment( pdb );
327     while (*pptr && (*pptr != pdb)) pptr = &(*pptr)->next;
328     if (*pptr) *pptr = pdb->next;
329     if (pdb->heap && (pdb->heap != pdb->system_heap)) HeapDestroy( pdb->heap );
330     HeapFree( SystemHeap, 0, pdb );
331 }
332
333
334 /***********************************************************************
335  *           PROCESS_CreatePDB
336  *
337  * Allocate and fill a PDB structure.
338  * Runs in the context of the parent process.
339  */
340 static PDB *PROCESS_CreatePDB( PDB *parent, BOOL inherit )
341 {
342     PDB *pdb = HeapAlloc( SystemHeap, HEAP_ZERO_MEMORY, sizeof(PDB) );
343
344     if (!pdb) return NULL;
345     pdb->exit_code       = 0x103; /* STILL_ACTIVE */
346     pdb->threads         = 1;
347     pdb->running_threads = 1;
348     pdb->ring0_threads   = 1;
349     pdb->system_heap     = SystemHeap;
350     pdb->parent          = parent;
351     pdb->group           = pdb;
352     pdb->priority        = 8;  /* Normal */
353     pdb->heap            = pdb->system_heap;  /* will be changed later on */
354     pdb->next            = PROCESS_First;
355     PROCESS_First = pdb;
356     return pdb;
357 }
358
359
360 /***********************************************************************
361  *           PROCESS_Init
362  */
363 BOOL PROCESS_Init(void)
364 {
365     THDB *thdb;
366     int server_fd;
367
368     /* Start the server */
369     server_fd = CLIENT_InitServer();
370
371     /* Fill the initial process structure */
372     initial_pdb.exit_code       = 0x103; /* STILL_ACTIVE */
373     initial_pdb.threads         = 1;
374     initial_pdb.running_threads = 1;
375     initial_pdb.ring0_threads   = 1;
376     initial_pdb.group           = &initial_pdb;
377     initial_pdb.priority        = 8;  /* Normal */
378     initial_pdb.flags           = PDB32_WIN16_PROC;
379
380     /* Initialize virtual memory management */
381     if (!VIRTUAL_Init()) return FALSE;
382
383     /* Create the initial thread structure and socket pair */
384     if (!(thdb = THREAD_CreateInitialThread( &initial_pdb, server_fd ))) return FALSE;
385
386     /* Remember TEB selector of initial process for emergency use */
387     SYSLEVEL_EmergencyTeb = thdb->teb_sel;
388
389     /* Create the system heap */
390     if (!(SystemHeap = HeapCreate( HEAP_GROWABLE, 0x10000, 0 ))) return FALSE;
391     initial_pdb.system_heap = initial_pdb.heap = SystemHeap;
392
393     /* Create the environment DB of the first process */
394     if (!PROCESS_BuildEnvDB( &initial_pdb )) return FALSE;
395
396     /* Create the SEGPTR heap */
397     if (!(SegptrHeap = HeapCreate( HEAP_WINE_SEGPTR, 0, 0 ))) return FALSE;
398
399     /* Initialize the first process critical section */
400     InitializeCriticalSection( &initial_pdb.crit_section );
401
402     return TRUE;
403 }
404
405
406 /***********************************************************************
407  *           PROCESS_Start
408  *
409  * Startup routine of a new process. Called in the context of the new process.
410  */
411 void PROCESS_Start(void)
412 {
413     UINT cmdShow = 0;
414     LPTHREAD_START_ROUTINE entry = NULL;
415     THDB *thdb = THREAD_Current();
416     PDB *pdb = thdb->process;
417     NE_MODULE *pModule = NE_GetPtr( pdb->module );
418     OFSTRUCT *ofs = (OFSTRUCT *)((char*)(pModule) + (pModule)->fileinfo);
419     IMAGE_OPTIONAL_HEADER *header = !pModule->module32? NULL :
420                                     &PE_HEADER(pModule->module32)->OptionalHeader;
421
422     /* Get process type */
423     enum { PROC_DOS, PROC_WIN16, PROC_WIN32 } type;
424     if ( pdb->flags & PDB32_DOS_PROC )
425         type = PROC_DOS;
426     else if ( pdb->flags & PDB32_WIN16_PROC )
427         type = PROC_WIN16;
428     else
429         type = PROC_WIN32;
430
431     /* Map system DLLs into this process (from initial process) */
432     /* FIXME: this is a hack */
433     pdb->modref_list = PROCESS_Initial()->modref_list;
434
435     /* Initialize the critical section */
436     InitializeCriticalSection( &pdb->crit_section );
437
438     /* Create the heap */
439     if (!(pdb->heap = HeapCreate( HEAP_GROWABLE, 
440                                   header? header->SizeOfHeapReserve : 0x10000,
441                                   header? header->SizeOfHeapCommit  : 0 ))) 
442         goto error;
443     pdb->heap_list = pdb->heap;
444
445     /* Create the environment db */
446     if (!PROCESS_CreateEnvDB()) goto error;
447
448     /* Create a task for this process */
449     if (pdb->env_db->startup_info->dwFlags & STARTF_USESHOWWINDOW)
450         cmdShow = pdb->env_db->startup_info->wShowWindow;
451     if (!TASK_Create( thdb, pModule, pdb->hInstance, pdb->hPrevInstance, cmdShow ))
452         goto error;
453
454     /* Note: The USIG_PROCESS_CREATE signal is supposed to be sent in the
455      *       context of the parent process.  Actually, the USER signal proc
456      *       doesn't really care about that, but it *does* require that the
457      *       startup parameters are correctly set up, so that GetProcessDword
458      *       works.  Furthermore, before calling the USER signal proc the 
459      *       16-bit stack must be set up, which it is only after TASK_Create
460      *       in the case of a 16-bit process. Thus, we send the signal here.
461      */
462     PROCESS_CallUserSignalProc( USIG_PROCESS_CREATE, 0 );
463
464     PROCESS_CallUserSignalProc( USIG_THREAD_INIT, 0 );  /* for initial thread */
465
466     PROCESS_CallUserSignalProc( USIG_PROCESS_INIT, 0 );
467
468     /* Signal the parent process to continue */
469     SetEvent( pdb->load_done_evt );
470     CloseHandle( pdb->load_done_evt );
471     pdb->load_done_evt = INVALID_HANDLE_VALUE;
472
473     /* Perform Win32 specific process initialization */
474     if ( type == PROC_WIN32 )
475     {
476         /* Send the debug event to the debugger */
477         entry = (LPTHREAD_START_ROUTINE)RVA_PTR(pModule->module32,
478                                                 OptionalHeader.AddressOfEntryPoint);
479         if (pdb->flags & PDB32_DEBUGGED)
480             DEBUG_SendCreateProcessEvent( -1 /*FIXME*/, pModule->module32, entry );
481
482         /* Create 32-bit MODREF */
483         if (!PE_CreateModule( pModule->module32, ofs, 0, FALSE )) goto error;
484
485         /* Increment EXE refcount */
486         assert( pdb->exe_modref );
487         pdb->exe_modref->refCount++;
488
489         /* Initialize thread-local storage */
490         PE_InitTls();
491     }
492
493     PROCESS_CallUserSignalProc( USIG_PROCESS_LOADED, 0 );   /* FIXME: correct location? */
494
495     if ( (pdb->flags & PDB32_CONSOLE_PROC) || (pdb->flags & PDB32_DOS_PROC) )
496         AllocConsole();
497
498     if ( type == PROC_WIN32 )
499     {
500         EnterCriticalSection( &pdb->crit_section );
501         MODULE_DllProcessAttach( pdb->exe_modref, (LPVOID)1 );
502         LeaveCriticalSection( &pdb->crit_section );
503     }
504
505     /* Now call the entry point */
506     PROCESS_CallUserSignalProc( USIG_PROCESS_RUNNING, 0 );
507
508     switch ( type )
509     {
510     case PROC_DOS:
511         TRACE_(relay)( "Starting DOS process\n" );
512         DOSVM_Enter( NULL );
513         ERR_(relay)( "DOSVM_Enter returned; should not happen!\n" );
514         ExitProcess( 0 );
515
516     case PROC_WIN16:
517         TRACE_(relay)( "Starting Win16 process\n" );
518         TASK_CallToStart();
519         ERR_(relay)( "TASK_CallToStart returned; should not happen!\n" );
520         ExitProcess( 0 );
521
522     case PROC_WIN32:
523         TRACE_(relay)( "Starting Win32 process (entryproc=%p)\n", entry );
524         ExitProcess( entry(NULL) );
525     }
526
527  error:
528     ExitProcess( GetLastError() );
529 }
530
531
532 /***********************************************************************
533  *           PROCESS_Create
534  *
535  * Create a new process database and associated info.
536  */
537 PDB *PROCESS_Create( NE_MODULE *pModule, LPCSTR cmd_line, LPCSTR env,
538                      HINSTANCE16 hInstance, HINSTANCE16 hPrevInstance,
539                      LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
540                      BOOL inherit, DWORD flags, STARTUPINFOA *startup,
541                      PROCESS_INFORMATION *info )
542 {
543     HANDLE handles[2], load_done_evt = INVALID_HANDLE_VALUE;
544     DWORD exitcode, size;
545     int server_thandle;
546     struct new_process_request req;
547     struct new_process_reply reply;
548     THDB *thdb = NULL;
549     PDB *parent = PROCESS_Current();
550     PDB *pdb = PROCESS_CreatePDB( parent, inherit );
551
552     if (!pdb) return NULL;
553     info->hThread = info->hProcess = INVALID_HANDLE_VALUE;
554
555     /* Create the process on the server side */
556
557     req.inherit      = (psa && (psa->nLength >= sizeof(*psa)) && psa->bInheritHandle);
558     req.inherit_all  = inherit;
559     req.create_flags = flags;
560     req.start_flags  = startup->dwFlags;
561     if (startup->dwFlags & STARTF_USESTDHANDLES)
562     {
563         req.hstdin  = startup->hStdInput;
564         req.hstdout = startup->hStdOutput;
565         req.hstderr = startup->hStdError;
566     }
567     else
568     {
569         req.hstdin  = GetStdHandle( STD_INPUT_HANDLE );
570         req.hstdout = GetStdHandle( STD_OUTPUT_HANDLE );
571         req.hstderr = GetStdHandle( STD_ERROR_HANDLE );
572     }
573     req.cmd_show = startup->wShowWindow;
574     req.env_ptr = (void*)env;  /* FIXME: hack */
575     CLIENT_SendRequest( REQ_NEW_PROCESS, -1, 2,
576                         &req, sizeof(req), cmd_line, strlen(cmd_line) + 1 );
577     if (CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL )) goto error;
578     pdb->server_pid   = reply.pid;
579     info->hProcess    = reply.handle;
580     info->dwProcessId = (DWORD)pdb->server_pid;
581
582     if ((flags & DEBUG_PROCESS) ||
583         ((parent->flags & PDB32_DEBUGGED) && !(flags & DEBUG_ONLY_THIS_PROCESS)))
584         pdb->flags |= PDB32_DEBUGGED;
585
586     if (pModule->module32)   /* Win32 process */
587     {
588         IMAGE_OPTIONAL_HEADER *header = &PE_HEADER(pModule->module32)->OptionalHeader;
589         size = header->SizeOfStackReserve;
590         if (header->Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI) 
591             pdb->flags |= PDB32_CONSOLE_PROC;
592     }
593     else if (!pModule->dos_image) /* Win16 process */
594     {
595         size = 0;
596         pdb->flags |= PDB32_WIN16_PROC;
597     }
598     else  /* DOS process */
599     {
600         size = 0;
601         pdb->flags |= PDB32_DOS_PROC;
602     }
603
604     /* Create the main thread */
605
606     if (!(thdb = THREAD_Create( pdb, 0L, size, hInstance == 0, tsa, &server_thandle ))) 
607         goto error;
608     info->hThread     = server_thandle;
609     info->dwThreadId  = (DWORD)thdb->teb.tid;
610     thdb->startup     = PROCESS_Start;
611
612     /* Create the load-done event */
613     load_done_evt = CreateEventA( NULL, TRUE, FALSE, NULL );
614     DuplicateHandle( GetCurrentProcess(), load_done_evt,
615                      info->hProcess, &pdb->load_done_evt, 0, TRUE, DUPLICATE_SAME_ACCESS );
616
617     /* Pass module/instance to new process (FIXME: hack) */
618     pdb->module = pModule->self;
619     pdb->hInstance = hInstance;
620     pdb->hPrevInstance = hPrevInstance;
621     SYSDEPS_SpawnThread( thdb );
622
623     /* Wait until process is initialized (or initialization failed) */
624     handles[0] = info->hProcess;
625     handles[1] = load_done_evt;
626
627     switch ( WaitForMultipleObjects( 2, handles, FALSE, INFINITE ) )
628     {
629     default: 
630         ERR_(process)( "WaitForMultipleObjects failed\n" );
631         break;
632
633     case 0:
634         /* Child initialization code returns error condition as exitcode */
635         if ( GetExitCodeProcess( info->hProcess, &exitcode ) )
636             SetLastError( exitcode );
637         goto error;
638
639     case 1:
640         /* Get 16-bit task up and running */
641         if ( pdb->flags & PDB32_WIN16_PROC )
642         {
643             /* Post event to start the task */
644             PostEvent16( pdb->task );
645
646             /* If we ourselves are a 16-bit task, we Yield() directly. */
647             if ( parent->flags & PDB32_WIN16_PROC )
648                 OldYield16();
649         }
650         break;
651     } 
652
653     CloseHandle( load_done_evt );
654     load_done_evt = INVALID_HANDLE_VALUE;
655
656     return pdb;
657
658 error:
659     if (load_done_evt != INVALID_HANDLE_VALUE) CloseHandle( load_done_evt );
660     if (info->hThread != INVALID_HANDLE_VALUE) CloseHandle( info->hThread );
661     if (info->hProcess != INVALID_HANDLE_VALUE) CloseHandle( info->hProcess );
662     PROCESS_FreePDB( pdb );
663     return NULL;
664 }
665
666
667 /***********************************************************************
668  *           ExitProcess   (KERNEL32.100)
669  */
670 void WINAPI ExitProcess( DWORD status )
671 {
672     EnterCriticalSection( &PROCESS_Current()->crit_section );
673     MODULE_DllProcessDetach( TRUE, (LPVOID)1 );
674     LeaveCriticalSection( &PROCESS_Current()->crit_section );
675
676     TASK_KillTask( 0 );
677     TerminateProcess( GetCurrentProcess(), status );
678 }
679
680 /***********************************************************************
681  *           ExitProcess16   (KERNEL.466)
682  */
683 void WINAPI ExitProcess16( WORD status )
684 {
685     SYSLEVEL_ReleaseWin16Lock();
686     ExitProcess( status );
687 }
688
689 /******************************************************************************
690  *           TerminateProcess   (KERNEL32.684)
691  */
692 BOOL WINAPI TerminateProcess( HANDLE handle, DWORD exit_code )
693 {
694     struct terminate_process_request req;
695     req.handle    = handle;
696     req.exit_code = exit_code;
697     CLIENT_SendRequest( REQ_TERMINATE_PROCESS, -1, 1, &req, sizeof(req) );
698     return !CLIENT_WaitReply( NULL, NULL, 0 );
699 }
700
701
702 /***********************************************************************
703  *           GetProcessDword    (KERNEL32.18) (KERNEL.485)
704  * 'Of course you cannot directly access Windows internal structures'
705  */
706 DWORD WINAPI GetProcessDword( DWORD dwProcessID, INT offset )
707 {
708     PDB *process = PROCESS_IdToPDB( dwProcessID );
709     TDB *pTask;
710     DWORD x, y;
711
712     TRACE_(win32)("(%ld, %d)\n", dwProcessID, offset );
713     if ( !process ) return 0;
714
715     switch ( offset ) 
716     {
717     case GPD_APP_COMPAT_FLAGS:
718         pTask = (TDB *)GlobalLock16( process->task );
719         return pTask? pTask->compat_flags : 0;
720
721     case GPD_LOAD_DONE_EVENT:
722         return process->load_done_evt;
723
724     case GPD_HINSTANCE16:
725         pTask = (TDB *)GlobalLock16( process->task );
726         return pTask? pTask->hInstance : 0;
727
728     case GPD_WINDOWS_VERSION:
729         pTask = (TDB *)GlobalLock16( process->task );
730         return pTask? pTask->version : 0;
731
732     case GPD_THDB:
733         if ( process != PROCESS_Current() ) return 0;
734         return (DWORD)THREAD_Current();
735
736     case GPD_PDB:
737         return (DWORD)process;
738
739     case GPD_STARTF_SHELLDATA: /* return stdoutput handle from startupinfo ??? */
740         return process->env_db->startup_info->hStdOutput;
741
742     case GPD_STARTF_HOTKEY: /* return stdinput handle from startupinfo ??? */
743         return process->env_db->startup_info->hStdInput;
744
745     case GPD_STARTF_SHOWWINDOW:
746         return process->env_db->startup_info->wShowWindow;
747
748     case GPD_STARTF_SIZE:
749         x = process->env_db->startup_info->dwXSize;
750         if ( x == CW_USEDEFAULT ) x = CW_USEDEFAULT16;
751         y = process->env_db->startup_info->dwYSize;
752         if ( y == CW_USEDEFAULT ) y = CW_USEDEFAULT16;
753         return MAKELONG( x, y );
754
755     case GPD_STARTF_POSITION:
756         x = process->env_db->startup_info->dwX;
757         if ( x == CW_USEDEFAULT ) x = CW_USEDEFAULT16;
758         y = process->env_db->startup_info->dwY;
759         if ( y == CW_USEDEFAULT ) y = CW_USEDEFAULT16;
760         return MAKELONG( x, y );
761
762     case GPD_STARTF_FLAGS:
763         return process->env_db->startup_info->dwFlags;
764
765     case GPD_PARENT:
766         return (DWORD)process->parent->server_pid;
767
768     case GPD_FLAGS:
769         return process->flags;
770
771     case GPD_USERDATA:
772         return process->process_dword;
773
774     default:
775         ERR_(win32)("Unknown offset %d\n", offset );
776         return 0;
777     }
778 }
779
780 /***********************************************************************
781  *           SetProcessDword    (KERNEL.484)
782  * 'Of course you cannot directly access Windows internal structures'
783  */
784 void WINAPI SetProcessDword( DWORD dwProcessID, INT offset, DWORD value )
785 {
786     PDB *process = PROCESS_IdToPDB( dwProcessID );
787
788     TRACE_(win32)("(%ld, %d)\n", dwProcessID, offset );
789     if ( !process ) return;
790
791     switch ( offset ) 
792     {
793     case GPD_APP_COMPAT_FLAGS:
794     case GPD_LOAD_DONE_EVENT:
795     case GPD_HINSTANCE16:
796     case GPD_WINDOWS_VERSION:
797     case GPD_THDB:
798     case GPD_PDB:
799     case GPD_STARTF_SHELLDATA:
800     case GPD_STARTF_HOTKEY:
801     case GPD_STARTF_SHOWWINDOW:
802     case GPD_STARTF_SIZE:
803     case GPD_STARTF_POSITION:
804     case GPD_STARTF_FLAGS:
805     case GPD_PARENT:
806     case GPD_FLAGS:
807         ERR_(win32)("Not allowed to modify offset %d\n", offset );
808         break;
809
810     case GPD_USERDATA:
811         process->process_dword = value; 
812         break;
813
814     default:
815         ERR_(win32)("Unknown offset %d\n", offset );
816         break;
817     }
818 }
819
820
821 /***********************************************************************
822  *           GetCurrentProcess   (KERNEL32.198)
823  */
824 HANDLE WINAPI GetCurrentProcess(void)
825 {
826     return CURRENT_PROCESS_PSEUDOHANDLE;
827 }
828
829
830 /*********************************************************************
831  *           OpenProcess   (KERNEL32.543)
832  */
833 HANDLE WINAPI OpenProcess( DWORD access, BOOL inherit, DWORD id )
834 {
835     struct open_process_request req;
836     struct open_process_reply reply;
837
838     req.pid     = (void *)id;
839     req.access  = access;
840     req.inherit = inherit;
841     CLIENT_SendRequest( REQ_OPEN_PROCESS, -1, 1, &req, sizeof(req) );
842     if (CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL )) return 0;
843     return reply.handle;
844 }                             
845
846 /*********************************************************************
847  *           MapProcessHandle   (KERNEL.483)
848  */
849 DWORD WINAPI MapProcessHandle( HANDLE handle )
850 {
851     struct get_process_info_reply reply;
852     if ( !PROCESS_QueryInfo( handle, &reply ) ) return 0;
853     return (DWORD)reply.pid;
854 }
855
856 /***********************************************************************
857  *           GetCurrentProcessId   (KERNEL32.199)
858  */
859 DWORD WINAPI GetCurrentProcessId(void)
860 {
861     return (DWORD)PROCESS_Current()->server_pid;
862 }
863
864
865 /***********************************************************************
866  *           GetProcessHeap    (KERNEL32.259)
867  */
868 HANDLE WINAPI GetProcessHeap(void)
869 {
870     PDB *pdb = PROCESS_Current();
871     return pdb->heap ? pdb->heap : SystemHeap;
872 }
873
874
875 /***********************************************************************
876  *           GetThreadLocale    (KERNEL32.295)
877  */
878 LCID WINAPI GetThreadLocale(void)
879 {
880     return PROCESS_Current()->locale;
881 }
882
883
884 /***********************************************************************
885  *           SetPriorityClass   (KERNEL32.503)
886  */
887 BOOL WINAPI SetPriorityClass( HANDLE hprocess, DWORD priorityclass )
888 {
889     struct set_process_info_request req;
890     req.handle   = hprocess;
891     req.priority = priorityclass;
892     req.mask     = SET_PROCESS_INFO_PRIORITY;
893     CLIENT_SendRequest( REQ_SET_PROCESS_INFO, -1, 1, &req, sizeof(req) );
894     return !CLIENT_WaitReply( NULL, NULL, 0 );
895 }
896
897
898 /***********************************************************************
899  *           GetPriorityClass   (KERNEL32.250)
900  */
901 DWORD WINAPI GetPriorityClass(HANDLE hprocess)
902 {
903     struct get_process_info_reply reply;
904     if (!PROCESS_QueryInfo( hprocess, &reply )) return 0;
905     return reply.priority;
906 }
907
908
909 /***********************************************************************
910  *          SetProcessAffinityMask   (KERNEL32.662)
911  */
912 BOOL WINAPI SetProcessAffinityMask( HANDLE hProcess, DWORD affmask )
913 {
914     struct set_process_info_request req;
915     req.handle   = hProcess;
916     req.affinity = affmask;
917     req.mask     = SET_PROCESS_INFO_AFFINITY;
918     CLIENT_SendRequest( REQ_SET_PROCESS_INFO, -1, 1, &req, sizeof(req) );
919     return !CLIENT_WaitReply( NULL, NULL, 0 );
920 }
921
922 /**********************************************************************
923  *          GetProcessAffinityMask    (KERNEL32.373)
924  */
925 BOOL WINAPI GetProcessAffinityMask( HANDLE hProcess,
926                                       LPDWORD lpProcessAffinityMask,
927                                       LPDWORD lpSystemAffinityMask )
928 {
929     struct get_process_info_reply reply;
930     if (!PROCESS_QueryInfo( hProcess, &reply )) return FALSE;
931     if (lpProcessAffinityMask) *lpProcessAffinityMask = reply.process_affinity;
932     if (lpSystemAffinityMask) *lpSystemAffinityMask = reply.system_affinity;
933     return TRUE;
934 }
935
936
937 /***********************************************************************
938  *           GetStdHandle    (KERNEL32.276)
939  */
940 HANDLE WINAPI GetStdHandle( DWORD std_handle )
941 {
942     PDB *pdb = PROCESS_Current();
943
944     switch(std_handle)
945     {
946     case STD_INPUT_HANDLE:  return pdb->env_db->hStdin;
947     case STD_OUTPUT_HANDLE: return pdb->env_db->hStdout;
948     case STD_ERROR_HANDLE:  return pdb->env_db->hStderr;
949     }
950     SetLastError( ERROR_INVALID_PARAMETER );
951     return INVALID_HANDLE_VALUE;
952 }
953
954
955 /***********************************************************************
956  *           SetStdHandle    (KERNEL32.506)
957  */
958 BOOL WINAPI SetStdHandle( DWORD std_handle, HANDLE handle )
959 {
960     PDB *pdb = PROCESS_Current();
961     /* FIXME: should we close the previous handle? */
962     switch(std_handle)
963     {
964     case STD_INPUT_HANDLE:
965         pdb->env_db->hStdin = handle;
966         return TRUE;
967     case STD_OUTPUT_HANDLE:
968         pdb->env_db->hStdout = handle;
969         return TRUE;
970     case STD_ERROR_HANDLE:
971         pdb->env_db->hStderr = handle;
972         return TRUE;
973     }
974     SetLastError( ERROR_INVALID_PARAMETER );
975     return FALSE;
976 }
977
978 /***********************************************************************
979  *           GetProcessVersion    (KERNEL32)
980  */
981 DWORD WINAPI GetProcessVersion( DWORD processid )
982 {
983     TDB *pTask;
984     PDB *pdb = PROCESS_IdToPDB( processid );
985
986     if (!pdb) return 0;
987     if (!(pTask = (TDB *)GlobalLock16( pdb->task ))) return 0;
988     return (pTask->version&0xff) | (((pTask->version >>8) & 0xff)<<16);
989 }
990
991 /***********************************************************************
992  *           GetProcessFlags    (KERNEL32)
993  */
994 DWORD WINAPI GetProcessFlags( DWORD processid )
995 {
996     PDB *pdb = PROCESS_IdToPDB( processid );
997     if (!pdb) return 0;
998     return pdb->flags;
999 }
1000
1001 /***********************************************************************
1002  *              SetProcessWorkingSetSize        [KERNEL32.662]
1003  * Sets the min/max working set sizes for a specified process.
1004  *
1005  * PARAMS
1006  *    hProcess [I] Handle to the process of interest
1007  *    minset   [I] Specifies minimum working set size
1008  *    maxset   [I] Specifies maximum working set size
1009  *
1010  * RETURNS  STD
1011  */
1012 BOOL WINAPI SetProcessWorkingSetSize(HANDLE hProcess,DWORD minset,
1013                                        DWORD maxset)
1014 {
1015     FIXME_(process)("(0x%08x,%ld,%ld): stub - harmless\n",hProcess,minset,maxset);
1016     if(( minset == -1) && (maxset == -1)) {
1017         /* Trim the working set to zero */
1018         /* Swap the process out of physical RAM */
1019     }
1020     return TRUE;
1021 }
1022
1023 /***********************************************************************
1024  *           GetProcessWorkingSetSize    (KERNEL32)
1025  */
1026 BOOL WINAPI GetProcessWorkingSetSize(HANDLE hProcess,LPDWORD minset,
1027                                        LPDWORD maxset)
1028 {
1029         FIXME_(process)("(0x%08x,%p,%p): stub\n",hProcess,minset,maxset);
1030         /* 32 MB working set size */
1031         if (minset) *minset = 32*1024*1024;
1032         if (maxset) *maxset = 32*1024*1024;
1033         return TRUE;
1034 }
1035
1036 /***********************************************************************
1037  *           SetProcessShutdownParameters    (KERNEL32)
1038  *
1039  * CHANGED - James Sutherland (JamesSutherland@gmx.de)
1040  * Now tracks changes made (but does not act on these changes)
1041  * NOTE: the definition for SHUTDOWN_NORETRY was done on guesswork.
1042  * It really shouldn't be here, but I'll move it when it's been checked!
1043  */
1044 #define SHUTDOWN_NORETRY 1
1045 static unsigned int shutdown_noretry = 0;
1046 static unsigned int shutdown_priority = 0x280L;
1047 BOOL WINAPI SetProcessShutdownParameters(DWORD level,DWORD flags)
1048 {
1049     if (flags & SHUTDOWN_NORETRY)
1050       shutdown_noretry = 1;
1051     else
1052       shutdown_noretry = 0;
1053     if (level > 0x100L && level < 0x3FFL)
1054       shutdown_priority = level;
1055     else
1056       {
1057         ERR_(process)("invalid priority level 0x%08lx\n", level);
1058         return FALSE;
1059       }
1060     return TRUE;
1061 }
1062
1063
1064 /***********************************************************************
1065  * GetProcessShutdownParameters                 (KERNEL32)
1066  *
1067  */
1068 BOOL WINAPI GetProcessShutdownParameters( LPDWORD lpdwLevel,
1069                                             LPDWORD lpdwFlags )
1070 {
1071   (*lpdwLevel) = shutdown_priority;
1072   (*lpdwFlags) = (shutdown_noretry * SHUTDOWN_NORETRY);
1073   return TRUE;
1074 }
1075 /***********************************************************************
1076  *           SetProcessPriorityBoost    (KERNEL32)
1077  */
1078 BOOL WINAPI SetProcessPriorityBoost(HANDLE hprocess,BOOL disableboost)
1079 {
1080     FIXME_(process)("(%d,%d): stub\n",hprocess,disableboost);
1081     /* Say we can do it. I doubt the program will notice that we don't. */
1082     return TRUE;
1083 }
1084
1085 /***********************************************************************
1086  *           ReadProcessMemory                  (KERNEL32)
1087  * FIXME: check this, if we ever run win32 binaries in different addressspaces
1088  *        ... and add a sizecheck
1089  */
1090 BOOL WINAPI ReadProcessMemory( HANDLE hProcess, LPCVOID lpBaseAddress,
1091                                  LPVOID lpBuffer, DWORD nSize,
1092                                  LPDWORD lpNumberOfBytesRead )
1093 {
1094         memcpy(lpBuffer,lpBaseAddress,nSize);
1095         if (lpNumberOfBytesRead) *lpNumberOfBytesRead = nSize;
1096         return TRUE;
1097 }
1098
1099 /***********************************************************************
1100  *           WriteProcessMemory                 (KERNEL32)
1101  * FIXME: check this, if we ever run win32 binaries in different addressspaces
1102  *        ... and add a sizecheck
1103  */
1104 BOOL WINAPI WriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress,
1105                                  LPVOID lpBuffer, DWORD nSize,
1106                                  LPDWORD lpNumberOfBytesWritten )
1107 {
1108         memcpy(lpBaseAddress,lpBuffer,nSize);
1109         if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = nSize;
1110         return TRUE;
1111 }
1112
1113 /***********************************************************************
1114  *           RegisterServiceProcess             (KERNEL, KERNEL32)
1115  *
1116  * A service process calls this function to ensure that it continues to run
1117  * even after a user logged off.
1118  */
1119 DWORD WINAPI RegisterServiceProcess(DWORD dwProcessId, DWORD dwType)
1120 {
1121         /* I don't think that Wine needs to do anything in that function */
1122         return 1; /* success */
1123 }
1124
1125 /***********************************************************************
1126  * GetExitCodeProcess [KERNEL32.325]
1127  *
1128  * Gets termination status of specified process
1129  * 
1130  * RETURNS
1131  *   Success: TRUE
1132  *   Failure: FALSE
1133  */
1134 BOOL WINAPI GetExitCodeProcess(
1135     HANDLE hProcess,  /* [I] handle to the process */
1136     LPDWORD lpExitCode) /* [O] address to receive termination status */
1137 {
1138     struct get_process_info_reply reply;
1139     if (!PROCESS_QueryInfo( hProcess, &reply )) return FALSE;
1140     if (lpExitCode) *lpExitCode = reply.exit_code;
1141     return TRUE;
1142 }
1143
1144
1145 /***********************************************************************
1146  * GetProcessHeaps [KERNEL32.376]
1147  */
1148 DWORD WINAPI GetProcessHeaps(DWORD nrofheaps,HANDLE *heaps) {
1149         FIXME_(win32)("(%ld,%p), incomplete implementation.\n",nrofheaps,heaps);
1150
1151         if (nrofheaps) {
1152                 heaps[0] = GetProcessHeap();
1153                 /* ... probably SystemHeap too ? */
1154                 return 1;
1155         }
1156         /* number of available heaps */
1157         return 1;
1158 }
1159