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