Release 980726
[wine.git] / scheduler / process.c
blobc213d2a59fd15ce2db04ddd497e6ded5b5bf5220
1 /*
2 * Win32 processes
4 * Copyright 1996, 1998 Alexandre Julliard
5 */
7 #include <assert.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include "process.h"
12 #include "module.h"
13 #include "file.h"
14 #include "global.h"
15 #include "heap.h"
16 #include "task.h"
17 #include "ldt.h"
18 #include "thread.h"
19 #include "winerror.h"
20 #include "pe_image.h"
21 #include "task.h"
22 #include "server.h"
23 #include "debug.h"
25 /* Process self-handle */
26 #define PROCESS_SELF ((HANDLE32)0x7fffffff)
28 static BOOL32 PROCESS_Signaled( K32OBJ *obj, DWORD thread_id );
29 static BOOL32 PROCESS_Satisfied( K32OBJ *obj, DWORD thread_id );
30 static void PROCESS_AddWait( K32OBJ *obj, DWORD thread_id );
31 static void PROCESS_RemoveWait( K32OBJ *obj, DWORD thread_id );
32 static void PROCESS_Destroy( K32OBJ *obj );
34 const K32OBJ_OPS PROCESS_Ops =
36 PROCESS_Signaled, /* signaled */
37 PROCESS_Satisfied, /* satisfied */
38 PROCESS_AddWait, /* add_wait */
39 PROCESS_RemoveWait, /* remove_wait */
40 NULL, /* read */
41 NULL, /* write */
42 PROCESS_Destroy /* destroy */
46 /***********************************************************************
47 * PROCESS_Current
49 PDB32 *PROCESS_Current(void)
51 return THREAD_Current()->process;
55 /***********************************************************************
56 * PROCESS_GetPtr
58 * Get a process from a handle, incrementing the PDB refcount.
60 PDB32 *PROCESS_GetPtr( HANDLE32 handle, DWORD access )
62 PDB32 *pdb = PROCESS_Current();
64 if (handle == PROCESS_SELF)
66 K32OBJ_IncCount( &pdb->header );
67 return pdb;
69 return (PDB32 *)HANDLE_GetObjPtr( pdb, handle, K32OBJ_PROCESS, access );
73 /***********************************************************************
74 * PROCESS_IdToPDB
76 * Convert a process id to a PDB, making sure it is valid.
78 PDB32 *PROCESS_IdToPDB( DWORD id )
80 PDB32 *pdb;
82 if (!id) return PROCESS_Current();
83 pdb = PROCESS_ID_TO_PDB( id );
84 if (!K32OBJ_IsValid( &pdb->header, K32OBJ_PROCESS ))
86 SetLastError( ERROR_INVALID_PARAMETER );
87 return NULL;
89 return pdb;
94 /***********************************************************************
95 * PROCESS_BuildEnvDB
97 * Build the env DB for the initial process
99 static BOOL32 PROCESS_BuildEnvDB( PDB32 *pdb )
101 /* Allocate the env DB (FIXME: should not be on the system heap) */
103 if (!(pdb->env_db = HeapAlloc(SystemHeap,HEAP_ZERO_MEMORY,sizeof(ENVDB))))
104 return FALSE;
105 InitializeCriticalSection( &pdb->env_db->section );
107 /* Allocate the standard handles */
109 pdb->env_db->hStdin = FILE_DupUnixHandle( 0 );
110 pdb->env_db->hStdout = FILE_DupUnixHandle( 1 );
111 pdb->env_db->hStderr = FILE_DupUnixHandle( 2 );
112 FILE_SetFileType( pdb->env_db->hStdin, FILE_TYPE_CHAR );
113 FILE_SetFileType( pdb->env_db->hStdout, FILE_TYPE_CHAR );
114 FILE_SetFileType( pdb->env_db->hStderr, FILE_TYPE_CHAR );
116 /* Build the command-line */
118 pdb->env_db->cmd_line = HEAP_strdupA( SystemHeap, 0, "kernel32" );
120 /* Build the environment strings */
122 return ENV_BuildEnvironment( pdb );
126 /***********************************************************************
127 * PROCESS_InheritEnvDB
129 static BOOL32 PROCESS_InheritEnvDB( PDB32 *pdb, LPCSTR cmd_line, LPCSTR env )
131 if (!(pdb->env_db = HeapAlloc(pdb->heap, HEAP_ZERO_MEMORY, sizeof(ENVDB))))
132 return FALSE;
133 InitializeCriticalSection( &pdb->env_db->section );
135 /* Copy the parent environment */
137 if (!ENV_InheritEnvironment( pdb, env )) return FALSE;
139 /* Copy the command line */
141 if (!(pdb->env_db->cmd_line = HEAP_strdupA( pdb->heap, 0, cmd_line )))
142 return FALSE;
144 /* Inherit the standard handles */
145 pdb->env_db->hStdin = pdb->parent->env_db->hStdin;
146 pdb->env_db->hStdout = pdb->parent->env_db->hStdout;
147 pdb->env_db->hStderr = pdb->parent->env_db->hStderr;
149 return TRUE;
153 /***********************************************************************
154 * PROCESS_FreePDB
156 * Free a PDB and all associated storage.
158 static void PROCESS_FreePDB( PDB32 *pdb )
160 pdb->header.type = K32OBJ_UNKNOWN;
161 if (pdb->handle_table) HANDLE_CloseAll( pdb, NULL );
162 ENV_FreeEnvironment( pdb );
163 if (pdb->heap && (pdb->heap != pdb->system_heap)) HeapDestroy( pdb->heap );
164 if (pdb->load_done_evt) K32OBJ_DecCount( pdb->load_done_evt );
165 if (pdb->event) K32OBJ_DecCount( pdb->event );
166 DeleteCriticalSection( &pdb->crit_section );
167 HeapFree( SystemHeap, 0, pdb );
171 /***********************************************************************
172 * PROCESS_CreatePDB
174 * Allocate and fill a PDB structure.
175 * Runs in the context of the parent process.
177 static PDB32 *PROCESS_CreatePDB( PDB32 *parent )
179 PDB32 *pdb = HeapAlloc( SystemHeap, HEAP_ZERO_MEMORY, sizeof(PDB32) );
181 if (!pdb) return NULL;
182 pdb->header.type = K32OBJ_PROCESS;
183 pdb->header.refcount = 1;
184 pdb->exit_code = 0x103; /* STILL_ACTIVE */
185 pdb->threads = 1;
186 pdb->running_threads = 1;
187 pdb->ring0_threads = 1;
188 pdb->system_heap = SystemHeap;
189 pdb->parent = parent;
190 pdb->group = pdb;
191 pdb->priority = 8; /* Normal */
192 pdb->heap = pdb->system_heap; /* will be changed later on */
194 InitializeCriticalSection( &pdb->crit_section );
196 /* Allocate the events */
198 if (!(pdb->event = EVENT_Create( TRUE, FALSE ))) goto error;
199 if (!(pdb->load_done_evt = EVENT_Create( TRUE, FALSE ))) goto error;
201 /* Create the handle table */
203 if (!HANDLE_CreateTable( pdb, TRUE )) goto error;
205 return pdb;
207 error:
208 PROCESS_FreePDB( pdb );
209 return NULL;
213 /***********************************************************************
214 * PROCESS_Init
216 BOOL32 PROCESS_Init(void)
218 PDB32 *pdb;
219 THDB *thdb;
221 /* Initialize virtual memory management */
222 if (!VIRTUAL_Init()) return FALSE;
224 /* Create the system and SEGPTR heaps */
225 if (!(SystemHeap = HeapCreate( HEAP_GROWABLE, 0x10000, 0 ))) return FALSE;
226 if (!(SegptrHeap = HeapCreate( HEAP_WINE_SEGPTR, 0, 0 ))) return FALSE;
228 /* Create the initial process and thread structures */
229 if (!(pdb = PROCESS_CreatePDB( NULL ))) return FALSE;
230 if (!(thdb = THREAD_Create( pdb, 0, FALSE, NULL, NULL ))) return FALSE;
231 thdb->unix_pid = getpid();
233 /* Create the environment DB of the first process */
234 if (!PROCESS_BuildEnvDB( pdb )) return FALSE;
236 /* Initialize the first thread */
237 if (CLIENT_InitThread()) return FALSE;
239 return TRUE;
243 /***********************************************************************
244 * PROCESS_Create
246 * Create a new process database and associated info.
248 PDB32 *PROCESS_Create( NE_MODULE *pModule, LPCSTR cmd_line, LPCSTR env,
249 HINSTANCE16 hInstance, HINSTANCE16 hPrevInstance,
250 UINT32 cmdShow )
252 DWORD size, commit;
253 THDB *thdb = NULL;
254 PDB32 *parent = PROCESS_Current();
255 PDB32 *pdb = PROCESS_CreatePDB( parent );
257 if (!pdb) return NULL;
259 /* Create the heap */
261 if (pModule->module32)
263 size = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfHeapReserve;
264 commit = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfHeapCommit;
266 else
268 size = 0x10000;
269 commit = 0;
270 pdb->flags |= PDB32_WIN16_PROC; /* This is a Win16 process */
272 if (!(pdb->heap = HeapCreate( HEAP_GROWABLE, size, commit ))) goto error;
273 pdb->heap_list = pdb->heap;
275 /* Inherit the env DB from the parent */
277 if (!PROCESS_InheritEnvDB( pdb, cmd_line, env )) goto error;
279 /* Create the main thread */
281 if (pModule->module32)
282 size = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfStackReserve;
283 else
284 size = 0;
285 if (!(thdb = THREAD_Create( pdb, size, FALSE, NULL, NULL ))) goto error;
287 thdb->unix_pid = getpid(); /* FIXME: wrong here ... */
289 /* Create a Win16 task for this process */
291 pdb->task = TASK_Create( thdb, pModule, hInstance, hPrevInstance, cmdShow);
292 if (!pdb->task) goto error;
294 return pdb;
296 error:
297 if (thdb) K32OBJ_DecCount( &thdb->header );
298 PROCESS_FreePDB( pdb );
299 return NULL;
303 /***********************************************************************
304 * PROCESS_Signaled
306 static BOOL32 PROCESS_Signaled( K32OBJ *obj, DWORD thread_id )
308 PDB32 *pdb = (PDB32 *)obj;
309 assert( obj->type == K32OBJ_PROCESS );
310 return K32OBJ_OPS( pdb->event )->signaled( pdb->event, thread_id );
314 /***********************************************************************
315 * PROCESS_Satisfied
317 * Wait on this object has been satisfied.
319 static BOOL32 PROCESS_Satisfied( K32OBJ *obj, DWORD thread_id )
321 PDB32 *pdb = (PDB32 *)obj;
322 assert( obj->type == K32OBJ_PROCESS );
323 return K32OBJ_OPS( pdb->event )->satisfied( pdb->event, thread_id );
327 /***********************************************************************
328 * PROCESS_AddWait
330 * Add thread to object wait queue.
332 static void PROCESS_AddWait( K32OBJ *obj, DWORD thread_id )
334 PDB32 *pdb = (PDB32 *)obj;
335 assert( obj->type == K32OBJ_PROCESS );
336 return K32OBJ_OPS( pdb->event )->add_wait( pdb->event, thread_id );
340 /***********************************************************************
341 * PROCESS_RemoveWait
343 * Remove thread from object wait queue.
345 static void PROCESS_RemoveWait( K32OBJ *obj, DWORD thread_id )
347 PDB32 *pdb = (PDB32 *)obj;
348 assert( obj->type == K32OBJ_PROCESS );
349 return K32OBJ_OPS( pdb->event )->remove_wait( pdb->event, thread_id );
353 /***********************************************************************
354 * PROCESS_Destroy
356 static void PROCESS_Destroy( K32OBJ *ptr )
358 PDB32 *pdb = (PDB32 *)ptr;
359 assert( ptr->type == K32OBJ_PROCESS );
361 /* Free everything */
363 ptr->type = K32OBJ_UNKNOWN;
364 PROCESS_FreePDB( pdb );
368 /***********************************************************************
369 * ExitProcess (KERNEL32.100)
371 void WINAPI ExitProcess( DWORD status )
373 PDB32 *pdb = PROCESS_Current();
375 SYSTEM_LOCK();
376 /* FIXME: should kill all running threads of this process */
377 pdb->exit_code = status;
378 EVENT_Set( pdb->event );
379 if (pdb->console) FreeConsole();
380 SYSTEM_UNLOCK();
382 __RESTORE_ES; /* Necessary for Pietrek's showseh example program */
383 TASK_KillCurrentTask( status );
387 /***********************************************************************
388 * GetCurrentProcess (KERNEL32.198)
390 HANDLE32 WINAPI GetCurrentProcess(void)
392 return 0x7fffffff;
396 /*********************************************************************
397 * OpenProcess (KERNEL32.543)
399 HANDLE32 WINAPI OpenProcess( DWORD access, BOOL32 inherit, DWORD id )
401 PDB32 *pdb = PROCESS_ID_TO_PDB(id);
402 if (!K32OBJ_IsValid( &pdb->header, K32OBJ_PROCESS ))
404 SetLastError( ERROR_INVALID_HANDLE );
405 return 0;
407 return HANDLE_Alloc( PROCESS_Current(), &pdb->header, access, inherit );
411 /***********************************************************************
412 * GetCurrentProcessId (KERNEL32.199)
414 DWORD WINAPI GetCurrentProcessId(void)
416 PDB32 *pdb = PROCESS_Current();
417 return PDB_TO_PROCESS_ID( pdb );
421 /***********************************************************************
422 * GetProcessHeap (KERNEL32.259)
424 HANDLE32 WINAPI GetProcessHeap(void)
426 PDB32 *pdb = PROCESS_Current();
427 return pdb->heap ? pdb->heap : SystemHeap;
431 /***********************************************************************
432 * GetThreadLocale (KERNEL32.295)
434 LCID WINAPI GetThreadLocale(void)
436 return PROCESS_Current()->locale;
440 /***********************************************************************
441 * SetPriorityClass (KERNEL32.503)
443 BOOL32 WINAPI SetPriorityClass( HANDLE32 hprocess, DWORD priorityclass )
445 PDB32 *pdb = PROCESS_GetPtr( hprocess, PROCESS_SET_INFORMATION );
446 if (!pdb) return FALSE;
447 switch (priorityclass)
449 case NORMAL_PRIORITY_CLASS:
450 pdb->priority = 0x00000008;
451 break;
452 case IDLE_PRIORITY_CLASS:
453 pdb->priority = 0x00000004;
454 break;
455 case HIGH_PRIORITY_CLASS:
456 pdb->priority = 0x0000000d;
457 break;
458 case REALTIME_PRIORITY_CLASS:
459 pdb->priority = 0x00000018;
460 break;
461 default:
462 WARN(process,"Unknown priority class %ld\n",priorityclass);
463 break;
465 K32OBJ_DecCount( &pdb->header );
466 return TRUE;
470 /***********************************************************************
471 * GetPriorityClass (KERNEL32.250)
473 DWORD WINAPI GetPriorityClass(HANDLE32 hprocess)
475 PDB32 *pdb = PROCESS_GetPtr( hprocess, PROCESS_QUERY_INFORMATION );
476 DWORD ret = 0;
477 if (pdb)
479 switch (pdb->priority)
481 case 0x00000008:
482 ret = NORMAL_PRIORITY_CLASS;
483 break;
484 case 0x00000004:
485 ret = IDLE_PRIORITY_CLASS;
486 break;
487 case 0x0000000d:
488 ret = HIGH_PRIORITY_CLASS;
489 break;
490 case 0x00000018:
491 ret = REALTIME_PRIORITY_CLASS;
492 break;
493 default:
494 WARN(process,"Unknown priority %ld\n",pdb->priority);
496 K32OBJ_DecCount( &pdb->header );
498 return ret;
502 /***********************************************************************
503 * GetStdHandle (KERNEL32.276)
505 * FIXME: These should be allocated when a console is created, or inherited
506 * from the parent.
508 HANDLE32 WINAPI GetStdHandle( DWORD std_handle )
510 HFILE32 hFile;
511 int fd;
512 PDB32 *pdb = PROCESS_Current();
514 switch(std_handle)
516 case STD_INPUT_HANDLE:
517 if (pdb->env_db->hStdin) return pdb->env_db->hStdin;
518 fd = 0;
519 break;
520 case STD_OUTPUT_HANDLE:
521 if (pdb->env_db->hStdout) return pdb->env_db->hStdout;
522 fd = 1;
523 break;
524 case STD_ERROR_HANDLE:
525 if (pdb->env_db->hStderr) return pdb->env_db->hStderr;
526 fd = 2;
527 break;
528 default:
529 SetLastError( ERROR_INVALID_PARAMETER );
530 return INVALID_HANDLE_VALUE32;
532 hFile = FILE_DupUnixHandle( fd );
533 if (hFile != HFILE_ERROR32)
535 FILE_SetFileType( hFile, FILE_TYPE_CHAR );
536 switch(std_handle)
538 case STD_INPUT_HANDLE: pdb->env_db->hStdin = hFile; break;
539 case STD_OUTPUT_HANDLE: pdb->env_db->hStdout = hFile; break;
540 case STD_ERROR_HANDLE: pdb->env_db->hStderr = hFile; break;
543 return hFile;
547 /***********************************************************************
548 * SetStdHandle (KERNEL32.506)
550 BOOL32 WINAPI SetStdHandle( DWORD std_handle, HANDLE32 handle )
552 PDB32 *pdb = PROCESS_Current();
553 /* FIXME: should we close the previous handle? */
554 switch(std_handle)
556 case STD_INPUT_HANDLE:
557 pdb->env_db->hStdin = handle;
558 return TRUE;
559 case STD_OUTPUT_HANDLE:
560 pdb->env_db->hStdout = handle;
561 return TRUE;
562 case STD_ERROR_HANDLE:
563 pdb->env_db->hStderr = handle;
564 return TRUE;
566 SetLastError( ERROR_INVALID_PARAMETER );
567 return FALSE;
570 /***********************************************************************
571 * GetProcessVersion (KERNEL32)
573 DWORD WINAPI GetProcessVersion( DWORD processid )
575 TDB *pTask;
576 PDB32 *pdb = PROCESS_IdToPDB( processid );
578 if (!pdb) return 0;
579 if (!(pTask = (TDB *)GlobalLock16( pdb->task ))) return 0;
580 return (pTask->version&0xff) | (((pTask->version >>8) & 0xff)<<16);
583 /***********************************************************************
584 * GetProcessFlags (KERNEL32)
586 DWORD WINAPI GetProcessFlags( DWORD processid )
588 PDB32 *pdb = PROCESS_IdToPDB( processid );
589 if (!pdb) return 0;
590 return pdb->flags;
593 /***********************************************************************
594 * SetProcessWorkingSetSize (KERNEL32)
596 BOOL32 WINAPI SetProcessWorkingSetSize(HANDLE32 hProcess,DWORD minset,
597 DWORD maxset)
599 FIXME(process,"(0x%08x,%ld,%ld): stub\n",hProcess,minset,maxset);
600 return TRUE;
603 /***********************************************************************
604 * GetProcessWorkingSetSize (KERNEL32)
606 BOOL32 WINAPI GetProcessWorkingSetSize(HANDLE32 hProcess,LPDWORD minset,
607 LPDWORD maxset)
609 FIXME(process,"(0x%08x,%p,%p): stub\n",hProcess,minset,maxset);
610 /* 32 MB working set size */
611 if (minset) *minset = 32*1024*1024;
612 if (maxset) *maxset = 32*1024*1024;
613 return TRUE;
616 /***********************************************************************
617 * SetProcessShutdownParameters (KERNEL32)
619 BOOL32 WINAPI SetProcessShutdownParameters(DWORD level,DWORD flags)
621 FIXME(process,"(%ld,0x%08lx): stub\n",level,flags);
622 return TRUE;
625 /***********************************************************************
626 * ReadProcessMemory (KERNEL32)
627 * FIXME: check this, if we ever run win32 binaries in different addressspaces
628 * ... and add a sizecheck
630 BOOL32 WINAPI ReadProcessMemory( HANDLE32 hProcess, LPCVOID lpBaseAddress,
631 LPVOID lpBuffer, DWORD nSize,
632 LPDWORD lpNumberOfBytesRead )
634 memcpy(lpBuffer,lpBaseAddress,nSize);
635 if (lpNumberOfBytesRead) *lpNumberOfBytesRead = nSize;
636 return TRUE;
639 /***********************************************************************
640 * WriteProcessMemory (KERNEL32)
641 * FIXME: check this, if we ever run win32 binaries in different addressspaces
642 * ... and add a sizecheck
644 BOOL32 WINAPI WriteProcessMemory(HANDLE32 hProcess, LPVOID lpBaseAddress,
645 LPVOID lpBuffer, DWORD nSize,
646 LPDWORD lpNumberOfBytesWritten )
648 memcpy(lpBaseAddress,lpBuffer,nSize);
649 if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = nSize;
650 return TRUE;
653 /***********************************************************************
654 * ConvertToGlobalHandle (KERNEL32)
655 * FIXME: this is not correctly implemented...
657 HANDLE32 WINAPI ConvertToGlobalHandle(HANDLE32 h)
659 FIXME(process,"(%d): stub\n",h);
660 return h;
663 /***********************************************************************
664 * RegisterServiceProcess (KERNEL32)
666 * A service process calls this function to ensure that it continues to run
667 * even after a user logged off.
669 DWORD RegisterServiceProcess(DWORD dwProcessId, DWORD dwType)
671 /* I don't think that Wine needs to do anything in that function */
672 return 1; /* success */
675 /***********************************************************************
676 * GetExitCodeProcess [KERNEL32.325]
678 * Gets termination status of specified process
680 * RETURNS
681 * Success: TRUE
682 * Failure: FALSE
684 * FIXME
685 * Should call SetLastError (but doesn't).
687 BOOL32 WINAPI GetExitCodeProcess(
688 HANDLE32 hProcess, /* [I] handle to the process */
689 LPDWORD lpExitCode) /* [O] address to receive termination status */
691 PDB32 *process;
693 if (!(process = PROCESS_GetPtr( hProcess, PROCESS_QUERY_INFORMATION )))
694 return FALSE;
695 if (lpExitCode) *lpExitCode = process->exit_code;
696 K32OBJ_DecCount( &process->header );
697 return TRUE;
700 /***********************************************************************
701 * GetProcessHeaps [KERNEL32.376]
703 DWORD WINAPI GetProcessHeaps(DWORD nrofheaps,HANDLE32 *heaps) {
704 FIXME(win32,"(%ld,%p), incomplete implementation.\n",nrofheaps,heaps);
706 if (nrofheaps) {
707 heaps[0] = GetProcessHeap();
708 /* ... probably SystemHeap too ? */
709 return 1;
711 /* number of available heaps */
712 return 1;