Release 980503
[wine/hacks.git] / scheduler / process.c
blob361875e015667877f5c8628191b4dd503911788a
1 /*
2 * Win32 processes
4 * Copyright 1996, 1998 Alexandre Julliard
5 */
7 #include <assert.h>
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include "process.h"
12 #include "module.h"
13 #include "file.h"
14 #include "heap.h"
15 #include "task.h"
16 #include "ldt.h"
17 #include "thread.h"
18 #include "winerror.h"
19 #include "pe_image.h"
20 #include "task.h"
21 #include "debug.h"
23 /* Process self-handle */
24 #define PROCESS_SELF ((HANDLE32)0x7fffffff)
26 static BOOL32 PROCESS_Signaled( K32OBJ *obj, DWORD thread_id );
27 static BOOL32 PROCESS_Satisfied( K32OBJ *obj, DWORD thread_id );
28 static void PROCESS_AddWait( K32OBJ *obj, DWORD thread_id );
29 static void PROCESS_RemoveWait( K32OBJ *obj, DWORD thread_id );
30 static void PROCESS_Destroy( K32OBJ *obj );
32 const K32OBJ_OPS PROCESS_Ops =
34 PROCESS_Signaled, /* signaled */
35 PROCESS_Satisfied, /* satisfied */
36 PROCESS_AddWait, /* add_wait */
37 PROCESS_RemoveWait, /* remove_wait */
38 NULL, /* read */
39 NULL, /* write */
40 PROCESS_Destroy /* destroy */
44 /***********************************************************************
45 * PROCESS_Current
47 PDB32 *PROCESS_Current(void)
49 return THREAD_Current()->process;
53 /***********************************************************************
54 * PROCESS_GetPtr
56 * Get a process from a handle, incrementing the PDB refcount.
58 PDB32 *PROCESS_GetPtr( HANDLE32 handle, DWORD access )
60 PDB32 *pdb = PROCESS_Current();
62 if (handle == PROCESS_SELF)
64 K32OBJ_IncCount( &pdb->header );
65 return pdb;
67 return (PDB32 *)HANDLE_GetObjPtr( pdb, handle, K32OBJ_PROCESS, access );
71 /***********************************************************************
72 * PROCESS_IdToPDB
74 * Convert a process id to a PDB, making sure it is valid.
76 PDB32 *PROCESS_IdToPDB( DWORD id )
78 PDB32 *pdb;
80 if (!id) return PROCESS_Current();
81 pdb = PROCESS_ID_TO_PDB( id );
82 if (!K32OBJ_IsValid( &pdb->header, K32OBJ_PROCESS ))
84 SetLastError( ERROR_INVALID_PARAMETER );
85 return NULL;
87 return pdb;
92 /***********************************************************************
93 * PROCESS_BuildEnvDB
95 * Build the env DB for the initial process
97 static BOOL32 PROCESS_BuildEnvDB( PDB32 *pdb )
99 /* Allocate the env DB (FIXME: should not be on the system heap) */
101 if (!(pdb->env_db = HeapAlloc(SystemHeap,HEAP_ZERO_MEMORY,sizeof(ENVDB))))
102 return FALSE;
103 InitializeCriticalSection( &pdb->env_db->section );
105 /* Allocate the standard handles */
107 pdb->env_db->hStdin = FILE_DupUnixHandle( 0 );
108 pdb->env_db->hStdout = FILE_DupUnixHandle( 1 );
109 pdb->env_db->hStderr = FILE_DupUnixHandle( 2 );
110 FILE_SetFileType( pdb->env_db->hStdin, FILE_TYPE_CHAR );
111 FILE_SetFileType( pdb->env_db->hStdout, FILE_TYPE_CHAR );
112 FILE_SetFileType( pdb->env_db->hStderr, FILE_TYPE_CHAR );
114 /* Build the environment strings */
116 return ENV_BuildEnvironment( pdb );
120 /***********************************************************************
121 * PROCESS_InheritEnvDB
123 static BOOL32 PROCESS_InheritEnvDB( PDB32 *pdb, LPCSTR cmd_line, LPCSTR env )
125 if (!(pdb->env_db = HeapAlloc(pdb->heap, HEAP_ZERO_MEMORY, sizeof(ENVDB))))
126 return FALSE;
127 InitializeCriticalSection( &pdb->env_db->section );
129 /* Copy the parent environment */
131 if (!ENV_InheritEnvironment( pdb, env )) return FALSE;
133 /* Copy the command line */
135 if (!(pdb->env_db->cmd_line = HEAP_strdupA( pdb->heap, 0, cmd_line )))
136 return FALSE;
138 /* Inherit the standard handles */
139 pdb->env_db->hStdin = pdb->parent->env_db->hStdin;
140 pdb->env_db->hStdout = pdb->parent->env_db->hStdout;
141 pdb->env_db->hStderr = pdb->parent->env_db->hStderr;
143 return TRUE;
147 /***********************************************************************
148 * PROCESS_FreePDB
150 * Free a PDB and all associated storage.
152 static void PROCESS_FreePDB( PDB32 *pdb )
154 pdb->header.type = K32OBJ_UNKNOWN;
155 if (pdb->handle_table) HANDLE_CloseAll( pdb, NULL );
156 ENV_FreeEnvironment( pdb );
157 if (pdb->heap && (pdb->heap != pdb->system_heap)) HeapDestroy( pdb->heap );
158 if (pdb->load_done_evt) K32OBJ_DecCount( pdb->load_done_evt );
159 if (pdb->event) K32OBJ_DecCount( pdb->event );
160 DeleteCriticalSection( &pdb->crit_section );
161 HeapFree( SystemHeap, 0, pdb );
165 /***********************************************************************
166 * PROCESS_CreatePDB
168 * Allocate and fill a PDB structure.
169 * Runs in the context of the parent process.
171 static PDB32 *PROCESS_CreatePDB( PDB32 *parent )
173 PDB32 *pdb = HeapAlloc( SystemHeap, HEAP_ZERO_MEMORY, sizeof(PDB32) );
175 if (!pdb) return NULL;
176 pdb->header.type = K32OBJ_PROCESS;
177 pdb->header.refcount = 1;
178 pdb->exit_code = 0x103; /* STILL_ACTIVE */
179 pdb->threads = 1;
180 pdb->running_threads = 1;
181 pdb->ring0_threads = 1;
182 pdb->system_heap = SystemHeap;
183 pdb->parent = parent;
184 pdb->group = pdb;
185 pdb->priority = 8; /* Normal */
186 pdb->heap = pdb->system_heap; /* will be changed later on */
188 InitializeCriticalSection( &pdb->crit_section );
190 /* Allocate the events */
192 if (!(pdb->event = EVENT_Create( TRUE, FALSE ))) goto error;
193 if (!(pdb->load_done_evt = EVENT_Create( TRUE, FALSE ))) goto error;
195 /* Create the handle table */
197 if (!HANDLE_CreateTable( pdb, TRUE )) goto error;
199 return pdb;
201 error:
202 PROCESS_FreePDB( pdb );
203 return NULL;
207 /***********************************************************************
208 * PROCESS_Init
210 BOOL32 PROCESS_Init(void)
212 extern BOOL32 VIRTUAL_Init(void);
213 extern BOOL32 THREAD_InitDone;
214 PDB32 *pdb;
215 THDB *thdb;
217 /* Initialize virtual memory management */
218 if (!VIRTUAL_Init()) return FALSE;
220 /* Create the system and SEGPTR heaps */
221 if (!(SystemHeap = HeapCreate( HEAP_GROWABLE, 0x10000, 0 ))) return FALSE;
222 if (!(SegptrHeap = HeapCreate( HEAP_WINE_SEGPTR, 0, 0 ))) return FALSE;
224 /* Create the initial process and thread structures */
225 if (!(pdb = PROCESS_CreatePDB( NULL ))) return FALSE;
226 if (!(thdb = THREAD_Create( pdb, 0, FALSE, NULL, NULL ))) return FALSE;
227 SET_CUR_THREAD( thdb );
228 THREAD_InitDone = TRUE;
230 /* Create the environment DB of the first process */
231 if (!PROCESS_BuildEnvDB( pdb )) return FALSE;
233 return TRUE;
237 /***********************************************************************
238 * PROCESS_Create
240 * Create a new process database and associated info.
242 PDB32 *PROCESS_Create( NE_MODULE *pModule, LPCSTR cmd_line, LPCSTR env,
243 HINSTANCE16 hInstance, HINSTANCE16 hPrevInstance,
244 UINT32 cmdShow )
246 DWORD size, commit;
247 THDB *thdb = NULL;
248 PDB32 *parent = PROCESS_Current();
249 PDB32 *pdb = PROCESS_CreatePDB( parent );
251 if (!pdb) return NULL;
253 /* Create the heap */
255 if (pModule->module32)
257 size = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfHeapReserve;
258 commit = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfHeapCommit;
260 else
262 size = 0x10000;
263 commit = 0;
264 pdb->flags |= PDB32_WIN16_PROC; /* This is a Win16 process */
266 if (!(pdb->heap = HeapCreate( HEAP_GROWABLE, size, commit ))) goto error;
267 pdb->heap_list = pdb->heap;
269 /* Inherit the env DB from the parent */
271 if (!PROCESS_InheritEnvDB( pdb, cmd_line, env )) goto error;
273 /* Create the main thread */
275 if (pModule->module32)
276 size = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfStackReserve;
277 else
278 size = 0;
279 if (!(thdb = THREAD_Create( pdb, size, FALSE, NULL, NULL ))) goto error;
281 /* Create a Win16 task for this process */
283 pdb->task = TASK_Create( thdb, pModule, hInstance, hPrevInstance, cmdShow);
284 if (!pdb->task) goto error;
286 return pdb;
288 error:
289 if (thdb) K32OBJ_DecCount( &thdb->header );
290 PROCESS_FreePDB( pdb );
291 return NULL;
295 /***********************************************************************
296 * PROCESS_Signaled
298 static BOOL32 PROCESS_Signaled( K32OBJ *obj, DWORD thread_id )
300 PDB32 *pdb = (PDB32 *)obj;
301 assert( obj->type == K32OBJ_PROCESS );
302 return K32OBJ_OPS( pdb->event )->signaled( pdb->event, thread_id );
306 /***********************************************************************
307 * PROCESS_Satisfied
309 * Wait on this object has been satisfied.
311 static BOOL32 PROCESS_Satisfied( K32OBJ *obj, DWORD thread_id )
313 PDB32 *pdb = (PDB32 *)obj;
314 assert( obj->type == K32OBJ_PROCESS );
315 return K32OBJ_OPS( pdb->event )->satisfied( pdb->event, thread_id );
319 /***********************************************************************
320 * PROCESS_AddWait
322 * Add thread to object wait queue.
324 static void PROCESS_AddWait( K32OBJ *obj, DWORD thread_id )
326 PDB32 *pdb = (PDB32 *)obj;
327 assert( obj->type == K32OBJ_PROCESS );
328 return K32OBJ_OPS( pdb->event )->add_wait( pdb->event, thread_id );
332 /***********************************************************************
333 * PROCESS_RemoveWait
335 * Remove thread from object wait queue.
337 static void PROCESS_RemoveWait( K32OBJ *obj, DWORD thread_id )
339 PDB32 *pdb = (PDB32 *)obj;
340 assert( obj->type == K32OBJ_PROCESS );
341 return K32OBJ_OPS( pdb->event )->remove_wait( pdb->event, thread_id );
345 /***********************************************************************
346 * PROCESS_Destroy
348 static void PROCESS_Destroy( K32OBJ *ptr )
350 PDB32 *pdb = (PDB32 *)ptr;
351 assert( ptr->type == K32OBJ_PROCESS );
353 /* Free everything */
355 ptr->type = K32OBJ_UNKNOWN;
356 PROCESS_FreePDB( pdb );
360 /***********************************************************************
361 * ExitProcess (KERNEL32.100)
363 void WINAPI ExitProcess( DWORD status )
365 PDB32 *pdb = PROCESS_Current();
367 SYSTEM_LOCK();
368 /* FIXME: should kill all running threads of this process */
369 pdb->exit_code = status;
370 EVENT_Set( pdb->event );
371 if (pdb->console) FreeConsole();
372 SYSTEM_UNLOCK();
374 __RESTORE_ES; /* Necessary for Pietrek's showseh example program */
375 TASK_KillCurrentTask( status );
379 /***********************************************************************
380 * GetCurrentProcess (KERNEL32.198)
382 HANDLE32 WINAPI GetCurrentProcess(void)
384 return 0x7fffffff;
388 /*********************************************************************
389 * OpenProcess (KERNEL32.543)
391 HANDLE32 WINAPI OpenProcess( DWORD access, BOOL32 inherit, DWORD id )
393 PDB32 *pdb = PROCESS_ID_TO_PDB(id);
394 if (!K32OBJ_IsValid( &pdb->header, K32OBJ_PROCESS ))
396 SetLastError( ERROR_INVALID_HANDLE );
397 return 0;
399 return HANDLE_Alloc( PROCESS_Current(), &pdb->header, access, inherit );
403 /***********************************************************************
404 * GetCurrentProcessId (KERNEL32.199)
406 DWORD WINAPI GetCurrentProcessId(void)
408 PDB32 *pdb = PROCESS_Current();
409 return PDB_TO_PROCESS_ID( pdb );
413 /***********************************************************************
414 * GetProcessHeap (KERNEL32.259)
416 HANDLE32 WINAPI GetProcessHeap(void)
418 PDB32 *pdb = PROCESS_Current();
419 return pdb->heap ? pdb->heap : SystemHeap;
423 /***********************************************************************
424 * GetThreadLocale (KERNEL32.295)
426 LCID WINAPI GetThreadLocale(void)
428 return PROCESS_Current()->locale;
432 /***********************************************************************
433 * SetPriorityClass (KERNEL32.503)
435 BOOL32 WINAPI SetPriorityClass( HANDLE32 hprocess, DWORD priorityclass )
437 PDB32 *pdb = PROCESS_GetPtr( hprocess, PROCESS_SET_INFORMATION );
438 if (!pdb) return FALSE;
439 switch (priorityclass)
441 case NORMAL_PRIORITY_CLASS:
442 pdb->priority = 0x00000008;
443 break;
444 case IDLE_PRIORITY_CLASS:
445 pdb->priority = 0x00000004;
446 break;
447 case HIGH_PRIORITY_CLASS:
448 pdb->priority = 0x0000000d;
449 break;
450 case REALTIME_PRIORITY_CLASS:
451 pdb->priority = 0x00000018;
452 break;
453 default:
454 fprintf(stderr,"SetPriorityClass: unknown priority class %ld\n",priorityclass);
455 break;
457 K32OBJ_DecCount( &pdb->header );
458 return TRUE;
462 /***********************************************************************
463 * GetPriorityClass (KERNEL32.250)
465 DWORD WINAPI GetPriorityClass(HANDLE32 hprocess)
467 PDB32 *pdb = PROCESS_GetPtr( hprocess, PROCESS_QUERY_INFORMATION );
468 DWORD ret = 0;
469 if (pdb)
471 switch (pdb->priority)
473 case 0x00000008:
474 ret = NORMAL_PRIORITY_CLASS;
475 break;
476 case 0x00000004:
477 ret = IDLE_PRIORITY_CLASS;
478 break;
479 case 0x0000000d:
480 ret = HIGH_PRIORITY_CLASS;
481 break;
482 case 0x00000018:
483 ret = REALTIME_PRIORITY_CLASS;
484 break;
485 default:
486 fprintf(stderr,"GetPriorityClass: unknown priority %ld\n",pdb->priority);
488 K32OBJ_DecCount( &pdb->header );
490 return ret;
494 /***********************************************************************
495 * GetStdHandle (KERNEL32.276)
497 * FIXME: These should be allocated when a console is created, or inherited
498 * from the parent.
500 HANDLE32 WINAPI GetStdHandle( DWORD std_handle )
502 HFILE32 hFile;
503 int fd;
504 PDB32 *pdb = PROCESS_Current();
506 switch(std_handle)
508 case STD_INPUT_HANDLE:
509 if (pdb->env_db->hStdin) return pdb->env_db->hStdin;
510 fd = 0;
511 break;
512 case STD_OUTPUT_HANDLE:
513 if (pdb->env_db->hStdout) return pdb->env_db->hStdout;
514 fd = 1;
515 break;
516 case STD_ERROR_HANDLE:
517 if (pdb->env_db->hStderr) return pdb->env_db->hStderr;
518 fd = 2;
519 break;
520 default:
521 SetLastError( ERROR_INVALID_PARAMETER );
522 return INVALID_HANDLE_VALUE32;
524 hFile = FILE_DupUnixHandle( fd );
525 if (hFile != HFILE_ERROR32)
527 FILE_SetFileType( hFile, FILE_TYPE_CHAR );
528 switch(std_handle)
530 case STD_INPUT_HANDLE: pdb->env_db->hStdin = hFile; break;
531 case STD_OUTPUT_HANDLE: pdb->env_db->hStdout = hFile; break;
532 case STD_ERROR_HANDLE: pdb->env_db->hStderr = hFile; break;
535 return hFile;
539 /***********************************************************************
540 * SetStdHandle (KERNEL32.506)
542 BOOL32 WINAPI SetStdHandle( DWORD std_handle, HANDLE32 handle )
544 PDB32 *pdb = PROCESS_Current();
545 /* FIXME: should we close the previous handle? */
546 switch(std_handle)
548 case STD_INPUT_HANDLE:
549 pdb->env_db->hStdin = handle;
550 return TRUE;
551 case STD_OUTPUT_HANDLE:
552 pdb->env_db->hStdout = handle;
553 return TRUE;
554 case STD_ERROR_HANDLE:
555 pdb->env_db->hStderr = handle;
556 return TRUE;
558 SetLastError( ERROR_INVALID_PARAMETER );
559 return FALSE;
562 /***********************************************************************
563 * GetProcessVersion (KERNEL32)
565 DWORD WINAPI GetProcessVersion( DWORD processid )
567 TDB *pTask;
568 PDB32 *pdb = PROCESS_IdToPDB( processid );
570 if (!pdb) return 0;
571 if (!(pTask = (TDB *)GlobalLock16( pdb->task ))) return 0;
572 return (pTask->version&0xff) | (((pTask->version >>8) & 0xff)<<16);
575 /***********************************************************************
576 * GetProcessFlags (KERNEL32)
578 DWORD WINAPI GetProcessFlags( DWORD processid )
580 PDB32 *pdb = PROCESS_IdToPDB( processid );
581 if (!pdb) return 0;
582 return pdb->flags;
585 /***********************************************************************
586 * SetProcessWorkingSetSize (KERNEL32)
588 BOOL32 WINAPI SetProcessWorkingSetSize(HANDLE32 hProcess,DWORD minset,
589 DWORD maxset)
591 fprintf(stderr,"SetProcessWorkingSetSize(0x%08x,%ld,%ld), STUB!\n",
592 hProcess,minset,maxset
594 return TRUE;
597 /***********************************************************************
598 * GetProcessWorkingSetSize (KERNEL32)
600 BOOL32 WINAPI GetProcessWorkingSetSize(HANDLE32 hProcess,LPDWORD minset,
601 LPDWORD maxset)
603 fprintf(stderr,"SetProcessWorkingSetSize(0x%08x,%p,%p), STUB!\n",
604 hProcess,minset,maxset
606 /* 32 MB working set size */
607 if (minset) *minset = 32*1024*1024;
608 if (maxset) *maxset = 32*1024*1024;
609 return TRUE;
612 /***********************************************************************
613 * SetProcessShutdownParameters (KERNEL32)
615 BOOL32 WINAPI SetProcessShutdownParameters(DWORD level,DWORD flags)
617 fprintf(stderr,"SetProcessShutdownParameters(%ld,0x%08lx), STUB!\n",
618 level,flags
620 return TRUE;
623 /***********************************************************************
624 * ReadProcessMemory (KERNEL32)
625 * FIXME: check this, if we ever run win32 binaries in different addressspaces
626 * ... and add a sizecheck
628 BOOL32 WINAPI ReadProcessMemory( HANDLE32 hProcess, LPCVOID lpBaseAddress,
629 LPVOID lpBuffer, DWORD nSize,
630 LPDWORD lpNumberOfBytesRead )
632 memcpy(lpBuffer,lpBaseAddress,nSize);
633 if (lpNumberOfBytesRead) *lpNumberOfBytesRead = nSize;
634 return TRUE;
637 /***********************************************************************
638 * WriteProcessMemory (KERNEL32)
639 * FIXME: check this, if we ever run win32 binaries in different addressspaces
640 * ... and add a sizecheck
642 BOOL32 WINAPI WriteProcessMemory(HANDLE32 hProcess, LPVOID lpBaseAddress,
643 LPVOID lpBuffer, DWORD nSize,
644 LPDWORD lpNumberOfBytesWritten )
646 memcpy(lpBaseAddress,lpBuffer,nSize);
647 if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = nSize;
648 return TRUE;
651 /***********************************************************************
652 * ConvertToGlobalHandle (KERNEL32)
653 * FIXME: this is not correctly implemented...
655 HANDLE32 WINAPI ConvertToGlobalHandle(HANDLE32 h)
657 fprintf(stderr,"ConvertToGlobalHandle(%d),stub!\n",h);
658 return h;
661 /***********************************************************************
662 * RegisterServiceProcess (KERNEL32)
664 * A service process calls this function to ensure that it continues to run
665 * even after a user logged off.
667 DWORD RegisterServiceProcess(DWORD dwProcessId, DWORD dwType)
669 /* I don't think that Wine needs to do anything in that function */
670 return 1; /* success */
673 /***********************************************************************
674 * GetExitCodeProcess [KERNEL32.325]
676 * Gets termination status of specified process
678 * RETURNS
679 * Success: TRUE
680 * Failure: FALSE
682 * FIXME
683 * Should call SetLastError (but doesn't).
685 BOOL32 WINAPI GetExitCodeProcess(
686 HANDLE32 hProcess, /* [I] handle to the process */
687 LPDWORD lpExitCode) /* [O] address to receive termination status */
689 PDB32 *process;
691 if (!(process = PROCESS_GetPtr( hProcess, PROCESS_QUERY_INFORMATION )))
692 return FALSE;
693 if (lpExitCode) *lpExitCode = process->exit_code;
694 K32OBJ_DecCount( &process->header );
695 return TRUE;