Fixed small ==, != mixup.
[wine] / server / process.c
1 /*
2  * Server-side process management
3  *
4  * Copyright (C) 1998 Alexandre Julliard
5  */
6
7 #include <assert.h>
8 #include <limits.h>
9 #include <string.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <sys/time.h>
13 #include <unistd.h>
14
15 #include "winerror.h"
16 #include "winbase.h"
17 #include "winnt.h"
18
19 #include "server.h"
20 #include "server/process.h"
21 #include "server/thread.h"
22
23 /* reserved handle access rights */
24 #define RESERVED_SHIFT         25
25 #define RESERVED_INHERIT       (HANDLE_FLAG_INHERIT << RESERVED_SHIFT)
26 #define RESERVED_CLOSE_PROTECT (HANDLE_FLAG_PROTECT_FROM_CLOSE << RESERVED_SHIFT)
27 #define RESERVED_ALL           (RESERVED_INHERIT | RESERVED_CLOSE_PROTECT)
28
29 /* global handle macros */
30 #define HANDLE_OBFUSCATOR         0x544a4def
31 #define HANDLE_IS_GLOBAL(h)       (((h) ^ HANDLE_OBFUSCATOR) < 0x10000)
32 #define HANDLE_LOCAL_TO_GLOBAL(h) ((h) ^ HANDLE_OBFUSCATOR)
33 #define HANDLE_GLOBAL_TO_LOCAL(h) ((h) ^ HANDLE_OBFUSCATOR)
34
35 struct handle_entry
36 {
37     struct object *ptr;
38     unsigned int   access;
39 };
40
41 /* process structure */
42 struct process
43 {
44     struct object        obj;             /* object header */
45     struct process      *next;            /* system-wide process list */
46     struct process      *prev;
47     struct thread       *thread_list;     /* head of the thread list */
48     struct handle_entry *entries;         /* handle entry table */
49     int                  handle_count;    /* nb of allocated handle entries */
50     int                  handle_last;     /* last used handle entry */
51     int                  exit_code;       /* process exit code */
52     int                  running_threads; /* number of threads running in this process */
53     struct timeval       start_time;      /* absolute time at process start */
54     struct timeval       end_time;        /* absolute time at process end */
55     int                  priority;        /* priority class */
56     int                  affinity;        /* process affinity mask */
57     struct object       *console_in;      /* console input */
58     struct object       *console_out;     /* console output */
59     struct new_process_request *info;     /* startup info (freed after startup) */
60 };
61
62
63 static struct process initial_process;
64 static struct process *first_process = &initial_process;
65 static int running_processes;
66
67 #define MIN_HANDLE_ENTRIES  32
68
69 /* process operations */
70
71 static void process_dump( struct object *obj, int verbose );
72 static int process_signaled( struct object *obj, struct thread *thread );
73 static void process_destroy( struct object *obj );
74 static void free_handles( struct process *process );
75 static int copy_handle_table( struct process *process, struct process *parent );
76
77 static const struct object_ops process_ops =
78 {
79     process_dump,
80     add_queue,
81     remove_queue,
82     process_signaled,
83     no_satisfied,
84     no_read_fd,
85     no_write_fd,
86     no_flush,
87     no_get_file_info,
88     process_destroy
89 };
90
91
92 /* initialization of a process structure */
93 static void init_process( struct process *process )
94 {
95     init_object( &process->obj, &process_ops, NULL );
96     process->next            = NULL;
97     process->prev            = NULL;
98     process->thread_list     = NULL;
99     process->exit_code       = 0x103;  /* STILL_ACTIVE */
100     process->running_threads = 0;
101     process->priority        = NORMAL_PRIORITY_CLASS;
102     process->affinity        = 1;
103     process->console_in      = NULL;
104     process->console_out     = NULL;
105     process->info            = NULL;
106     gettimeofday( &process->start_time, NULL );
107     /* alloc a handle for the process itself */
108     alloc_handle( process, process, PROCESS_ALL_ACCESS, 0 );
109 }
110
111 /* create the initial process */
112 struct process *create_initial_process(void)
113 {
114     struct new_process_request *info;
115
116     copy_handle_table( &initial_process, NULL );
117     init_process( &initial_process );
118
119     if (!alloc_console( &initial_process )) return NULL;
120     if (!(info = mem_alloc( sizeof(*info) ))) return NULL;
121     info->start_flags = STARTF_USESTDHANDLES;
122     info->hstdin  = alloc_handle( &initial_process, initial_process.console_in,
123                                   GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
124     info->hstdout = alloc_handle( &initial_process, initial_process.console_out,
125                                   GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
126     info->hstderr = alloc_handle( &initial_process, initial_process.console_out,
127                                   GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
128     initial_process.info = info;
129     grab_object( &initial_process ); /* so that we never free it */
130     return &initial_process;
131
132 }
133
134 /* create a new process */
135 struct process *create_process( struct new_process_request *req )
136 {
137     struct process *process = NULL;
138     struct process *parent = current->process;
139
140     if (!(process = mem_alloc( sizeof(*process) ))) return NULL;
141     if (!copy_handle_table( process, req->inherit_all ? parent : NULL ))
142     {
143         free( process );
144         return NULL;
145     }
146     init_process( process );
147     if (parent->console_in) process->console_in = grab_object( parent->console_in );
148     if (parent->console_out) process->console_out = grab_object( parent->console_out );
149
150     if (!(process->info = mem_alloc( sizeof(*process->info) ))) goto error;
151     memcpy( process->info, req, sizeof(*req) );
152
153     if (!req->inherit_all && !(req->start_flags & STARTF_USESTDHANDLES))
154     {
155         process->info->hstdin  = duplicate_handle( parent, req->hstdin, process,
156                                                    0, TRUE, DUPLICATE_SAME_ACCESS );
157         process->info->hstdout = duplicate_handle( parent, req->hstdout, process,
158                                                    0, TRUE, DUPLICATE_SAME_ACCESS );
159         process->info->hstderr = duplicate_handle( parent, req->hstderr, process,
160                                                    0, TRUE, DUPLICATE_SAME_ACCESS );
161     }
162
163     process->next = first_process;
164     first_process->prev = process;
165     first_process = process;
166     return process;
167
168  error:
169     release_object( process );
170     return NULL;
171 }
172
173 /* destroy a process when its refcount is 0 */
174 static void process_destroy( struct object *obj )
175 {
176     struct process *process = (struct process *)obj;
177     assert( obj->ops == &process_ops );
178     assert( process != &initial_process );
179
180     /* we can't have a thread remaining */
181     assert( !process->thread_list );
182     if (process->next) process->next->prev = process->prev;
183     if (process->prev) process->prev->next = process->next;
184     else first_process = process->next;
185     free_console( process );
186     free_handles( process );
187     if (process->info) free( process->info );
188     if (debug_level) memset( process, 0xbb, sizeof(process) );  /* catch errors */
189     free( process );
190 }
191
192 /* dump a process on stdout for debugging purposes */
193 static void process_dump( struct object *obj, int verbose )
194 {
195     struct process *process = (struct process *)obj;
196     assert( obj->ops == &process_ops );
197
198     printf( "Process next=%p prev=%p\n", process->next, process->prev );
199 }
200
201 static int process_signaled( struct object *obj, struct thread *thread )
202 {
203     struct process *process = (struct process *)obj;
204     return !process->running_threads;
205 }
206
207
208 /* get a process from an id (and increment the refcount) */
209 struct process *get_process_from_id( void *id )
210 {
211     struct process *p = first_process;
212     while (p && (p != id)) p = p->next;
213     if (p) grab_object( p );
214     else SET_ERROR( ERROR_INVALID_PARAMETER );
215     return p;
216 }
217
218 /* get a process from a handle (and increment the refcount) */
219 struct process *get_process_from_handle( int handle, unsigned int access )
220 {
221     return (struct process *)get_handle_obj( current->process, handle,
222                                              access, &process_ops );
223 }
224
225 /* retrieve the initialization info for a new process */
226 int get_process_init_info( struct process *process, struct init_process_reply *reply )
227 {
228     struct new_process_request *info;
229     if (!(info = process->info)) return 0;
230     process->info = NULL;
231     reply->start_flags = info->start_flags;
232     reply->hstdin      = info->hstdin;
233     reply->hstdout     = info->hstdout;
234     reply->hstderr     = info->hstderr;
235     free( info );
236     return 1;
237 }
238
239 /* a process has been killed (i.e. its last thread died) */
240 static void process_killed( struct process *process, int exit_code )
241 {
242     assert( !process->thread_list );
243     process->exit_code = exit_code;
244     gettimeofday( &process->end_time, NULL );
245     wake_up( &process->obj, 0 );
246     free_handles( process );
247 }
248
249 /* free the process handle entries */
250 static void free_handles( struct process *process )
251 {
252     struct handle_entry *entry;
253     int handle;
254
255     if (!(entry = process->entries)) return;
256     for (handle = 0; handle <= process->handle_last; handle++, entry++)
257     {
258         struct object *obj = entry->ptr;
259         entry->ptr = NULL;
260         if (obj) release_object( obj );
261     }
262     free( process->entries );
263     process->handle_count = 0;
264     process->handle_last  = -1;
265     process->entries = NULL;
266 }
267
268 /* add a thread to a process running threads list */
269 void add_process_thread( struct process *process, struct thread *thread )
270 {
271     thread->proc_next = process->thread_list;
272     thread->proc_prev = NULL;
273     if (thread->proc_next) thread->proc_next->proc_prev = thread;
274     process->thread_list = thread;
275     if (!process->running_threads++) running_processes++;
276     grab_object( thread );
277 }
278
279 /* remove a thread from a process running threads list */
280 void remove_process_thread( struct process *process, struct thread *thread )
281 {
282     assert( process->running_threads > 0 );
283     assert( process->thread_list );
284
285     if (thread->proc_next) thread->proc_next->proc_prev = thread->proc_prev;
286     if (thread->proc_prev) thread->proc_prev->proc_next = thread->proc_next;
287     else process->thread_list = thread->proc_next;
288
289     if (!--process->running_threads)
290     {
291         /* we have removed the last running thread, exit the process */
292         running_processes--;
293         process_killed( process, thread->exit_code );
294     }
295     release_object( thread );
296 }
297
298 /* grow a handle table */
299 /* return 1 if OK, 0 on error */
300 static int grow_handle_table( struct process *process )
301 {
302     struct handle_entry *new_entries;
303     int count = process->handle_count;
304
305     if (count >= INT_MAX / 2) return 0;
306     count *= 2;
307     if (!(new_entries = realloc( process->entries, count * sizeof(struct handle_entry) )))
308     {
309         SET_ERROR( ERROR_OUTOFMEMORY );
310         return 0;
311     }
312     process->handle_count = count;
313     process->entries      = new_entries;
314     return 1;
315 }
316
317 /* allocate a handle for an object, incrementing its refcount */
318 /* return the handle, or -1 on error */
319 int alloc_handle( struct process *process, void *obj, unsigned int access,
320                   int inherit )
321 {
322     struct handle_entry *entry;
323     int handle;
324
325     assert( !(access & RESERVED_ALL) );
326     if (inherit) access |= RESERVED_INHERIT;
327
328     /* find the first free entry */
329
330     if (!(entry = process->entries)) return -1;
331     for (handle = 0; handle <= process->handle_last; handle++, entry++)
332         if (!entry->ptr) goto found;
333
334     if (handle >= process->handle_count)
335     {
336         if (!grow_handle_table( process )) return -1;
337         entry = process->entries + handle;  /* the table may have moved */
338     }
339     process->handle_last = handle;
340
341  found:
342     entry->ptr    = grab_object( obj );
343     entry->access = access;
344     return handle + 1;  /* avoid handle 0 */
345 }
346
347 /* return an handle entry, or NULL if the handle is invalid */
348 static struct handle_entry *get_handle( struct process *process, int handle )
349 {
350     struct handle_entry *entry;
351
352     if (HANDLE_IS_GLOBAL(handle))
353     {
354         handle = HANDLE_GLOBAL_TO_LOCAL(handle);
355         process = &initial_process;
356     }
357     handle--;  /* handles start at 1 */
358     if ((handle < 0) || (handle > process->handle_last)) goto error;
359     entry = process->entries + handle;
360     if (!entry->ptr) goto error;
361     return entry;
362
363  error:
364     SET_ERROR( ERROR_INVALID_HANDLE );
365     return NULL;
366 }
367
368 /* attempt to shrink a table */
369 /* return 1 if OK, 0 on error */
370 static int shrink_handle_table( struct process *process )
371 {
372     struct handle_entry *new_entries;
373     struct handle_entry *entry = process->entries + process->handle_last;
374     int count = process->handle_count;
375
376     while (process->handle_last >= 0)
377     {
378         if (entry->ptr) break;
379         process->handle_last--;
380         entry--;
381     }
382     if (process->handle_last >= count / 4) return 1;  /* no need to shrink */
383     if (count < MIN_HANDLE_ENTRIES * 2) return 1;  /* too small to shrink */
384     count /= 2;
385     if (!(new_entries = realloc( process->entries,
386                                  count * sizeof(struct handle_entry) )))
387         return 0;
388     process->handle_count = count;
389     process->entries      = new_entries;
390     return 1;
391 }
392
393 /* copy the handle table of the parent process */
394 /* return 1 if OK, 0 on error */
395 static int copy_handle_table( struct process *process, struct process *parent )
396 {
397     struct handle_entry *ptr;
398     int i, count, last;
399
400     if (!parent)  /* first process */
401     {
402         count = MIN_HANDLE_ENTRIES;
403         last  = -1;
404     }
405     else
406     {
407         assert( parent->entries );
408         count = parent->handle_count;
409         last  = parent->handle_last;
410     }
411
412     if (!(ptr = mem_alloc( count * sizeof(struct handle_entry)))) return 0;
413     process->entries      = ptr;
414     process->handle_count = count;
415     process->handle_last  = last;
416
417     if (last >= 0)
418     {
419         memcpy( ptr, parent->entries, (last + 1) * sizeof(struct handle_entry) );
420         for (i = 0; i <= last; i++, ptr++)
421         {
422             if (!ptr->ptr) continue;
423             if (ptr->access & RESERVED_INHERIT) grab_object( ptr->ptr );
424             else ptr->ptr = NULL; /* don't inherit this entry */
425         }
426     }
427     /* attempt to shrink the table */
428     shrink_handle_table( process );
429     return 1;
430 }
431
432 /* close a handle and decrement the refcount of the associated object */
433 /* return 1 if OK, 0 on error */
434 int close_handle( struct process *process, int handle )
435 {
436     struct handle_entry *entry;
437     struct object *obj;
438
439     if (HANDLE_IS_GLOBAL(handle))
440     {
441         handle = HANDLE_GLOBAL_TO_LOCAL(handle);
442         process = &initial_process;
443     }
444     if (!(entry = get_handle( process, handle ))) return 0;
445     if (entry->access & RESERVED_CLOSE_PROTECT) return 0;  /* FIXME: error code */
446     obj = entry->ptr;
447     entry->ptr = NULL;
448     if (handle-1 == process->handle_last) shrink_handle_table( process );
449     release_object( obj );
450     return 1;
451 }
452
453 /* retrieve the object corresponding to a handle, incrementing its refcount */
454 struct object *get_handle_obj( struct process *process, int handle,
455                                unsigned int access, const struct object_ops *ops )
456 {
457     struct handle_entry *entry;
458     struct object *obj;
459
460     switch( handle )
461     {
462     case 0xfffffffe:  /* current thread pseudo-handle */
463         obj = &current->obj;
464         break;
465     case 0x7fffffff:  /* current process pseudo-handle */
466         obj = (struct object *)current->process;
467         break;
468     default:
469         if (!(entry = get_handle( process, handle ))) return NULL;
470         if ((entry->access & access) != access)
471         {
472             SET_ERROR( ERROR_ACCESS_DENIED );
473             return NULL;
474         }
475         obj = entry->ptr;
476         break;
477     }
478     if (ops && (obj->ops != ops))
479     {
480         SET_ERROR( ERROR_INVALID_HANDLE );  /* not the right type */
481         return NULL;
482     }
483     return grab_object( obj );
484 }
485
486 /* get/set the handle reserved flags */
487 /* return the new flags (or -1 on error) */
488 int set_handle_info( struct process *process, int handle, int mask, int flags )
489 {
490     struct handle_entry *entry;
491
492     if (!(entry = get_handle( process, handle ))) return -1;
493     mask  = (mask << RESERVED_SHIFT) & RESERVED_ALL;
494     flags = (flags << RESERVED_SHIFT) & mask;
495     entry->access = (entry->access & ~mask) | flags;
496     return (entry->access & RESERVED_ALL) >> RESERVED_SHIFT;
497 }
498
499 /* duplicate a handle */
500 int duplicate_handle( struct process *src, int src_handle, struct process *dst,
501                       unsigned int access, int inherit, int options )
502 {
503     int res;
504     struct handle_entry *entry = get_handle( src, src_handle );
505     if (!entry) return -1;
506
507     if (options & DUP_HANDLE_SAME_ACCESS) access = entry->access;
508     if (options & DUP_HANDLE_MAKE_GLOBAL) dst = &initial_process;
509     access &= ~RESERVED_ALL;
510     res = alloc_handle( dst, entry->ptr, access, inherit );
511     if (options & DUP_HANDLE_MAKE_GLOBAL) res = HANDLE_LOCAL_TO_GLOBAL(res);
512     return res;
513 }
514
515 /* open a new handle to an existing object */
516 int open_object( const char *name, const struct object_ops *ops,
517                  unsigned int access, int inherit )
518 {
519     struct object *obj = find_object( name );
520     if (!obj) 
521     {
522         SET_ERROR( ERROR_FILE_NOT_FOUND );
523         return -1;
524     }
525     if (ops && obj->ops != ops)
526     {
527         release_object( obj );
528         SET_ERROR( ERROR_INVALID_HANDLE );  /* FIXME: not the right type */ 
529         return -1;
530     }
531     return alloc_handle( current->process, obj, access, inherit );
532 }
533
534 /* dump a handle table on stdout */
535 void dump_handles( struct process *process )
536 {
537     struct handle_entry *entry;
538     int i;
539
540     if (!process->entries) return;
541     entry = process->entries;
542     for (i = 0; i <= process->handle_last; i++, entry++)
543     {
544         if (!entry->ptr) continue;
545         printf( "%5d: %p %08x ", i + 1, entry->ptr, entry->access );
546         entry->ptr->ops->dump( entry->ptr, 0 );
547     }
548 }
549
550 /* kill a process on the spot */
551 void kill_process( struct process *process, int exit_code )
552 {
553     while (process->thread_list)
554         kill_thread( process->thread_list, exit_code );
555 }
556
557 /* get all information about a process */
558 void get_process_info( struct process *process,
559                        struct get_process_info_reply *reply )
560 {
561     reply->pid              = process;
562     reply->exit_code        = process->exit_code;
563     reply->priority         = process->priority;
564     reply->process_affinity = process->affinity;
565     reply->system_affinity  = 1;
566 }
567
568 /* set all information about a process */
569 void set_process_info( struct process *process,
570                        struct set_process_info_request *req )
571 {
572     if (req->mask & SET_PROCESS_INFO_PRIORITY)
573         process->priority = req->priority;
574     if (req->mask & SET_PROCESS_INFO_AFFINITY)
575     {
576         if (req->affinity != 1) SET_ERROR( ERROR_INVALID_PARAMETER );
577         else process->affinity = req->affinity;
578     }
579 }
580
581 /* allocate a console for this process */
582 int alloc_console( struct process *process )
583 {
584     struct object *obj[2];
585     if (process->console_in || process->console_out)
586     {
587         SET_ERROR( ERROR_ACCESS_DENIED );
588         return 0;
589     }
590     if (!create_console( -1, obj )) return 0;
591     process->console_in  = obj[0];
592     process->console_out = obj[1];
593     return 1;
594 }
595
596 /* free the console for this process */
597 int free_console( struct process *process )
598 {
599     if (process->console_in) release_object( process->console_in );
600     if (process->console_out) release_object( process->console_out );
601     process->console_in = process->console_out = NULL;
602     return 1;
603 }
604
605 /* get the process console */
606 struct object *get_console( struct process *process, int output )
607 {
608     struct object *obj;
609     if (!(obj = output ? process->console_out : process->console_in))
610         return NULL;
611     return grab_object( obj );
612 }
613
614 /* take a snapshot of currently running processes */
615 struct process_snapshot *process_snap( int *count )
616 {
617     struct process_snapshot *snapshot, *ptr;
618     struct process *process;
619     if (!running_processes) return NULL;
620     if (!(snapshot = mem_alloc( sizeof(*snapshot) * running_processes )))
621         return NULL;
622     ptr = snapshot;
623     for (process = first_process; process; process = process->next)
624     {
625         if (!process->running_threads) continue;
626         ptr->process  = process;
627         ptr->threads  = process->running_threads;
628         ptr->priority = process->priority;
629         grab_object( process );
630         ptr++;
631     }
632     *count = running_processes;
633     return snapshot;
634 }