2 * Server-side process management
4 * Copyright (C) 1998 Alexandre Julliard
25 /* process structure */
27 static struct process initial_process
;
28 static struct process
*first_process
= &initial_process
;
29 static int running_processes
;
31 /* process operations */
33 static void process_dump( struct object
*obj
, int verbose
);
34 static int process_signaled( struct object
*obj
, struct thread
*thread
);
35 static void process_destroy( struct object
*obj
);
37 static const struct object_ops process_ops
=
52 /* initialization of a process structure */
53 static void init_process( struct process
*process
)
55 init_object( &process
->obj
, &process_ops
, NULL
);
58 process
->thread_list
= NULL
;
59 process
->debug_next
= NULL
;
60 process
->debug_prev
= NULL
;
61 process
->debugger
= NULL
;
62 process
->exit_code
= 0x103; /* STILL_ACTIVE */
63 process
->running_threads
= 0;
64 process
->priority
= NORMAL_PRIORITY_CLASS
;
65 process
->affinity
= 1;
67 process
->console_in
= NULL
;
68 process
->console_out
= NULL
;
70 gettimeofday( &process
->start_time
, NULL
);
71 /* alloc a handle for the process itself */
72 alloc_handle( process
, process
, PROCESS_ALL_ACCESS
, 0 );
75 /* create the initial process */
76 struct process
*create_initial_process(void)
78 struct new_process_request
*info
;
80 copy_handle_table( &initial_process
, NULL
);
81 init_process( &initial_process
);
83 if (!alloc_console( &initial_process
)) return NULL
;
84 if (!(info
= mem_alloc( sizeof(*info
) ))) return NULL
;
85 info
->start_flags
= STARTF_USESTDHANDLES
;
86 info
->hstdin
= alloc_handle( &initial_process
, initial_process
.console_in
,
87 GENERIC_READ
| GENERIC_WRITE
| SYNCHRONIZE
, 1 );
88 info
->hstdout
= alloc_handle( &initial_process
, initial_process
.console_out
,
89 GENERIC_READ
| GENERIC_WRITE
| SYNCHRONIZE
, 1 );
90 info
->hstderr
= alloc_handle( &initial_process
, initial_process
.console_out
,
91 GENERIC_READ
| GENERIC_WRITE
| SYNCHRONIZE
, 1 );
93 initial_process
.info
= info
;
94 grab_object( &initial_process
); /* so that we never free it */
95 return &initial_process
;
99 /* create a new process */
100 static struct process
*create_process( struct new_process_request
*req
)
102 struct process
*process
= NULL
;
103 struct process
*parent
= current
->process
;
105 if (!(process
= mem_alloc( sizeof(*process
) ))) return NULL
;
106 if (!copy_handle_table( process
, req
->inherit_all
? parent
: NULL
))
111 init_process( process
);
113 if (!(process
->info
= mem_alloc( sizeof(*process
->info
) ))) goto error
;
114 memcpy( process
->info
, req
, sizeof(*req
) );
116 /* set the process console */
117 if (req
->create_flags
& CREATE_NEW_CONSOLE
)
119 if (!alloc_console( process
)) goto error
;
121 else if (!(req
->create_flags
& DETACHED_PROCESS
))
123 if (parent
->console_in
) process
->console_in
= grab_object( parent
->console_in
);
124 if (parent
->console_out
) process
->console_out
= grab_object( parent
->console_out
);
127 if (!req
->inherit_all
&& !(req
->start_flags
& STARTF_USESTDHANDLES
))
129 process
->info
->hstdin
= duplicate_handle( parent
, req
->hstdin
, process
,
130 0, TRUE
, DUPLICATE_SAME_ACCESS
);
131 process
->info
->hstdout
= duplicate_handle( parent
, req
->hstdout
, process
,
132 0, TRUE
, DUPLICATE_SAME_ACCESS
);
133 process
->info
->hstderr
= duplicate_handle( parent
, req
->hstderr
, process
,
134 0, TRUE
, DUPLICATE_SAME_ACCESS
);
137 /* attach to the debugger if requested */
138 if (req
->create_flags
& DEBUG_PROCESS
)
139 debugger_attach( process
, current
);
140 else if (parent
->debugger
&& !(req
->create_flags
& DEBUG_ONLY_THIS_PROCESS
))
141 debugger_attach( process
, parent
->debugger
);
143 process
->next
= first_process
;
144 first_process
->prev
= process
;
145 first_process
= process
;
149 release_object( process
);
153 /* destroy a process when its refcount is 0 */
154 static void process_destroy( struct object
*obj
)
156 struct process
*process
= (struct process
*)obj
;
157 assert( obj
->ops
== &process_ops
);
158 assert( process
!= &initial_process
);
160 /* we can't have a thread remaining */
161 assert( !process
->thread_list
);
162 if (process
->next
) process
->next
->prev
= process
->prev
;
163 if (process
->prev
) process
->prev
->next
= process
->next
;
164 else first_process
= process
->next
;
165 free_console( process
);
166 free_handles( process
);
167 if (process
->info
) free( process
->info
);
168 if (debug_level
) memset( process
, 0xbb, sizeof(process
) ); /* catch errors */
172 /* dump a process on stdout for debugging purposes */
173 static void process_dump( struct object
*obj
, int verbose
)
175 struct process
*process
= (struct process
*)obj
;
176 assert( obj
->ops
== &process_ops
);
178 printf( "Process next=%p prev=%p\n", process
->next
, process
->prev
);
181 static int process_signaled( struct object
*obj
, struct thread
*thread
)
183 struct process
*process
= (struct process
*)obj
;
184 return !process
->running_threads
;
188 /* get a process from an id (and increment the refcount) */
189 struct process
*get_process_from_id( void *id
)
191 struct process
*p
= first_process
;
192 while (p
&& (p
!= id
)) p
= p
->next
;
193 if (p
) grab_object( p
);
194 else SET_ERROR( ERROR_INVALID_PARAMETER
);
198 /* get a process from a handle (and increment the refcount) */
199 struct process
*get_process_from_handle( int handle
, unsigned int access
)
201 return (struct process
*)get_handle_obj( current
->process
, handle
,
202 access
, &process_ops
);
205 /* retrieve the initialization info for a new process */
206 static int get_process_init_info( struct process
*process
, struct init_process_reply
*reply
)
208 struct new_process_request
*info
;
209 if (!(info
= process
->info
)) return 0;
210 process
->info
= NULL
;
211 reply
->start_flags
= info
->start_flags
;
212 reply
->hstdin
= info
->hstdin
;
213 reply
->hstdout
= info
->hstdout
;
214 reply
->hstderr
= info
->hstderr
;
215 reply
->env_ptr
= info
->env_ptr
;
220 /* a process has been killed (i.e. its last thread died) */
221 static void process_killed( struct process
*process
, int exit_code
)
223 assert( !process
->thread_list
);
224 process
->exit_code
= exit_code
;
225 gettimeofday( &process
->end_time
, NULL
);
226 wake_up( &process
->obj
, 0 );
227 free_handles( process
);
230 /* add a thread to a process running threads list */
231 void add_process_thread( struct process
*process
, struct thread
*thread
)
233 thread
->proc_next
= process
->thread_list
;
234 thread
->proc_prev
= NULL
;
235 if (thread
->proc_next
) thread
->proc_next
->proc_prev
= thread
;
236 process
->thread_list
= thread
;
237 if (!process
->running_threads
++) running_processes
++;
238 grab_object( thread
);
241 /* remove a thread from a process running threads list */
242 void remove_process_thread( struct process
*process
, struct thread
*thread
)
244 assert( process
->running_threads
> 0 );
245 assert( process
->thread_list
);
247 if (thread
->proc_next
) thread
->proc_next
->proc_prev
= thread
->proc_prev
;
248 if (thread
->proc_prev
) thread
->proc_prev
->proc_next
= thread
->proc_next
;
249 else process
->thread_list
= thread
->proc_next
;
251 if (!--process
->running_threads
)
253 /* we have removed the last running thread, exit the process */
255 process_killed( process
, thread
->exit_code
);
257 release_object( thread
);
260 /* suspend all the threads of a process */
261 void suspend_process( struct process
*process
)
263 if (!process
->suspend
++)
265 struct thread
*thread
= process
->thread_list
;
266 for (; thread
; thread
= thread
->proc_next
)
268 if (!thread
->suspend
&& thread
->unix_pid
)
269 kill( thread
->unix_pid
, SIGSTOP
);
274 /* resume all the threads of a process */
275 void resume_process( struct process
*process
)
277 assert (process
->suspend
> 0);
278 if (!--process
->suspend
)
280 struct thread
*thread
= process
->thread_list
;
281 for (; thread
; thread
= thread
->proc_next
)
283 if (!thread
->suspend
&& thread
->unix_pid
)
284 kill( thread
->unix_pid
, SIGCONT
);
289 /* kill a process on the spot */
290 void kill_process( struct process
*process
, int exit_code
)
292 while (process
->thread_list
)
293 kill_thread( process
->thread_list
, exit_code
);
296 /* get all information about a process */
297 static void get_process_info( struct process
*process
,
298 struct get_process_info_reply
*reply
)
300 reply
->pid
= process
;
301 reply
->exit_code
= process
->exit_code
;
302 reply
->priority
= process
->priority
;
303 reply
->process_affinity
= process
->affinity
;
304 reply
->system_affinity
= 1;
307 /* set all information about a process */
308 static void set_process_info( struct process
*process
,
309 struct set_process_info_request
*req
)
311 if (req
->mask
& SET_PROCESS_INFO_PRIORITY
)
312 process
->priority
= req
->priority
;
313 if (req
->mask
& SET_PROCESS_INFO_AFFINITY
)
315 if (req
->affinity
!= 1) SET_ERROR( ERROR_INVALID_PARAMETER
);
316 else process
->affinity
= req
->affinity
;
320 /* allocate a console for this process */
321 int alloc_console( struct process
*process
)
323 struct object
*obj
[2];
324 if (process
->console_in
|| process
->console_out
)
326 SET_ERROR( ERROR_ACCESS_DENIED
);
329 if (!create_console( -1, obj
)) return 0;
330 process
->console_in
= obj
[0];
331 process
->console_out
= obj
[1];
335 /* free the console for this process */
336 int free_console( struct process
*process
)
338 if (process
->console_in
) release_object( process
->console_in
);
339 if (process
->console_out
) release_object( process
->console_out
);
340 process
->console_in
= process
->console_out
= NULL
;
344 /* get the process console */
345 struct object
*get_console( struct process
*process
, int output
)
348 if (!(obj
= output
? process
->console_out
: process
->console_in
))
350 return grab_object( obj
);
353 /* take a snapshot of currently running processes */
354 struct process_snapshot
*process_snap( int *count
)
356 struct process_snapshot
*snapshot
, *ptr
;
357 struct process
*process
;
358 if (!running_processes
) return NULL
;
359 if (!(snapshot
= mem_alloc( sizeof(*snapshot
) * running_processes
)))
362 for (process
= first_process
; process
; process
= process
->next
)
364 if (!process
->running_threads
) continue;
365 ptr
->process
= process
;
366 ptr
->threads
= process
->running_threads
;
367 ptr
->priority
= process
->priority
;
368 grab_object( process
);
371 *count
= running_processes
;
375 /* create a new process */
376 DECL_HANDLER(new_process
)
378 struct new_process_reply reply
;
379 struct process
*process
;
381 if ((process
= create_process( req
)))
384 reply
.handle
= alloc_handle( current
->process
, process
,
385 PROCESS_ALL_ACCESS
, req
->inherit
);
386 release_object( process
);
393 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
396 /* initialize a new process */
397 DECL_HANDLER(init_process
)
399 struct init_process_reply reply
;
400 if (current
->state
!= RUNNING
)
402 fatal_protocol_error( "init_process: init_thread not called yet\n" );
405 if (!get_process_init_info( current
->process
, &reply
))
407 fatal_protocol_error( "init_process: called twice\n" );
410 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
413 /* open a handle to a process */
414 DECL_HANDLER(open_process
)
416 struct open_process_reply reply
= { -1 };
417 struct process
*process
= get_process_from_id( req
->pid
);
420 reply
.handle
= alloc_handle( current
->process
, process
,
421 req
->access
, req
->inherit
);
422 release_object( process
);
424 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
427 /* terminate a process */
428 DECL_HANDLER(terminate_process
)
430 struct process
*process
;
432 if ((process
= get_process_from_handle( req
->handle
, PROCESS_TERMINATE
)))
434 kill_process( process
, req
->exit_code
);
435 release_object( process
);
437 if (current
) send_reply( current
, -1, 0 );
440 /* fetch information about a process */
441 DECL_HANDLER(get_process_info
)
443 struct process
*process
;
444 struct get_process_info_reply reply
= { 0, 0, 0 };
446 if ((process
= get_process_from_handle( req
->handle
, PROCESS_QUERY_INFORMATION
)))
448 get_process_info( process
, &reply
);
449 release_object( process
);
451 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
454 /* set information about a process */
455 DECL_HANDLER(set_process_info
)
457 struct process
*process
;
459 if ((process
= get_process_from_handle( req
->handle
, PROCESS_SET_INFORMATION
)))
461 set_process_info( process
, req
);
462 release_object( process
);
464 send_reply( current
, -1, 0 );